Bläddra i källkod

v3.5.0: 新增了一些功能,详细见【更新日志】

sansan 5 månader sedan
förälder
incheckning
e6b95ada77
13 ändrade filer med 2630 tillägg och 398 borttagningar
  1. 84 9
      .github/workflows/docker.yml
  2. 863 64
      README-EN.md
  3. 844 73
      README.md
  4. 27 9
      config/config.yaml
  5. 35 9
      docker/.env
  6. 18 19
      docker/Dockerfile
  7. 23 0
      docker/Dockerfile.mcp
  8. 26 0
      docker/docker-compose-build.yml
  9. 24 0
      docker/docker-compose.yml
  10. 7 1
      docker/entrypoint.sh
  11. 167 14
      docker/manage.py
  12. 511 199
      main.py
  13. 1 1
      version

+ 84 - 9
.github/workflows/docker.yml

@@ -1,17 +1,33 @@
-name: Build and Push Multi-Arch Docker Images
+name: Build and Push Docker Images
 
 on:
   push:
-    tags: ["v*"]
+    tags:
+      - "v*" # 主项目版本
+      - "mcp-v*" # MCP 版本
   workflow_dispatch:
+    inputs:
+      image:
+        description: "选择要构建的镜像"
+        required: true
+        default: "all"
+        type: choice
+        options:
+          - all
+          - crawler
+          - mcp
 
 env:
   REGISTRY: docker.io
-  IMAGE_NAME: wantcat/trendradar
 
 jobs:
-  build:
+  build-crawler:
     runs-on: ubuntu-latest
+    # 条件:v* 标签(排除 mcp-v*)或手动触发选择 all/crawler
+    if: |
+      (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && !startsWith(github.ref, 'refs/tags/mcp-v')) ||
+      (github.event_name == 'workflow_dispatch' && (github.event.inputs.image == 'all' || github.event.inputs.image == 'crawler'))
+
     steps:
       - name: Checkout
         uses: actions/checkout@v4
@@ -35,12 +51,11 @@ jobs:
         id: meta
         uses: docker/metadata-action@v5
         with:
-          images: ${{ env.IMAGE_NAME }}
+          images: wantcat/trendradar
           tags: |
-            type=ref,event=branch
             type=semver,pattern={{version}}
             type=semver,pattern={{major}}.{{minor}}
-            type=raw,value=latest,enable={{is_default_branch}}
+            type=raw,value=latest
 
       - name: Build and push
         uses: docker/build-push-action@v5
@@ -55,5 +70,65 @@ jobs:
           labels: ${{ steps.meta.outputs.labels }}
           cache-from: type=gha
           cache-to: type=gha,mode=max
-          build-args: |
-            BUILDKIT_INLINE_CACHE=1
+
+  build-mcp:
+    runs-on: ubuntu-latest
+    # 条件:mcp-v* 标签 或手动触发选择 all/mcp
+    if: |
+      (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/mcp-v')) ||
+      (github.event_name == 'workflow_dispatch' && (github.event.inputs.image == 'all' || github.event.inputs.image == 'mcp'))
+
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4
+
+      - name: Set up QEMU
+        uses: docker/setup-qemu-action@v3
+
+      - name: Set up Docker Buildx
+        uses: docker/setup-buildx-action@v3
+        with:
+          driver-opts: |
+            network=host
+
+      - name: Login to Docker Hub
+        uses: docker/login-action@v3
+        with:
+          username: ${{ secrets.DOCKERHUB_USERNAME }}
+          password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+      - name: Extract version from tag
+        id: version
+        run: |
+          if [[ "${{ github.ref }}" == refs/tags/mcp-v* ]]; then
+            VERSION="${GITHUB_REF#refs/tags/mcp-v}"
+            echo "version=${VERSION}" >> $GITHUB_OUTPUT
+            echo "major_minor=$(echo $VERSION | cut -d. -f1,2)" >> $GITHUB_OUTPUT
+          else
+            echo "version=latest" >> $GITHUB_OUTPUT
+            echo "major_minor=latest" >> $GITHUB_OUTPUT
+          fi
+
+      - name: Extract metadata
+        id: meta
+        uses: docker/metadata-action@v5
+        with:
+          images: wantcat/trendradar-mcp
+          tags: |
+            type=raw,value=${{ steps.version.outputs.version }}
+            type=raw,value=${{ steps.version.outputs.major_minor }}
+            type=raw,value=latest
+
+      - name: Build and push
+        uses: docker/build-push-action@v5
+        env:
+          BUILDKIT_PROGRESS: plain
+        with:
+          context: .
+          file: ./docker/Dockerfile.mcp
+          platforms: linux/amd64,linux/arm64
+          push: true
+          tags: ${{ steps.meta.outputs.tags }}
+          labels: ${{ steps.meta.outputs.labels }}
+          cache-from: type=gha
+          cache-to: type=gha,mode=max

+ 863 - 64
README-EN.md

@@ -4,7 +4,7 @@
   <img src="/_image/banner.webp" alt="TrendRadar Banner" width="80%">
 </a>
 
-🚀 Deploy in <strong>30 seconds</strong> — Your Smart Trending News Assistant
+🚀 Deploy in <strong>30 seconds</strong> — Say goodbye to endless scrolling, only see the news you truly care about
 
 <a href="https://trendshift.io/repositories/14726" target="_blank"><img src="https://trendshift.io/api/badge/repositories/14726" alt="sansan0%2FTrendRadar | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
 
@@ -14,7 +14,7 @@
 [![GitHub Stars](https://img.shields.io/github/stars/sansan0/TrendRadar?style=flat-square&logo=github&color=yellow)](https://github.com/sansan0/TrendRadar/stargazers)
 [![GitHub Forks](https://img.shields.io/github/forks/sansan0/TrendRadar?style=flat-square&logo=github&color=blue)](https://github.com/sansan0/TrendRadar/network/members)
 [![License](https://img.shields.io/badge/license-GPL--3.0-blue.svg?style=flat-square)](LICENSE)
-[![Version](https://img.shields.io/badge/version-v3.4.1-blue.svg)](https://github.com/sansan0/TrendRadar)
+[![Version](https://img.shields.io/badge/version-v3.5.0-blue.svg)](https://github.com/sansan0/TrendRadar)
 [![MCP](https://img.shields.io/badge/MCP-v1.0.3-green.svg)](https://github.com/sansan0/TrendRadar)
 
 [![WeWork](https://img.shields.io/badge/WeWork-Notification-00D4AA?style=flat-square)](https://work.weixin.qq.com/)
@@ -44,6 +44,34 @@
 
 > This project is designed to be lightweight and easy to deploy
 
+<details>
+<summary>⚠️ Click to expand: <strong>Fork Guide: Docs, Resource Limits & Deployment Options</strong></summary>
+<br>
+
+**📄 Documentation Version:**
+
+If you use this project via **Fork**, you might be viewing outdated documentation. Fork copies the documentation version at that time, but the original project may have been updated.
+
+**👉 [Click to View Latest Official Documentation](https://github.com/sansan0/TrendRadar?tab=readme-ov-file)**
+
+**How to Tell?** Check the repository address at the top of the page:
+- `github.com/your-username/TrendRadar` ← Your forked version
+- `github.com/sansan0/TrendRadar` ← Latest official version
+
+---
+
+**🛡️ Resource Limits & Safety Tips:**
+
+GitHub provides limited Actions resources per account. To avoid being flagged for abuse and risking account suspension:
+
+- **Platform Count**: Keep it around **10 platforms** — more platforms consume more resources
+- **Run Frequency**: Minimum interval of **30 minutes** — more frequent runs are unnecessary
+- **Fair Use**: GitHub Actions is designed for lightweight scheduled tasks, not high-frequency crawlers
+
+💡 **Want more freedom?** Try [🐳 Docker Deployment](#6-docker-deployment) on your own server with no restrictions.
+
+</details>
+
 <br>
 
 ## 📑 Quick Navigation
@@ -156,23 +184,25 @@ Default monitoring of 11 mainstream platforms, with support for adding custom pl
 >
 > For detailed comparison and configuration, see [Configuration Guide - Push Mode Details](#3-push-mode-details)
 
-**Additional Feature - Push Time Window Control** (Optional):
+**Additional Features** (Optional):
 
-- Set push time range (e.g., 09:00-18:00), push only within specified time
-- Configure multiple pushes within window or once per day
-- Avoid notifications during non-work hours
+| Feature | Description | Default |
+|---------|-------------|---------|
+| **Push Time Window Control** | Set push time range (e.g., 09:00-18:00) to avoid non-work hours notifications | Disabled |
+| **Content Order Configuration** | Adjust display order of "Trending Keywords Stats" and "New Trending News" (v3.5.0 new) | Stats first |
 
-> 💡 This feature is disabled by default, see [Quick Start](#-quick-start) for configuration
+> 💡 For detailed configuration, see [Configuration Guide - Report Configuration](#7-report-configuration) and [Configuration Guide - Push Window](#8-push-window-configuration)
 
 ### **Precise Content Filtering**
 
 Set personal keywords (e.g., AI, BYD, Education Policy) to receive only relevant trending news, filtering out noise.
 
-**Basic Syntax** (4 types):
+**Basic Syntax** (5 types):
 - Normal words: Basic matching
 - Required words `+`: Narrow scope
 - Filter words `!`: Exclude noise
 - Count limit `@`: Control display count (v3.2.0 new)
+- Global filter `[GLOBAL_FILTER]`: Globally exclude specified content (v3.5.0 new)
 
 **Advanced Features** (v3.2.0 new):
 - 🔢 **Keyword Sorting Control**: Sort by popularity or config order
@@ -214,6 +244,14 @@ No longer controlled by platform algorithms, TrendRadar reorganizes all trending
 
 Supports **WeWork** (+ WeChat push solution), **Feishu**, **DingTalk**, **Telegram**, **Email**, **ntfy**, **Bark**, **Slack** — messages delivered directly to phone and email.
 
+**📌 Multi-Account Push Notes (v3.5.0 New Feature):**
+
+- ✅ **Multi-Account Configuration Support**: All push channels (Feishu, DingTalk, WeWork, Telegram, ntfy, Bark, Slack) support configuring multiple accounts
+- ✅ **Configuration Method**: Use English semicolon `;` to separate multiple account values
+- ✅ **Example**: Set `FEISHU_WEBHOOK_URL` Secret value to `https://webhook1;https://webhook2`
+- ⚠️ **Paired Configuration**: Telegram and ntfy require paired parameter quantities to match (e.g., token and chat_id both have 2 values)
+- ⚠️ **Quantity Limit**: Default maximum 3 accounts per channel, exceeded values will be truncated
+
 ### **Multi-Platform Support**
 - **GitHub Pages**: Auto-generate beautiful web reports, PC/mobile adapted
 - **Docker Deployment**: Supports multi-architecture containerized operation
@@ -272,6 +310,62 @@ Transform from "algorithm recommendation captivity" to "actively getting the inf
 - **Major Version Upgrade**: Upgrading from v1.x to v2.y, recommend deleting existing fork and re-forking to save effort and avoid config conflicts
 
 
+### 2025/12/03 - v3.5.0
+
+**🎉 Core Feature Enhancements**
+
+1. **Multi-Account Push Support**
+   - All push channels (Feishu, DingTalk, WeWork, Telegram, ntfy, Bark, Slack) support multiple account configuration
+   - Use semicolon `;` to separate multiple accounts, e.g., `FEISHU_WEBHOOK_URL=url1;url2`
+   - Automatic validation for paired configurations (e.g., Telegram's token and chat_id)
+
+2. **Configurable Push Content Order**
+   - Added `reverse_content_order` configuration option
+   - Customize display order of trending keywords stats and new trending news
+
+3. **Global Filter Keywords**
+   - Added `[GLOBAL_FILTER]` region marker for filtering unwanted content globally
+   - Use cases: Filter ads, marketing, low-quality content, etc.
+
+**🐳 Docker Dual-Path HTML Generation Optimization**
+
+- **Bug Fix**: Resolved issue where `index.html` could not sync to host in Docker environment
+- **Dual-Path Generation**: Daily summary HTML is generated to two locations simultaneously
+  - `index.html` (project root): For GitHub Pages access
+  - `output/index.html`: Accessible on host via Docker Volume mount
+- **Compatibility**: Ensures web reports are accessible in Docker, GitHub Actions, and local environments
+
+**🐳 Docker MCP Image Support**
+
+- Added independent MCP service image `wantcat/trendradar-mcp`
+- Supports Docker deployment of AI analysis features via HTTP interface (port 3333)
+- Dual-container architecture: News push service and MCP service run independently, can be scaled and restarted separately
+- See [Docker Deployment - MCP Service](#6-docker-deployment) for details
+
+**🌐 Web Server Support**
+
+- Added built-in web server for browser access to generated reports
+- Control via `manage.py` commands: `docker exec -it trend-radar python manage.py start_webserver`
+- Access URL: `http://localhost:8080` (port configurable)
+- Security features: Static file service, directory restriction, localhost binding
+- Supports both auto-start and manual control modes
+
+**📖 Documentation Optimization**
+
+- Added [Report Configuration](#7-report-configuration) section: report-related parameter details
+- Added [Push Window Configuration](#8-push-window-configuration) section: push_window configuration tutorial
+- Added [Execution Frequency Configuration](#9-execution-frequency-configuration) section: Cron expression explanation and common examples
+- Added [Multi-Account Push Configuration](#10-multiple-account-push-configuration) section: multi-account push configuration details
+- Optimized all configuration sections: Unified "Configuration Location" instructions
+- Simplified Quick Start configuration: Three core files at a glance
+- Optimized [Docker Deployment](#6-docker-deployment) section: Added image description, recommended git clone deployment, reorganized deployment methods
+
+**🔧 Upgrade Instructions**:
+- **GitHub Fork Users**: Update `main.py`, `config/config.yaml` (Added multi-account push support, existing single-account configuration unaffected)
+- **Docker Users**: Update `.env`, `docker-compose.yml` or set environment variables `REVERSE_CONTENT_ORDER`, `MAX_ACCOUNTS_PER_CHANNEL`
+- **Multi-Account Push**: New feature, disabled by default, existing single-account configuration unaffected
+
+
 ### 2025/11/28 - v3.4.1
 
 **🔧 Format Optimization**
@@ -705,6 +799,24 @@ frequency_words.txt file added **required word** feature, using + sign
    - ⚠️ **DO NOT Create Custom Names**: The Secret Name must **strictly use** the names listed below (e.g., `WEWORK_WEBHOOK_URL`, `FEISHU_WEBHOOK_URL`, etc.). Do not modify or create new names arbitrarily, or the system will not recognize them
    - 💡 **Can Configure Multiple Platforms**: The system will send notifications to all configured platforms
 
+   **📌 Multi-Account Push Notes (v3.5.0 New Feature):**
+
+   - ✅ **Multi-Account Configuration Support**: All push channels (Feishu, DingTalk, WeWork, Telegram, ntfy, Bark, Slack) support configuring multiple accounts
+   - ✅ **Configuration Method**: Use English semicolon `;` to separate multiple account values
+   - ✅ **Example**: Set `FEISHU_WEBHOOK_URL` Secret value to `https://webhook1;https://webhook2`
+   - ⚠️ **Paired Configuration**: Telegram and ntfy require paired parameter quantities to match (e.g., token and chat_id both have 2 values)
+   - ⚠️ **Quantity Limit**: Default maximum 3 accounts per channel, exceeded values will be truncated
+
+   **Multi-Account Configuration Examples**:
+
+   | Name | Secret (Value) Example |
+   |------|------------------------|
+   | `FEISHU_WEBHOOK_URL` | `https://webhook1;https://webhook2;https://webhook3` |
+   | `TELEGRAM_BOT_TOKEN` | `token1;token2` |
+   | `TELEGRAM_CHAT_ID` | `chatid1;chatid2` |
+   | `NTFY_TOPIC` | `topic1;topic2` |
+   | `NTFY_TOKEN` | `;token2` (1st has no token, use empty string as placeholder) |
+
    **Configuration Example:**
 
    <img src="_image/secrets.png" alt="GitHub Secrets Configuration Example"/>
@@ -1316,15 +1428,21 @@ frequency_words.txt file added **required word** feature, using + sign
    3. Click **"Run workflow"** button on the right to run
    4. Wait about 1 minute, messages will be pushed to your configured platform
 
+   > ⏱️ **Testing Tips**:
+   > - Don't test too frequently to avoid triggering GitHub Actions limits
+   > - After clicking Run workflow, you need to **refresh the browser page** to see the new run record
+
 4. **Configuration Notes (Optional)**:
 
-    > 💡 Default configuration works normally, only adjust if you need personalization
+    > 💡 **Default configuration works normally**, only adjust if you need personalization, understand these three files:
 
-    - **Push Settings**: Configure push mode and notification options in [config/config.yaml](config/config.yaml) → [Push Mode Details](#3-push-mode-details)
-    - **Keyword Settings**: Add your interested keywords in [config/frequency_words.txt](config/frequency_words.txt) → [Keyword Configuration Tutorial](#2-keyword-configuration)
-    - **Push Frequency Adjustment**: In [.github/workflows/crawler.yml](.github/workflows/crawler.yml) adjust carefully, don't be greedy
+    | File | Purpose |
+    |------|---------|
+    | `config/config.yaml` | Main config file: push mode, time window, platform list, hotspot weights, etc. |
+    | `config/frequency_words.txt` | Keyword file: set your interested keywords, filter push content |
+    | `.github/workflows/crawler.yml` | Execution frequency: control how often to run (⚠️ modify carefully) |
 
-    **Note**: Suggest only adjusting explicitly documented config items, other options mainly for author's development testing
+    👉 **Detailed Configuration Tutorial**: [Configuration Guide](#configuration-guide)
 
 5. **🎉 Deployment Success! Share Your Experience**
 
@@ -1365,6 +1483,8 @@ frequency_words.txt file added **required word** feature, using + sign
 <summary>👉 Click to expand: <strong>Custom Monitoring Platforms</strong></summary>
 <br>
 
+**Configuration Location:** `platforms` section in `config/config.yaml`
+
 This project's news data comes from [newsnow](https://github.com/ourongxing/newsnow). You can click the [website](https://newsnow.busiyi.world/), click [More], to see if there are platforms you want.
 
 For specific additions, visit [project source code](https://github.com/ourongxing/newsnow/tree/main/server/sources), based on the file names there, modify the `platforms` configuration in `config/config.yaml` file:
@@ -1379,13 +1499,18 @@ platforms:
     name: "Wallstreetcn"
   # Add more platforms...
 ```
-If you don't know how to look, you can directly copy the partially organized [Platform Configuration](https://github.com/sansan0/TrendRadar/issues/95)
+
+> 💡 **Shortcut**: If you don't know how to read source code, you can copy from others' organized [Platform Configuration Summary](https://github.com/sansan0/TrendRadar/issues/95)
+
+> ⚠️ **Note**: More platforms is not always better, suggest choosing 10-15 core platforms. Too many platforms will cause information overload and actually reduce user experience.
 
 </details>
 
 ### 2. Keyword Configuration
 
-Configure monitoring keywords in `frequency_words.txt` with four syntax types and grouping features.
+**Configuration Location:** `config/frequency_words.txt`
+
+Configure monitoring keywords in `frequency_words.txt` with five syntax types, region markers, and grouping features.
 
 | Syntax Type | Symbol | Purpose | Example | Matching Logic |
 |------------|--------|---------|---------|----------------|
@@ -1393,6 +1518,7 @@ Configure monitoring keywords in `frequency_words.txt` with four syntax types an
 | **Required** | `+` | Scope limiting | `+phone` | Must include both |
 | **Filter** | `!` | Noise exclusion | `!ad` | Exclude if included |
 | **Count Limit** | `@` | Control display count | `@10` | Max 10 news (v3.2.0 new) |
+| **Global Filter** | `[GLOBAL_FILTER]` | Globally exclude content | See example below | Filter under any circumstances (v3.5.0 new) |
 
 #### 2.1 Basic Syntax
 
@@ -1437,6 +1563,55 @@ Musk
 
 **Priority:** `@number` > Global config > Unlimited
 
+##### 5. **Global Filter** `[GLOBAL_FILTER]` - Globally Exclude Content (v3.5.0 new)
+```txt
+[GLOBAL_FILTER]
+advertisement
+promotion
+marketing
+shocking
+clickbait
+
+[WORD_GROUPS]
+technology
+AI
+
+Huawei
+HarmonyOS
+!car
+```
+**Effect:** Filters news containing specified words under **any circumstances**, with **highest priority**
+
+**Use Cases:**
+- Filter low-quality content: shocking, clickbait, breaking news, etc.
+- Filter marketing content: advertisement, promotion, sponsorship, etc.
+- Filter specific topics: entertainment, gossip (based on needs)
+
+**Filter Priority:** Global Filter > Group Filter(`!`) > Group Matching
+
+**Region Markers:**
+- `[GLOBAL_FILTER]`: Global filter region, words are filtered under any circumstances
+- `[WORD_GROUPS]`: Keyword groups region, maintains existing syntax (`!`, `+`, `@`)
+- If no region markers are used, all content is treated as keyword groups (backward compatible)
+
+**Matching Examples:**
+```txt
+[GLOBAL_FILTER]
+advertisement
+
+[WORD_GROUPS]
+technology
+AI
+```
+- ❌ "Advertisement: Latest tech product launch" ← Contains global filter word "advertisement", rejected
+- ✅ "Tech company launches new AI product" ← No global filter words, matches "technology" group
+- ✅ "AI technology breakthrough draws attention" ← No global filter words, matches "AI" in "technology" group
+
+**Important Notes:**
+- Use global filter words carefully to avoid over-filtering and missing valuable content
+- Recommended to keep global filter words under 5-15
+- For group-specific filtering, prioritize using group filter words (`!` prefix)
+
 ---
 
 #### 🔗 Group Feature - Importance of Empty Lines
@@ -1625,6 +1800,15 @@ BYD
 <summary>👉 Click to expand: <strong>Three Push Modes Detailed Comparison</strong></summary>
 <br>
 
+**Configuration Location:** `report.mode` in `config/config.yaml`
+
+```yaml
+report:
+  mode: "daily"  # Options: "daily" | "incremental" | "current"
+```
+
+**Docker Environment Variable:** `REPORT_MODE=incremental`
+
 #### Detailed Comparison Table
 
 | Mode | Target Users | Push Timing | Display Content | Typical Use Case |
@@ -1678,6 +1862,15 @@ Assume you monitor "Apple" keyword, execute once per hour:
 <summary>👉 Click to expand: <strong>Hotspot Weight Adjustment</strong></summary>
 <br>
 
+**Configuration Location:** `weight` section in `config/config.yaml`
+
+```yaml
+weight:
+  rank_weight: 0.6       # Ranking weight
+  frequency_weight: 0.3  # Frequency weight
+  hotness_weight: 0.1    # Hotness weight
+```
+
 Current default configuration is balanced.
 
 #### Two Core Scenarios
@@ -1775,50 +1968,33 @@ Updated: 2025-01-15 12:30:15
 <summary>👉 Click to expand: <strong>Complete Docker Deployment Guide</strong></summary>
 <br>
 
-#### Method 1: Quick Experience (One-Line Command)
+**Image Description:**
 
-**Linux/macOS System:**
-```bash
-# Create config directory and download config files
-mkdir -p config output
-wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/config/config.yaml -P config/
-wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/config/frequency_words.txt -P config/
-```
-Or **Manual Creation**:
-1. Create `config` folder in current directory
-2. Download config files:
-   - Visit https://raw.githubusercontent.com/sansan0/TrendRadar/master/config/config.yaml → Right-click "Save As" → Save to `config\config.yaml`
-   - Visit https://raw.githubusercontent.com/sansan0/TrendRadar/master/config/frequency_words.txt → Right-click "Save As" → Save to `config\frequency_words.txt`
+TrendRadar provides two independent Docker images, deploy according to your needs:
 
-Final directory structure should be:
-```
-current directory/
-└── config/
-    ├── config.yaml
-    └── frequency_words.txt
-```
+| Image Name | Purpose | Description |
+|---------|------|------|
+| `wantcat/trendradar` | News Push Service | Scheduled news crawling, push notifications (Required) |
+| `wantcat/trendradar-mcp` | AI Analysis Service | MCP protocol support, AI dialogue analysis (Optional) |
 
-```bash
-docker run -d --name trend-radar \
-  -v ./config:/app/config:ro \
-  -v ./output:/app/output \
-  -e FEISHU_WEBHOOK_URL="your feishu webhook" \
-  -e DINGTALK_WEBHOOK_URL="your dingtalk webhook" \
-  -e WEWORK_WEBHOOK_URL="your wework webhook" \
-  -e TELEGRAM_BOT_TOKEN="your telegram_bot_token" \
-  -e TELEGRAM_CHAT_ID="your telegram_chat_id" \
-  -e EMAIL_FROM="your sender email" \
-  -e EMAIL_PASSWORD="your email password or auth code" \
-  -e EMAIL_TO="recipient email" \
-  -e CRON_SCHEDULE="*/30 * * * *" \
-  -e RUN_MODE="cron" \
-  -e IMMEDIATE_RUN="true" \
-  wantcat/trendradar:latest
-```
-
-#### Method 2: Using docker-compose (Recommended)
+> 💡 **Recommendations**:
+> - Only need push functionality: Deploy `wantcat/trendradar` image only
+> - Need AI analysis: Deploy both images
+
+---
+
+#### Method 1: Using docker-compose (Recommended)
 
 1. **Create Project Directory and Config**:
+
+   **Method 1-A: Using git clone (Recommended, Simplest)**
+   ```bash
+   # Clone project to local
+   git clone https://github.com/sansan0/TrendRadar.git
+   cd TrendRadar
+   ```
+
+   **Method 1-B: Using wget to download config files**
    ```bash
    # Create directory structure
    mkdir -p trendradar/{config,docker}
@@ -1829,11 +2005,11 @@ docker run -d --name trend-radar \
    wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/config/frequency_words.txt -P config/
 
    # Download docker-compose config
-   wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/docker/.env
-   wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/docker/docker-compose.yml
+   wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/docker/.env -P docker/
+   wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/docker/docker-compose.yml -P docker/
    ```
 
-Final directory structure should be:
+   > 💡 **Note**: Key directory structure required for Docker deployment:
 ```
 current directory/
 ├── config/
@@ -1858,10 +2034,13 @@ current directory/
    | `ENABLE_CRAWLER` | `crawler.enable_crawler` | `true` / `false` | Enable crawler |
    | `ENABLE_NOTIFICATION` | `notification.enable_notification` | `true` / `false` | Enable notification |
    | `REPORT_MODE` | `report.mode` | `daily` / `incremental` / `current`| Report mode |
+   | `MAX_ACCOUNTS_PER_CHANNEL` | `notification.max_accounts_per_channel` | `3` | Maximum accounts per channel |
    | `PUSH_WINDOW_ENABLED` | `notification.push_window.enabled` | `true` / `false` | Push time window switch |
    | `PUSH_WINDOW_START` | `notification.push_window.time_range.start` | `08:00` | Push start time |
    | `PUSH_WINDOW_END` | `notification.push_window.time_range.end` | `22:00` | Push end time |
-   | `FEISHU_WEBHOOK_URL` | `notification.webhooks.feishu_url` | `https://...` | Feishu Webhook |
+   | `ENABLE_WEBSERVER` | - | `true` / `false` | Auto-start web server |
+   | `WEBSERVER_PORT` | - | `8080` | Web server port (default 8080) |
+   | `FEISHU_WEBHOOK_URL` | `notification.webhooks.feishu_url` | `https://...` | Feishu Webhook (supports multi-account, use `;` separator) |
 
    **Config Priority**: Environment Variables > config.yaml
 
@@ -1872,22 +2051,52 @@ current directory/
 
 
 3. **Start Service**:
+
+   **Option A: Start All Services (Push + AI Analysis)**
    ```bash
-   # Pull latest image and start
+   # Pull latest images
    docker-compose pull
+
+   # Start all services (trend-radar + trend-radar-mcp)
    docker-compose up -d
    ```
 
+   **Option B: Start News Push Service Only**
+   ```bash
+   # Start trend-radar only (scheduled crawling and push)
+   docker-compose pull trend-radar
+   docker-compose up -d trend-radar
+   ```
+
+   **Option C: Start MCP AI Analysis Service Only**
+   ```bash
+   # Start trend-radar-mcp only (AI analysis interface)
+   docker-compose pull trend-radar-mcp
+   docker-compose up -d trend-radar-mcp
+   ```
+
+   > 💡 **Tips**:
+   > - Most users only need to start `trend-radar` for news push functionality
+   > - Only start `trend-radar-mcp` when using Claude/ChatGPT for AI dialogue analysis
+   > - Both services are independent and can be flexibly combined
+
 4. **Check Running Status**:
    ```bash
-   # View logs
+   # View news push service logs
    docker logs -f trend-radar
 
-   # View container status
+   # View MCP AI analysis service logs
+   docker logs -f trend-radar-mcp
+
+   # View all container status
    docker ps | grep trend-radar
+
+   # Stop specific service
+   docker-compose stop trend-radar      # Stop push service
+   docker-compose stop trend-radar-mcp  # Stop MCP service
    ```
 
-#### Method 3: Local Build (Developer Option)
+#### Method 2: Local Build (Developer Option)
 
 If you need custom code modifications or build your own image:
 
@@ -1903,17 +2112,38 @@ vim config/frequency_words.txt
 # Use build version docker-compose
 cd docker
 cp docker-compose-build.yml docker-compose.yml
+```
+
+**Build and Start Services**:
 
-# Build and start
+```bash
+# Option A: Build and start all services
 docker-compose build
 docker-compose up -d
+
+# Option B: Build and start news push service only
+docker-compose build trend-radar
+docker-compose up -d trend-radar
+
+# Option C: Build and start MCP AI analysis service only
+docker-compose build trend-radar-mcp
+docker-compose up -d trend-radar-mcp
 ```
 
+> 💡 **Architecture Parameter Notes**:
+> - Default builds `amd64` architecture images (suitable for most x86_64 servers)
+> - To build `arm64` architecture (Apple Silicon, Raspberry Pi, etc.), set environment variable:
+>   ```bash
+>   export DOCKER_ARCH=arm64
+>   docker-compose build
+>   ```
+
 #### Image Update
 
 ```bash
-# Method 1: Manual update
+# Method 1: Manual update (Crawler + MCP images)
 docker pull wantcat/trendradar:latest
+docker pull wantcat/trendradar-mcp:latest
 docker-compose down
 docker-compose up -d
 
@@ -1922,6 +2152,13 @@ docker-compose pull
 docker-compose up -d
 ```
 
+**Available Images**:
+
+| Image Name | Purpose | Description |
+|---------|------|---------|
+| `wantcat/trendradar` | News Push Service | Scheduled news crawling, push notifications |
+| `wantcat/trendradar-mcp` | MCP Service | AI analysis features (optional) |
+
 #### Service Management Commands
 
 ```bash
@@ -1940,6 +2177,11 @@ docker exec -it trend-radar python manage.py config
 # Display output files
 docker exec -it trend-radar python manage.py files
 
+# Web server management (for browser access to generated reports)
+docker exec -it trend-radar python manage.py start_webserver   # Start web server
+docker exec -it trend-radar python manage.py stop_webserver    # Stop web server
+docker exec -it trend-radar python manage.py webserver_status  # Check web server status
+
 # View help info
 docker exec -it trend-radar python manage.py help
 
@@ -1953,10 +2195,52 @@ docker stop trend-radar
 docker rm trend-radar
 ```
 
+> 💡 **Web Server Notes**:
+> - After starting, access latest report at `http://localhost:8080`
+> - Access historical reports via directory navigation (e.g., `http://localhost:8080/2025年xx月xx日/`)
+> - Port can be configured in `.env` file with `WEBSERVER_PORT` parameter
+> - Auto-start: Set `ENABLE_WEBSERVER=true` in `.env`
+> - Security: Static files only, limited to output directory, localhost binding only
+
 #### Data Persistence
 
 Generated reports and data are saved in `./output` directory by default. Data persists even if container is restarted or removed.
 
+**📊 Web Report Access Paths**:
+
+TrendRadar generates daily summary HTML reports to two locations simultaneously:
+
+| File Location | Access Method | Use Case |
+|--------------|---------------|----------|
+| `output/index.html` | Direct host access | **Docker Deployment** (via Volume mount, visible on host) |
+| `index.html` | Root directory access | **GitHub Pages** (repository root, auto-detected by Pages) |
+| `output/YYYY年MM月DD日/html/当日汇总.html` | Historical reports | All environments (archived by date) |
+
+**Local Access Examples**:
+```bash
+# Method 1: Via Web Server (recommended, Docker environment)
+# 1. Start web server
+docker exec -it trend-radar python manage.py start_webserver
+# 2. Access in browser
+http://localhost:8080                           # Access latest report (default index.html)
+http://localhost:8080/2025年xx月xx日/            # Access reports for specific date
+http://localhost:8080/2025年xx月xx日/html/       # Browse all HTML files for that date
+
+# Method 2: Direct file access (local environment)
+open ./output/index.html             # macOS
+start ./output/index.html            # Windows
+xdg-open ./output/index.html         # Linux
+
+# Method 3: Access historical archives
+open ./output/2025年xx月xx日/html/当日汇总.html
+```
+
+**Why two index.html files?**
+- `output/index.html`: Docker Volume mounted to host, can be opened locally
+- `index.html`: Pushed to repository by GitHub Actions, auto-deployed by GitHub Pages
+
+> 💡 **Tip**: Both files have identical content, choose either one to access.
+
 #### Troubleshooting
 
 ```bash
@@ -1973,6 +2257,521 @@ docker exec -it trend-radar /bin/bash
 docker exec -it trend-radar ls -la /app/config/
 ```
 
+#### MCP Service Deployment (AI Analysis Feature)
+
+If you need to use AI analysis features, you can deploy the standalone MCP service container.
+
+**Architecture Description**:
+
+```mermaid
+flowchart TB
+    subgraph trend-radar["trend-radar"]
+        A1[Scheduled News Fetching]
+        A2[Push Notifications]
+    end
+    
+    subgraph trend-radar-mcp["trend-radar-mcp"]
+        B1[127.0.0.1:3333]
+        B2[AI Analysis API]
+    end
+    
+    subgraph shared["Shared Volume"]
+        C1["config/ (ro)"]
+        C2["output/ (ro)"]
+    end
+    
+    trend-radar --> shared
+    trend-radar-mcp --> shared
+```
+
+**Quick Start**:
+
+Use docker-compose to start both news push and MCP services:
+
+```bash
+# Download latest docker-compose.yml (includes MCP service config)
+wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/docker/docker-compose.yml
+
+# Start all services
+docker-compose up -d
+
+# Check running status
+docker ps | grep trend-radar
+```
+
+**Start MCP Service Separately**:
+
+```bash
+docker run -d --name trend-radar-mcp \
+  -p 127.0.0.1:3333:3333 \
+  -v ./config:/app/config:ro \
+  -v ./output:/app/output:ro \
+  -e TZ=Asia/Shanghai \
+  wantcat/trendradar-mcp:latest
+```
+
+**Verify Service**:
+
+```bash
+# Check if MCP service is running properly
+curl http://127.0.0.1:3333/mcp
+
+# View MCP service logs
+docker logs -f trend-radar-mcp
+```
+
+**Configure in AI Clients**:
+
+After MCP service starts, configure in Claude Desktop, Cherry Studio, Cursor, etc.:
+
+```json
+{
+  "mcpServers": {
+    "trendradar": {
+      "url": "http://127.0.0.1:3333/mcp",
+      "description": "TrendRadar News Trending Analysis"
+    }
+  }
+}
+```
+
+> 💡 **Tip**: MCP service only listens on local port (127.0.0.1) for security. For remote access, configure reverse proxy and authentication yourself.
+
+</details>
+
+### 7. Report Configuration
+
+<details>
+<summary>👉 Click to expand: <strong>Report-Related Parameter Configuration</strong></summary>
+<br>
+
+**Configuration Location:** `report` section in `config/config.yaml`
+
+```yaml
+report:
+  mode: "daily"                    # Push mode
+  rank_threshold: 5                # Ranking highlight threshold
+  sort_by_position_first: false    # Sorting priority
+  max_news_per_keyword: 0          # Maximum display count per keyword
+  reverse_content_order: false     # Content order configuration
+```
+
+#### Configuration Details
+
+| Config Item | Type | Default | Description |
+|------------|------|---------|-------------|
+| `mode` | string | `daily` | Push mode, options: `daily`/`incremental`/`current`, see [Push Mode Details](#3-push-mode-details) |
+| `rank_threshold` | int | `5` | Ranking highlight threshold, news with rank ≤ this value will be displayed in bold |
+| `sort_by_position_first` | bool | `false` | Sorting priority: `false`=sort by news count, `true`=sort by config position |
+| `max_news_per_keyword` | int | `0` | Maximum display count per keyword, `0`=unlimited |
+| `reverse_content_order` | bool | `false` | Content order: `false`=trending keywords stats first, `true`=new trending news first |
+
+#### Content Order Configuration (v3.5.0 New)
+
+Controls display order of two content sections in push messages and HTML reports:
+
+| Config Value | Display Order |
+|-------------|--------------|
+| `false` (default) | ① Trending Keywords Stats → ② New Trending News |
+| `true` | ① New Trending News → ② Trending Keywords Stats |
+
+**Use Cases:**
+- `false` (default): Suitable for users focusing on keyword match results, view categorized stats first
+- `true`: Suitable for users focusing on latest updates, prioritize viewing new trending topics
+
+**Docker Environment Variable:**
+```bash
+REVERSE_CONTENT_ORDER=true
+```
+
+#### Sorting Priority Configuration
+
+**Example Scenario:** Config order A, B, C, news count A(3), B(10), C(5)
+
+| Config Value | Display Order | Use Case |
+|-------------|--------------|----------|
+| `false` (default) | B(10) → C(5) → A(3) | Focus on popularity trends |
+| `true` | A(3) → B(10) → C(5) | Focus on personal priority |
+
+**Docker Environment Variables:**
+```bash
+SORT_BY_POSITION_FIRST=true
+MAX_NEWS_PER_KEYWORD=10
+```
+
+</details>
+
+### 8. Push Window Configuration
+
+<details>
+<summary>👉 Click to expand: <strong>Push Time Window Control Details</strong></summary>
+<br>
+
+**Configuration Location:** `notification.push_window` section in `config/config.yaml`
+
+```yaml
+notification:
+  push_window:
+    enabled: false                    # Whether to enable
+    time_range:
+      start: "20:00"                  # Start time (Beijing time)
+      end: "22:00"                    # End time (Beijing time)
+    once_per_day: true                # Push only once per day
+    push_record_retention_days: 7     # Push record retention days
+```
+
+#### Configuration Details
+
+| Config Item | Type | Default | Description |
+|------------|------|---------|-------------|
+| `enabled` | bool | `false` | Whether to enable push time window control |
+| `time_range.start` | string | `"20:00"` | Push window start time (Beijing time, HH:MM format) |
+| `time_range.end` | string | `"22:00"` | Push window end time (Beijing time, HH:MM format) |
+| `once_per_day` | bool | `true` | `true`=push only once per day within window, `false`=push every execution within window |
+| `push_record_retention_days` | int | `7` | Push record retention days (used to determine if already pushed) |
+
+#### Use Cases
+
+| Scenario | Configuration Example |
+|----------|---------------------|
+| **Working Hours Push** | `start: "09:00"`, `end: "18:00"`, `once_per_day: false` |
+| **Evening Summary Push** | `start: "20:00"`, `end: "22:00"`, `once_per_day: true` |
+| **Lunch Break Push** | `start: "12:00"`, `end: "13:00"`, `once_per_day: true` |
+
+#### Important Notice
+
+> ⚠️ **GitHub Actions Users Note:**
+> - GitHub Actions execution time is unstable, may have ±15 minutes deviation
+> - Time range should be at least **2 hours** wide
+> - For precise timed push, recommend **Docker deployment** on personal server
+
+#### Docker Environment Variables
+
+```bash
+PUSH_WINDOW_ENABLED=true
+PUSH_WINDOW_START=09:00
+PUSH_WINDOW_END=18:00
+PUSH_WINDOW_ONCE_PER_DAY=false
+PUSH_WINDOW_RETENTION_DAYS=7
+```
+
+#### Complete Configuration Examples
+
+**Scenario: Push once between 8-10 PM daily**
+
+```yaml
+notification:
+  push_window:
+    enabled: true
+    time_range:
+      start: "20:00"
+      end: "22:00"
+    once_per_day: true
+    push_record_retention_days: 7
+```
+
+**Scenario: Push every hour during working hours**
+
+```yaml
+notification:
+  push_window:
+    enabled: true
+    time_range:
+      start: "09:00"
+      end: "18:00"
+    once_per_day: false
+    push_record_retention_days: 7
+```
+
+</details>
+
+### 9. Execution Frequency Configuration
+
+<details>
+<summary>👉 Click to expand: <strong>Automatic Execution Frequency Settings</strong></summary>
+<br>
+
+**Configuration Location:** `schedule` section in `.github/workflows/crawler.yml`
+
+```yaml
+on:
+  schedule:
+    - cron: "0 * * * *"  # Run every hour
+```
+
+#### What is a Cron Expression?
+
+Cron is a time-based job scheduler format, consisting of 5 parts: `minute hour day month weekday`
+
+```
+┌───────────── minute (0-59)
+│ ┌───────────── hour (0-23)
+│ │ ┌───────────── day (1-31)
+│ │ │ ┌───────────── month (1-12)
+│ │ │ │ ┌───────────── weekday (0-6, 0=Sunday)
+│ │ │ │ │
+* * * * *
+```
+
+#### Common Configuration Examples
+
+| Desired Effect | Cron Expression | Description |
+|---------------|----------------|-------------|
+| Every hour | `0 * * * *` | Run at minute 0 of every hour (default) |
+| Every 30 minutes | `*/30 * * * *` | Run every 30 minutes |
+| Daily at 8 AM | `0 0 * * *` | UTC 0:00 = Beijing 8:00 AM |
+| Working hours | `*/30 0-14 * * *` | Beijing 8:00-22:00, every 30 minutes |
+| 3 times daily | `0 0,6,12 * * *` | Beijing 8:00, 14:00, 20:00 |
+
+#### Important Notes
+
+> ⚠️ **Time Zone Note**: GitHub Actions uses **UTC time**, Beijing time needs to **subtract 8 hours**
+> - Want Beijing 8:00 AM run → Set UTC 0:00
+> - Want Beijing 8:00 PM run → Set UTC 12:00
+
+> ⚠️ **Frequency Limit**: GitHub has a limit on Actions execution count per account
+> - **Recommendation**: Don't set intervals shorter than 30 minutes
+> - **Reason**: Too frequent may be considered abuse, facing account ban risk
+> - **Reality**: GitHub Actions execution time has inherent deviation, setting too precise is meaningless
+
+#### Modification Method
+
+1. Open your forked repository
+2. Find `.github/workflows/crawler.yml` file
+3. Click edit (pencil icon)
+4. Modify the expression in `cron: "0 * * * *"`
+5. Click "Commit changes" to save
+
+</details>
+
+### 10. Multiple Account Push Configuration
+
+<details>
+<summary>👉 Click to expand: <strong>Multiple Account Push Configuration Guide</strong></summary>
+<br>
+
+**Configuration Location:** `notification` section in `config/config.yaml`
+
+> ### ⚠️ **Security Warning**
+> **GitHub Fork Users: DO NOT configure push information in `config.yaml`!**
+>
+> - **Risk**: `config.yaml` will be committed to public Git repositories. Configuring push information (Webhook URLs, Tokens, etc.) will expose sensitive data
+> - **Recommended Methods**:
+>   - **GitHub Actions Users** → Use GitHub Secrets environment variables
+>   - **Docker Users** → Use [`.env` file configuration](#6-docker-deployment) (`.env` is in `.gitignore` and won't be committed)
+> - **Local Development Users**: Can configure in `config.yaml` (ensure it won't be pushed to public repositories)
+
+#### Supported Channels
+
+| Channel | Configuration Item | Pairing Required | Description |
+|---------|-------------------|-----------------|-------------|
+| **Feishu** | `feishu_url` | No | Multiple webhook URLs |
+| **DingTalk** | `dingtalk_url` | No | Multiple webhook URLs |
+| **WeWork** | `wework_url` | No | Multiple webhook URLs |
+| **Telegram** | `telegram_bot_token` + `telegram_chat_id` | ✅ Yes | Token and chat_id quantities must match |
+| **ntfy** | `ntfy_topic` + `ntfy_token` | ✅ Yes | Topic and token quantities must match (token optional) |
+| **Bark** | `bark_url` | No | Multiple push URLs |
+| **Slack** | `slack_webhook_url` | No | Multiple webhook URLs |
+| **Email** | `email_to` | - | Already supports multiple recipients (comma-separated), no modification needed |
+
+#### Recommended Method 1: GitHub Actions Environment Variables
+
+**Configuration Location**: GitHub Repo → Settings → Secrets and variables → Actions → Repository secrets
+
+**Basic Configuration Example**:
+```bash
+# Multi-account quantity limit
+MAX_ACCOUNTS_PER_CHANNEL=3
+
+# Feishu multi-account (3 groups)
+FEISHU_WEBHOOK_URL=https://hook1.feishu.cn/xxx;https://hook2.feishu.cn/yyy;https://hook3.feishu.cn/zzz
+
+# DingTalk multi-account (2 groups)
+DINGTALK_WEBHOOK_URL=https://oapi.dingtalk.com/xxx;https://oapi.dingtalk.com/yyy
+
+# WeWork multi-account (2 groups)
+WEWORK_WEBHOOK_URL=https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx;https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=yyy
+
+# Bark multi-account (2 devices)
+BARK_URL=https://api.day.app/key1;https://api.day.app/key2
+
+# Slack multi-account (2 channels)
+SLACK_WEBHOOK_URL=https://hooks.slack.com/xxx;https://hooks.slack.com/yyy
+```
+
+**Paired Configuration Examples (Telegram and ntfy)**:
+
+<details>
+<summary><strong>Telegram Paired Configuration</strong></summary>
+
+```bash
+# ✅ Correct: 2 tokens correspond to 2 chat_ids
+TELEGRAM_BOT_TOKEN=123456:AAA-BBB;789012:CCC-DDD
+TELEGRAM_CHAT_ID=-100111;-100222
+
+# ❌ Incorrect: quantities don't match, push will be skipped
+TELEGRAM_BOT_TOKEN=token1;token2;token3
+TELEGRAM_CHAT_ID=id1;id2
+```
+
+**Note**: The quantities of `token` and `chat_id` must match exactly, otherwise the channel push will be skipped.
+
+</details>
+
+<details>
+<summary><strong>ntfy Paired Configuration</strong></summary>
+
+```bash
+# ✅ Correct: 3 topics, only the 2nd needs a token
+NTFY_TOPIC=topic1;topic2;topic3
+NTFY_TOKEN=;token_for_topic2;
+
+# ✅ Correct: 2 topics both need tokens
+NTFY_TOPIC=topic1;topic2
+NTFY_TOKEN=token1;token2
+
+# ❌ Incorrect: topic and token quantities don't match
+NTFY_TOPIC=topic1;topic2
+NTFY_TOKEN=token1;token2;token3
+```
+
+**Notes**:
+- If a topic doesn't need a token, leave it empty at the corresponding position (between two semicolons)
+- The quantities of `topic` and `token` must match
+
+</details>
+
+---
+
+#### Recommended Method 2: Docker Environment Variables (.env)
+
+**Configuration Location**: `docker/.env` file in project root directory
+
+**Basic Configuration Example**:
+```bash
+# Multi-account quantity limit
+MAX_ACCOUNTS_PER_CHANNEL=3
+
+# Feishu multi-account (3 groups)
+FEISHU_WEBHOOK_URL=https://hook1.feishu.cn/xxx;https://hook2.feishu.cn/yyy;https://hook3.feishu.cn/zzz
+
+# DingTalk multi-account (2 groups)
+DINGTALK_WEBHOOK_URL=https://oapi.dingtalk.com/xxx;https://oapi.dingtalk.com/yyy
+
+# WeWork multi-account (2 groups)
+WEWORK_WEBHOOK_URL=https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx;https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=yyy
+
+# Bark multi-account (2 devices)
+BARK_URL=https://api.day.app/key1;https://api.day.app/key2
+
+# Slack multi-account (2 channels)
+SLACK_WEBHOOK_URL=https://hooks.slack.com/xxx;https://hooks.slack.com/yyy
+```
+
+**Paired Configuration Examples (Telegram and ntfy)**:
+
+<details>
+<summary><strong>Telegram Paired Configuration</strong></summary>
+
+```bash
+# ✅ Correct: 2 tokens correspond to 2 chat_ids
+TELEGRAM_BOT_TOKEN=123456:AAA-BBB;789012:CCC-DDD
+TELEGRAM_CHAT_ID=-100111;-100222
+
+# ❌ Incorrect: quantities don't match, push will be skipped
+TELEGRAM_BOT_TOKEN=token1;token2;token3
+TELEGRAM_CHAT_ID=id1;id2
+```
+
+**Note**: The quantities of `token` and `chat_id` must match exactly, otherwise the channel push will be skipped.
+
+</details>
+
+<details>
+<summary><strong>ntfy Paired Configuration</strong></summary>
+
+```bash
+# ✅ Correct: 3 topics, only the 2nd needs a token
+NTFY_TOPIC=topic1;topic2;topic3
+NTFY_TOKEN=;token_for_topic2;
+
+# ✅ Correct: 2 topics both need tokens
+NTFY_TOPIC=topic1;topic2
+NTFY_TOKEN=token1;token2
+
+# ❌ Incorrect: topic and token quantities don't match
+NTFY_TOPIC=topic1;topic2
+NTFY_TOKEN=token1;token2;token3
+```
+
+**Notes**:
+- If a topic doesn't need a token, leave it empty at the corresponding position (between two semicolons)
+- The quantities of `topic` and `token` must match
+
+</details>
+
+---
+
+#### Push Behavior Description
+
+1. **Independent Push**: Each account sends independently, one failure doesn't affect other accounts
+2. **Partial Success**: As long as one account sends successfully, the overall result is considered successful
+3. **Log Differentiation**: Multi-account logs show "Account 1", "Account 2", etc.
+4. **Batch Interval**: Multi-account increases total send time (each account independently calculates batch interval)
+
+---
+
+#### FAQ
+
+<details>
+<summary><strong>Q1: What happens if more than 3 accounts are configured?</strong></summary>
+<br>
+
+The system will automatically truncate to the configured maximum quantity and output warning logs. You can adjust the limit via `max_accounts_per_channel`.
+
+**⚠️ Special Note for GitHub Actions Users**:
+- **Not recommended to configure too many accounts** (suggest no more than 3), which may cause:
+  - **Trigger GitHub Actions rate limits**: Frequent network requests may be identified as abnormal behavior
+  - **Affect Workflow execution time**: Multi-account pushing will extend runtime and may exceed free quotas
+  - **Potential account risks**: Excessive use of GitHub Actions resources may affect account status
+- **Recommended Practices**:
+  - Use `max_accounts_per_channel: 3` or lower values
+  - Adjust Cron execution frequency (e.g., change from hourly to every 2-3 hours)
+  - Prioritize the most important push channels and avoid configuring too many accounts
+
+</details>
+
+<details>
+<summary><strong>Q2: Will multi-accounts affect push speed?</strong></summary>
+<br>
+
+Yes. Each account sends independently, total time = number of accounts × single account send time. Recommend controlling the number of accounts.
+
+</details>
+
+<details>
+<summary><strong>Q3: How can local development users configure in config.yaml?</strong></summary>
+<br>
+
+If you are doing local development and **will not push code to public repositories**, you can configure directly in `config/config.yaml`:
+
+```yaml
+notification:
+  enable_notification: true
+  max_accounts_per_channel: 3
+
+  webhooks:
+    feishu_url: "https://hook1.feishu.cn/xxx;https://hook2.feishu.cn/yyy"
+    telegram_bot_token: "token1;token2"
+    telegram_chat_id: "id1;id2"
+```
+
+**⚠️ Important Reminder**:
+- Ensure `config/config.yaml` is in `.gitignore` (if you will commit code)
+- Or only use in local development environment, **never commit to public repositories**
+
+</details>
+
 </details>
 
 <br>

+ 844 - 73
README.md

@@ -14,7 +14,7 @@
 [![GitHub Stars](https://img.shields.io/github/stars/sansan0/TrendRadar?style=flat-square&logo=github&color=yellow)](https://github.com/sansan0/TrendRadar/stargazers)
 [![GitHub Forks](https://img.shields.io/github/forks/sansan0/TrendRadar?style=flat-square&logo=github&color=blue)](https://github.com/sansan0/TrendRadar/network/members)
 [![License](https://img.shields.io/badge/license-GPL--3.0-blue.svg?style=flat-square)](LICENSE)
-[![Version](https://img.shields.io/badge/version-v3.4.1-blue.svg)](https://github.com/sansan0/TrendRadar)
+[![Version](https://img.shields.io/badge/version-v3.5.0-blue.svg)](https://github.com/sansan0/TrendRadar)
 [![MCP](https://img.shields.io/badge/MCP-v1.0.3-green.svg)](https://github.com/sansan0/TrendRadar)
 
 [![企业微信通知](https://img.shields.io/badge/企业微信-通知-00D4AA?style=flat-square)](https://work.weixin.qq.com/)
@@ -44,14 +44,12 @@
 > 本项目以轻量,易部署为目标
 
 <details>
-<summary>⚠️ 点击展开:<strong>查看最新文档</strong>(Fork 用户必读)</summary>
+<summary>⚠️ 点击展开:<strong>Fork 须知:文档更新、资源限制与部署建议</strong></summary>
 <br>
 
-最近有很多第一次接触 GitHub 的新用户使用本项目,因此特别补充这个说明。
+**📄 文档版本说明:**
 
-**问题**:如果你是通过 **Fork** 使用本项目,你看到的可能是旧版文档。
-
-**原因**:Fork 时会复制当时的文档版本,但原项目可能已更新。
+如果你是通过 **Fork** 使用本项目,你看到的可能是旧版文档。因为 Fork 时会复制当时的文档版本,但原项目可能已更新。
 
 **👉 [点击查看最新官方文档](https://github.com/sansan0/TrendRadar?tab=readme-ov-file)**
 
@@ -59,6 +57,18 @@
 - `github.com/你的用户名/TrendRadar` ← 你 fork 的版本
 - `github.com/sansan0/TrendRadar` ← 最新官方版本
 
+---
+
+**🛡️ 资源限制与安全提示:**
+
+GitHub 为每个账号提供的 Actions 资源是有限额的。为了避免被官方判定为滥用而面临封号风险,请注意:
+
+- **监控平台数量**:建议控制在 **10 个左右**,过多平台会消耗更多资源
+- **执行频率**:建议最短间隔为 **30 分钟**,过于频繁无实际意义
+- **合理使用**:GitHub Actions 适合轻量级定时任务,而非高频爬虫
+
+💡 **想要更自由地使用?** 推荐 [🐳 Docker 部署](#6-docker-部署),在自己的服务器上运行。
+
 </details>
 
 <br>
@@ -222,23 +232,25 @@
 >
 > 详细对比和配置教程见 [配置详解 - 推送模式详解](#3-推送模式详解)
 
-**附加功能 - 推送时间窗口控制**(可选):
+**附加功能**(可选):
 
-- 设定推送时间范围(如 09:00-18:00),只在指定时间内推送
-- 可配置窗口内多次推送或每天仅推送一次
-- 避免非工作时间打扰
+| 功能 | 说明 | 默认 |
+|------|------|------|
+| **推送时间窗口控制** | 设定推送时间范围(如 09:00-18:00),避免非工作时间打扰 | 关闭 |
+| **内容顺序配置** | 调整"热点词汇统计"和"新增热点新闻"的显示顺序(v3.5.0 新增) | 统计在前 |
 
-> 💡 此功能默认关闭,配置方法见 [快速开始](#-快速开始)
+> 💡 详细配置教程见 [配置详解 - 报告配置](#7-报告配置) 和 [配置详解 - 推送时间窗口](#8-推送时间窗口配置)
 
 ### **精准内容筛选**
 
 设置个人关键词(如:AI、比亚迪、教育政策),只推送相关热点,过滤无关信息
 
-**基础语法**(4种):
+**基础语法**(5种):
 - 普通词:基础匹配
 - 必须词 `+`:限定范围
 - 过滤词 `!`:排除干扰
 - 数量限制 `@`:控制显示数量(v3.2.0 新增)
+- 全局过滤 `[GLOBAL_FILTER]`:全局排除指定内容(v3.5.0 新增)
 
 **高级功能**(v3.2.0 新增):
 - 🔢 **关键词排序控制**:按热度优先 or 配置顺序优先
@@ -279,6 +291,14 @@
 
 支持**企业微信**(+ 微信推送方案)、**飞书**、**钉钉**、**Telegram**、**邮件**、**ntfy**、**Bark**、**Slack**,消息直达手机和邮箱
 
+**📌 多账号推送说明(v3.5.0 新增):**
+
+- ✅ **支持多账号配置**:所有推送渠道(飞书、钉钉、企业微信、Telegram、ntfy、Bark、Slack)均支持配置多个账号
+- ✅ **配置方式**:使用英文分号 `;` 分隔多个账号值
+- ✅ **示例**:`FEISHU_WEBHOOK_URL` 的 Secret 值填写 `https://webhook1;https://webhook2`
+- ⚠️ **配对配置**:Telegram 和 ntfy 需要保证配对参数数量一致(如 token 和 chat_id 都是 2 个)
+- ⚠️ **数量限制**:默认每个渠道最多 3 个账号,超出会被截断
+
 ### **多端适配**
 - **GitHub Pages**:自动生成精美网页报告,PC/移动端适配
 - **Docker部署**:支持多架构容器化运行
@@ -337,6 +357,61 @@ GitHub 一键 Fork 即可使用,无需编程基础。
 - **大版本升级**:从 v1.x 升级到 v2.y,建议删除现有 fork 后重新 fork,这样更省力且避免配置冲突
 
 
+### 2025/12/03 - v3.5.0
+
+**🎉 核心功能增强**
+
+1. **多账号推送支持**
+   - 所有推送渠道(飞书、钉钉、企业微信、Telegram、ntfy、Bark、Slack)支持多账号配置
+   - 使用分号 `;` 分隔多个账号,例如:`FEISHU_WEBHOOK_URL=url1;url2`
+   - 自动验证配对配置(如 Telegram 的 token 和 chat_id)数量一致性
+
+2. **推送内容顺序可配置**
+   - 新增 `reverse_content_order` 配置项
+   - 支持自定义热点词汇统计与新增热点新闻的显示顺序
+
+3. **全局过滤关键词**
+   - 新增 `[GLOBAL_FILTER]` 区域标记,支持全局过滤不想看到的内容
+   - 适用场景:过滤广告、营销、低质内容等
+
+**🐳 Docker 双路径 HTML 生成优化**
+
+- **问题修复**:解决 Docker 环境下 `index.html` 无法同步到宿主机的问题
+- **双路径生成**:当日汇总 HTML 同时生成到两个位置
+  - `index.html`(项目根目录):供 GitHub Pages 访问
+  - `output/index.html`:通过 Docker Volume 挂载,宿主机可直接访问
+- **兼容性**:确保 Docker、GitHub Actions、本地运行环境均能正常访问网页版报告
+
+**🐳 Docker MCP 镜像支持**
+
+- 新增独立的 MCP 服务镜像 `wantcat/trendradar-mcp`
+- 支持 Docker 部署 AI 分析功能,通过 HTTP 接口(端口 3333)提供服务
+- 双容器架构:新闻推送服务与 MCP 服务独立运行,可分别扩展和重启
+- 详见 [Docker 部署 - MCP 服务](#6-docker-部署)
+
+**🌐 Web 服务器支持**
+
+- 新增内置 Web 服务器,支持通过浏览器访问生成的报告
+- 通过 `manage.py` 命令控制启动/停止:`docker exec -it trend-radar python manage.py start_webserver`
+- 访问地址:`http://localhost:8080`(端口可配置)
+- 安全特性:静态文件服务、目录限制、本地访问
+- 支持自动启动和手动控制两种模式
+
+**📖 文档优化**
+
+- 新增 [报告配置](#7-报告配置) 章节:report 相关参数详解
+- 新增 [推送时间窗口配置](#8-推送时间窗口配置) 章节:push_window 配置教程
+- 新增 [执行频率配置](#9-执行频率配置) 章节:Cron 表达式说明和常用示例
+- 新增 [多账号推送配置](#10-多账号推送配置) 章节:多账号推送配置详解
+- 优化各配置章节:统一添加"配置位置"说明
+- 简化快速开始配置说明:三个核心文件一目了然
+- 优化 [Docker 部署](#6-docker-部署) 章节:新增镜像说明、推荐 git clone 部署、重组部署方式
+
+**🔧 升级说明**:
+- **GitHub Fork 用户**:更新 `main.py`、`config/config.yaml`(新增多账号推送支持,无需修改现有配置)
+- **多账号推送**:新功能,默认不启用,现有单账号配置不受影响
+
+
 ### 2025/11/26 - mcp-v1.0.3
 
   **MCP 模块更新:**
@@ -344,6 +419,11 @@ GitHub 一键 Fork 即可使用,无需编程基础。
   - 支持自然语言日期表达式解析(本周、最近7天、上月等)
   - 工具总数从 13 个增加到 14 个
 
+
+<details>
+<summary>👉 点击展开:<strong>历史更新</strong></summary>
+
+
 ### 2025/11/28 - v3.4.1
 
 **🔧 格式优化**
@@ -366,10 +446,6 @@ GitHub 一键 Fork 即可使用,无需编程基础。
 - **GitHub Fork 用户**:更新 `main.py`,`config.yaml`
 
 
-<details>
-<summary>👉 点击展开:<strong>历史更新</strong></summary>
-
-
 ### 2025/11/25 - v3.4.0
 
 **🎉 新增 Slack 推送支持**
@@ -760,6 +836,24 @@ frequency_words.txt 文件增加了一个【必须词】功能,使用 + 号
    - ⚠️ **严禁自创名称**:Secret 的 Name(名称)必须**严格使用**下方列出的名称(如 `WEWORK_WEBHOOK_URL`、`FEISHU_WEBHOOK_URL` 等),不能自己随意修改或创造新名称,否则系统无法识别
    - 💡 **可以同时配置多个平台**:系统会向所有配置的平台发送通知
 
+   **📌 多账号推送说明(v3.5.0 新增):**
+
+   - ✅ **支持多账号配置**:所有推送渠道(飞书、钉钉、企业微信、Telegram、ntfy、Bark、Slack)均支持配置多个账号
+   - ✅ **配置方式**:使用英文分号 `;` 分隔多个账号值
+   - ✅ **示例**:`FEISHU_WEBHOOK_URL` 的 Secret 值填写 `https://webhook1;https://webhook2`
+   - ⚠️ **配对配置**:Telegram 和 ntfy 需要保证配对参数数量一致(如 token 和 chat_id 都是 2 个)
+   - ⚠️ **数量限制**:默认每个渠道最多 3 个账号,超出部分被截断
+
+   **多账号配置示例**:
+
+   | Name(名称) | Secret(值)示例 |
+   |-------------|-----------------|
+   | `FEISHU_WEBHOOK_URL` | `https://webhook1;https://webhook2;https://webhook3` |
+   | `TELEGRAM_BOT_TOKEN` | `token1;token2` |
+   | `TELEGRAM_CHAT_ID` | `chatid1;chatid2` |
+   | `NTFY_TOPIC` | `topic1;topic2` |
+   | `NTFY_TOKEN` | `;token2`(第一个无 token 时留空占位) |
+
    **配置示例:**
 
    <img src="_image/secrets.png" alt="GitHub Secrets 配置示例"/>
@@ -1364,15 +1458,21 @@ frequency_words.txt 文件增加了一个【必须词】功能,使用 + 号
    3. 点击右侧的 **"Run workflow"** 按钮运行
    4. 等待 1 分钟左右,消息会推送到你配置的平台
 
+   > ⏱️ **测试提示**:
+   > - 手动测试不要太频繁,避免触发 GitHub Actions 限制
+   > - 点击 Run workflow 后需要**刷新浏览器页面**才能看到新的运行记录
+
 4. **配置说明(可选)**:
 
-    > 💡 默认配置已可正常使用,如需个性化调整,可参考以下选项
+    > 💡 **默认配置已可正常使用**,如需个性化调整,了解以下三个文件即可
 
-    - **推送设置**:在 [config/config.yaml](config/config.yaml) 中配置推送模式和通知选项 → [推送模式详解](#3-推送模式详解)
-    - **关键词设置**:在 [config/frequency_words.txt](config/frequency_words.txt) 中添加你关心的关键词 → [关键词配置教程](#2-关键词配置)
-    - **推送频率调整**:在 [.github/workflows/crawler.yml](.github/workflows/crawler.yml) 请谨慎调整,别贪心
+    | 文件 | 作用 |
+    |------|------|
+    | `config/config.yaml` | 主配置文件:推送模式、时间窗口、平台列表、热点权重等 |
+    | `config/frequency_words.txt` | 关键词文件:设置你关心的词汇,筛选推送内容 |
+    | `.github/workflows/crawler.yml` | 执行频率:控制多久运行一次(⚠️ 谨慎修改) |
 
-    **注意**:建议只调整文档中明确说明的配置项,其他选项主要供作者开发时测试使用
+    👉 **详细配置教程**:[配置详解](#配置详解)
 
 5. **🎉 部署成功!分享你的使用体验**
 
@@ -1413,6 +1513,8 @@ frequency_words.txt 文件增加了一个【必须词】功能,使用 + 号
 <summary>👉 点击展开:<strong>自定义监控平台</strong></summary>
 <br>
 
+**配置位置:** `config/config.yaml` 的 `platforms` 部分
+
 本项目的资讯数据来源于 [newsnow](https://github.com/ourongxing/newsnow) ,你可以点击[网站](https://newsnow.busiyi.world/),点击[更多],查看是否有你想要的平台。
 
 具体添加可访问 [项目源代码](https://github.com/ourongxing/newsnow/tree/main/server/sources),根据里面的文件名,在 `config/config.yaml` 文件中修改 `platforms` 配置:
@@ -1427,15 +1529,16 @@ platforms:
     name: "华尔街见闻"
   # 添加更多平台...
 ```
-如果不会看的话,可以有选择的复制他人整理好的部分[平台配置](https://github.com/sansan0/TrendRadar/issues/95)
 
-> 💡 平台不是越多越好,别贪心大量信息,你要进行筛选,否则依然只会被大量信息淹没。
+> 💡 **快捷方式**:如果不会看源代码,可以复制他人整理好的 [平台配置汇总](https://github.com/sansan0/TrendRadar/issues/95)
+
+> ⚠️ **注意**:平台不是越多越好,建议选择 10-15 个核心平台。过多平台会导致信息过载,反而降低使用体验。
 
 </details>
 
 ### 2. 关键词配置
 
-在 `frequency_words.txt` 文件中配置监控的关键词,支持四种语法和词组功能。
+在 `frequency_words.txt` 文件中配置监控的关键词,支持五种语法、区域标记和词组功能。
 
 | 语法类型 | 符号 | 作用 | 示例 | 匹配逻辑 |
 |---------|------|------|------|---------|
@@ -1443,6 +1546,7 @@ platforms:
 | **必须词** | `+` | 限定范围 | `+手机` | 必须同时包含 |
 | **过滤词** | `!` | 排除干扰 | `!广告` | 包含则直接排除 |
 | **数量限制** | `@` | 控制显示数量 | `@10` | 最多显示10条新闻(v3.2.0新增) |
+| **全局过滤** | `[GLOBAL_FILTER]` | 全局排除指定内容 | 见下方示例 | 任何情况下都过滤(v3.5.0新增) |
 
 #### 2.1 基础语法
 
@@ -1452,6 +1556,8 @@ platforms:
 <summary>👉 点击展开:<strong>基础语法教程</strong></summary>
 <br>
 
+**配置位置:** `config/frequency_words.txt`
+
 ##### 1. **普通关键词** - 基础匹配
 ```txt
 华为
@@ -1487,6 +1593,55 @@ OPPO
 
 **配置优先级:** `@数字` > 全局配置 > 不限制
 
+##### 5. **全局过滤** `[GLOBAL_FILTER]` - 全局排除指定内容(v3.5.0 新增)
+```txt
+[GLOBAL_FILTER]
+广告
+推广
+营销
+震惊
+标题党
+
+[WORD_GROUPS]
+科技
+AI
+
+华为
+鸿蒙
+!车
+```
+**作用:** 在任何情况下过滤包含指定词的新闻,**优先级最高**
+
+**使用场景:**
+- 过滤低质内容:震惊、标题党、爆料等
+- 过滤营销内容:广告、推广、赞助等
+- 过滤特定主题:娱乐、八卦(根据需求)
+
+**过滤优先级:** 全局过滤 > 词组内过滤(`!`) > 词组匹配
+
+**区域说明:**
+- `[GLOBAL_FILTER]`:全局过滤区,包含的词在任何情况下都会被过滤
+- `[WORD_GROUPS]`:词组区,保持现有语法(`!`、`+`、`@`)
+- 如果不使用区域标记,默认全部作为词组处理(向后兼容)
+
+**匹配示例:**
+```txt
+[GLOBAL_FILTER]
+广告
+
+[WORD_GROUPS]
+科技
+AI
+```
+- ❌ "广告:最新科技产品发布" ← 包含全局过滤词"广告",直接拒绝
+- ✅ "科技公司发布AI新产品" ← 不包含全局过滤词,匹配"科技"词组
+- ✅ "AI技术突破引发关注" ← 不包含全局过滤词,匹配"科技"词组中的"AI"
+
+**注意事项:**
+- 全局过滤词应谨慎使用,避免过度过滤导致遗漏有价值内容
+- 建议全局过滤词控制在 5-15 个以内
+- 对于特定词组的过滤,优先使用词组内过滤词(`!` 前缀)
+
 ---
 
 #### 🔗 词组功能 - 空行分隔的重要作用
@@ -1672,6 +1827,15 @@ report:
 <summary>👉 点击展开:<strong>三种推送模式详细对比</strong></summary>
 <br>
 
+**配置位置:** `config/config.yaml` 的 `report.mode`
+
+```yaml
+report:
+  mode: "daily"  # 可选: "daily" | "incremental" | "current"
+```
+
+**Docker 环境变量:** `REPORT_MODE=incremental`
+
 #### 详细对比表格
 
 | 模式 | 适用人群 | 推送时机 | 显示内容 | 典型使用场景 |
@@ -1725,6 +1889,15 @@ report:
 <summary>👉 点击展开:<strong>热点权重调整</strong></summary>
 <br>
 
+**配置位置:** `config/config.yaml` 的 `weight` 部分
+
+```yaml
+weight:
+  rank_weight: 0.6       # 排名权重
+  frequency_weight: 0.3  # 频次权重
+  hotness_weight: 0.1    # 热度权重
+```
+
 当前默认的配置是平衡性配置
 
 #### 两个核心场景
@@ -1822,50 +1995,33 @@ weight:
 <summary>👉 点击展开:<strong>Docker 部署完整指南</strong></summary>
 <br>
 
-#### 方式一:快速体验(一行命令)
+**镜像说明:**
 
-**Linux/macOS 系统:**
-```bash
-# 创建配置目录并下载配置文件
-mkdir -p config output
-wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/config/config.yaml -P config/
-wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/config/frequency_words.txt -P config/
-```
-或者**手动创建**:
-1. 在当前目录创建 `config` 文件夹
-2. 下载配置文件:
-   - 访问 https://raw.githubusercontent.com/sansan0/TrendRadar/master/config/config.yaml → 右键"另存为" → 保存到 `config\config.yaml`
-   - 访问 https://raw.githubusercontent.com/sansan0/TrendRadar/master/config/frequency_words.txt → 右键"另存为" → 保存到 `config\frequency_words.txt`
+TrendRadar 提供两个独立的 Docker 镜像,可根据需求选择部署:
 
-完成后的目录结构应该是:
-```
-当前目录/
-└── config/
-    ├── config.yaml
-    └── frequency_words.txt
-```
+| 镜像名称 | 用途 | 说明 |
+|---------|------|------|
+| `wantcat/trendradar` | 新闻推送服务 | 定时抓取新闻、推送通知(必选) |
+| `wantcat/trendradar-mcp` | AI 分析服务 | MCP 协议支持、AI 对话分析(可选) |
 
-```bash
-docker run -d --name trend-radar \
-  -v ./config:/app/config:ro \
-  -v ./output:/app/output \
-  -e FEISHU_WEBHOOK_URL="你的飞书webhook" \
-  -e DINGTALK_WEBHOOK_URL="你的钉钉webhook" \
-  -e WEWORK_WEBHOOK_URL="你的企业微信webhook" \
-  -e TELEGRAM_BOT_TOKEN="你的telegram_bot_token" \
-  -e TELEGRAM_CHAT_ID="你的telegram_chat_id" \
-  -e EMAIL_FROM="你的发件邮箱" \
-  -e EMAIL_PASSWORD="你的邮箱密码或授权码" \
-  -e EMAIL_TO="收件人邮箱" \
-  -e CRON_SCHEDULE="*/30 * * * *" \
-  -e RUN_MODE="cron" \
-  -e IMMEDIATE_RUN="true" \
-  wantcat/trendradar:latest
-```
-
-#### 方式二:使用 docker-compose(推荐)
+> 💡 **建议**:
+> - 只需要推送功能:仅部署 `wantcat/trendradar` 镜像
+> - 需要 AI 分析功能:同时部署两个镜像
+
+---
+
+#### 方式一:使用 docker-compose(推荐)
 
 1. **创建项目目录和配置**:
+
+   **方式 1-A:使用 git clone(推荐,最简单)**
+   ```bash
+   # 克隆项目到本地
+   git clone https://github.com/sansan0/TrendRadar.git
+   cd TrendRadar
+   ```
+
+   **方式 1-B:使用 wget 下载配置文件**
    ```bash
    # 创建目录结构
    mkdir -p trendradar/{config,docker}
@@ -1876,11 +2032,11 @@ docker run -d --name trend-radar \
    wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/config/frequency_words.txt -P config/
 
    # 下载 docker-compose 配置
-   wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/docker/.env
-   wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/docker/docker-compose.yml
+   wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/docker/.env  -P docker/
+   wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/docker/docker-compose.yml  -P docker/
    ```
 
-完成后的目录结构应该是
+   > 💡 **说明**:Docker 部署需要的关键目录结构如下
 ```
 当前目录/
 ├── config/
@@ -1905,10 +2061,13 @@ docker run -d --name trend-radar \
    | `ENABLE_CRAWLER` | `crawler.enable_crawler` | `true` / `false` | 是否启用爬虫 |
    | `ENABLE_NOTIFICATION` | `notification.enable_notification` | `true` / `false` | 是否启用通知 |
    | `REPORT_MODE` | `report.mode` | `daily` / `incremental` / `current`| 报告模式 |
+   | `MAX_ACCOUNTS_PER_CHANNEL` | `notification.max_accounts_per_channel` | `3` | 每个渠道最大账号数 |
    | `PUSH_WINDOW_ENABLED` | `notification.push_window.enabled` | `true` / `false` | 推送时间窗口开关 |
    | `PUSH_WINDOW_START` | `notification.push_window.time_range.start` | `08:00` | 推送开始时间 |
    | `PUSH_WINDOW_END` | `notification.push_window.time_range.end` | `22:00` | 推送结束时间 |
-   | `FEISHU_WEBHOOK_URL` | `notification.webhooks.feishu_url` | `https://...` | 飞书 Webhook |
+   | `ENABLE_WEBSERVER` | - | `true` / `false` | 是否自动启动 Web 服务器 |
+   | `WEBSERVER_PORT` | - | `8080` | Web 服务器端口(默认 8080) |
+   | `FEISHU_WEBHOOK_URL` | `notification.webhooks.feishu_url` | `https://...` | 飞书 Webhook(支持多账号,用 `;` 分隔) |
 
    **配置优先级**:环境变量 > config.yaml
 
@@ -1919,22 +2078,52 @@ docker run -d --name trend-radar \
 
 
 3. **启动服务**:
+
+   **选项 A:启动所有服务(推送 + AI 分析)**
    ```bash
-   # 拉取最新镜像并启动
+   # 拉取最新镜像
    docker-compose pull
+
+   # 启动所有服务(trend-radar + trend-radar-mcp)
    docker-compose up -d
    ```
 
+   **选项 B:仅启动新闻推送服务**
+   ```bash
+   # 只启动 trend-radar(定时抓取和推送)
+   docker-compose pull trend-radar
+   docker-compose up -d trend-radar
+   ```
+
+   **选项 C:仅启动 MCP AI 分析服务**
+   ```bash
+   # 只启动 trend-radar-mcp(提供 AI 分析接口)
+   docker-compose pull trend-radar-mcp
+   docker-compose up -d trend-radar-mcp
+   ```
+
+   > 💡 **提示**:
+   > - 大多数用户只需启动 `trend-radar` 即可实现新闻推送功能
+   > - 只有需要使用 Claude/ChatGPT 进行 AI 对话分析时,才需启动 `trend-radar-mcp`
+   > - 两个服务相互独立,可根据需求灵活组合
+
 4. **查看运行状态**:
    ```bash
-   # 查看日志
+   # 查看新闻推送服务日志
    docker logs -f trend-radar
 
-   # 查看容器状态
+   # 查看 MCP AI 分析服务日志
+   docker logs -f trend-radar-mcp
+
+   # 查看所有容器状态
    docker ps | grep trend-radar
+
+   # 停止特定服务
+   docker-compose stop trend-radar      # 停止推送服务
+   docker-compose stop trend-radar-mcp  # 停止 MCP 服务
    ```
 
-#### 方式三:本地构建(开发者选项)
+#### 方式:本地构建(开发者选项)
 
 如果需要自定义修改代码或构建自己的镜像:
 
@@ -1950,17 +2139,38 @@ vim config/frequency_words.txt
 # 使用构建版本的 docker-compose
 cd docker
 cp docker-compose-build.yml docker-compose.yml
+```
+
+**构建并启动服务**:
 
-# 构建并启动
+```bash
+# 选项 A:构建并启动所有服务
 docker-compose build
 docker-compose up -d
+
+# 选项 B:仅构建并启动新闻推送服务
+docker-compose build trend-radar
+docker-compose up -d trend-radar
+
+# 选项 C:仅构建并启动 MCP AI 分析服务
+docker-compose build trend-radar-mcp
+docker-compose up -d trend-radar-mcp
 ```
 
+> 💡 **架构参数说明**:
+> - 默认构建 `amd64` 架构镜像(适用于大多数 x86_64 服务器)
+> - 如需构建 `arm64` 架构(Apple Silicon、树莓派等),设置环境变量:
+>   ```bash
+>   export DOCKER_ARCH=arm64
+>   docker-compose build
+>   ```
+
 #### 镜像更新
 
 ```bash
-# 方式一:手动更新
+# 方式一:手动更新(爬虫 + MCP 镜像)
 docker pull wantcat/trendradar:latest
+docker pull wantcat/trendradar-mcp:latest
 docker-compose down
 docker-compose up -d
 
@@ -1969,6 +2179,13 @@ docker-compose pull
 docker-compose up -d
 ```
 
+**可用镜像**:
+
+| 镜像名称 | 用途 | 说明 |
+|---------|------|------|
+| `wantcat/trendradar` | 新闻推送服务 | 定时抓取新闻、推送通知 |
+| `wantcat/trendradar-mcp` | MCP 服务 | AI 分析功能(可选) |
+
 #### 服务管理命令
 
 ```bash
@@ -1987,6 +2204,11 @@ docker exec -it trend-radar python manage.py config
 # 显示输出文件
 docker exec -it trend-radar python manage.py files
 
+# Web 服务器管理(用于浏览器访问生成的报告)
+docker exec -it trend-radar python manage.py start_webserver   # 启动 Web 服务器
+docker exec -it trend-radar python manage.py stop_webserver    # 停止 Web 服务器
+docker exec -it trend-radar python manage.py webserver_status  # 查看 Web 服务器状态
+
 # 查看帮助信息
 docker exec -it trend-radar python manage.py help
 
@@ -2000,10 +2222,52 @@ docker stop trend-radar
 docker rm trend-radar
 ```
 
+> 💡 **Web 服务器说明**:
+> - 启动后可通过浏览器访问 `http://localhost:8080` 查看最新报告
+> - 通过目录导航访问历史报告(如:`http://localhost:8080/2025年xx月xx日/`)
+> - 端口可在 `.env` 文件中配置 `WEBSERVER_PORT` 参数
+> - 自动启动:在 `.env` 中设置 `ENABLE_WEBSERVER=true`
+> - 安全提示:仅提供静态文件访问,限制在 output 目录,只绑定本地访问
+
 #### 数据持久化
 
 生成的报告和数据默认保存在 `./output` 目录下,即使容器重启或删除,数据也会保留。
 
+**📊 网页版报告访问路径**:
+
+TrendRadar 生成的当日汇总 HTML 报告会同时保存到两个位置:
+
+| 文件位置 | 访问方式 | 适用场景 |
+|---------|---------|---------|
+| `output/index.html` | 宿主机直接访问 | **Docker 部署**(通过 Volume 挂载,宿主机可见) |
+| `index.html` | 根目录访问 | **GitHub Pages**(仓库根目录,Pages 自动识别) |
+| `output/YYYY年MM月DD日/html/当日汇总.html` | 历史报告访问 | 所有环境(按日期归档) |
+
+**本地访问示例**:
+```bash
+# 方式 1:通过 Web 服务器访问(推荐,Docker 环境)
+# 1. 启动 Web 服务器
+docker exec -it trend-radar python manage.py start_webserver
+# 2. 在浏览器访问
+http://localhost:8080                           # 访问最新报告(默认 index.html)
+http://localhost:8080/2025年xx月xx日/            # 访问指定日期的报告
+http://localhost:8080/2025年xx月xx日/html/       # 浏览该日期下的所有 HTML 文件
+
+# 方式 2:直接打开文件(本地环境)
+open ./output/index.html             # macOS
+start ./output/index.html            # Windows
+xdg-open ./output/index.html         # Linux
+
+# 方式 3:访问历史归档
+open ./output/2025年xx月xx日/html/当日汇总.html
+```
+
+**为什么有两个 index.html?**
+- `output/index.html`:Docker Volume 挂载到宿主机,本地可直接打开
+- `index.html`:GitHub Actions 推送到仓库,GitHub Pages 自动部署
+
+> 💡 **提示**:两个文件内容完全相同,选择任意一个访问即可。
+
 #### 故障排查
 
 ```bash
@@ -2020,6 +2284,513 @@ docker exec -it trend-radar /bin/bash
 docker exec -it trend-radar ls -la /app/config/
 ```
 
+#### MCP 服务部署(AI 分析功能)
+
+如果需要使用 AI 分析功能,可以部署独立的 MCP 服务容器。
+
+**架构说明**:
+
+```mermaid
+flowchart TB
+    subgraph trend-radar["trend-radar"]
+        A1[定时抓取新闻]
+        A2[推送通知]
+    end
+    
+    subgraph trend-radar-mcp["trend-radar-mcp"]
+        B1[127.0.0.1:3333]
+        B2[AI 分析接口]
+    end
+    
+    subgraph shared["共享卷"]
+        C1["config/ (ro)"]
+        C2["output/ (ro)"]
+    end
+    
+    trend-radar --> shared
+    trend-radar-mcp --> shared
+```
+
+**快速启动**:
+
+使用 docker-compose 同时启动新闻推送和 MCP 服务:
+
+```bash
+# 下载最新的 docker-compose.yml(已包含 MCP 服务配置)
+wget https://raw.githubusercontent.com/sansan0/TrendRadar/master/docker/docker-compose.yml
+
+# 启动所有服务
+docker-compose up -d
+
+# 查看运行状态
+docker ps | grep trend-radar
+```
+
+**单独启动 MCP 服务**:
+
+```bash
+docker run -d --name trend-radar-mcp \
+  -p 127.0.0.1:3333:3333 \
+  -v ./config:/app/config:ro \
+  -v ./output:/app/output:ro \
+  -e TZ=Asia/Shanghai \
+  wantcat/trendradar-mcp:latest
+```
+
+**验证服务**:
+
+```bash
+# 检查 MCP 服务是否正常运行
+curl http://127.0.0.1:3333/mcp
+
+# 查看 MCP 服务日志
+docker logs -f trend-radar-mcp
+```
+
+**在 AI 客户端中配置**:
+
+MCP 服务启动后,在 Claude Desktop、Cherry Studio、Cursor 等客户端中配置:
+
+```json
+{
+  "mcpServers": {
+    "trendradar": {
+      "url": "http://127.0.0.1:3333/mcp",
+      "description": "TrendRadar 新闻热点分析"
+    }
+  }
+}
+```
+
+> 💡 **提示**:MCP 服务仅监听本地端口(127.0.0.1),确保安全性。如需远程访问,请自行配置反向代理和认证。
+
+</details>
+
+### 7. 报告配置
+
+<details>
+<summary>👉 点击展开:<strong>报告相关参数配置</strong></summary>
+<br>
+
+**配置位置:** `config/config.yaml` 的 `report` 部分
+
+```yaml
+report:
+  mode: "daily"                    # 推送模式
+  rank_threshold: 5                # 排名高亮阈值
+  sort_by_position_first: false    # 排序优先级
+  max_news_per_keyword: 0          # 每个关键词最大显示数量
+  reverse_content_order: false     # 内容顺序配置
+```
+
+#### 配置项详解
+
+| 配置项 | 类型 | 默认值 | 说明 |
+|-------|------|-------|------|
+| `mode` | string | `daily` | 推送模式,可选 `daily`/`incremental`/`current`,详见 [推送模式详解](#3-推送模式详解) |
+| `rank_threshold` | int | `5` | 排名高亮阈值,排名 ≤ 该值的新闻会加粗显示 |
+| `sort_by_position_first` | bool | `false` | 排序优先级:`false`=按热点条数排序,`true`=按配置位置排序 |
+| `max_news_per_keyword` | int | `0` | 每个关键词最大显示数量,`0`=不限制 |
+| `reverse_content_order` | bool | `false` | 内容顺序:`false`=热点词汇统计在前,`true`=新增热点新闻在前 |
+
+#### 内容顺序配置(v3.5.0 新增)
+
+控制推送消息和 HTML 报告中两部分内容的显示顺序:
+
+| 配置值 | 显示顺序 |
+|-------|---------|
+| `false`(默认) | ① 热点词汇统计 → ② 新增热点新闻 |
+| `true` | ① 新增热点新闻 → ② 热点词汇统计 |
+
+**适用场景:**
+- `false`(默认):适合关注关键词匹配结果的用户,先看分类统计
+- `true`:适合关注最新动态的用户,优先查看新增热点
+
+**Docker 环境变量:**
+```bash
+REVERSE_CONTENT_ORDER=true
+```
+
+#### 排序优先级配置
+
+**示例场景:** 配置顺序 A、B、C,热点数 A(3条)、B(10条)、C(5条)
+
+| 配置值 | 显示顺序 | 适用场景 |
+|-------|---------|---------|
+| `false`(默认) | B(10条) → C(5条) → A(3条) | 关注热度趋势 |
+| `true` | A(3条) → B(10条) → C(5条) | 关注个人优先级 |
+
+**Docker 环境变量:**
+```bash
+SORT_BY_POSITION_FIRST=true
+MAX_NEWS_PER_KEYWORD=10
+```
+
+</details>
+
+### 8. 推送时间窗口配置
+
+<details>
+<summary>👉 点击展开:<strong>推送时间窗口控制详解</strong></summary>
+<br>
+
+**配置位置:** `config/config.yaml` 的 `notification.push_window` 部分
+
+```yaml
+notification:
+  push_window:
+    enabled: false                    # 是否启用
+    time_range:
+      start: "20:00"                  # 开始时间(北京时间)
+      end: "22:00"                    # 结束时间(北京时间)
+    once_per_day: true                # 每天只推送一次
+    push_record_retention_days: 7     # 推送记录保留天数
+```
+
+#### 配置项详解
+
+| 配置项 | 类型 | 默认值 | 说明 |
+|-------|------|-------|------|
+| `enabled` | bool | `false` | 是否启用推送时间窗口控制 |
+| `time_range.start` | string | `"20:00"` | 推送时间窗口开始时间(北京时间,HH:MM 格式) |
+| `time_range.end` | string | `"22:00"` | 推送时间窗口结束时间(北京时间,HH:MM 格式) |
+| `once_per_day` | bool | `true` | `true`=每天在窗口内只推送一次,`false`=窗口内每次执行都推送 |
+| `push_record_retention_days` | int | `7` | 推送记录保留天数(用于判断是否已推送) |
+
+#### 使用场景
+
+| 场景 | 配置示例 |
+|------|---------|
+| **工作时间推送** | `start: "09:00"`, `end: "18:00"`, `once_per_day: false` |
+| **晚间汇总推送** | `start: "20:00"`, `end: "22:00"`, `once_per_day: true` |
+| **午休时间推送** | `start: "12:00"`, `end: "13:00"`, `once_per_day: true` |
+
+#### 重要提示
+
+> ⚠️ **GitHub Actions 用户注意:**
+> - GitHub Actions 执行时间不稳定,可能有 ±15 分钟的偏差
+> - 时间范围建议至少留足 **2 小时**
+> - 如果想要精准的定时推送,建议使用 **Docker 部署**在个人服务器上
+
+#### Docker 环境变量
+
+```bash
+PUSH_WINDOW_ENABLED=true
+PUSH_WINDOW_START=09:00
+PUSH_WINDOW_END=18:00
+PUSH_WINDOW_ONCE_PER_DAY=false
+PUSH_WINDOW_RETENTION_DAYS=7
+```
+
+#### 完整配置示例
+
+**场景:每天晚上 8-10 点只推送一次汇总**
+
+```yaml
+notification:
+  push_window:
+    enabled: true
+    time_range:
+      start: "20:00"
+      end: "22:00"
+    once_per_day: true
+    push_record_retention_days: 7
+```
+
+**场景:工作时间内每小时推送**
+
+```yaml
+notification:
+  push_window:
+    enabled: true
+    time_range:
+      start: "09:00"
+      end: "18:00"
+    once_per_day: false
+    push_record_retention_days: 7
+```
+
+</details>
+
+### 9. 执行频率配置
+
+<details>
+<summary>👉 点击展开:<strong>自动运行频率设置</strong></summary>
+<br>
+
+**配置位置:** `.github/workflows/crawler.yml` 的 `schedule` 部分
+
+```yaml
+on:
+  schedule:
+    - cron: "0 * * * *"  # 每小时运行一次
+```
+
+#### 什么是 Cron 表达式?
+
+Cron 是一种定时任务格式,由 5 个部分组成:`分 时 日 月 周`
+
+```
+┌───────────── 分钟 (0-59)
+│ ┌───────────── 小时 (0-23)
+│ │ ┌───────────── 日期 (1-31)
+│ │ │ ┌───────────── 月份 (1-12)
+│ │ │ │ ┌───────────── 星期 (0-6,0=周日)
+│ │ │ │ │
+* * * * *
+```
+
+#### 常用配置示例
+
+| 想要的效果 | Cron 表达式 | 说明 |
+|-----------|------------|------|
+| 每小时运行 | `0 * * * *` | 每小时的第 0 分钟运行(默认) |
+| 每 30 分钟运行 | `*/30 * * * *` | 每隔 30 分钟运行一次 |
+| 每天早 8 点运行 | `0 0 * * *` | UTC 0:00 = 北京时间 8:00 |
+| 工作时间运行 | `*/30 0-14 * * *` | 北京 8:00-22:00,每 30 分钟 |
+| 每天 3 次 | `0 0,6,12 * * *` | 北京 8:00、14:00、20:00 |
+
+#### 重要提示
+
+> ⚠️ **时区注意**:GitHub Actions 使用 **UTC 时间**,北京时间需要 **减 8 小时**
+> - 想要北京时间 8:00 运行 → 设置 UTC 0:00
+> - 想要北京时间 20:00 运行 → 设置 UTC 12:00
+
+> ⚠️ **频率限制**:GitHub 对每个账号的 Actions 运行次数有限额
+> - **建议**:不要设置比 30 分钟更短的间隔
+> - **原因**:过于频繁可能被判定为滥用,面临封号风险
+> - **实际情况**:GitHub Actions 执行时间本身就有偏差,设置太精确意义不大
+
+#### 修改方法
+
+1. 打开你 fork 的仓库
+2. 找到 `.github/workflows/crawler.yml` 文件
+3. 点击编辑(铅笔图标)
+4. 修改 `cron: "0 * * * *"` 中的表达式
+5. 点击 "Commit changes" 保存
+
+</details>
+
+### 10. 多账号推送配置
+
+<details>
+<summary>👉 点击展开:<strong>多账号推送配置详解</strong></summary>
+
+> ### ⚠️ **安全警告**
+> **GitHub Fork 用户请勿在 `config.yaml` 中配置推送信息!**
+>
+> - **风险说明**:`config.yaml` 会被提交到公开的 Git 仓库,配置推送信息(Webhook URL、Token 等)会泄露敏感数据
+> - **推荐方式**:
+>   - **GitHub Actions 用户** → 使用 GitHub Secrets 环境变量
+>   - **Docker 用户** → 使用 [`.env` 文件配置](#6-docker-部署)(`.env` 已在 `.gitignore` 中,不会被提交)
+> - **本地开发用户**:可以在 `config.yaml` 中配置(确保不会 push 到公开仓库)
+
+#### 支持的渠道
+
+| 渠道 | 配置项 | 是否需要配对 | 说明 |
+|------|--------|-------------|------|
+| **飞书** | `feishu_url` | 否 | 多个 webhook URL |
+| **钉钉** | `dingtalk_url` | 否 | 多个 webhook URL |
+| **企业微信** | `wework_url` | 否 | 多个 webhook URL |
+| **Telegram** | `telegram_bot_token` + `telegram_chat_id` | ✅ 是 | token 和 chat_id 数量必须一致 |
+| **ntfy** | `ntfy_topic` + `ntfy_token` | ✅ 是 | topic 和 token 数量必须一致(token 可选) |
+| **Bark** | `bark_url` | 否 | 多个推送 URL |
+| **Slack** | `slack_webhook_url` | 否 | 多个 webhook URL |
+| **邮件** | `email_to` | - | 已支持多收件人(逗号分隔),无需修改 |
+
+#### 推荐配置方式 1:GitHub Actions 环境变量
+
+**配置位置**:GitHub Repo → Settings → Secrets and variables → Actions → Repository secrets
+
+**基础配置示例**:
+```bash
+# 多账号数量限制
+MAX_ACCOUNTS_PER_CHANNEL=3
+
+# 飞书多账号(3个群组)
+FEISHU_WEBHOOK_URL=https://hook1.feishu.cn/xxx;https://hook2.feishu.cn/yyy;https://hook3.feishu.cn/zzz
+
+# 钉钉多账号(2个群组)
+DINGTALK_WEBHOOK_URL=https://oapi.dingtalk.com/xxx;https://oapi.dingtalk.com/yyy
+
+# 企业微信多账号(2个群组)
+WEWORK_WEBHOOK_URL=https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx;https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=yyy
+
+# Bark多账号(2个设备)
+BARK_URL=https://api.day.app/key1;https://api.day.app/key2
+
+# Slack多账号(2个频道)
+SLACK_WEBHOOK_URL=https://hooks.slack.com/xxx;https://hooks.slack.com/yyy
+```
+
+**配对配置示例(Telegram 和 ntfy)**:
+
+<details>
+<summary><strong>Telegram 配对配置</strong></summary>
+
+```bash
+# ✅ 正确配置:2个token对应2个chat_id
+TELEGRAM_BOT_TOKEN=123456:AAA-BBB;789012:CCC-DDD
+TELEGRAM_CHAT_ID=-100111;-100222
+
+# ❌ 错误配置:数量不一致,将跳过推送
+TELEGRAM_BOT_TOKEN=token1;token2;token3
+TELEGRAM_CHAT_ID=id1;id2
+```
+
+**说明**:`token` 和 `chat_id` 的数量必须完全一致,否则该渠道推送会被跳过。
+
+</details>
+
+<details>
+<summary><strong>ntfy 配对配置</strong></summary>
+
+```bash
+# ✅ 正确配置:3个topic,只有第2个需要token
+NTFY_TOPIC=topic1;topic2;topic3
+NTFY_TOKEN=;token_for_topic2;
+
+# ✅ 正确配置:2个topic都需要token
+NTFY_TOPIC=topic1;topic2
+NTFY_TOKEN=token1;token2
+
+# ❌ 错误配置:topic和token数量不匹配
+NTFY_TOPIC=topic1;topic2
+NTFY_TOKEN=token1;token2;token3
+```
+
+**说明**:
+- 如果某个 topic 不需要 token,在对应位置留空(两个分号之间)
+- `topic` 和 `token` 的数量必须一致
+
+</details>
+
+---
+
+#### 推荐配置方式 2:Docker 环境变量(.env)
+
+**配置位置**:项目根目录 `docker/.env` 文件
+
+**基础配置示例**:
+```bash
+# 多账号数量限制
+MAX_ACCOUNTS_PER_CHANNEL=3
+
+# 飞书多账号(3个群组)
+FEISHU_WEBHOOK_URL=https://hook1.feishu.cn/xxx;https://hook2.feishu.cn/yyy;https://hook3.feishu.cn/zzz
+
+# 钉钉多账号(2个群组)
+DINGTALK_WEBHOOK_URL=https://oapi.dingtalk.com/xxx;https://oapi.dingtalk.com/yyy
+
+# 企业微信多账号(2个群组)
+WEWORK_WEBHOOK_URL=https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx;https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=yyy
+
+# Bark多账号(2个设备)
+BARK_URL=https://api.day.app/key1;https://api.day.app/key2
+
+# Slack多账号(2个频道)
+SLACK_WEBHOOK_URL=https://hooks.slack.com/xxx;https://hooks.slack.com/yyy
+```
+
+**配对配置示例(Telegram 和 ntfy)**:
+
+<details>
+<summary><strong>Telegram 配对配置</strong></summary>
+
+```bash
+# ✅ 正确配置:2个token对应2个chat_id
+TELEGRAM_BOT_TOKEN=123456:AAA-BBB;789012:CCC-DDD
+TELEGRAM_CHAT_ID=-100111;-100222
+
+# ❌ 错误配置:数量不一致,将跳过推送
+TELEGRAM_BOT_TOKEN=token1;token2;token3
+TELEGRAM_CHAT_ID=id1;id2
+```
+
+**说明**:`token` 和 `chat_id` 的数量必须完全一致,否则该渠道推送会被跳过。
+
+</details>
+
+<details>
+<summary><strong>ntfy 配对配置</strong></summary>
+
+```bash
+# ✅ 正确配置:3个topic,只有第2个需要token
+NTFY_TOPIC=topic1;topic2;topic3
+NTFY_TOKEN=;token_for_topic2;
+
+# ✅ 正确配置:2个topic都需要token
+NTFY_TOPIC=topic1;topic2
+NTFY_TOKEN=token1;token2
+
+# ❌ 错误配置:topic和token数量不匹配
+NTFY_TOPIC=topic1;topic2
+NTFY_TOKEN=token1;token2;token3
+```
+
+**说明**:
+- 如果某个 topic 不需要 token,在对应位置留空(两个分号之间)
+- `topic` 和 `token` 的数量必须一致
+
+</details>
+
+---
+
+#### 推送行为说明
+
+1. **独立推送**:每个账号独立发送,一个失败不影响其他账号
+2. **部分成功判定**:只要有一个账号发送成功,整体视为成功
+3. **日志区分**:多账号时日志会显示"账号1"、"账号2"等标签
+4. **批次间隔**:多账号会增加总发送时间(每个账号独立计算批次间隔)
+
+---
+
+#### 常见问题
+
+<details>
+<summary><strong>Q1: 超过 3 个账号会怎样?</strong></summary>
+<br>
+
+系统会自动截断到配置的最大数量,并输出警告日志。可通过 `max_accounts_per_channel` 调整限制。
+
+**⚠️ GitHub Actions 用户特别注意**:
+- **不建议配置过多账号**(建议不超过 3 个),可能导致:
+  - **触发 GitHub Actions 速率限制**:频繁的网络请求可能被识别为异常行为
+  - **潜在账号风险**:过度使用 GitHub Actions 资源可能影响账号状态
+
+</details>
+
+<details>
+<summary><strong>Q2: 多账号会影响推送速度吗?</strong></summary>
+<br>
+
+会。每个账号独立发送,总时间 = 账号数 × 单账号发送时间。建议控制账号数量。
+
+</details>
+
+<details>
+<summary><strong>Q3: 本地开发用户如何在 config.yaml 中配置?</strong></summary>
+<br>
+
+如果你是本地开发且**不会将代码推送到公开仓库**,可以直接在 `config/config.yaml` 中配置:
+
+```yaml
+notification:
+  enable_notification: true
+  max_accounts_per_channel: 3
+
+  webhooks:
+    feishu_url: "https://hook1.feishu.cn/xxx;https://hook2.feishu.cn/yyy"
+    telegram_bot_token: "token1;token2"
+    telegram_chat_id: "id1;id2"
+```
+
+**⚠️ 重要提醒**:
+- 确保 `config/config.yaml` 在 `.gitignore` 中(如果会提交代码)
+- 或者只在本地开发环境使用,**绝不提交到公开仓库**
+
+</details>
+
 </details>
 
 <br>

+ 27 - 9
config/config.yaml

@@ -29,6 +29,7 @@ report:
   rank_threshold: 5 # 排名高亮阈值
   sort_by_position_first: false # 排序优先级:true=先按配置位置排序,false=先按热点条数排序
   max_news_per_keyword: 0 # 每个关键词最大显示数量,0=不限制
+  reverse_content_order: false # 内容顺序:false=热点词汇统计在前,true=新增热点新闻在前
 
 notification:
   enable_notification: true # 是否启用通知功能,如果 false,则不发送手机通知
@@ -39,6 +40,7 @@ notification:
   slack_batch_size: 4000 # Slack消息分批大小(字节)
   batch_send_interval: 3 # 批次发送间隔(秒)
   feishu_message_separator: "━━━━━━━━━━━━━━━━━━━" # feishu 消息分割线
+  max_accounts_per_channel: 3 # 每个渠道最大账号数量,建议不超过 3
 
   # 🕐 推送时间窗口控制(可选功能)
   # 用途:限制推送的时间范围,避免非工作时间打扰
@@ -71,23 +73,39 @@ notification:
   #    - Minor: Spam notifications flooding your devices
   #    - Severe: Webhook abuse leading to security incidents (malicious messages, phishing links, etc.)
   #
+  # ⚠️⚠️⚠️ 多账号推送说明 / MULTI-ACCOUNT PUSH NOTICE ⚠️⚠️⚠️
+  #
+  # 🔸 多账号支持:
+  #   • 请使用分号(;)分隔多个账号,如:"url1;url2;url3"
+  #   • 示例:telegram_bot_token: "token1;token2" 对应 telegram_chat_id: "id1;id2"
+  #   • 对于需要配对的配置(如 Telegram 的 token 和 chat_id),数量必须一致
+  #   • 每个渠道最多支持 max_accounts_per_channel 个账号(见上方配置)
+  #   • 邮箱已支持多收件人(逗号分隔),保持不变
+  #
+  # 🔸 Multi-Account Support:
+  #   • Use semicolon(;) to separate multiple accounts, e.g., "url1;url2;url3"
+  #   • Example: telegram_bot_token: "token1;token2" with telegram_chat_id: "id1;id2"
+  #   • For paired configs (e.g., Telegram token and chat_id), quantities must match
+  #   • Each channel supports up to max_accounts_per_channel accounts (see above config)
+  #   • Email already supports multiple recipients (comma-separated), unchanged
+  #
   webhooks:
-    feishu_url: "" # 飞书机器人的 webhook URL
-    dingtalk_url: "" # 钉钉机器人的 webhook URL
-    wework_url: "" # 企业微信机器人的 webhook URL
+    feishu_url: "" # 飞书机器人的 webhook URL(多账号用 ; 分隔)
+    dingtalk_url: "" # 钉钉机器人的 webhook URL(多账号用 ; 分隔)
+    wework_url: "" # 企业微信机器人的 webhook URL(多账号用 ; 分隔)
     wework_msg_type: "markdown" # 企业微信消息类型:markdown(群机器人) 或 text(个人微信应用)
-    telegram_bot_token: "" # Telegram Bot Token
-    telegram_chat_id: "" # Telegram Chat ID
+    telegram_bot_token: "" # Telegram Bot Token(多账号用 ; 分隔,需与 chat_id 数量一致)
+    telegram_chat_id: "" # Telegram Chat ID(多账号用 ; 分隔,需与 bot_token 数量一致)
     email_from: "" # 发件人邮箱地址
     email_password: "" # 发件人邮箱密码或授权码
     email_to: "" # 收件人邮箱地址,多个收件人用逗号分隔
     email_smtp_server: "" # SMTP服务器地址(可选,留空自动识别)
     email_smtp_port: "" # SMTP端口(可选,留空自动识别)
     ntfy_server_url: "https://ntfy.sh" # ntfy服务器地址,默认使用公共服务,可改为自托管地址
-    ntfy_topic: "" # ntfy主题名称
-    ntfy_token: "" # ntfy访问令牌(可选,用于私有主题)
-    bark_url: "" # Bark推送URL(格式:https://api.day.app/your_device_key 或自建服务器地址)
-    slack_webhook_url: "" # Slack Incoming Webhook URL(格式:https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX)
+    ntfy_topic: "" # ntfy主题名称(多账号用 ; 分隔)
+    ntfy_token: "" # ntfy访问令牌(可选,用于私有主题,多账号用 ; 分隔
+    bark_url: "" # Bark推送URL(多账号用 ; 分隔,格式:https://api.day.app/your_device_key 或自建服务器地址)
+    slack_webhook_url: "" # Slack Incoming Webhook URL(多账号用 ; 分隔,格式:https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX)
 
 # 用于让关注度更高的新闻在更前面显示,即用算法重新组合不同平台的热搜排序形成你侧重的热搜,合起来是 1 就行
 weight:

+ 35 - 9
docker/.env

@@ -12,6 +12,21 @@ REPORT_MODE=
 SORT_BY_POSITION_FIRST=
 # 每个关键词最大显示数量 (0=不限制,>0=限制数量)
 MAX_NEWS_PER_KEYWORD=
+# 内容顺序:false=热点词汇统计在前,true=新增热点新闻在前
+REVERSE_CONTENT_ORDER=
+
+# ============================================
+# Web 服务器配置
+# ============================================
+
+# 是否自动启动 Web 服务器托管 output 目录 (true/false)
+# 启用后可通过 http://localhost:{WEBSERVER_PORT} 访问生成的报告
+# 手动控制:docker exec -it trend-radar python manage.py start_webserver
+ENABLE_WEBSERVER=false
+
+# Web 服务器端口(默认 8080,可自定义避免冲突)
+# 注意:修改后需要重启容器生效
+WEBSERVER_PORT=8080
 
 # ============================================
 # 推送时间窗口配置
@@ -29,36 +44,47 @@ PUSH_WINDOW_ONCE_PER_DAY=
 PUSH_WINDOW_RETENTION_DAYS=
 
 # ============================================
-# 通知渠道配置
+# 多账号配置
+# ============================================
+
+# 每个渠道最大账号数量(建议不超过 3,避免fork用户触发账号风险)
+MAX_ACCOUNTS_PER_CHANNEL=
+
+# ============================================
+# 通知渠道配置(多账号用 ; 分隔)
 # ============================================
 
-# 推送配置
+# 飞书机器人 webhook URL(多账号用 ; 分隔)
 FEISHU_WEBHOOK_URL=
+# Telegram Bot Token(多账号用 ; 分隔,需与 chat_id 数量一致)
 TELEGRAM_BOT_TOKEN=
+# Telegram Chat ID(多账号用 ; 分隔,需与 bot_token 数量一致)
 TELEGRAM_CHAT_ID=
+# 钉钉机器人 webhook URL(多账号用 ; 分隔)
 DINGTALK_WEBHOOK_URL=
+# 企业微信机器人 webhook URL(多账号用 ; 分隔)
 WEWORK_WEBHOOK_URL=
+# 企业微信消息类型(markdown 或 text)
 WEWORK_MSG_TYPE=
 
+# 邮件配置(邮箱已支持多收件人,逗号分隔)
 EMAIL_FROM=
 EMAIL_PASSWORD=
 EMAIL_TO=
 EMAIL_SMTP_SERVER=
 EMAIL_SMTP_PORT=
 
-# ntfy 推送配置
+# ntfy 推送配置(多账号用 ; 分隔,topic 和 token 数量需一致)
 NTFY_SERVER_URL=https://ntfy.sh
-# ntfy主题名称
+# ntfy主题名称(多账号用 ; 分隔)
 NTFY_TOPIC=
-# 可选:访问令牌(用于私有主题)
+# 可选:访问令牌(用于私有主题,多账号用 ; 分隔,无令牌的留空占位如 ";token2")
 NTFY_TOKEN=
 
-# Bark 推送配置
-# Bark推送URL(格式:https://api.day.app/your_device_key 或自建服务器地址)
+# Bark 推送配置(多账号用 ; 分隔)
 BARK_URL=
 
-# Slack 推送配置
-# Slack Incoming Webhook URL(格式:https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX)
+# Slack 推送配置(多账号用 ; 分隔)
 SLACK_WEBHOOK_URL=
 
 # ============================================

+ 18 - 19
docker/Dockerfile

@@ -2,9 +2,9 @@ FROM python:3.10-slim
 
 WORKDIR /app
 
-# https://github.com/aptible/supercronic
+# Latest releases available at https://github.com/aptible/supercronic/releases
 ARG TARGETARCH
-ENV SUPERCRONIC_VERSION=v0.2.34
+ENV SUPERCRONIC_VERSION=v0.2.39
 
 RUN set -ex && \
     apt-get update && \
@@ -12,12 +12,12 @@ RUN set -ex && \
     case ${TARGETARCH} in \
     amd64) \
     export SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/${SUPERCRONIC_VERSION}/supercronic-linux-amd64; \
-    export SUPERCRONIC_SHA1SUM=e8631edc1775000d119b70fd40339a7238eece14; \
+    export SUPERCRONIC_SHA1SUM=c98bbf82c5f648aaac8708c182cc83046fe48423; \
     export SUPERCRONIC=supercronic-linux-amd64; \
     ;; \
     arm64) \
     export SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/${SUPERCRONIC_VERSION}/supercronic-linux-arm64; \
-    export SUPERCRONIC_SHA1SUM=4ab6343b52bf9da592e8b4bb7ae6eb5a8e21b71e; \
+    export SUPERCRONIC_SHA1SUM=5ef4ccc3d43f12d0f6c3763758bc37cc4e5af76e; \
     export SUPERCRONIC=supercronic-linux-arm64; \
     ;; \
     *) \
@@ -26,26 +26,25 @@ RUN set -ex && \
     ;; \
     esac && \
     echo "Downloading supercronic for ${TARGETARCH} from ${SUPERCRONIC_URL}" && \
-    # 添加重试机制和超时设置
-    for i in 1 2 3 4 5; do \
-    echo "Download attempt $i/5"; \
-    if curl --fail --silent --show-error --location --retry 3 --retry-delay 2 --connect-timeout 30 --max-time 120 -o "$SUPERCRONIC" "$SUPERCRONIC_URL"; then \
-    echo "Download successful"; \
-    break; \
-    else \
-    echo "Download attempt $i failed, exit code: $?"; \
-    if [ $i -eq 5 ]; then \
-    echo "All download attempts failed"; \
-    exit 1; \
-    fi; \
-    sleep $((i * 2)); \
-    fi; \
+    # 重试机制:最多3次,每次超时30秒
+    for i in 1 2 3; do \
+        echo "Download attempt $i/3"; \
+        if curl -fsSL --connect-timeout 30 --max-time 60 -o "$SUPERCRONIC" "$SUPERCRONIC_URL"; then \
+            echo "Download successful"; \
+            break; \
+        else \
+            echo "Download attempt $i failed"; \
+            if [ $i -eq 3 ]; then \
+                echo "All download attempts failed"; \
+                exit 1; \
+            fi; \
+            sleep 2; \
+        fi; \
     done && \
     echo "${SUPERCRONIC_SHA1SUM}  ${SUPERCRONIC}" | sha1sum -c - && \
     chmod +x "$SUPERCRONIC" && \
     mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" && \
     ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic && \
-    # 验证安装
     supercronic -version && \
     apt-get remove -y curl && \
     apt-get clean && \

+ 23 - 0
docker/Dockerfile.mcp

@@ -0,0 +1,23 @@
+FROM python:3.10-slim
+
+WORKDIR /app
+
+# 安装依赖
+COPY requirements.txt .
+RUN pip install --no-cache-dir -r requirements.txt
+
+# 复制 MCP 服务器代码
+COPY mcp_server/ ./mcp_server/
+
+# 创建必要目录
+RUN mkdir -p /app/config /app/output
+
+ENV PYTHONUNBUFFERED=1 \
+    CONFIG_PATH=/app/config/config.yaml \
+    FREQUENCY_WORDS_PATH=/app/config/frequency_words.txt
+
+# MCP HTTP 服务端口
+EXPOSE 3333
+
+# 启动 MCP 服务器(HTTP 模式)
+CMD ["python", "-m", "mcp_server.server", "--transport", "http", "--host", "0.0.0.0", "--port", "3333"]

+ 26 - 0
docker/docker-compose-build.yml

@@ -6,6 +6,9 @@ services:
     container_name: trend-radar
     restart: unless-stopped
 
+    ports:
+      - "127.0.0.1:${WEBSERVER_PORT:-8080}:${WEBSERVER_PORT:-8080}"
+
     volumes:
       - ../config:/app/config:ro
       - ../output:/app/output
@@ -18,6 +21,12 @@ services:
       - REPORT_MODE=${REPORT_MODE:-}
       - SORT_BY_POSITION_FIRST=${SORT_BY_POSITION_FIRST:-}
       - MAX_NEWS_PER_KEYWORD=${MAX_NEWS_PER_KEYWORD:-}
+      - REVERSE_CONTENT_ORDER=${REVERSE_CONTENT_ORDER:-}
+      # Web 服务器
+      - ENABLE_WEBSERVER=${ENABLE_WEBSERVER:-false}
+      - WEBSERVER_PORT=${WEBSERVER_PORT:-8080}
+      # 多账号配置
+      - MAX_ACCOUNTS_PER_CHANNEL=${MAX_ACCOUNTS_PER_CHANNEL:-}
       # 推送时间窗口
       - PUSH_WINDOW_ENABLED=${PUSH_WINDOW_ENABLED:-}
       - PUSH_WINDOW_START=${PUSH_WINDOW_START:-}
@@ -49,3 +58,20 @@ services:
       - CRON_SCHEDULE=${CRON_SCHEDULE:-*/5 * * * *}
       - RUN_MODE=${RUN_MODE:-cron}
       - IMMEDIATE_RUN=${IMMEDIATE_RUN:-true}
+
+  trend-radar-mcp:
+    build:
+      context: ..
+      dockerfile: docker/Dockerfile.mcp
+    container_name: trend-radar-mcp
+    restart: unless-stopped
+
+    ports:
+      - "127.0.0.1:3333:3333"
+
+    volumes:
+      - ../config:/app/config:ro
+      - ../output:/app/output:ro
+
+    environment:
+      - TZ=Asia/Shanghai

+ 24 - 0
docker/docker-compose.yml

@@ -4,6 +4,9 @@ services:
     container_name: trend-radar
     restart: unless-stopped
 
+    ports:
+      - "127.0.0.1:${WEBSERVER_PORT:-8080}:${WEBSERVER_PORT:-8080}"
+
     volumes:
       - ../config:/app/config:ro
       - ../output:/app/output
@@ -16,6 +19,12 @@ services:
       - REPORT_MODE=${REPORT_MODE:-}
       - SORT_BY_POSITION_FIRST=${SORT_BY_POSITION_FIRST:-}
       - MAX_NEWS_PER_KEYWORD=${MAX_NEWS_PER_KEYWORD:-}
+      - REVERSE_CONTENT_ORDER=${REVERSE_CONTENT_ORDER:-}
+      # Web 服务器
+      - ENABLE_WEBSERVER=${ENABLE_WEBSERVER:-false}
+      - WEBSERVER_PORT=${WEBSERVER_PORT:-8080}
+      # 多账号配置
+      - MAX_ACCOUNTS_PER_CHANNEL=${MAX_ACCOUNTS_PER_CHANNEL:-}
       # 推送时间窗口
       - PUSH_WINDOW_ENABLED=${PUSH_WINDOW_ENABLED:-}
       - PUSH_WINDOW_START=${PUSH_WINDOW_START:-}
@@ -47,3 +56,18 @@ services:
       - CRON_SCHEDULE=${CRON_SCHEDULE:-*/5 * * * *}
       - RUN_MODE=${RUN_MODE:-cron}
       - IMMEDIATE_RUN=${IMMEDIATE_RUN:-true}
+
+  trend-radar-mcp:
+    image: wantcat/trendradar-mcp:latest
+    container_name: trend-radar-mcp
+    restart: unless-stopped
+
+    ports:
+      - "127.0.0.1:3333:3333"
+
+    volumes:
+      - ../config:/app/config:ro
+      - ../output:/app/output:ro
+
+    environment:
+      - TZ=Asia/Shanghai

+ 7 - 1
docker/entrypoint.sh

@@ -33,9 +33,15 @@ case "${RUN_MODE:-cron}" in
         /usr/local/bin/python main.py
     fi
 
+    # 启动 Web 服务器(如果配置了)
+    if [ "${ENABLE_WEBSERVER:-false}" = "true" ]; then
+        echo "🌐 启动 Web 服务器..."
+        /usr/local/bin/python manage.py start_webserver
+    fi
+
     echo "⏰ 启动supercronic: ${CRON_SCHEDULE:-*/30 * * * *}"
     echo "🎯 supercronic 将作为 PID 1 运行"
-    
+
     exec /usr/local/bin/supercronic -passthrough-logs /tmp/crontab
     ;;
 *)

+ 167 - 14
docker/manage.py

@@ -8,8 +8,14 @@ import os
 import sys
 import subprocess
 import time
+import signal
 from pathlib import Path
 
+# Web 服务器配置
+WEBSERVER_PORT = int(os.environ.get("WEBSERVER_PORT", "8080"))
+WEBSERVER_DIR = "/app/output"
+WEBSERVER_PID_FILE = "/tmp/webserver.pid"
+
 
 def run_command(cmd, shell=True, capture_output=True):
     """执行系统命令"""
@@ -374,13 +380,13 @@ def restart_supercronic():
     """重启supercronic进程"""
     print("🔄 重启supercronic...")
     print("⚠️ 注意: supercronic 是 PID 1,无法直接重启")
-    
+
     # 检查当前 PID 1
     try:
         with open('/proc/1/cmdline', 'r') as f:
             pid1_cmdline = f.read().replace('\x00', ' ').strip()
         print(f"  🔍 当前 PID 1: {pid1_cmdline}")
-        
+
         if "supercronic" in pid1_cmdline.lower():
             print("  ✅ PID 1 是 supercronic")
             print("  💡 要重启 supercronic,需要重启整个容器:")
@@ -394,29 +400,167 @@ def restart_supercronic():
         print("  💡 建议重启容器: docker restart trend-radar")
 
 
+def start_webserver():
+    """启动 Web 服务器托管 output 目录"""
+    print(f"🌐 启动 Web 服务器 (端口: {WEBSERVER_PORT})...")
+    print(f"  🔒 安全提示:仅提供静态文件访问,限制在 {WEBSERVER_DIR} 目录")
+
+    # 检查是否已经运行
+    if Path(WEBSERVER_PID_FILE).exists():
+        try:
+            with open(WEBSERVER_PID_FILE, 'r') as f:
+                old_pid = int(f.read().strip())
+            try:
+                os.kill(old_pid, 0)  # 检查进程是否存在
+                print(f"  ⚠️ Web 服务器已在运行 (PID: {old_pid})")
+                print(f"  💡 访问: http://localhost:{WEBSERVER_PORT}")
+                print("  💡 停止服务: python manage.py stop_webserver")
+                return
+            except OSError:
+                # 进程不存在,删除旧的 PID 文件
+                os.remove(WEBSERVER_PID_FILE)
+        except Exception as e:
+            print(f"  ⚠️ 清理旧的 PID 文件: {e}")
+            try:
+                os.remove(WEBSERVER_PID_FILE)
+            except:
+                pass
+
+    # 检查目录是否存在
+    if not Path(WEBSERVER_DIR).exists():
+        print(f"  ❌ 目录不存在: {WEBSERVER_DIR}")
+        return
+
+    try:
+        # 启动 HTTP 服务器
+        # 使用 --bind 绑定到 0.0.0.0 使容器内部可访问
+        # 工作目录限制在 WEBSERVER_DIR,防止访问其他目录
+        process = subprocess.Popen(
+            [sys.executable, '-m', 'http.server', str(WEBSERVER_PORT), '--bind', '0.0.0.0'],
+            cwd=WEBSERVER_DIR,
+            stdout=subprocess.DEVNULL,
+            stderr=subprocess.DEVNULL,
+            start_new_session=True
+        )
+
+        # 等待一下确保服务器启动
+        time.sleep(1)
+
+        # 检查进程是否还在运行
+        if process.poll() is None:
+            # 保存 PID
+            with open(WEBSERVER_PID_FILE, 'w') as f:
+                f.write(str(process.pid))
+
+            print(f"  ✅ Web 服务器已启动 (PID: {process.pid})")
+            print(f"  📁 服务目录: {WEBSERVER_DIR} (只读,仅静态文件)")
+            print(f"  🌐 访问地址: http://localhost:{WEBSERVER_PORT}")
+            print(f"  📄 首页: http://localhost:{WEBSERVER_PORT}/index.html")
+            print("  💡 停止服务: python manage.py stop_webserver")
+        else:
+            print(f"  ❌ Web 服务器启动失败")
+    except Exception as e:
+        print(f"  ❌ 启动失败: {e}")
+
+
+def stop_webserver():
+    """停止 Web 服务器"""
+    print("🛑 停止 Web 服务器...")
+
+    if not Path(WEBSERVER_PID_FILE).exists():
+        print("  ℹ️ Web 服务器未运行")
+        return
+
+    try:
+        with open(WEBSERVER_PID_FILE, 'r') as f:
+            pid = int(f.read().strip())
+
+        try:
+            # 尝试终止进程
+            os.kill(pid, signal.SIGTERM)
+            time.sleep(0.5)
+
+            # 检查进程是否已终止
+            try:
+                os.kill(pid, 0)
+                # 进程还在,强制杀死
+                os.kill(pid, signal.SIGKILL)
+                print(f"  ⚠️ 强制停止 Web 服务器 (PID: {pid})")
+            except OSError:
+                print(f"  ✅ Web 服务器已停止 (PID: {pid})")
+        except OSError as e:
+            if e.errno == 3:  # No such process
+                print(f"  ℹ️ 进程已不存在 (PID: {pid})")
+            else:
+                raise
+
+        # 删除 PID 文件
+        os.remove(WEBSERVER_PID_FILE)
+    except Exception as e:
+        print(f"  ❌ 停止失败: {e}")
+        # 尝试清理 PID 文件
+        try:
+            os.remove(WEBSERVER_PID_FILE)
+        except:
+            pass
+
+
+def webserver_status():
+    """查看 Web 服务器状态"""
+    print("🌐 Web 服务器状态:")
+
+    if not Path(WEBSERVER_PID_FILE).exists():
+        print("  ⭕ 未运行")
+        print(f"  💡 启动服务: python manage.py start_webserver")
+        return
+
+    try:
+        with open(WEBSERVER_PID_FILE, 'r') as f:
+            pid = int(f.read().strip())
+
+        try:
+            os.kill(pid, 0)  # 检查进程是否存在
+            print(f"  ✅ 运行中 (PID: {pid})")
+            print(f"  📁 服务目录: {WEBSERVER_DIR}")
+            print(f"  🌐 访问地址: http://localhost:{WEBSERVER_PORT}")
+            print(f"  📄 首页: http://localhost:{WEBSERVER_PORT}/index.html")
+            print("  💡 停止服务: python manage.py stop_webserver")
+        except OSError:
+            print(f"  ⭕ 未运行 (PID 文件存在但进程不存在)")
+            os.remove(WEBSERVER_PID_FILE)
+            print("  💡 启动服务: python manage.py start_webserver")
+    except Exception as e:
+        print(f"  ❌ 状态检查失败: {e}")
+
+
 def show_help():
     """显示帮助信息"""
     help_text = """
 🐳 TrendRadar 容器管理工具
 
 📋 命令列表:
-  run         - 手动执行一次爬虫
-  status      - 显示容器运行状态
-  config      - 显示当前配置
-  files       - 显示输出文件
-  logs        - 实时查看日志
-  restart     - 重启说明
-  help        - 显示此帮助
+  run              - 手动执行一次爬虫
+  status           - 显示容器运行状态
+  config           - 显示当前配置
+  files            - 显示输出文件
+  logs             - 实时查看日志
+  restart          - 重启说明
+  start_webserver  - 启动 Web 服务器托管 output 目录
+  stop_webserver   - 停止 Web 服务器
+  webserver_status - 查看 Web 服务器状态
+  help             - 显示此帮助
 
 📖 使用示例:
   # 在容器中执行
   python manage.py run
   python manage.py status
   python manage.py logs
-  
+  python manage.py start_webserver
+
   # 在宿主机执行
   docker exec -it trend-radar python manage.py run
   docker exec -it trend-radar python manage.py status
+  docker exec -it trend-radar python manage.py start_webserver
   docker logs trend-radar
 
 💡 常用操作指南:
@@ -424,18 +568,24 @@ def show_help():
      - 查看 supercronic 是否为 PID 1
      - 检查配置文件和关键文件
      - 查看 cron 调度设置
-  
-  2. 手动执行测试: run  
+
+  2. 手动执行测试: run
      - 立即执行一次新闻爬取
      - 测试程序是否正常工作
-  
+
   3. 查看日志: logs
      - 实时监控运行情况
      - 也可使用: docker logs trend-radar
-  
+
   4. 重启服务: restart
      - 由于 supercronic 是 PID 1,需要重启整个容器
      - 使用: docker restart trend-radar
+
+  5. Web 服务器管理:
+     - 启动: start_webserver
+     - 停止: stop_webserver
+     - 状态: webserver_status
+     - 访问: http://localhost:8080
 """
     print(help_text)
 
@@ -453,6 +603,9 @@ def main():
         "files": show_files,
         "logs": show_logs,
         "restart": restart_supercronic,
+        "start_webserver": start_webserver,
+        "stop_webserver": stop_webserver,
+        "webserver_status": webserver_status,
         "help": show_help,
     }
 

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 511 - 199
main.py


+ 1 - 1
version

@@ -1 +1 @@
-3.4.1
+3.5.0

Vissa filer visades inte eftersom för många filer har ändrats