295 lines
12 KiB
Markdown
295 lines
12 KiB
Markdown
# 喜报处理 Web
|
||
|
||
按 `config/xibao_logic.json` 解析接龙文本,批量生成喜报图片并下载。
|
||
|
||
## 项目情况(2026-02-24)
|
||
|
||
- 线上域名:`https://zc.workyai.cn`
|
||
- Nginx 转发:`zc.workyai.cn -> 127.0.0.1:8787`
|
||
- 运行服务:`xibao-web.service`
|
||
- 代码目录:`/opt/xibao-web/app`
|
||
- Python 环境:`/opt/xibao-web/venv`
|
||
|
||
## 当前能力
|
||
|
||
- 根据 `#接龙` 文本逐行解析。
|
||
- 支持一条文本拆分多个产品(如同一行里的定期 + 理财)。
|
||
- 支持别名映射(如 `中心所 -> 潇水南路`、`营江路所 -> 营江路`)。
|
||
- 只保留 13 个白名单网点,不在名单内自动跳过。
|
||
- 保险默认期交(`page_3`),若未写明年限会要求选择 `3年交 / 5年交`。
|
||
- 仅“微信提现12万”这类未写明确期限的记录,按活期场景处理,默认不生成。
|
||
- 金额识别支持阿拉伯数字和常见中文写法。
|
||
- 中文金额口语兼容:`十万`、`两万五`、`一万二`、`两万五千`、`二点五万`。
|
||
- 金额统一按现有规则向下取整到 `N万`(例如 `2.5万 -> 2万`、`7.8万 -> 7万`)。
|
||
- 去重策略:有序号时优先按“序号+行内产品序位+行内容指纹”去重;无序号时回退 `branch+amount+type`(历史去重 + 本次输入去重)。
|
||
- 每条数据生成独立 PPT,并按其 `page_x` 只导出对应页 PNG。
|
||
- 多张 PNG 前端逐图下载(无需解压)。
|
||
- 每天 00:00 自动清理 `output/` 下历史截图任务。
|
||
- 支持手工强制清理截图(与 00:00 自动清理同逻辑)。
|
||
- 支持复盘日志(手工标记识别错/生成错、自动记录解析跳过与异常)。
|
||
- 标记识别错/生成错时支持填写备注(前端弹窗输入)。
|
||
- 支持“已标识错误”列表查看、编辑、删除。
|
||
- 手动“修正并生成”成功后,会自动清除同原始行的活跃标识(转为已解决)。
|
||
- 重复记录支持直接预览与下载(若历史图片仍存在)。
|
||
- 生成时可查看实时进度(解析、生成PPT、转PDF、导图、收尾)。
|
||
- 刷新页面后可查看历史记录并继续标注(支持历史图预览/下载)。
|
||
- 生成阶段支持低配模式:默认单任务单并发(同一时刻只允许一个生成任务)。
|
||
- 生成策略支持“页面模板缓存”(默认):多条生成时先按 `page_x` 预构建单页模板,单线程落盘以降低峰值内存。
|
||
- 生成完成后启用内存回收(`gc.collect + malloc_trim`,可配置开关)。
|
||
- 字体保护不变:仍按 run 级别替换文本,仅改数字/状态/网点目标 run,不改字体样式与字号。
|
||
- 预览图按顺序逐张加载(前面的先加载),避免大批量并发请求导致预览异常。
|
||
- 图片下载接口支持限速(默认 `300KB/s`),可在 `performance.image_delivery.max_kbps` 调整。
|
||
- 跳过明细支持“屏蔽”单条(屏蔽后不再展示,清空历史时一并清空屏蔽)。
|
||
|
||
## 最近修复
|
||
|
||
- 修复“识别正确但生成网点变成潇水南路”的问题。
|
||
- 原因是模板不同页面的网点文本框索引不一致,旧逻辑固定 `shape_index=3`。
|
||
- 现逻辑会优先定位包含“营业所”的文本段再替换,避免错位替换。
|
||
- 修复中文金额 `amount_not_found`(例如 `蚣坝揽收十万现金定期一年`)。
|
||
- 新增中文金额解析后,补充了兼容保护,避免把单独“万/亿”误识别成 `0万`。
|
||
- 状态识别增强:支持“关键词中间夹金额/文本”的句式(如 `揽收十万现金`、`揽收16万礼金`、`微信17万提现`、`商户20万提现`、`揽收20万商户`)。
|
||
- 理财页文案调整为 `两三年期理财`,并在生成时对标题文本关闭自动换行,避免多字后折行。
|
||
|
||
## 技术实现
|
||
|
||
- PPT 文本替换:`python-pptx`
|
||
- PPT 转 PDF、PDF 按页转 PNG:优先本机 `libreoffice + pdftoppm`,无本机环境时回退 Docker `minidocks/libreoffice`
|
||
- 生成链路:`解析 -> 页面模板缓存(可配置) -> 生成PPT(默认单线程) -> 批量转PDF -> PDF导图(默认单线程)`
|
||
- 前端迁移策略:主页面已直接接入 Vue(`static/js/main.js`),不再依赖 legacy 保底脚本。
|
||
- Vue 运行时采用本地静态文件:`static/vendor/vue.global.prod.js`(由 `npm run sync:vue` 同步)。
|
||
|
||
默认会在启动时后台预热转换镜像;若已完成部署初始化,首次生成通常不会再等待拉取镜像。
|
||
|
||
## 目录
|
||
|
||
- `server.py`: 后端(标准库 HTTP API + 生成逻辑)
|
||
- `api_get_routes.py`: GET 接口路由分发(从 `server.py` 抽离)
|
||
- `api_post_routes.py`: POST 接口路由分发(从 `server.py` 抽离)
|
||
- `services/workflows.py`: 解析/生成/修正业务流程服务层
|
||
- `services/post_ops.py`: 标识/历史/清理等通用 POST 业务服务层
|
||
- `repositories/history_repository.py`: 历史读写仓储层
|
||
- `static/index.html`: 前端页面
|
||
- `static/app.js`: 前端加载入口(仅负责加载脚本)
|
||
- `static/js/core/state.js`: 前端共享状态与常量
|
||
- `static/js/main.js`: 主前端脚本(Vue + 业务逻辑)
|
||
- `static/vendor/vue.global.prod.js`: 本地 Vue 运行时
|
||
- `static/styles.css`: 页面样式
|
||
- `config/xibao_logic.json`: 处理规则配置
|
||
- `data/generated_history.json`: 去重历史
|
||
- `data/manual_rules.json`: 手工规则
|
||
- `data/review_logs/review_YYYY-MM-DD.jsonl`: 当日复盘日志
|
||
- `output/`: 生成输出目录(每次任务图片)
|
||
- `tests/`: 自动化单元测试
|
||
- `scripts/smoke_api.sh`: 接口烟雾测试脚本
|
||
- `package.json`: 前端工具脚本(`lint/test/smoke/sync:vue`)
|
||
- `Makefile`: 一键检查入口(`make check`)
|
||
- `app.js`: 历史遗留文件,不参与线上页面加载
|
||
|
||
## 启动与运维
|
||
|
||
### 本地直接启动
|
||
|
||
```bash
|
||
cd /opt/xibao-web/app
|
||
/opt/xibao-web/venv/bin/python server.py --host 127.0.0.1 --port 8787
|
||
```
|
||
|
||
可选参数:
|
||
|
||
- `--prewarm-blocking`: 启动前阻塞预热镜像(确保服务起来后镜像一定可用)
|
||
- `--skip-prewarm`: 跳过启动时预热
|
||
|
||
### 开发检查(推荐)
|
||
|
||
```bash
|
||
cd /opt/xibao-web/app
|
||
|
||
# 1) 语法/静态检查
|
||
make lint
|
||
|
||
# 2) 单元测试
|
||
make test
|
||
|
||
# 3) 线上接口烟雾回归(默认 zc.workyai.cn)
|
||
make smoke
|
||
|
||
# 一键全跑
|
||
make check
|
||
```
|
||
|
||
前端工具脚本:
|
||
|
||
```bash
|
||
# 同步本地 Vue 运行时到 static/vendor
|
||
npm run sync:vue
|
||
```
|
||
|
||
### systemd(线上)
|
||
|
||
```bash
|
||
systemctl status xibao-web.service
|
||
systemctl restart xibao-web.service
|
||
journalctl -u xibao-web.service -n 200 --no-pager
|
||
```
|
||
|
||
### Nginx(线上)
|
||
|
||
```bash
|
||
cat /etc/nginx/sites-available/zc.workyai.cn
|
||
nginx -t
|
||
systemctl reload nginx
|
||
```
|
||
|
||
## API(核心)
|
||
|
||
- `GET /api/config`: 获取配置摘要
|
||
- `POST /api/parse`: 仅解析预览
|
||
- `POST /api/generate`: 解析 + 生成 + 返回图片下载地址
|
||
- `GET /api/download/{token}`: 下载单张图片
|
||
- `GET /api/progress/{token}`: 查询本次生成进度
|
||
- `POST /api/output/clear`: 强制清理输出目录截图/任务文件
|
||
- `GET /api/history/view?limit=500`: 获取可预览/下载的历史记录视图
|
||
- `POST /api/log/mark`: 标记识别错误/生成错误到复盘日志(支持 `note` 备注)
|
||
- `GET /api/issues?status=active|resolved|all&limit=500`: 查看标识列表
|
||
- `POST /api/issues/update`: 修改标识(类型/原始行/备注)
|
||
- `POST /api/issues/delete`: 删除标识
|
||
- `GET /api/log/today`: 查看今日日志
|
||
- `POST /api/history/clear`: 清空历史
|
||
|
||
## 微信机器人接入(新增)
|
||
|
||
项目内置桥接脚本:`wechat_bot_bridge.py`,用于把微信消息接入到本项目:
|
||
|
||
- 拉取微信新消息:`/message/HttpSyncMsg`
|
||
- 识别指令后调用:
|
||
- `POST /api/parse`
|
||
- `POST /api/generate`
|
||
- 将结果回发微信:
|
||
- 文本:`/message/SendTextMessage`
|
||
- 图片:`/message/SendImageNewMessage`
|
||
|
||
### 快速启动
|
||
|
||
```bash
|
||
cd /root/zc.workyai.cn/app
|
||
python3 wechat_bot_bridge.py \
|
||
--wechat-base-url http://127.0.0.1:18238 \
|
||
--wechat-session-file /root/WeChatPadPro_test_20260227/webui/.session.json \
|
||
--xibao-base-url https://zc.workyai.cn
|
||
```
|
||
|
||
可选参数:
|
||
|
||
- `--wechat-auth-key`:直接指定 authKey(不走 session 文件)
|
||
- `--allow-from wxid_a,wxid_b`:仅处理白名单发送者
|
||
- `--max-images 3`:每次最多回发几张图
|
||
- `--dry-run`:只打印,不实际回消息
|
||
- `--once`:只轮询一次(调试用)
|
||
|
||
### 微信指令
|
||
|
||
- `/喜报 帮助`
|
||
- `/喜报 解析 + 文本`
|
||
- `/喜报 生成 + 文本`
|
||
- `跳过N`(例如 `跳过3` / `跳过(3)`,当天自动跳过前 N 条序号内容)
|
||
- `跳过0`(取消当天自动跳过)
|
||
- `反馈+序号+说明`(记录到复盘/问题列表)
|
||
- 直接发送包含 `#接龙` 的文本也会触发生成
|
||
|
||
说明:
|
||
|
||
- 仅处理私聊文本消息(不处理群聊)。
|
||
- 跳过/屏蔽项不单独发送通知,识别与过滤完全使用本项目现有逻辑。
|
||
- 每日按 `--daily-cleanup-time` 自动清空输出图片与历史记录(不会清空反馈记录)。
|
||
|
||
## 常用排查命令
|
||
|
||
```bash
|
||
# 1) 服务是否存活
|
||
systemctl status xibao-web.service
|
||
ss -lntp | rg ':8787'
|
||
|
||
# 2) 配置是否正常
|
||
curl -sS http://127.0.0.1:8787/api/config
|
||
|
||
# 3) 单条解析复现
|
||
curl -sS -X POST http://127.0.0.1:8787/api/parse \
|
||
-H 'Content-Type: application/json' \
|
||
--data '{"raw_text":"2、 蚣坝揽收十万现金定期一年"}'
|
||
|
||
# 4) 查看复盘日志(识别错/生成错/skip/异常)
|
||
tail -n 200 /opt/xibao-web/app/data/review_logs/review_$(date +%F).jsonl
|
||
|
||
# 5) 查看活跃标识
|
||
curl -sS 'http://127.0.0.1:8787/api/issues?status=active&limit=200'
|
||
|
||
# 6) 查看手工规则(是否有误命中)
|
||
cat /opt/xibao-web/app/data/manual_rules.json
|
||
|
||
# 7) 查看历史去重(为什么没新生成)
|
||
cat /opt/xibao-web/app/data/generated_history.json
|
||
```
|
||
|
||
## 故障排除指南
|
||
|
||
### 问题 1:识别正确,但图片里网点不对(例如固定变成“潇水南路”)
|
||
|
||
- 先确认 `api/parse` 输出的 `branch` 是否正确。
|
||
- 若解析正确但图错,重点检查模板页网点文本是否包含“营业所”字样。
|
||
- 当前替换逻辑按“营业所”文本段定位;模板若不含该标记,可能回退到配置索引。
|
||
- 模板调整后建议先用一条数据做小流量验证。
|
||
|
||
### 问题 2:`amount_not_found`
|
||
|
||
- 先用 `api/parse` 复现并看 `skipped` 原因。
|
||
- 已支持常见中文金额:`十万`、`两万五`、`一万二`、`二点五万`。
|
||
- 若仍失败,先看原文是否存在金额信息,再检查是否被特殊格式拆断。
|
||
|
||
### 问题 3:点“生成”后没有新图
|
||
|
||
- 查看返回里的 `duplicate_records` 和 `summary.duplicate`。
|
||
- 常见原因是去重命中(有序号时按序号键,无序号时按 `branch+amount+type`)。
|
||
- 需要重生成可清历史后再生成:`POST /api/history/clear`。
|
||
|
||
### 问题 4:日志里出现 `demand_deposit_not_generate`
|
||
|
||
- 这是预期策略:只出现活期类关键词且未写明确期限时默认不生成。
|
||
- 解决方式是补上产品期限或类型(例如“存一年”“理财”“保险5年交”)。
|
||
|
||
### 问题 5:转换失败(Docker 镜像拉取/转换异常)
|
||
|
||
- 先执行 `docker info` 确认 Docker 可用。
|
||
- 执行 `docker pull minidocks/libreoffice` 预热镜像。
|
||
- 查看服务日志:`journalctl -u xibao-web.service -n 300 --no-pager`。
|
||
|
||
### 问题 6:需要回溯某次“识别错/生成错”
|
||
|
||
- 进入 `data/review_logs/review_YYYY-MM-DD.jsonl` 查 `manual_mark`。
|
||
- 字段 `mark_type` 区分识别错/生成错,`source_line` 是原句,`note` 是备注。
|
||
- 结合同文件内的 `parse_skip`、`manual_correction_apply` 可还原完整过程。
|
||
|
||
### 问题 7:标识想改备注或删掉
|
||
|
||
- 页面“已标识错误”面板可直接编辑或删除。
|
||
- 或调用接口:
|
||
- `POST /api/issues/update`(按 `id` 修改)
|
||
- `POST /api/issues/delete`(按 `id` 删除)
|
||
|
||
## /api/generate 示例
|
||
|
||
```json
|
||
{
|
||
"raw_text": "#接龙\n1、营江路张三30万存一年\n2、潇水南路保险2万",
|
||
"insurance_year": "5",
|
||
"template_file": "/opt/xibao-web/templates/黄金三十天喜报模版(余额、保险、理财)(1).pptx",
|
||
"output_dir": "/opt/xibao-web/app/output",
|
||
"save_history": true
|
||
}
|
||
```
|
||
|
||
## 注意
|
||
|
||
- 需要本机 Docker 可用(`docker info` 正常)。
|
||
- 当前下载 token 默认 1 小时过期。
|