{"id":48279295,"url":"https://github.com/wang-h/werss","last_synced_at":"2026-04-04T22:42:36.140Z","repository":{"id":328637868,"uuid":"1116211241","full_name":"wang-h/werss","owner":"wang-h","description":"WeRSS - 微信公众号热度分析系统","archived":false,"fork":false,"pushed_at":"2026-03-21T05:01:42.000Z","size":6259,"stargazers_count":35,"open_issues_count":0,"forks_count":6,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-21T07:38:06.462Z","etag":null,"topics":["keyword-extraction","topic-modeling","wechat"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wang-h.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"docs/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-14T12:28:20.000Z","updated_at":"2026-03-21T05:01:46.000Z","dependencies_parsed_at":"2026-01-02T20:12:19.893Z","dependency_job_id":null,"html_url":"https://github.com/wang-h/werss","commit_stats":null,"previous_names":["wang-h/werss"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/wang-h/werss","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wang-h%2Fwerss","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wang-h%2Fwerss/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wang-h%2Fwerss/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wang-h%2Fwerss/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wang-h","download_url":"https://codeload.github.com/wang-h/werss/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wang-h%2Fwerss/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31417867,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T20:09:54.854Z","status":"ssl_error","status_checked_at":"2026-04-04T20:09:44.350Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["keyword-extraction","topic-modeling","wechat"],"created_at":"2026-04-04T22:42:36.029Z","updated_at":"2026-04-04T22:42:36.118Z","avatar_url":"https://github.com/wang-h.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cimg src=\"https://raw.githubusercontent.com/wang-h/werss/main/static/logo.svg\" alt=\"WeRSS Logo\" width=\"100\" height=\"100\"\u003e\n\n# WeRSS - 微信公众号热度分析系统\n\n![Version](https://img.shields.io/badge/version-1.1.0-blue.svg)\n![Python](https://img.shields.io/badge/python-3.11+-green.svg)\n![License](https://img.shields.io/badge/license-MIT-orange.svg)\n![GitHub Stars](https://img.shields.io/github/stars/wang-h/werss?style=social)\n![GitHub Forks](https://img.shields.io/github/forks/wang-h/werss?style=social)\n\n**一个功能强大的微信公众号热度分析系统，支持自动采集、标签管理、多格式导出、主题词提取与热度追踪等功能**\n\n[功能特性](#-功能特性) • [快速开始](#-快速开始) • [配置说明](#-配置说明) • [API文档](#-api文档) • [开发指南](#-开发指南) • [路线图与维护](#-路线图与维护)\n\n\u003c/div\u003e\n\n---\n\n## 路线图与维护\n\n**维护说明：** 当前本项目的日常维护（Issue 与 PR 的跟进、文档与发布节奏等）**主要依托 [OpenClaw](https://openclaw.ai)** 进行；社区贡献与学术合作仍照常欢迎。\n\n**路线图与待办（摘要）：**\n\n| 方向 | 概要 |\n|------|------|\n| 微信成文 Skill | 按给定 **topic** 生成公众号向文章/大纲，与现有入库与审核流程对齐 |\n| 关键词 / 标签 | 探索基于 **GLiNER** 的轻量化抽取，与现有 KeyBERT、LLM 管线对照或级联 |\n| 共建维护 | 欢迎学术研究者与开源贡献者参与长期维护（见贡献指南） |\n\n完整表格与可勾选待办见 **[docs/ROADMAP.md](docs/ROADMAP.md)**。\n\n---\n\n## 📖 项目简介\n\nWeRSS 是一个前后端分离的微信公众号热度分析系统，可以帮助用户将微信公众号文章转换为RSS订阅源，支持自动采集、内容管理、标签分类、多格式导出等功能。\n\n### 技术栈\n\n**后端：**\n- **FastAPI** - 现代化的 Python Web 框架\n- **SQLAlchemy** - Python ORM 框架\n- **Playwright** - 浏览器自动化\n- **APScheduler** - 定时任务调度\n\n**前端：**\n- **React 18** - UI 框架\n- **TypeScript** - 类型系统\n- **Vite** - 构建工具\n- **Tailwind CSS** - 实用优先的 CSS 框架\n- **Radix UI / shadcn/ui** - 组件库\n- **React Router v6** - 路由管理\n- **Zustand** - 状态管理\n- **Axios** - HTTP 客户端\n\n### 核心能力\n\n- 🔄 **自动采集**：支持多种采集模式（web/api/app），自动抓取公众号文章\n- 📰 **RSS生成**：将公众号文章转换为标准RSS订阅源\n- 🏷️ **标签管理**：支持手动和AI自动标签提取\n- 📤 **多格式导出**：支持PDF、Markdown格式导出\n- 🔔 **消息通知**：支持钉钉、微信、飞书等通知方式\n- 🔐 **用户认证**：完整的用户认证和权限管理\n- ⏰ **定时任务**：自动执行文章采集和内容更新\n\n---\n\n## 🖼️ 界面预览\n\n### 数据概览\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/wang-h/werss/main/images/dashboard.png\" alt=\"数据概览（浅色主题）\" width=\"800\"/\u003e\n  \u003cbr/\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/wang-h/werss/main/images/dashboard-dark.png\" alt=\"数据概览（深色主题）\" width=\"800\"/\u003e\n\u003c/div\u003e\n\n### 热点追踪\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/wang-h/werss/main/images/hot-topics.png\" alt=\"热点追踪\" width=\"800\"/\u003e\n\u003c/div\u003e\n\n### 文章列表\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/wang-h/werss/main/images/articlelist.png\" alt=\"文章列表\" width=\"800\"/\u003e\n\u003c/div\u003e\n\n### RSS订阅\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/wang-h/werss/main/images/rss.png\" alt=\"RSS订阅\" width=\"800\"/\u003e\n\u003c/div\u003e\n\n---\n\n## ✨ 功能特性\n\n### 文章管理\n- ✅ 自动采集微信公众号文章\n- ✅ 支持多种采集模式（web/api/app）\n- ✅ 文章内容自动提取和清理\n- ✅ 文章搜索和筛选\n- ✅ 文章标签分类管理\n\n### RSS订阅\n- ✅ 标准RSS 2.0格式输出\n- ✅ 支持全文/摘要模式\n- ✅ 自定义RSS标题、描述、封面\n- ✅ 支持CDATA格式\n- ✅ 分页支持\n\n### 标签系统\n- ✅ 手动标签管理\n- ✅ 自动标签提取（TextRank/KeyBERT/AI）\n  - **TextRank**：基于图算法的本地关键词提取，无需外部依赖\n  - **KeyBERT**：基于 BERT 的语义关键词提取，支持多语言模型\n  - **AI (OpenAI 兼容)**：使用 OpenAI 兼容 API（DeepSeek、Qwen3 等）进行智能标签提取，准确度最高\n    - 优先提取公司名称、产品名称、技术名称等重要实体\n    - 支持 Qwen3 模型（自动禁用思考功能）\n- ✅ 基于公众号的自动标签关联\n- ✅ 标签统计和分析\n- ✅ 智能标签自动创建\n\n### 导出功能\n- ✅ PDF导出（需启用）\n- ✅ Markdown导出（需启用）\n- ✅ 批量导出支持\n\n### 图片存储\n- ✅ MinIO 对象存储支持\n- ✅ 文章图片自动下载和上传\n- ✅ 图片URL自动替换为MinIO链接\n\n### 通知系统\n- ✅ 钉钉Webhook通知\n- ✅ 企业微信Webhook通知\n- ✅ 飞书Webhook通知\n- ✅ 自定义Webhook通知\n- ✅ 授权二维码过期通知\n- ✅ 消息订阅模板（支持单个公众号和多公众号汇总）\n\n### 消息订阅模板\n\n系统支持通过消息任务定时发送公众号文章汇总，支持自定义消息模板。\n\n#### 模板类型\n\n**1. 单个公众号模板**\n\n适用于单个公众号的消息推送，模板变量：\n- `{{feed.mp_name}}` - 公众号名称\n- `{{articles}}` - 文章列表\n- `{{article.title}}` - 文章标题\n- `{{article.url}}` - 文章链接\n- `{{article.publish_time}}` - 发布时间\n- `{{article.description}}` - 文章描述\n- `{{article.pic_url}}` - 封面图URL\n\n**示例模板：**\n```jinja2\n### {{feed.mp_name}} 订阅消息：\n{% if articles %}\n{% for article in articles %}\n- [**{{ article.title }}**]({{article.url}}) ({{ article.publish_time }})\n{% endfor %}\n{% else %}\n- 暂无文章\n{% endif %}\n```\n\n**2. 多个公众号汇总模板（推荐）**\n\n适用于汇总多个公众号的文章，模板变量：\n- `{{feeds_with_articles}}` - 公众号及文章列表（数组）\n- `{{item.feed.mp_name}}` - 公众号名称\n- `{{item.articles}}` - 该公众号的文章列表\n- `{{total_articles}}` - 总文章数\n- `{{feeds_count}}` - 公众号数量\n- `{{task.name}}` - 任务名称\n- `{{now}}` - 当前时间\n\n**默认汇总模板：**\n```jinja2\n# 每日订阅汇总\n\n{% for item in feeds_with_articles %}\n## {{ item.feed.mp_name }}\n\n{% for article in item.articles %}\n- [**{{ article.title }}**]({{ article.url }}){% if article.publish_time %} ({{ article.publish_time }}){% endif %}\n{% endfor %}\n\n{% endfor %}\n\n---\n共 {{ total_articles }} 篇文章，来自 {{ feeds_count }} 个公众号\n```\n\n**自定义汇总模板示例：**\n```jinja2\n# 每日订阅汇总\n\n{% for item in feeds_with_articles %}\n### {{ item.feed.mp_name }} 订阅消息：\n\n{% for article in item.articles %}\n- [**{{ article.title }}**]({{ article.url }}) ({{ article.publish_time }})\n{% endfor %}\n\n{% endfor %}\n\n---\n共 {{ total_articles }} 篇文章，来自 {{ feeds_count }} 个公众号\n```\n\n#### 模板语法\n\n系统使用 Jinja2 风格的模板语法，支持：\n- **变量输出**：`{{ variable }}`\n- **条件判断**：`{% if condition %}...{% endif %}`\n- **循环遍历**：`{% for item in items %}...{% endfor %}`\n- **点号访问**：`{{ item.feed.mp_name }}`（访问嵌套属性）\n\n#### 模板选择逻辑\n\n- 如果自定义模板中包含 `feeds_with_articles` 变量，系统会使用自定义模板进行汇总\n- 如果自定义模板不包含 `feeds_with_articles`，系统会使用默认的汇总模板\n- 单个公众号模板仅适用于单个公众号的消息推送场景\n\n#### 支持的通知平台\n\n消息模板支持以下通知平台：\n- ✅ **飞书**：支持富文本（post）和文本格式，自动降级\n- ✅ **钉钉**：支持 Markdown 格式\n- ✅ **企业微信**：支持 Markdown 格式\n- ✅ **自定义 Webhook**：支持 JSON 格式\n\n#### 使用建议\n\n1. **多公众号汇总**：使用包含 `feeds_with_articles` 的模板，可以一次性汇总所有公众号的文章\n2. **单个公众号**：使用单个公众号模板，适合针对特定公众号的推送\n3. **模板测试**：在消息任务中可以使用\"测试\"功能预览模板渲染结果\n4. **Markdown 格式**：模板支持 Markdown 语法，可以美化消息格式\n\n### 其他功能\n- ✅ 用户认证和权限管理\n- ✅ 系统配置管理\n- ✅ 定时任务管理\n- ✅ 系统信息监控\n- ✅ 数据统计面板\n\n---\n\n## 🚀 快速开始\n\n### 环境要求\n\n**后端：**\n- **Python**: 3.11 或更高版本\n- **数据库**: SQLite / MySQL / PostgreSQL\n- **浏览器**: Firefox / Chromium / WebKit（用于Playwright）\n\n**前端：**\n- **Node.js**: 18+ 或更高版本\n- **包管理器**: pnpm（推荐）或 npm\n\n### 方式一：一键启动开发环境（推荐）\n\n```bash\n# 克隆项目\ngit clone https://github.com/wang-h/werss.git\ncd werss\n\n# 运行一键启动脚本（自动配置环境、安装依赖、启动前后端）\nchmod +x start_dev.sh\n./start_dev.sh\n```\n\n启动后访问：\n- 前端界面: http://localhost:5173\n- 后台API: http://localhost:8001\n- API文档: http://localhost:8001/api/docs\n\n### 方式二：手动安装\n\n#### 1. 安装系统依赖\n\n**Ubuntu/Debian:**\n```bash\nsudo apt-get update\nsudo apt-get install -y \\\n    wget git build-essential zlib1g-dev \\\n    libgdbm-dev libnss3-dev libssl-dev libreadline-dev \\\n    libffi-dev libsqlite3-dev procps\n```\n\n**macOS:**\n```bash\nbrew install python@3.11\n```\n\n#### 2. 创建虚拟环境\n\n**使用 uv（推荐，更快）:**\n```bash\n# 安装 uv\ncurl -LsSf https://astral.sh/uv/install.sh | sh\n\n# 创建虚拟环境\nuv venv\n\n# 激活虚拟环境\nsource .venv/bin/activate  # Linux/Mac\n# 或\n.venv\\Scripts\\activate  # Windows\n```\n\n**使用传统方式:**\n```bash\npython3 -m venv venv\nsource venv/bin/activate  # Linux/Mac\n# 或\nvenv\\Scripts\\activate  # Windows\n```\n\n#### 3. 安装Python依赖\n\n```bash\n# 使用 uv（推荐）\nuv pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple\n\n# 或使用 pip\npip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple\n```\n\n#### 4. 安装Playwright浏览器\n\n```bash\nplaywright install firefox  # 或 webkit, chromium\n```\n\n#### 5. 配置环境\n\n```bash\n# 复制配置文件模板\ncp config.example.yaml config.yaml\n\n# 编辑配置文件（或使用环境变量）\nvim config.yaml\n```\n\n#### 6. 初始化数据库\n\n```bash\n# 设置环境变量（首次运行需要）\nexport WERSS_USERNAME=admin\nexport WERSS_PASSWORD=your_password\n\n# 数据库配置（必须配置 DB 环境变量）\n# 使用 SQLite（默认，无需额外配置）\nexport DB=sqlite:///data/db.db\n\n# 或使用 PostgreSQL（推荐）\nexport DB=postgresql://admin:12345678@localhost:5432/werss_db\n# 注意：使用 PostgreSQL 前需要先启动 PostgreSQL 服务\n\n# 初始化数据库\npython main.py -init True\n```\n\n#### 7. 启动后端服务\n\n```bash\n# 启动服务（包含定时任务）\npython main.py -job True -init False\n\n# 或仅启动API服务（不启动定时任务）\npython main.py -job False -init False\n```\n\n#### 8. 前端开发（可选）\n\n如果需要单独开发前端：\n\n```bash\n# 进入前端目录\ncd web_ui\n\n# 安装依赖（推荐使用 pnpm）\npnpm install\n# 或使用 npm\nnpm install\n\n# 创建前端环境变量文件\necho \"VITE_API_BASE_URL=http://localhost:8001\" \u003e .env\n\n# 启动前端开发服务器\npnpm dev\n# 或\nnpm run dev\n```\n\n前端服务启动后访问：http://localhost:5173\n\n### 方式三：Docker部署\n\n#### 标准版本（使用官方镜像源）\n\n```bash\n# 构建镜像（会自动构建前端）\ndocker build -t werss:latest .\n\n# 运行容器\ndocker run -d -p 8001:8001 werss:latest\n\n# 访问应用\n# 前端界面: http://localhost:8001\n# API文档: http://localhost:8001/api/docs\n```\n\n#### 国内镜像源版本（推荐国内用户使用）\n\n```bash\n# 构建镜像（使用国内镜像源，构建速度更快）\ndocker build -f Dockerfile.cn -t werss:latest .\n\n# 运行容器\ndocker run -d -p 8001:8001 werss:latest\n\n# 访问应用\n# 前端界面: http://localhost:8001\n# API文档: http://localhost:8001/api/docs\n```\n\n**注意**：Docker 镜像已包含前端构建，无需单独启动前端服务。前端和 API 都通过 `http://localhost:8001` 访问。\n\n#### Docker Compose：已有外部数据库 / 对象存储\n\n若机器上已有 PostgreSQL 和 MinIO，不需要完整栈（会再起一套库并占用端口）。请使用仅包含应用容器的编排：\n\n```bash\ndocker compose -f docker-compose.app-only.yml up -d --build\n```\n\n说明见 [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md)。\n\n**配置优先级与重启：** 默认情况下，控制台写入数据库表 `config_management` 的项会**优先于** `.env` / yaml 中同含义的配置；进程重启不会清空数据库中的这些值。若希望 **`.env` 优先**、仅在环境变量未设置或为空时才回退到表里的值，请设置 `WERSS_ENV_OVERRIDES_DB=true`。详见 [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) 中的「配置优先级」。\n\n#### Docker Compose 开发环境（推荐）\n\n`docker-compose.dev.yml` 提供了完整的本地开发环境，包含 PostgreSQL 数据库、MinIO 对象存储和 WeRSS 应用服务。\n\n**特点：**\n- ✅ 所有服务直接暴露端口，方便本地访问和调试\n- ✅ 不需要 Traefik 和域名配置\n- ✅ MinIO 使用 HTTP 访问（开发环境）\n- ✅ 简化配置，快速启动\n- ✅ 数据持久化到本地 `./data` 目录\n\n**快速开始：**\n\n1. **配置环境变量**\n\n```bash\n# 复制环境变量模板文件\ncp .env.example .env\n\n# 编辑环境变量（根据实际情况修改）\nvim .env\n```\n\n主要需要配置的环境变量：\n- `POSTGRES_DB` - PostgreSQL 数据库名（默认：werss_db）\n- `POSTGRES_USER` - PostgreSQL 用户名（默认：admin）\n- `POSTGRES_PASSWORD` - PostgreSQL 数据库密码\n- `DB` - **重要**：数据库连接字符串，格式：`postgresql://用户名:密码@localhost:5432/数据库名`\n  - 示例：`DB=postgresql://admin:12345678@localhost:5432/werss_db`\n  - 如果不配置 `DB`，应用会默认使用 SQLite（`sqlite:///data/db.db`）\n- `WERSS_USERNAME` - WeRSS 管理员用户名\n- `WERSS_PASSWORD` - WeRSS 管理员密码\n- `MINIO_ROOT_USER` - MinIO 用户名（默认：admin）\n- `MINIO_ROOT_PASSWORD` - MinIO 管理员密码\n- `OPENAI_API_KEY` - OpenAI 兼容 API Key（用于 AI 标签提取，可选）\n\n**重要提示：**\n- `docker-compose.dev.yml` 已配置自动从 `.env` 文件加载环境变量\n- **必须配置 `DB` 环境变量**才能使用 PostgreSQL，否则会使用 SQLite\n- 如果使用 `docker-compose` 命令，环境变量会在启动时自动加载\n- 如果修改了环境变量，需要重启服务：`docker-compose -f docker-compose.dev.yml restart werss`\n\n2. **启动所有服务**\n\n```bash\n# 启动所有服务（PostgreSQL、MinIO、WeRSS）\ndocker-compose -f docker-compose.dev.yml up -d\n\n# 查看所有服务状态\ndocker-compose -f docker-compose.dev.yml ps\n\n# 查看日志\ndocker-compose -f docker-compose.dev.yml logs -f\n```\n\n3. **访问服务**\n\n启动成功后，可以通过以下地址访问：\n\n- **WeRSS 前端界面**: http://localhost:8001\n- **WeRSS API 文档**: http://localhost:8001/api/docs\n- **PostgreSQL 数据库**: localhost:5432\n  - 数据库名: `werss_db`（或 `POSTGRES_DB` 配置的值）\n  - 用户名: `admin`（或 `POSTGRES_USER` 配置的值）\n  - 密码: 环境变量中配置的 `POSTGRES_PASSWORD`\n  - **注意**：确保在 `.env` 文件中配置了 `DB` 环境变量，格式：`DB=postgresql://用户名:密码@localhost:5432/数据库名`\n- **MinIO 控制台**: http://localhost:9001\n  - 用户名: `admin`（或 `MINIO_ROOT_USER` 配置的值）\n  - 密码: 环境变量中配置的 `MINIO_ROOT_PASSWORD`\n- **MinIO API**: http://localhost:9000\n\n4. **常用操作**\n\n```bash\n# 停止所有服务\ndocker-compose -f docker-compose.dev.yml down\n\n# 停止并删除数据卷（注意：会删除所有数据）\ndocker-compose -f docker-compose.dev.yml down -v\n\n# 重启单个服务\ndocker-compose -f docker-compose.dev.yml restart werss\n\n# 查看特定服务的日志\ndocker-compose -f docker-compose.dev.yml logs -f werss\ndocker-compose -f docker-compose.dev.yml logs -f postgres\ndocker-compose -f docker-compose.dev.yml logs -f minio\n\n# 进入容器执行命令\ndocker-compose -f docker-compose.dev.yml exec werss bash\ndocker-compose -f docker-compose.dev.yml exec postgres psql -U admin -d werss_db\n\n# 重新构建并启动（代码更新后）\ndocker-compose -f docker-compose.dev.yml up -d --build\n```\n\n5. **数据目录说明**\n\n开发环境的数据会保存在项目根目录的 `./data` 目录下：\n\n```\ndata/\n├── postgres-data-dev/    # PostgreSQL 数据文件\n├── minio-data-dev/       # MinIO 数据文件\n└── werss-data/           # WeRSS 应用数据\n    ├── cache/            # 缓存目录\n    ├── pdf/              # PDF 导出目录（如果启用）\n    └── markdown/         # Markdown 导出目录（如果启用）\n```\n\n**注意事项：**\n\n- 开发环境使用 `-dev` 后缀的数据目录，避免与生产环境冲突\n- **数据库配置**：必须在 `.env` 文件中配置 `DB` 环境变量才能使用 PostgreSQL\n  - 格式：`DB=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}`\n  - 如果不配置 `DB`，应用会使用 SQLite（`sqlite:///data/db.db`）\n- 首次启动会自动初始化数据库和创建管理员账号\n- 如果修改了环境变量，需要重启服务才能生效：`docker-compose -f docker-compose.dev.yml restart`\n- 开发环境默认启用 DEBUG 模式，日志级别为 DEBUG\n- MinIO 在开发环境使用 HTTP，生产环境建议使用 HTTPS\n\n**故障排查：**\n\n```bash\n# 检查服务健康状态\ndocker-compose -f docker-compose.dev.yml ps\n\n# 查看服务启动日志\ndocker-compose -f docker-compose.dev.yml logs werss\n\n# 检查数据库连接\ndocker-compose -f docker-compose.dev.yml exec postgres pg_isready -U admin\n\n# 检查 MinIO 服务\ncurl http://localhost:9000/minio/health/live\n\n# 重置环境（删除所有数据并重新启动）\ndocker-compose -f docker-compose.dev.yml down -v\ndocker-compose -f docker-compose.dev.yml up -d\n```\n\n---\n\n## ⚙️ 配置说明\n\n### 配置文件\n\n项目使用 `config.yaml` 进行配置，首次运行请从模板复制：\n\n```bash\ncp config.example.yaml config.yaml\n```\n\n### 环境变量配置\n\n项目支持通过环境变量覆盖配置文件中的设置，环境变量优先级更高：\n\n```bash\n# 数据库配置\nexport DB=postgresql://user:password@localhost:5432/werss_db\n\n# 服务器配置\nexport PORT=8001\nexport DEBUG=False\nexport AUTO_RELOAD=False\n\n# 用户认证（首次运行）\nexport WERSS_USERNAME=admin\nexport WERSS_PASSWORD=your_password\n\n# 定时任务\nexport ENABLE_JOB=True\nexport THREADS=2\n\n# RSS配置\nexport RSS_BASE_URL=https://your-domain.com/\nexport RSS_TITLE=我的RSS订阅\nexport RSS_DESCRIPTION=微信公众号热度分析系统\n\n# 通知配置\nexport DINGDING_WEBHOOK=https://oapi.dingtalk.com/robot/send?access_token=xxx\nexport WECHAT_WEBHOOK=https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx\nexport FEISHU_WEBHOOK=https://open.feishu.cn/open-apis/bot/v2/hook/xxx\n\n# AI标签提取（可选）\nexport DEEPSEEK_API_KEY=sk-xxx\nexport DEEPSEEK_BASE_URL=https://api.deepseek.com\n```\n\n### 主要配置项说明\n\n#### 数据库配置\n\n```yaml\n# SQLite（默认）\ndb: sqlite:///data/db.db\n\n# PostgreSQL\ndb: postgresql://username:password@host:5432/database\n\n# MySQL\ndb: mysql+pymysql://username:password@host:3306/database?charset=utf8mb4\n```\n\n#### RSS配置\n\n```yaml\nrss:\n  base_url: https://your-domain.com/  # RSS域名地址\n  local: False  # 是否为本地RSS链接\n  title: 我的RSS订阅  # RSS标题\n  description: 微信公众号热度分析系统  # RSS描述\n  full_context: True  # 是否显示全文\n  add_cover: True  # 是否添加封面图片\n  page_size: 30  # RSS分页大小\n```\n\n#### 采集配置\n\n```yaml\ngather:\n  content: False  # 是否采集内容\n  model: app  # 采集模式：web/api/app\n  content_auto_check: False  # 是否自动检查未采集文章\n  content_auto_interval: 59  # 自动检查间隔（分钟）\n  browser_type: firefox  # 浏览器类型：firefox/edge/webkit\n```\n\n#### 标签配置\n\n```yaml\narticle_tag:\n  auto_assign_by_mp: True  # 根据公众号自动关联标签\n  auto_extract: False  # 是否自动提取标签\n  extract_method: ai  # 提取方式：textrank/keybert/ai\n  max_tags: 5  # 最大标签数量\n  # TextRank 配置\n  textrank:\n    allow_pos: n,nz,vn,a  # 允许的词性：n（名词）、nz（其他专名）、vn（动名词）、a（形容词）\n  # KeyBERT 配置\n  keybert:\n    model: minishlab/potion-multilingual-128M  # 模型名称（推荐多语言模型）\n    hybrid: True  # 是否使用混合方案（结合 TextRank 实体提取）\n  # AI 提取配置\n  ai:\n    auto_create: True  # 是否自动创建不存在的标签\n```\n\n#### OpenAI 兼容 API 配置（AI 标签提取）\n\n系统支持使用 OpenAI 兼容的 API 进行智能标签提取，支持 DeepSeek、Qwen3、OpenAI 等多种服务：\n\n```yaml\nopenai:\n  api_key: sk-xxx  # API Key（必填，用于 AI 标签提取）\n  base_url: https://api.deepseek.com  # API 地址（DeepSeek 默认）\n  # 或使用其他服务：\n  # base_url: https://api.openai.com/v1  # OpenAI\n  # base_url: https://dashscope.aliyuncs.com/compatible-mode/v1  # Qwen3\n  model: deepseek-chat  # 模型名称（默认）\n  # 或使用其他模型：\n  # model: gpt-4o  # OpenAI\n  # model: qwen-plus  # Qwen3\n```\n\n**环境变量配置：**\n```bash\n# OpenAI 兼容 API 配置\nexport OPENAI_API_KEY=sk-xxx\nexport OPENAI_BASE_URL=https://api.deepseek.com\nexport OPENAI_MODEL=deepseek-chat\n\n# 标签提取配置\nexport ARTICLE_TAG_AUTO_EXTRACT=True\nexport ARTICLE_TAG_EXTRACT_METHOD=ai\nexport ARTICLE_TAG_MAX_TAGS=5\nexport ARTICLE_TAG_AI_AUTO_CREATE=True\n```\n\n**支持的 API 服务：**\n- **DeepSeek**：https://api.deepseek.com（推荐，性价比高）\n- **OpenAI**：https://api.openai.com/v1\n- **Qwen3**：https://dashscope.aliyuncs.com/compatible-mode/v1（自动禁用思考功能）\n- 其他 OpenAI 兼容的 API 服务\n\n**AI 标签提取特性：**\n- ✅ 优先提取公司名称、产品名称、技术名称等重要实体\n- ✅ 智能理解文章上下文，提取最相关的标签\n- ✅ 自动过滤通用词汇（如\"AI\"、\"技术\"等）\n- ✅ 支持 Qwen3 模型（自动禁用思考功能，直接返回结果）\n- ✅ 每个标签 2-15 个字，按重要性排序\n\n**获取 API Key：**\n- **DeepSeek**：访问 [DeepSeek 官网](https://www.deepseek.com/) 注册并创建 API Key\n- **OpenAI**：访问 [OpenAI 官网](https://platform.openai.com/) 注册并创建 API Key\n- **Qwen3**：访问 [阿里云 DashScope](https://dashscope.aliyun.com/) 注册并创建 API Key\n\n**三种提取方式对比：**\n\n| 特性 | TextRank | KeyBERT | AI (OpenAI 兼容) |\n|------|----------|---------|------------------|\n| **准确度** | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |\n| **速度** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |\n| **依赖** | 无（内置） | 需要下载模型 | 需要 API Key |\n| **成本** | 免费 | 免费 | 按 API 调用计费 |\n| **多语言支持** | ✅ 中文 | ✅ 多语言 | ✅ 多语言 |\n| **上下文理解** | ❌ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |\n| **实体识别** | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐（优先提取公司名称等） |\n| **推荐场景** | 快速提取、离线环境 | 平衡准确度和速度 | 高质量标签提取 |\n\n**使用建议：**\n- **开发/测试环境**：使用 TextRank，无需配置，速度快\n- **生产环境（中等规模）**：使用 KeyBERT，准确度和速度平衡\n- **生产环境（高质量要求）**：使用 AI（OpenAI 兼容），准确度最高，适合对标签质量要求高的场景\n  - 推荐使用 DeepSeek（性价比高）或 Qwen3（自动禁用思考功能）\n  - AI 提取会优先提取公司名称、产品名称等重要实体\n\n#### MinIO配置（可选）\n\n```yaml\nminio:\n  enabled: false  # 是否启用MinIO图片上传\n  endpoint: \"localhost:9000\"  # MinIO服务地址\n  access_key: \"minioadmin\"  # 访问密钥\n  secret_key: \"minioadmin\"  # 密钥\n  bucket: \"articles\"  # 存储桶名称\n  secure: false  # 是否使用HTTPS\n  public_url: \"http://localhost:9000\"  # 公开访问URL（可选）\n```\n\n启用 MinIO 后，文章爬取时会自动下载图片并上传到 MinIO，文章内容中的图片 URL 会被替换为 MinIO 链接。\n\n#### AI 标签提取功能详解\n\n**功能概述：**\n系统支持三种标签提取方式，可以根据需求选择最适合的方案。\n\n**1. TextRank 提取（本地算法）**\n- **原理**：基于图算法的关键词提取，无需外部依赖\n- **优点**：速度快、无需网络、完全免费\n- **缺点**：准确度相对较低，主要基于词频和共现关系\n- **适用场景**：快速提取、离线环境、对准确度要求不高的场景\n\n**配置示例：**\n```yaml\narticle_tag:\n  auto_extract: True\n  extract_method: textrank\n  max_tags: 5\n  textrank:\n    allow_pos: n,nz,vn,a  # 允许的词性\n```\n\n**2. KeyBERT 提取（语义模型）**\n- **原理**：基于 BERT 的语义相似度计算，提取与文档最相关的关键词\n- **优点**：准确度较高、支持多语言、可本地运行\n- **缺点**：首次使用需要下载模型（约 200-500MB）、内存占用较大\n- **适用场景**：平衡准确度和速度的场景、需要多语言支持\n\n**配置示例：**\n```yaml\narticle_tag:\n  auto_extract: True\n  extract_method: keybert\n  max_tags: 5\n  keybert:\n    model: minishlab/potion-multilingual-128M  # 推荐多语言模型\n    hybrid: True  # 使用混合方案（结合 TextRank）\n```\n\n**推荐模型：**\n- `paraphrase-multilingual-MiniLM-L12-v2`：官方推荐多语言模型，准确度最高\n- `minishlab/potion-multilingual-128M`：轻量级多语言模型，CPU 友好\n- `all-MiniLM-L6-v2`：英文文档专用，更轻量级\n\n**3. AI (OpenAI 兼容) 提取（智能理解）**\n- **原理**：使用 OpenAI 兼容的大语言模型理解文章内容，智能提取标签\n- **优点**：准确度最高、理解上下文、支持复杂语义、优先提取公司名称等重要实体\n- **缺点**：需要 API Key、有调用成本、需要网络连接\n- **适用场景**：高质量标签提取、对准确度要求极高的场景\n- **支持的服务**：DeepSeek、OpenAI、Qwen3 等 OpenAI 兼容的 API\n\n**配置示例：**\n```yaml\narticle_tag:\n  auto_extract: True\n  extract_method: ai\n  max_tags: 5  # 最大标签数量（默认 5）\n  ai:\n    auto_create: True  # 自动创建不存在的标签\n\nopenai:\n  api_key: sk-xxx  # 必填\n  base_url: https://api.deepseek.com  # 或使用其他 OpenAI 兼容服务\n  model: deepseek-chat  # 或使用其他模型（如 gpt-4o、qwen-plus 等）\n```\n\n**AI 提取工作流程：**\n1. 系统读取文章标题、描述和内容\n2. 将内容发送到 OpenAI 兼容的 API\n3. AI 分析文章主题和关键信息，优先提取：\n   - 公司名称（如：字节跳动、腾讯、OpenAI 等）\n   - 产品/服务名称（如：ChatGPT、豆包、微信等）\n   - 技术/工具名称（如：React、TensorFlow 等）\n   - 人物名称、特定事件、特定领域等\n4. 返回最相关的标签关键词（默认最多 5 个）\n5. 系统自动创建标签（如果 `auto_create: True`）\n6. 将标签关联到文章\n\n**Qwen3 模型特殊支持：**\n- 使用 Qwen3 模型时，系统会自动禁用思考功能\n- 确保直接返回 JSON 格式的标签数组，无需额外处理思考过程\n\n**性能优化建议：**\n- 对于大量文章，建议使用 KeyBERT 或 TextRank\n- 对于重要文章，使用 AI 提取获得最佳效果\n- 可以混合使用：大部分文章用 KeyBERT，重要文章用 AI\n\n更多配置项请参考 `config.example.yaml` 文件。\n\n---\n\n## 📚 API文档\n\n启动服务后，可以通过以下地址访问 API 文档（实际前缀以 `API_BASE` 为准，默认为 **`/api/v1/wx`**）：\n\n- **Swagger UI**: http://localhost:8001/api/docs  \n- **ReDoc**: http://localhost:8001/api/redoc  \n- **OpenAPI Schema**: http://localhost:8001/api/openapi.json  \n\nSwagger 首页说明中包含 **JWT** 与 **API Key**（`X-API-Key`）两种认证方式；OpenAPI 组件中已注册 `ApiKeyHeader`，便于对接方引用。\n\n**文章列表查询**（`GET`/`POST` `/api/v1/wx/articles`）支持：\n\n- 分页：`offset`、`limit`\n- 标题搜索：`search`（多词 OR）\n- 公众号：`mp_id`\n- 发布时间：`publish_from` / `publish_to`（秒或毫秒，与库内 `publish_time` 一致），或日历日 `publish_date_from` / `publish_date_to`（`YYYY-MM-DD`，UTC）\n- 标签：`tag_id`、`tag_ids`（逗号分隔）、`tag_match`=`any`|`all`\n\n更细的字段说明与 `curl` 示例见 **[docs/ARTICLE_QUERY_API.md](docs/ARTICLE_QUERY_API.md)**。\n\n### 主要 API 端点（节选）\n\n#### 认证\n- `POST /api/v1/wx/auth/token` - OAuth2 密码模式获取 JWT\n- `POST /api/v1/wx/auth/login` - 用户登录（表单）\n- `GET /api/v1/wx/auth/verify` - 校验 Token\n\n#### API Key（需先登录创建）\n- `GET/POST /api/v1/wx/api-keys` - 列表 / 创建\n- `POST /api/v1/wx/api-keys/{id}/regenerate` - 轮换密钥\n\n#### 公众号\n- `GET /api/v1/wx/mps` - 公众号列表（`kw`、`limit`、`offset`）\n- `GET /api/v1/wx/mps/{mp_id}` - 详情（可匿名，见 Swagger）\n\n#### 文章\n- `GET`/`POST` `/api/v1/wx/articles` - 文章列表（见上文筛选参数）\n- `GET /api/v1/wx/articles/{id}` - 文章详情（可匿名）\n\n#### RSS / Feed（无 `/api/v1/wx` 前缀）\n- `GET /rss`、`GET /rss/{feed_id}` - RSS\n- `GET /feed/{feed_id}.xml` 等 - 订阅输出\n\n完整列表以 **Swagger** 为准。\n\n---\n\n## 🛠️ 开发指南\n\n### 项目结构\n\n```\nwerss/\n├── apis/              # API路由层\n│   ├── article.py     # 文章相关API\n│   ├── auth.py        # 认证相关API\n│   ├── mps.py         # 微信公众号相关API\n│   ├── rss.py         # RSS相关API\n│   └── ...\n├── core/              # 核心业务逻辑\n│   ├── config.py      # 配置管理\n│   ├── database.py    # 数据库操作\n│   ├── wx/            # 微信公众号核心逻辑\n│   ├── models/        # 数据模型\n│   ├── notice/        # 通知模块\n│   └── ...\n├── jobs/              # 定时任务\n│   ├── article.py     # 文章采集任务\n│   ├── mps.py         # 公众号更新任务\n│   └── ...\n├── driver/            # 浏览器驱动（Playwright）\n├── web_ui/            # 前端React应用\n│   ├── src/           # 前端源代码\n│   │   ├── api/       # API接口封装\n│   │   ├── components/# 组件\n│   │   ├── views/     # 页面组件\n│   │   └── ...\n│   ├── package.json   # 前端依赖配置\n│   └── vite.config.ts # Vite配置\n├── main.py            # 应用入口\n├── web.py             # FastAPI应用定义\n├── config.example.yaml # 配置文件模板\n└── requirements.txt   # Python依赖\n```\n\n### 开发环境设置\n\n详细开发指南请参考：\n- [快速开始指南](QUICK_START.md) - 开发环境快速设置\n- [开发指南](DEVELOPMENT.md) - 完整的开发文档\n- [uv使用指南](UV_VENV_GUIDE.md) - uv虚拟环境使用说明\n\n### 添加新功能\n\n1. **添加新API**：\n   ```python\n   # 在 apis/ 目录下创建新文件\n   # apis/my_feature.py\n   from fastapi import APIRouter\n   \n   router = APIRouter(prefix=\"/my-feature\", tags=[\"我的功能\"])\n   \n   @router.get(\"/\")\n   async def my_endpoint():\n       return {\"message\": \"Hello\"}\n   \n   # 在 web.py 中注册路由\n   from apis.my_feature import router as my_feature_router\n   api_router.include_router(my_feature_router)\n   ```\n\n2. **修改数据库模型**：\n   ```python\n   # 在 core/models/ 下修改模型\n   # 然后运行迁移\n   python main.py -init True\n   ```\n\n3. **添加定时任务**：\n   ```python\n   # 在 jobs/ 目录下创建任务文件\n   # 任务会自动注册\n   ```\n\n### 代码规范\n\n- 遵循 Python PEP 8 代码规范\n- 使用类型提示（Type Hints）\n- 编写清晰的注释和文档字符串\n\n---\n\n## 🔧 常见问题\n\n### 1. 端口被占用\n\n```bash\n# 检查端口占用\nlsof -i :8001  # Linux/Mac\nnetstat -ano | findstr :8001  # Windows\n\n# 修改端口\nexport PORT=8002\npython main.py -job True -init False\n```\n\n### 2. 数据库连接失败\n\n- 检查数据库服务是否启动\n- 确认连接字符串格式正确\n- 检查数据库用户权限\n\n### 3. Playwright浏览器未安装\n\n```bash\nplaywright install firefox\n# 或\nplaywright install chromium\n```\n\n### 4. 依赖安装失败\n\n```bash\n# 使用国内镜像\npip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple\n\n# 或使用uv（推荐）\nuv pip install -r requirements.txt\n```\n\n### 5. 权限问题\n\n```bash\n# 确保脚本有执行权限\nchmod +x start.sh start_dev.sh\n\n# 确保数据目录可写\nmkdir -p data\nchmod 755 data\n```\n\n更多问题请查看 [开发指南](DEVELOPMENT.md) 或提交 Issue。\n\n---\n\n## 📦 依赖说明\n\n### 核心依赖\n\n- **FastAPI**: Web框架\n- **SQLAlchemy**: ORM框架\n- **Playwright**: 浏览器自动化\n- **APScheduler**: 定时任务调度\n- **PyJWT**: JWT认证\n- **BeautifulSoup4**: HTML解析\n- **jieba**: 中文分词\n- **KeyBERT**: 关键词提取（可选，用于 KeyBERT 标签提取）\n- **openai**: OpenAI 兼容客户端（可选，用于 AI 标签提取，支持 DeepSeek、Qwen3、OpenAI 等）\n\n### 可选依赖\n\n- **psycopg2-binary**: PostgreSQL支持\n- **PyMySQL**: MySQL支持\n- **reportlab**: PDF导出支持\n- **python-docx**: Word文档处理\n- **minio**: MinIO 对象存储客户端（用于图片存储）\n\n完整依赖列表请查看 `requirements.txt`。\n\n---\n\n## 🤝 贡献指南\n\n欢迎贡献代码！请遵循以下步骤：\n\n1. [Fork 本项目](https://github.com/wang-h/werss/fork)\n2. 创建功能分支 (`git checkout -b feature/AmazingFeature`)\n3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)\n4. 推送到分支 (`git push origin feature/AmazingFeature`)\n5. [开启 Pull Request](https://github.com/wang-h/werss/pulls)\n\n详细贡献指南请查看 [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md)。路线图与课题向待办见 [docs/ROADMAP.md](docs/ROADMAP.md)。\n\n---\n\n## 📄 许可证\n\n本项目采用 MIT 许可证。详情请查看 [LICENSE](LICENSE) 文件。\n\n---\n\n## 🙏 致谢\n\n本项目在开发过程中参考和借鉴了以下优秀的开源项目，特此表示感谢：\n\n- **[we-mp-rss](https://github.com/wang-h/we-mp-rss)** - 微信公众号热度分析系统，提供了核心功能实现的参考\n- **[wewe-rss](https://github.com/cooderl/wewe-rss)** - 微信公众号RSS订阅工具，提供了架构设计的灵感\n- **[full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)** - FastAPI 全栈项目模板，提供了前后端分离架构的最佳实践\n\n感谢这些项目的开发者和贡献者们！\n\n---\n\n## 🔗 相关链接\n\n- [快速开始指南](QUICK_START.md)\n- [开发指南](DEVELOPMENT.md)\n- [uv使用指南](UV_VENV_GUIDE.md)\n- [贡献指南](docs/CONTRIBUTING.md)\n- [路线图与待办](docs/ROADMAP.md)\n\n---\n\n## 📞 支持\n\n如有问题或建议，请通过以下方式联系：\n\n- [提交 Issue](https://github.com/wang-h/werss/issues)\n- [发送 Pull Request](https://github.com/wang-h/werss/pulls)\n- [查看项目文档](https://github.com/wang-h/werss)\n\n---\n\n## 📋 更新日志\n\n### v1.1.0（2026-03-21）\n\n**采集稳定性**\n- 二维码登录存活时间延长并支持自动刷新，但是由于微信限制每天还是要重新扫码登录。\n- 爬取间隔 `SPAN_INTERVAL` 默认从 10 调高到 30，降低被微信流控/封禁的风险\n- `MAX_PAGE` 默认从 5 调低到 3，减少单次连续请求时长\n- User-Agent 去除 `WeRss` 标识，改为模拟真实 Chrome 浏览器\n\n**部署架构重构**\n- Compose 文件从 4 个叠加简化为 2 个：`docker-compose.yml`（完整栈）和 `docker-compose.app-only.yml`（仅应用）\n- 新用户 `cp .env.example .env \u0026\u0026 docker compose up -d` 一键启动\n- 子项目模式通过环境变量 `WERSS_EXTERNAL_NETWORK` / `WERSS_TRAEFIK_ENABLE` 配置，无需叠加额外 compose 文件\n- `.env.example` 重写为 4 个清晰区块，移除 WeRSS 不使用的变量\n- 全局匿名化，移除所有私有路径和域名引用\n- 脚本移除 monorepo 假设（不再加载上级目录 `.env`）\n- 文档合并为统一的 `docs/DEPLOYMENT.md`\n\n### v1.0.0\n\n初始发布版本。\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**⭐ 如果这个项目对你有帮助，请给个 Star ⭐**\n\nMade with ❤️ by Hao \n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwang-h%2Fwerss","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwang-h%2Fwerss","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwang-h%2Fwerss/lists"}