From f8d3e4de2309215eaa493cf4c3a5891bdbb050b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Tue, 29 Sep 2026 12:07:47 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=AE=9E=E6=96=BD=E8=AE=A1=E5=88=92?= =?UTF-8?q?=E2=80=94=E2=80=94=E6=8C=89=E5=AE=A1=E6=9F=A5=E6=84=8F=E8=A7=81?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3(robocopy=E5=89=8D=E7=BC=80/=E8=AF=9D?= =?UTF-8?q?=E6=9C=AF=E6=AE=8B=E7=95=99/ES=E6=B1=A0/mock=E7=AB=AF=E5=8F=A3/?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E6=B5=8B=E8=AF=95=E8=AF=B4=E6=98=8E)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Code --- .../2026-09-29-building-materials-ai-kefu.md | 566 ++++++++++++++++++ 1 file changed, 566 insertions(+) create mode 100644 docs/superpowers/plans/2026-09-29-building-materials-ai-kefu.md diff --git a/docs/superpowers/plans/2026-09-29-building-materials-ai-kefu.md b/docs/superpowers/plans/2026-09-29-building-materials-ai-kefu.md new file mode 100644 index 0000000..c851a45 --- /dev/null +++ b/docs/superpowers/plans/2026-09-29-building-materials-ai-kefu.md @@ -0,0 +1,566 @@ +# HESUPIPE 建材 AI 客服 实施计划 + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 复制 D:\refactor\ai-kefu 汽车AI客服到本项目并完成建材(HESUPIPE 管道外贸)行业定制。 + +**Architecture:** 方案A"完整拷贝+定制"——保留参考项目全部架构(FastAPI+SQLite+智谱GLM、WebSocket/REST 双通道、三重输出墙、联系方式管道、邮件+UniService推送、管理后台、170+测试),只定制约15%行业相关内容(4个提示词、多语言正则墙、前端文案、品牌更名)。 + +**Tech Stack:** Python 3.13 / FastAPI / SQLAlchemy(async)+aiosqlite / 智谱GLM(glm-4-flash) / 原生HTML-JS-CSS前端 / pytest+pytest-asyncio / Docker+OpenResty + +**设计文档:** `docs/superpowers/specs/2026-09-29-building-materials-ai-kefu-design.md`(本计划的所有决策依据) + +**参考项目:** `D:\refactor\ai-kefu`(只读,绝不修改) + +**重要约束:** +- ⚠️ 绝不拷贝参考项目的 `.env`(含真实密钥)和 `data/cc_ai_kefu.db`(含生产数据) +- 开发期 `PUSH_ENABLED=false`、NOTIFY_EMAIL 用测试邮箱(Task 11 验收通过后才切生产) +- 每个任务结束必须 `pytest -q` 全绿后才能 commit + +--- + +### Task 1: 项目拷贝、清理与测试基线 + +**Files:** +- Create: 整个项目骨架(从参考项目拷贝) +- Delete: `static/blog.html`、redis 相关配置 + +- [ ] **Step 1: 拷贝项目(排除密钥/数据/缓存)** + +```bash +cd /d/refactor +MSYS_NO_PATHCONV=1 robocopy "D:\\refactor\\ai-kefu" "D:\\refactor\\ai-kefu-jc" /E \ + /XD .git data __pycache__ .pytest_cache .ruff_cache .playwright-mcp .superpowers .vscode \ + /XF .env +``` + +⚠️ Git Bash 下 MSYS 会把 `/E` `/XD` 等开关当路径转换导致 robocopy 报"无效参数", +**必须加 `MSYS_NO_PATHCONV=1` 前缀**(实测验证;替代写法是 `//E //XD //XF` 双斜杠)。 +robocopy 返回码 0-7 都算成功(1=有文件拷贝),≥8 才是失败。 +`docs/superpowers/` 下会合入参考项目的汽车 specs/plans 归档,与本项目的建材设计文档共存,无冲突(文件名不同)。 + +**git 仓库说明**:本项目在设计阶段已 `git init` 并有 3 个 docs commit 在案; +robocopy 的 `/XD .git` 只排除源目录的 .git,不影响目标已有仓库。Step 6 前用 +`git rev-parse --is-inside-work-tree` 确认输出 `true` 即可(若在全新环境重跑本计划则先 `git init`)。 + +- [ ] **Step 2: 验证拷贝结果** + +```bash +cd /d/refactor/ai-kefu-jc && ls app/ static/ tests/ scripts/ +# 预期:四个目录都在;确认不存在 .env 和 data/cc_ai_kefu.db +test ! -f .env && echo OK-no-env +mkdir -p data +``` + +- [ ] **Step 3: 清理无用件** + +```bash +rm static/blog.html +``` + +移除 redis 三处: +1. `requirements.txt` 删除 `redis>=5.0.0` 行 +2. `docker-compose.yml` 删除整个 redis service 块(`cc-ai-kefu-redis`) +3. `.env.example` 删除 `REDIS_URL`/`REDIS_PASSWORD` 行及注释 + +- [ ] **Step 4: 安装依赖并建 .env 占位** + +```bash +pip install -r requirements.txt -r requirements-dev.txt +cp .env.example .env +``` + +`.env` 中 `ZHIPU_API_KEY` 先留占位(跑测试不需真实 Key,LLM 全 mock)。 + +- [ ] **Step 5: 基线测试——未改任何代码前必须全绿** + +```bash +python -m pytest -q +``` + +预期:170+ passed(参考项目全绿,拷贝后应同样全绿)。若有 Windows 环境性失败,先修复环境再继续(参考项目 conftest.py 头部有 Windows aiosqlite 清理说明)。 + +- [ ] **Step 6: Commit** + +```bash +git add -A && git commit -m "chore: 从汽车AI客服项目拷贝骨架并清理(blog页/redis)" +``` + +--- + +### Task 2: 公司事实卡 company_facts.md + +**Files:** +- Modify: `app/prompts/company_facts.md`(整体重写) +- Test: `tests/test_company_facts.py`(更新断言) + +- [ ] **Step 1: 抓取官网资料** + +用 WebFetch 依次抓取(提取硬事实,忽略模板化文案): +- `https://hesupipe.com/`(已抓取过:公司概况/十大产品线/联系方式) +- `https://hesupipe.com/about-us/`(或等价关于页) +- 产品分类页(HDPE/PVC/PPR 等主要品类页,取规格范围) +- `https://hesupipe.com/certificates/`(认证清单) +- `https://hesupipe.com/sales-network/`(销售网络/出口国家) +- 新闻页 1-2 篇真实项目案例(如智利农业供水管项目) + +- [ ] **Step 2: 重写事实卡** + +保留参考项目事实卡的**结构框架和使用规则段**(防编造的"统一兜底/不扩展"原则原样保留),替换内容段。结构: + +```markdown +# HESUPIPE 公司事实卡 +## 公司概况 +(1998年成立/2007年起出口/河南郑州/高新技术企业——只写官网可验证的) +## 产品线总表 +(HDPE管道及管件/HDPE波纹管/PVC管道及管件/PVC电工套管/PPR管道/球墨铸铁管/法兰阀门/HDPE渔网箱/门窗类——每类一行主要规格范围,如 DN20-DN1200) +## 应用领域 +(市政给水/燃气油气/排水排污/农业灌溉/电气保护/疏浚/海水养殖) +## 认证 +(证书页实际列出的,逐条;没有就整节省略,不编) +## 销售网络与出口市场 +(官网实际提及的国家/地区) +## 使用规则(原样保留参考项目的兜底原则) +(未列出的一律说"转客户经理确认";禁止推测/扩展/编造) +``` + +**红线自查**:不含价格、交期、MOQ、产能数字;不收录"world-class"类模板化空话。 + +- [ ] **Step 3: 更新 test_company_facts.py 断言** + +改为断言建材关键词(如 `HESUPIPE`、`HDPE` 或实际产品词)存在、汽车词(`BYD`/`Hesu Auto`/`vehicle`)不存在。 + +- [ ] **Step 4: 跑测试** + +```bash +python -m pytest tests/test_company_facts.py -q +``` +预期:PASS + +- [ ] **Step 5: Commit** + +```bash +git add -A && git commit -m "feat: HESUPIPE 公司事实卡(官网硬事实+防编造规则)" +``` + +**⚠️ 审核关卡(设计文档§4.2)**:事实卡完成后请需求方业务侧过目确认后方可上线(可异步,不阻塞后续任务)。 + +--- + +### Task 3: 系统提示词 system.md 重写 + +**Files:** +- Modify: `app/prompts/system.md`(整篇重写,框架保留) + +- [ ] **Step 1: 重写 system.md** + +保留参考项目的六段结构,逐段建材化: + +1. **语言规则(最高优先级)**:保留"客户用什么语言就用什么语言回复,默认英语";**新增**:拒绝价格/交期/MOQ/样品费等实质问题时,回复中必须包含固定英文短句 `Please leave your contact and our manager will send the full quotation.`(保证输出墙正则可靠命中) +2. **职能边界**:AI 只做需求了解+留资;价格/交期/MOQ/装柜方案/样品费/认证清单/库存→转客户经理;问实质问题时若已知意向品类:"确认品类+引导留资"一气呵成 +3. **红线**:不出现价格数字(含复述客户预算);不输出电话/邮箱;不再三索要已留资客户的联系方式 +4. **说话风格**:外贸销售式简短口语;时效承诺用 "reply within 12 hours"(不提中国作息) +5. **对话推进**:预算路径改为 `"Which application? Water supply, gas, drainage or irrigation?"`;规格追问(口径/压力/标准);围绕已说品类推进 +6. **好差示例**:6-8 组管道场景(例:客户说 "PE100 water pipe DN110",差:泛问 what do you need;好:确认 SDR11/SDR17? + 询问工程量;中文话术示例同步改管道语境) + +- [ ] **Step 2: 自查清单** + +- [ ] 所有汽车词(car/vehicle/BYD/Toyota/test drive/提车/试驾/续航)已清零:`grep -in "car\b\|vehicle\|byd\|toyota\|test drive\|试驾\|提车\|续航" app/prompts/system.md` 预期无输出 +- [ ] 红线覆盖:MOQ、lead time、container loading、sample fee、certificate、price range +- [ ] 固定英文拒绝短句原样出现(与 boundary_filter 的 DEFLECTIONS 措辞协调但不冲突——prompt 是"含义",墙是"兜底") + +- [ ] **Step 3: 跑全量测试(system.md 变更影响的测试)** + +```bash +python -m pytest -q +``` +预期:PASS(若有断言 system.md 内容的测试,同步更新) + +- [ ] **Step 4: Commit** + +```bash +git add -A && git commit -m "feat: 系统提示词建材化(管道外贸人设+多语言拒绝短句)" +``` + +--- + +### Task 4: 提取与评估提示词(extractor.md / evaluator.md) + +**Files:** +- Modify: `app/prompts/extractor.md`、`app/prompts/evaluator.md` + +- [ ] **Step 1: 重写 extractor.md 字段定义** + +中文键画像字段改建材语义(设计文档§4.3): +- `意向品类`(HDPE给水管/PVC排水管/PPR…) +- `规格要求`:**自由文本保留客户原话**(如 "DN110 PE100 SDR11"),明确指示不拆分不过度结构化 +- `标准要求`:单独一列(ISO4427/ASTM/EN/SCH 系列,客户提到才记) +- `采购数量`、`用途`(给水/燃气/排污/灌溉/…)、`项目类型`、`目标国家`、`预算提及`、`联系方式`字段原样保留参考项目机制 + +- [ ] **Step 2: 重写 evaluator.md 评估语义** + +三级保留;示例改管道采购:明确品类+规格+数量=interested;仅泛泛浏览=pending;明确无采购计划=not_interested。 + +- [ ] **Step 3: 新增 extractor 字段静态断言测试(spec §9.1 第4条落地)** + +`tests/test_company_facts.py` 风格,新建断言:extractor 提示词加载后包含 +`意向品类`、`规格要求`、`标准要求` 字段定义,且不含 `车型`/`意向品牌` 汽车字段。 +先跑红(当前还是汽车字段),重写后跑绿。 + +- [ ] **Step 4: 跑全量测试并 Commit** + +```bash +python -m pytest -q && git add -A && git commit -m "feat: 提取/评估提示词建材化(规格自由文本+标准单列)" +``` + +--- + +### Task 5: 多语言输出墙 boundary_filter.py(TDD 核心) + +**Files:** +- Modify: `app/services/boundary_filter.py` +- Test: `tests/test_boundary_filter.py` + +- [ ] **Step 1: 先写失败的多语言墙测试** + +在 `tests/test_boundary_filter.py` 追加(沿用该文件现有参数化风格): + +```python +# ---- 多语言价格墙(建材市场扩充): 必须拦截 ---- +MULTILINGUAL_PRICE_HITS = [ + "El precio es 500 dólares", # 西语 词前置 + "Costo por tonelada 320", # 西语 + "O preço é 1200 reais", # 葡语(巴西) + "Цена 500 за тонну", # 俄语 + "Стоимость 800 долларов", # 俄语 + "السعر 500 دولار", # 阿语 + "€500 per ton", # 欧元符号 + "£420 per container", # 英镑符号 + "500 dólares", # 数字+货币词后缀 + "Delivery in 15 días", # 西语时间承诺 + "Срок 2 недели", # 俄语时间承诺 +] +# ---- 建材规格形态: 不得误杀 ---- +SPEC_NON_HITS = [ + "DN800 double wall corrugated pipe", + "PN16 pressure rating", + "SDR11 and SDR17 both available", + "PE100 material", + "600mm diameter", + "SCH40 and SCH80", + "3/4 inch and 2 inch sizes", + "ISO4427 certified", + "20ft container load", "40ft HQ", + "5.8m and 11.8m lengths", + "PE80 PE100 grades", +] +``` + +断言:前者每个 `violates_boundary(s)` 为 True;后者每个为 False。 + +- [ ] **Step 2: 跑测试确认失败** + +```bash +python -m pytest tests/test_boundary_filter.py -q +``` +预期:多语言 HITS 用例 FAIL(现有正则拦不住) + +- [ ] **Step 3: 扩充 PRICE_PATTERNS** + +在 `PRICE_PATTERNS` 列表追加(保持参考项目"注释说明设计意图"的风格): + +```python +# ---- 多语言墙(建材市场: 欧/英/南美/俄语区/中东) ---- +# 货币符号: €/£ 参考项目只有 $ +re.compile(r"[€£]\s?\d"), +# 价格名词前置(西/葡/俄/阿): 词后 0-20 非数字字符内出现数字 +re.compile(r"(?:precio|costo|custo|preço|цена|стоимость|سعر|ثمن)[^\d\n]{0,20}\d", re.I), +# 货币名词后置(数字+货币词) +re.compile(r"\d[\d,.]*\s*(?:d[óo]lares?|euros?\b|рублей|руб\.?)", re.I), +# 多语言时间承诺(与英文 days/weeks 组同构) +re.compile(r"\d+\s*[- ]?(?:d[ií]as?|semanas?|дн(?:ей|я)|недел[ьи]|أيام)\b"), +``` + +同时审查现有汽车特定排除项: +- `\d[\d,.]*\s*(usd|美元|块钱|万块?(?!\s*(公里|km)))` 的 `公里|km` 排除 → 建材语境已无里程语义,但保留无害;确认不误杀建材形态 +- `(两|三|四|五|六|七|八|九|十)\s*万(?!\s*(公里|km))` 保留(中文预算) +- 时间承诺 `\d+\s*[- ]?(day|week|month)s?\b` 保留(英文交期承诺) + +- [ ] **Step 4: 跑测试至全绿** + +```bash +python -m pytest tests/test_boundary_filter.py -q +``` +预期:PASS(含原有全部用例不回归) + +- [ ] **Step 5: 迂回话术建材化 + ES 话术池(spec §6 第3层)** + +1. **行业残留清零**(用户可见输出,实测在参考项目 L54/L57): + - `DEFLECTIONS_EN_CONTACT` 的 "Anything else about the cars?" → "...about pipes?" + - `DEFLECTIONS_ZH_CONTACT` 的 "还想了解什么车?" → "还想了解什么管道产品?" + - 全文件扫一遍 DEFLECTIONS/PIVOTS/NO_CONTACT 各池,确认无其他汽车措辞 +2. **新增 ES 话术池**(南美第一大流量,spec §6.3): + - 新增 `DEFLECTIONS_ES`、`DEFLECTIONS_ES_CONTACT`、`PIVOTS_ES`、`PIVOTS_ES_CONTACT` + (西语版话术,如 "El precio exacto te lo envía nuestro gerente por WhatsApp, ¿me lo dejas?") + - `deflection_for()` / `pivot_for()` 现为"汉字→ZH,否则 EN"二分支,扩展为三分支: + 汉字 → ZH;西语特征(`re.search(r"[áéíóúñ¿¡]", msg)` 粗匹配,与参考项目 + 汉字检测同构)→ ES;否则 → EN +3. **测试**:`tests/test_boundary_filter.py` 追加——西语消息选 ES 池、英文选 EN、 + 中文选 ZH;"cars"/"什么车" 不再出现在任何话术池 + +- [ ] **Step 6: 同步 scripts/breach_rate.py** + +把上述新词表同步进 breach_rate.py 的统计模式(保持与墙一致,供上线观察期用)。 + +- [ ] **Step 7: 全量测试 + Commit** + +```bash +python -m pytest -q && git add -A && git commit -m "feat: 多语言输出墙(€/£/西葡俄阿价格词+时间承诺+ES话术池)+话术建材化+防误杀" +``` + +--- + +### Task 6: 会话编排与联系方式管道建材化 + +**Files:** +- Modify: `app/services/conversation.py`、`app/services/contact_pipeline.py` +- Test: `tests/test_contact_pipeline.py`、`tests/test_context_seeding.py` + +- [ ] **Step 1: 先写失败的阿语数字测试** + +`tests/test_contact_pipeline.py` 追加: + +```python +def test_arabic_digits_normalized(): + # 阿语数字(中东买家)提取后应转 ASCII,CRM 可直接拨 + confirmed, _ = split_validate({"whatsapp": "+٩٦٦٥٠١٢٣٤٥٦٧"}) + assert confirmed["whatsapp"] == "+966501234567" +``` + +(具体 API 名以参考项目实际函数签名为准——`split_validate`/canon 归一化入口。) + +- [ ] **Step 2: 跑测试确认失败** + +```bash +python -m pytest tests/test_contact_pipeline.py -q -k arabic +``` +预期:FAIL(号码原样保留阿语数字) + +- [ ] **Step 3: 实现数字归一化** + +`contact_pipeline.py` 顶部加: + +```python +# Unicode 十进制数字 → ASCII(阿语٠-٩/波斯语۰-۹), 中东买家号码 CRM 可直接拨 +_DIGIT_TRANSLATE = str.maketrans("٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹", "01234567890123456789") +``` + +在归一化入口(normalize_contacts/digits_only 调用链的最前端)对值做 `v.translate(_DIGIT_TRANSLATE)`。注意:正则 `\d` Unicode 模式本就匹配阿语数字,位数校验能过——本步只解决"存进去的形式"。 + +- [ ] **Step 4: conversation.py 建材化** + +1. `BOUNDARY_TRIGGER_RE`:确认已含 MOQ/lead time/delivery time/sample/certificate 类词;补 `container loading|装柜|起订`(以实际正则现状为准增补) +2. context 种子白名单:`vehicle_name/vehicle_id` → `product_name/product_id` +3. `_build_context_reminder`/`_enrich_short_message` 中的车型话术 → 产品方案话术 +4. 同步更新 `tests/test_context_seeding.py` 的键名 + +- [ ] **Step 5: 全量测试 + Commit** + +```bash +python -m pytest -q && git add -A && git commit -m "feat: 会话编排建材化+阿语号码转ASCII" +``` + +--- + +### Task 7: 服务端杂项更名 + +**Files:** +- Modify: `app/main.py`、`app/services/email_service.py`、`app/api/routes/chat_rest.py`、`app/services/rate_limit.py`、`app/config.py`(如有 DB 默认名) + +- [ ] **Step 1: 逐文件更名** + +| 文件 | 改动 | +|---|---| +| `app/main.py` | FastAPI(title="AI汽车客服") → title="HESUPIPE AI 客服" | +| `app/services/email_service.py` | 发件人 `【XYH】` → `【HESUPIPE】`;确认无汽车字段引用 | +| `app/api/routes/chat_rest.py` | docstring "HESU app" → HESUPIPE;种子键名若此处再有引用同步 | +| `app/services/rate_limit.py` | docstring "Mirrors hesu's" 更新 | +| `app/config.py` + `.env.example` | DATABASE_URL 默认 `data/hesupipe_ai_kefu.db` | + +- [ ] **Step 2: 全局残留扫描** + +```bash +grep -rin "汽车\|vehicle\|byd\|toyota\|hesu auto\|borderlesscar\|VOLT\|XYH\|cc-ai-kefu\|cc_ai_kefu\|car\b\|cars\|什么车\|车型\|车价" app/ tests/ scripts/ --include="*.py" | grep -v "docs/" +``` +预期:无输出(docstring/注释里的行业残留一并清零;`car\b|cars|什么车|车型` 抓 boundary_filter 话术池等用户可见输出)。 + +- [ ] **Step 3: 全量测试 + Commit** + +```bash +python -m pytest -q && git add -A && git commit -m "chore: 服务端品牌与行业残留更名清零" +``` + +--- + +### Task 8: 部署配置更名 + +**Files:** +- Modify: `docker-compose.yml`、`deploy.sh`、`openresty.conf`、`.env.example` + +- [ ] **Step 1: 更名** + +| 文件 | 改动 | +|---|---| +| `docker-compose.yml` | 容器名 `cc-ai-kefu`→`hs-ai-kefu`;端口 `8016:8000`→`8017:8000`(redis 服务已在 Task1 删) | +| `deploy.sh` | 健康检查 URL 8016→8017 | +| `openresty.conf` | upstream `cc_ai_kefu`→`hesupipe_ai_kefu`;127.0.0.1:8016→8017;alias `/www/cc_ai_kefu/`→`/www/hesupipe_ai_kefu/`;日志名同步(含注释掉的 HTTPS 段) | +| `.env.example` | `APP_PORT=8017`;`PUSH_EXTERNAL_KEY_PREFIX=ai-kefu-jc`;`PUSH_ENABLED=false`(开发期) | + +- [ ] **Step 2: 残留扫描** + +```bash +grep -rn "cc_ai_kefu\|cc-ai-kefu\|8016" docker-compose.yml deploy.sh openresty.conf .env.example +``` +预期:无输出。 + +- [ ] **Step 3: 测试 + Commit** + +```bash +python -m pytest -q && git add -A && git commit -m "chore: 部署配置更名(hs-ai-kefu/8017/hesupipe_ai_kefu)" +``` + +--- + +### Task 9: 前端建材化(文案/主题/GDPR + 静态断言同步) + +**Files:** +- Modify: `static/chat.html`、`static/widget.js`、`static/js/chat.js`、`static/js/theme.js`、`static/admin.html`、`static/widget-test.html` +- Test: `tests/test_invite_static.py`、`tests/test_theme_static.py` + +- [ ] **Step 1: 了解静态测试的真实性质(避免走错路)** + +`tests/test_invite_static.py`/`test_theme_static.py` 是**结构回归网**,不是文案断言—— +它们断言的是邀请卡面板出厂 hide、pointer-events、回流顺序、theme.js 与 widget.js +调色板逐字同步、无残留旧色 hex 等结构性质。所以本任务的测试策略是: +**直接改前端文件,然后跑结构回归测试防破坏**(它们会在你漏改某处色值/结构时指路)。 + +- [ ] **Step 2: 前端文案与配置** + +| 文件 | 改动 | +|---|---| +| `chat.html` | 标题 `HESUPIPE Support`;描述管道场景;欢迎语 "What kind of piping project are you working on?";热门话题 Get Quotation / Pipe Specifications / Delivery & Shipping;WhatsApp `+8615937108317`;邮箱 `hesu@hesuu.com` | +| `widget.js` | 默认 title/whatsapp/email 同上;邀请卡文案管道化(pipe specs, MOQ, delivery timing);话题按钮同步 | +| `js/chat.js` | WhatsApp/email fallback 默认值同步 | +| `admin.html` | VOLT → HESUPIPE(title/header/头像字母) | +| `js/theme.js` | 默认品牌色橙 `#f08a31` → HESUPIPE 品牌蓝(从 hesupipe.com CSS 取实际主色值)。⚠️ 色值有**三处**要同步:`theme.js` 的 DEFAULT_COLOR、`widget.js` 的 DEFAULT_PALETTE(内联副本,测试强制两份一致)、`css/style.css` 的 `:root` 槽位值——漏任何一处 test_theme_static 会红 | +| `widget.js` | **GDPR 行**:首次对话邀请卡/首条消息附加 "By chatting, you agree to our privacy policy."(链接指向 hesupipe.com 隐私政策页,URL 实施时与需求方确认,可先 `https://hesupipe.com/privacy-policy/` 占位) | +| 头像 | `kefu.png`/`kefu-small.png` 替换(需求方提供 logo 或用品牌蓝底 "H" 字母临时生成) | + +- [ ] **Step 3: 跑静态断言与全量测试至绿** + +```bash +python -m pytest tests/test_invite_static.py tests/test_theme_static.py -q +python -m pytest -q +``` + +- [ ] **Step 4: 残留扫描 + Commit** + +```bash +grep -rin "HESU Support\|hesu auto\|vehicle\|VOLT\|borderlesscar\|1903717\|f08a31" static/ | grep -v blog +git add -A && git commit -m "feat: 前端HESUPIPE品牌化+管道文案+GDPR提示" +``` + +--- + +### Task 10: 全量回归与收尾扫描 + +**Files:** 无新增(验证任务) + +- [ ] **Step 1: 全仓行业残留终扫** + +```bash +grep -rin "汽车\|vehicle\|byd\|toyota\|test drive\|试驾\|提车\|hesu auto\|borderlesscar\|VOLT\|XYH\|cc_ai_kefu\|cc-ai-kefu\|car\b\|cars\|什么车\|车型\|车价" app/ static/ tests/ scripts/ *.yml *.sh *.conf 2>/dev/null +``` +预期:仅 docs/ 归档 changelog 里有(允许——历史档案)。 + +- [ ] **Step 2: 全量测试** + +```bash +python -m pytest -q +``` +预期:全绿(170+,含新增多语言/阿语数字用例) + +- [ ] **Step 3: 本地起服务冒烟** + +```bash +python -m uvicorn app.main:app --port 8017 & +curl -s http://127.0.0.1:8017/health +# 预期 {"status":"ok"} 类响应; 浏览器开 http://127.0.0.1:8017/ 与 /admin 目检 +``` + +- [ ] **Step 4: Commit(如有收尾改动)** + +--- + +### Task 11: 真人验收(真实 LLM + mock 推送联调) + +**Files:** +- Create: `docs/test-checklist.md`(基于参考项目同名文件改写) +- 临时: `.env` 填真实智谱 Key + +- [ ] **Step 1: 编写真人验收清单** + +按设计文档 §9.2 全项写入 `docs/test-checklist.md`(问价×2语言/MOQ/样品/交期/认证→转留资;留资→画像+邮件[测试邮箱]+mock推送;换号→更正邮件;已留资不再索要;规格聊天不误杀;后台三视图核对)。 + +- [ ] **Step 2: 起 mock UniService 并配置联调** + +```bash +python scripts/mock_uniservice.py & # 本地假CRM, 默认端口 9099 +``` +`.env`:`PUSH_ENABLED=true`、`PUSH_API_URL=http://127.0.0.1:9099/open/v1/inquiry/push`、 +`PUSH_API_KEY=test-key-123`(mock 脚本期待的固定 Key,不设会 401)、 +NOTIFY_EMAIL=测试邮箱、真实智谱 Key。 + +- [ ] **Step 3: 逐项真人验收** + +按清单实聊(英文+西语+中文三种语言各至少一轮完整留资流程)。核对:邮件收到、mock 推送 accepted、admin 后台画像/意向/日志正确。 + +- [ ] **Step 4: 修复发现的问题直至清单全过 + Commit** + +```bash +git add -A && git commit -m "test: 真人验收清单+联调修复" +``` + +--- + +### Task 12: 交付物(嵌入代码/说明/CLAUDE.md) + +**Files:** +- Create: `docs/embed-guide.md`、`CLAUDE.md`、`README.md` + +- [ ] **Step 1: 官网嵌入说明 docs/embed-guide.md** + +内容:一段可粘贴的挂件代码(script 标签+data-* 配置示例:位置/主题色/WhatsApp/自动邀请),贴到 WordPress 哪里(页脚模板或主题设置)、隐私政策页要求。给官网管理员一页读完即可操作。 + +- [ ] **Step 2: CLAUDE.md 血缘记录** + +记录:上游参考项目 `D:\refactor\ai-kefu`、85%同源、上游修bug需对照其 `docs/` changelog 手动同步、本项目 external_key 前缀 ai-kefu-jc、开发期 PUSH 关闭约定、上线观察期跑 breach_rate.py。 + +- [ ] **Step 3: README.md** + +项目简介/本地启动(pip install、.env、uvicorn)/测试(pytest)/部署(deploy.sh+openresty)/管理后台入口。 + +- [ ] **Step 4: Commit** + +```bash +git add -A && git commit -m "docs: 官网嵌入指南+CLAUDE.md血缘+README" +``` + +--- + +## 上线切换(验收全过后,需求方操作确认) + +1. `.env` 切生产:`PUSH_API_URL` 指真实 UniService、真实 API Key、NOTIFY_EMAIL=客户经理邮箱 +2. 服务器部署:`deploy.sh`(端口 8017)+ openresty 域名配置(需求方提供,如 ai.hesupipe.com) +3. 官网按 `docs/embed-guide.md` 嵌入挂件 +4. **第一周观察期**:跑 `scripts/breach_rate.py` 看漏放/误杀,发现即补正则(设计文档 §9.3)