简报台
本地运行的网页应用,通过可插拔消息源(weflow-server 或 WeFlow 监听微信群,qqflow-server 监听 QQ 群)获取群消息,AI 自动分类筛选有价值的信息并结构化展示。
功能
- 消息获取:启动时后台自动回填一次(仅已启用会话参与;会话启用/从未轮询时按
BACKFILL_HOURS默认 24h 窗口回填一次,设为 -1 拉取全部历史——每次同步都会全量扫描,慎用),此后每轮按会话增量轮询(各会话独立水位,POLL_OVERLAP_SECONDS控制重叠容错),并辅以 SSE 实时监听(weflow-server / WeFlow 微信群、qqflow-server QQ 群可多源共存) - AI 分类:AI 自动将消息分类,内置 13 类、出厂默认启用 5 类(活动通知、社团招新、学术、交易、实习);可在设置中自定义类别(名称/提示词/颜色/启停)
- 图片 OCR:聊天图片自动 OCR 识别文字,识别结果纳入分类与展示
- 视觉分类(可选):AI_MODEL 支持图片输入(多模态)时开启
AI_VISION_ENABLED,含图消息把 OCR 文本连同图片一并送入分类;端点不支持图片时自动降级纯文本重试 - 语义去重:同一条信息在多个群转发时自动合并,保留多来源标注
- 原文上下文:展开信息卡片可查看原文及附近消息
- 人工审核:卡片可标记加入备忘录 / 已忽略,侧边栏按状态查看
- 同主体折叠:同一信息主体的卡片自动折叠成组,可展开
- 群聊筛选:设置中自由选择监控哪些群聊
- 分类过滤:设置中可选隐藏不需要的信息类型
快速开始
前置条件
- Python >= 3.12
- 任一消息源运行中:weflow-server(微信 4.x,默认
http://127.0.0.1:5033)、WeFlow(HTTP API 已开启,默认:5031)或 qqflow-server(默认http://127.0.0.1:5032) - AI API Key(环境变量
AI_API_KEY)
安装运行
cd briefdesk
# 安装(editable 便于改代码;普通安装 pip install . 同样可用——核心 SPA 与
# 插件前端随包分发,见 pyproject 的 [tool.setuptools.package-data])。
pip install -e .
# 可选:启用图片 OCR 需额外安装 OCR 依赖(rapidocr/onnxruntime,
# 体积较大;不安装时 OCR 插件自动禁用,其余功能不受影响)
pip install -e ".[ocr]"
首次使用需要创建配置文件(填入密钥,见下方 配置):
# Linux / macOS
cp .env.example .env
# Windows
copy .env.example .env
python main.py
浏览器打开 http://localhost:3000
从索引安装(发布版)
不改代码时直接装发布版:
pip install briefdesk # 可选图片 OCR:pip install "briefdesk[ocr]"
briefdesk # 或 python -m briefdesk
配置与数据目录口径同上(只有源码/editable 模式才读项目根 .env)。
试用预发布版(TestPyPI)
试发版本发在 TestPyPI(形如 0.1.0.dev1),装法与正式包不同——两段式,每段只对一个索引:
# 1) 本包:只对 TestPyPI,且先不解析依赖
pip install --no-deps --index-url https://test.pypi.org/simple/ briefdesk==0.1.0.dev1
# 2) 依赖:只对正式 PyPI(清单以包元数据为准:pip show briefdesk 的 Requires,
# 或 https://test.pypi.org/pypi/briefdesk/json)
pip install fastapi "uvicorn[standard]" httpx aiosqlite pydantic pydantic-settings \
openai python-dotenv Pillow numpy json-repair python-multipart keyring platformdirs
不要改成 --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ 一步装:
pip 会把两个索引合并后取最高版本,而 TestPyPI 上存在别人试传的同名依赖(实测 fastapi 1.0 稳定版
vs 正式 PyPI 的 0.142.x),依赖会被影子化成残缺包、构建直接失败。
首次使用(关键步骤)
首次打开页面会弹出首次使用向导(仅当浏览器从未完成过向导且尚未启用任何群聊时出现;后端不可用时不弹),分三步:
- 环境检查:展示各消息源连接状态;若后端有错误/警告(如
AI_API_KEY/ 所选消息源的必填密钥缺失、消息源未启动)会给出提示与常见原因; - 选择群聊:勾选要监控的会话——群聊默认勾选,私聊 / 公众号默认不勾(避免无意监控私聊)。会话列表为空时可先到 设置 → 群聊筛选 点「发现新群聊」拉取最新会话列表,再回来重试;
- 开始同步:首次会按
BACKFILL_HOURS(默认 24 小时)回填一次已启用会话的历史消息,此后按会话增量轮询 + SSE 实时监听;同步完成后回到主页面,AI 分类后的信息卡片会陆续出现。
随时可点右上角「跳过」(或按 Esc)退出向导,之后再手动操作:设置 → 群聊筛选 勾选群聊 → 顶部 同步消息。跳过或走完向导后不再弹出(浏览器 localStorage 记忆)。
未启用任何群聊时,前端空态会给出可操作的下一步提示:「去『群聊筛选』发现会话」/「去设置启用群聊」/「立即同步」,点击即可跳转;未启用会话不会拉取任何消息,这不是故障。
依赖
项目核心依赖(分类、去重、服务端、数据库)如下:
fastapiuvicorn[standard]httpxaiosqlitepydanticpydantic-settingsopenaipython-dotenvnumpyPillowjson-repair(AI 输出的 JSON 修复解析兜底)python-multipart(表单解析)keyring(系统密钥环:密钥型配置的第一解析层)platformdirs(用户配置目录定位)
OCR 依赖为可选(pip install -e ".[ocr]"):
rapidocr(RapidOCR,基于 ONNX 的跨平台 OCR 框架)onnxruntime(ONNX Runtime CPU 推理后端,无需 GPU / CUDA)
未安装 OCR 依赖时,OCR 阶段插件在启动时自禁用(PluginDisabledError,非致命),图片消息仍以原文入库展示,仅不做文字识别。
配置
所有配置通过项目根目录的 .env 文件读取,不配置时使用默认值。直接复制模板即可开始:
-
复制
.env.example为.env:# Linux / macOS cp .env.example .env # Windows copy .env.example .env
-
编辑
.env,填入必填项AI_API_KEY;消息源为weflow时需WEFLOW_API_TOKEN/WEFLOW_WXID/WEFLOW_DB_KEYS(微信每库独立密钥的 JSON 映射,一份完整 JSON 即可,超长时由系统自动分片存储;密钥项走系统钥匙串而非.env),为weflow-legacy时需WEFLOW_LEGACY_API_TOKEN,为qqflow时需QQFLOW_API_TOKEN/QQFLOW_QQ/QQFLOW_KEY(weflow/qqflow 缺失任一必填项 → 该插件自禁用)。消息源为可选插件,启用走PLUGINS显式列表(如PLUGINS=["weflow","qqflow"])或应用内「设置 → 插件」面板逐个开关,其余按需修改。 -
AI_MODEL默认deepseek-v4-flash:若你对接的 OpenAI 兼容服务没有该模型名,请改为实际模型名(如deepseek-chat、qwen-turbo等),否则首次分类会报模型不存在。
常用可调项(完整清单与逐项注释见 .env.example):
| 环境变量 | 默认 | 说明 |
|---|---|---|
PLUGINS |
[] |
可选插件(消息源/ocr/benchmark)显式启用列表(JSON 数组,无通配);核心插件恒装配,亦可在设置页「插件」面板逐个开关(不再使用 SOURCES) |
POLL_OVERLAP_SECONDS |
300 |
增量轮询窗口与水位间的重叠秒数(吸收边界秒/时钟偏差/翻页偏移;重叠部分由已处理表去重,无 AI 开销) |
POLL_INTERVAL_SECONDS |
0(禁用) |
周期同步间隔(秒):SSE 断连窗口的消息补齐兜底,>0 时按周期自动触发与「同步消息」同路径的同步(进行中互斥) |
IGNORE_SELF |
true |
过滤本账号自己发送的消息(SSE 实时 + REST 回填) |
MAX_CLASSIFY_TOKENS |
8192 |
单次 AI 分类最大输出 token(触顶截断会破坏 JSON) |
AI_MAX_CONCURRENCY |
4 |
AI 请求最大并发,0 = 不限制(本地模型建议设 1) |
AI_REASONING_EFFORT |
auto |
推理强度:auto 不干预 / off 尽力关闭思考(发送 reasoning_effort="none",端点明确拒收时自动改为不发送)/ omit 永不发送 / minimal…max 固定强度。DeepSeek 等思考系模型建议 off:思考输出挤占 max_tokens 会截断丢批(取值必须全小写) |
AI_VISION_ENABLED |
false |
视觉模型开关:AI_MODEL 支持图片输入时开启,含图消息将 OCR 文本连同图片一并送入分类(需启用 ocr 插件;端点不支持图片时自动降级纯文本重试并公告提示) |
AI_VISION_MAX_IMAGES |
4 |
单条消息随分类请求附图上限(1–20;多图超出部分只发 OCR 文本) |
REALTIME_BATCH_MAX_COUNT / REALTIME_BATCH_TIMEOUT_MS |
1 / 180000 |
实时批缓冲(攒够条数 / 超时毫秒触发处理) |
BACKFILL_BATCH_MAX_COUNT |
10 |
回填时单批 AI 分类的消息条数(默认已由 20 调为 10:批越大 AI 返回 index 漂移的绝对误差面越大) |
IGNORED_EXPIRY_HOURS |
0(禁用) |
启动时清理超过该时长的已忽略条目 |
MERGE_WINDOW_MINUTES / MERGE_MAX_CANDIDATES |
10 / 3 |
会话内同话题片段合并窗口(分钟)/ 候选上限;0 = 禁用合并 |
EMBED_API_BASE / EMBED_MODEL / EMBED_API_KEY |
空(禁用) | 嵌入向量去重:填入嵌入服务地址后启用余弦预筛(留空回退字符重叠预过滤) |
DEDUP_SIMILARITY_THRESHOLD / DEDUP_EMBED_THRESHOLD / DEDUP_EMBED_TOP_K / DEDUP_EMBED_FALLBACK_THRESHOLD / DEDUP_STRONG_THRESHOLD |
0.3 / 0.80 / 3 / 0.65 / 0.99 |
去重预筛与 AI 判重门禁阈值 |
LOG_LEVEL |
INFO |
日志级别(DEBUG 开逐条细节,并放出 uvicorn 的 HTTP 请求日志——默认静默以免逐请求刷屏) |
DB_PATH / SERVER_PORT |
用户数据目录 data/briefdesk.sqlite / 3000 |
SQLite 路径 / Web 端口 |
配置说明:
.env以项目根目录为基准解析,从任意目录启动(python main.py/python -m briefdesk/briefdesk)都会读到同一份配置;默认数据库落在平台用户数据目录(Windows%LOCALAPPDATA%\briefdesk\data\briefdesk.sqlite),可用DB_PATH覆盖(显式相对路径按当前工作目录解析,~不展开)。PLUGINS未启用任何消息源插件时进入降级启动:应用照常运行(UI/设置/向导可用),状态栏明示「无消息源」,消息采集不可用——配置消息源后重启生效。
数据与配置文件位置
运行期可写的东西都在平台用户目录,安装目录只放代码与只读资源:
| 内容 | 位置(Windows) | 覆盖入口 |
|---|---|---|
| SQLite 数据库 | %LOCALAPPDATA%\briefdesk\data\briefdesk.sqlite |
DB_PATH |
| UI 暂存配置 | %LOCALAPPDATA%\briefdesk\settings.env |
BRIEFDESK_SETTINGS_FILE |
| 基准用例与报告 | %LOCALAPPDATA%\briefdesk\benchmark\{cases,reports}\ |
BRIEFDESK_DATA_DIR |
| 基准运行目录 | %LOCALAPPDATA%\briefdesk\Cache\benchmark\runs\ |
BRIEFDESK_CACHE_DIR |
BRIEFDESK_DATA_DIR / BRIEFDESK_CACHE_DIR / BRIEFDESK_SETTINGS_FILE 只读进程环境变量
(写进 .env 无效);macOS / Linux 走各自平台约定目录(platformdirs)。
旧数据边界:本版本默认路径与旧版不同,不会自动发现、复制或迁移旧库,也不提供旧库的迁移、 导入或兼容转换指引;
DB_PATH只是通用的数据库文件覆盖入口,旧 schema、WAL 状态与兼容性不在支持范围。 配置文件(settings.env)的位置同样变化:旧位置的文件不再被读取,其中的插件开关与暂存项回到默认值。
项目结构
briefdesk/
├── main.py # 入口 shim,转发至 briefdesk/main.py(DB → 插件装配(含源注册/去重缓存预热)→ HTTP 服务器 → 插件激活 + 源监听启动 → 首轮回填)
├── .env.example # 环境配置模板(复制为 .env 后填写)
├── .env # 密钥配置(本地生成,不入库)
├── briefdesk/
│ ├── __main__.py # python -m briefdesk 入口
│ ├── config.py # pydantic Settings 读 .env(.env 与默认 DB 路径以项目根目录为基准)
│ ├── logger.py # 日志配置(格式/级别/uvicorn 统一)
│ ├── masking.py # 消息内容脱敏(mask_content)
│ ├── events.py # 内部事件总线(核心 ↔ 插件解耦)
│ ├── plugin/ # 插件框架:Plugin 协议 + PluginManager(entry points / PLUGIN_PATH 发现)
│ │ ├── base.py # Plugin 协议、PluginContext、加载约定
│ │ └── manager.py # 发现、过滤、拓扑排序、生命周期编排
│ ├── db.py # aiosqlite 数据库操作(主连接 + 向量连接,WAL + 外键)
│ ├── pipeline.py # 管道骨架(入口统一过滤 → 并行 enrich/classify → 锁内 dedup/跳过标记/post_insert → 通知)
│ ├── poll_cycle.py # 轮询周期业务编排(按会话增量窗口)
│ ├── realtime.py # 进程内发布/订阅(前端 SSE)
│ ├── status.py # 运行时状态 + 消息源注册表(/api/status 数据源)
│ ├── sync.py # 同步服务(trigger_sync:启动首轮回填与 /api/sync 共用)
│ ├── stages.py # 管道阶段注册表(槽位 enrich → classify → dedup → post_insert)
│ ├── ai_ports.py # AI 供应商端口(引擎经端口函数调用,核心不依赖具体供应商)
│ ├── sources_base.py # 消息源核心契约(SourceClient / RealtimeListener / SourceRuntime)
│ ├── types.py # 跨模块基础类型(含管道跨插件契约)
│ ├── server/ # FastAPI 服务子包(app/中间件/核心路由/类别路由/媒体代理/静态托管/插件注入/回调)
│ └── plugins/ # 内置插件(消息源 + AI 供应商 + 管道阶段 + Web 插件)
│ ├── weflow/ # weflow 消息源(微信 4.x,weflow-server :5033;同构六文件分层;API 契约见上游文档)
│ ├── weflow_legacy/ # WeFlow Legacy 消息源(plugin.py + client/config/normalize/poller/runtime/sse + weflow-legacy-api.md)
│ ├── qqflow/ # qqflow 消息源(plugin.py + 同构六文件分层;API 契约见上游文档)
│ ├── ai_provider/ # AI 供应商插件(plugin.py 注册端口 / engine.py OpenAI 兼容 chat + 嵌入)
│ ├── ocr/ # OCR 阶段插件(plugin.py 槽位 enrich / engine.py RapidOCR;依赖可选,未安装时自禁用)
│ ├── classify/ # AI 分类阶段插件(plugin.py 槽位 classify / engine.py 提示词与解析)
│ ├── dedup/ # 语义去重阶段插件(plugin.py 槽位 dedup / engine.py DedupEngine)
│ ├── merge/ # 同话题合并阶段插件(plugin.py 槽位 post_insert / engine.py 判官)
│ ├── calendar/ # 日历 Web 插件(plugin.py + router.py + db.py:/api/calendar;ui/ 含完整前端)
│ ├── reminders/ # 提醒 Web 插件(plugin.py + router.py:提醒设置 + 到期轮询;ui/ 含完整前端)
│ ├── rag/ # 检索问答 Web 插件(plugin.py + router.py + db.py + engine.py + prompts.py;ui/ 含完整前端)
│ └── benchmark/ # 实验基准(case 样例 + runner + 报告生成,见 benchmark/README.md;可选插件,默认禁用,PLUGINS 显式列名启用)
│ ├── ui/ # 核心 SPA(随包分发;挂载见 server/static.py)
│ │ ├── index.html # 桌面端页面
│ │ ├── app.js # 前端逻辑
│ │ ├── style.css # 样式
│ │ ├── icons/ # 图标资源(Lucide SVG 子集,见 icons/README.md)
│ │ └── icon-manifest.txt # 图标清单(源码维护资源,不进 wheel)
└── tests/
插件化
本体只保留核心(存储、管道骨架、HTTP、状态总线),扩展功能以插件挂载:
- 打包插件经
[project.entry-points."briefdesk.plugins"]声明;开发期插件放PLUGIN_PATH目录(每个.py暴露plugin实例)即可被加载 briefdesk/plugin/manager.py的PluginManager:发现 → 核心/可选分层过滤 (核心恒装配;可选按PLUGINS显式列表,互斥对先列者保留)→ 依赖拓扑 排序 → setup(HTTP 启动前)→ activate(服务器就绪后)→ teardown(逆序幂等)- 单插件失败只禁用该插件;
PLUGINS_REQUIRED名单内的失败则中止启动 - 依赖方向由
tests/test_no_core_imports_plugins.py守卫:核心永不 importbriefdesk.plugins.* - 插件分核心/可选两层:核心插件(ai_provider/classify/dedup/merge/rag/
calendar/reminders)恒装配;可选插件(weflow/weflow-legacy/qqflow/ocr/
benchmark)默认禁用,经
PLUGINS显式列名或设置页「插件」面板逐个开关 启用(不再使用 SOURCES);插件可声明conflicts互斥(weflow 与 weflow-legacy 互斥——同一上游新旧采集器,同开会重复采集) - 管道阶段化:OCR / AI 分类 / 语义去重 / 同话题合并各是一个阶段插件
(
briefdesk/plugins/{ocr,classify,dedup,merge}/,槽位 enrich → classify → dedup → post_insert),briefdesk/pipeline.py只做 编排(入口过滤 → 并行分类 → 锁内入库/合并 → 状态/通知);核心删除 卡片经事件总线通知去重插件清理缓存;OCR 依赖(rapidocr/onnxruntime) 为可选安装,未安装时 OCR 插件自禁用、纯图片消息(无文字)在入口被 屏蔽(不落库且水位照常推进,重新启用 OCR 后不会自动恢复——要找回 需重新停用/启用会话触发BACKFILL_HOURS回填,或临时设为 -1 全量回填), 图片+文字混合消息不受影响 - AI 供应商插件(
briefdesk/plugins/ai_provider/):chat + 嵌入能力注册到briefdesk/ai_ports.py端口,引擎经端口函数调用、核心不依赖具体供应商; 分类/去重/合并声明依赖 ai_provider(被禁用时随依赖降级,管道对 "阶段缺失"整批保留不标记,防消息丢失) - Web 插件(
WebPlugin协议:router + 静态资源):日历/提醒/检索问答路由为 示范插件(briefdesk/plugins/{calendar,reminders,rag}/);核心提供/api/plugins元数据与/plugin-assets/<name>/静态资源;插件的完整前端随插件包 分发——calendar 的按钮/视图容器/浮层/样式全在calendar/ui/(ui.js自建 DOM 并注册核心registerPluginView视图钩子接入 hash 路由与刷新联动,ui.css随注入);reminders 的提醒按钮/菜单、设置 面板「自动提醒」控件与到期轮询全在reminders/ui/(ui.js注册核心registerItemRowExtension行内扩展接入卡片动作区与handleRowAction, 经data-plugin-slot注入设置面板);核心briefdesk/ui/只留通用加载器与两类 扩展钩子(TestCoreFrontendBoundary守卫),不写死任何插件功能入口
当前阶段:消息源、管道四阶段、AI 供应商与 Web 插件全部插件化, 插件化改造完成(本体只保留存储、管道骨架、HTTP 与状态总线等核心)。
架构
简报台采用「核心骨架 + 插件」架构:可插拔消息源(weflow / weflow-legacy / qqflow)产出归一化消息,经 pipeline 入口统一过滤后进入阶段插件流水线(OCR 增强 → AI 分类 → 语义去重 → 同话题合并),结果写入 SQLite,由 FastAPI 服务端经 SSE 实时推送到原生 JS 前端;本体只保留存储、管道骨架、HTTP 与状态总线等核心。
完整的数据流图、模块职责、插件框架、数据库 Schema、配置项与设计陷阱详见 docs/architecture.md;日常使用(启动、配置、常见操作)详见 USAGE.md;想给简报台写插件(消息源/阶段/Web 扩展)请阅读第三方插件开发指南。
技术栈
- 运行时: Python + uvicorn
- Web 框架: FastAPI
- 数据库: SQLite (aiosqlite 异步)
- AI: AI Chat API (openai SDK 兼容)
- HTTP 客户端: httpx (异步)
- 前端: 原生 HTML + CSS + JavaScript(无框架)
- 消息源: 可插拔多源(weflow-server :5033 微信 4.x、WeFlow :5031、qqflow-server :5032;消息源为可选插件,通过
PLUGINS显式列表或设置页「插件」面板开关启用,JSON 数组格式)
Metadata
Release files for briefdesk 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| briefdesk-0.1.0.tar.gz | 545.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| briefdesk-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.2 MB
Release files / briefdesk-0.1.0.tar.gz
| Download URL | briefdesk-0.1.0.tar.gz |
|---|---|
| Size | 545.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d0f9477fd134be6f9de8721be25f3ff4aaef423bf6f0770c3ecae0ea730c8a4f
|
|
BLAKE2b-256 checksum How to use checksums |
c7ef7decc53de515e14f7b8a5ee866ceb53662641c5f13f108fdfdc21fdc1c49
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / briefdesk-0.1.0-py3-none-any.whl
| Download URL | briefdesk-0.1.0-py3-none-any.whl |
|---|---|
| Size | 620.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
601083a6f835eaf9ecaa8bc03834ebad171ca0f5cd39ee10047cc682c25b1388
|
|
BLAKE2b-256 checksum How to use checksums |
2f98f5989e763e31839f1ee6739ea34a128b8d6e94745bcca76d0e5889b5a814
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency log