17 KiB
17 KiB
模块导航与拆分规范
四阶段拆分已落地:am.py 保留命令及 WSGI 兼容入口,应用工厂和业务代码位于 logistics_chat/,页面样式与脚本位于 static/。本文描述当前结构及后续结构调整约定。
先定位,再阅读
从 AGENTS.md 选择文件,以函数、常量、接口为锚点,搜索后只读取相关实现和调用方。模块移动时更新索引,不保存易失效的行号。默认遵守 Git 忽略规则,排除附件、数据库、日志、备份、虚拟环境和工作草稿。
rg --files
rg -n -F 'calc_freight' logistics_chat/pricing.py
rg -n -F '/api/human/' logistics_chat/routes static/js examples
rg -n '^(def |class | def )' scripts tests -g '*.py'
PowerShell 下把目录和 -g '*.py' 分开传给 rg。报价字典可能整行很长,搜索时加 --max-columns 200 --max-columns-preview,避免输出整份数据。
当前模块索引
| 业务范围 | 实际文件与搜索锚点 | 联动位置 |
|---|---|---|
| 应用入口与配置 | am.py:main、延迟访问的 app;logistics_chat/__init__.py:create_app;config.py:default_config、get_setting;runtime.py:serve_app |
start.bat、.env.example |
| Jenkins 灰度部署 | Jenkinsfile、Dockerfile;deploy/gray_config.py:GrayConfig;publish-gray.sh、activate-gray.sh、prepare-gray-tls.sh、renew-gray-tls.sh |
部署指南;独立持久化数据、证书和回环端口;wsgi.py 提供容器内路径 |
| 请求钩子 | logistics_chat/hooks.py:rate_limit、no_cache_html |
工厂注册钩子;限流状态在 app.extensions['rate_hits'] |
| SQLite 与维护 | logistics_chat/db.py:connect、close_connections、init_db、backup_db、save_message、last_user_question、load_context |
维护 CLI 在 scripts/;旧会话自动清理仍未启用 |
| 历史接口 | logistics_chat/history_service.py:new_chat、get_history、get_messages、del_history、clear_all;对应 routes/history.py |
static/js/chat.js:ensureConv、loadHistory、openConversation |
| 知识检索 | logistics_chat/knowledge.py:knowledge_list、search_knowledge |
knowledge.md 与代码同步,程序不读取该文档 |
| 运费与附加费 | logistics_chat/pricing.py:RATES、parse_shipping_intent、dims_to_cm、pick_rate、calc_freight、freight_reply、calc_warehouse_card、detect_surcharge、check_island |
logistics_chat/rates_extra.py 为唯一扩展数据源,根目录同名文件仅兼容转发 |
| 卡片协议 | logistics_chat/tracking.py:CARD_PREFIX、card_to_text;旧 extract_tracking_no、build_track 仅兼容旧导入 |
static/js/chat.js:fillTrackCard、addTrackCard;新订单卡片由 order_data.py 提供,历史模拟轨迹标为演示数据 |
| 订单测试表 | logistics_chat/order_data.py:init_order_table、import_records、lookup_order、answer_query |
SQLite order_test_data 为可编辑快照;按订单号、入仓码、Shipment ID 精确查表。将来 MCP 在取数层替换 lookup_order,不让模型拼 SQL |
| AI 与 SSE | logistics_chat/chat_service.py:create_chat_stream、sse;ai_client.py:post_completion、compress_answer、gen_followups |
routes/chat.py:stream_chat;客户端 doSend、renderError、renderFollowups |
| 人工会话 | logistics_chat/human_service.py:human_*(含转接、备注、撤回);对应 routes/human.py |
输入状态在 app.extensions['human_typing'];客户 startHumanPoll;客服 loadQueue、poll、sendReply;人工申请每天 8:00–22:00 |
| 附件 | logistics_chat/file_service.py:upload_file、cleanup_uploads;routes/files.py:uploaded_file |
扩展名/大小/目录由配置提供;客户端 addMsg,客服端 appendMsg |
| 登录、统计、订单、留言、导出 | logistics_chat/business_service.py:admin_login、admin_stats、my_orders、add_ticket、list_tickets、export_chat |
routes/admin.py、routes/business.py;登录页 static/js/admin_login.js |
| 页面 | templates/index.html、templates/admin.html、templates/admin_login.html |
先加载共享 static/css/theme.css;客户与客服脚本先加载 support.js(表情、通知、评价);客服再加载 admin_tools.js(备注、转接、历史搜索),最后加载 admin.js;保留全局事件入口 |
| 回归 | tests/test_rules.py、test_storage.py、test_api.py、test_dev_integration.py、test_config.py、test_deployment.py、test_gray_config.py、test_gray_activation.py、test_startup.py、test_maintenance_scripts.py、test_frontend.py;tests/frontend/admin.test.cjs、chat.test.cjs |
Linux 回退模拟基础设施、实际操作临时文件;模型、数据库及上传隔离;Node 验证草稿、异步切换、转接、撤回及评价;浏览器使用临时测试库 |
除标明的根目录文件外,表内缩写的 Python 文件均相对 logistics_chat/。
当前文件布局
am.py # CLI;显式请求 am.app 时创建默认 WSGI 应用
rates_extra.py # 旧导入路径的兼容转发
logistics_chat/
├── __init__.py # create_app 与显式运行时初始化
├── config.py # 根目录 .env、环境变量、稳定根路径、服务/资源配置
├── db.py # 连接、schema、历史持久化、备份
├── knowledge.py # 知识与关键词检索
├── pricing.py # 运费规则、解析、换算、附加费说明
├── rates_extra.py # 扩展报价数据
├── tracking.py # 单号识别、模拟轨迹、卡片协议
├── order_data.py # 可编辑订单测试表、精确查询、快照导入与卡片事实
├── ai_client.py # 模型 HTTP、压缩与追问
├── chat_service.py # 问答编排与 SSE 帧
├── history_service.py # 历史会话 CRUD
├── human_service.py # 人工状态与消息
├── business_service.py # 反馈、评价、统计、登录、订单、留言、历史搜索、Excel/CSV
├── file_service.py # 附件校验、保存、清理
├── hooks.py # 限流及 HTML/SSE 缓存头
├── runtime.py # Waitress / Flask 启动
└── routes/
├── __init__.py # Blueprint 注册
├── chat.py
├── history.py
├── human.py
├── admin.py
├── business.py
├── files.py
└── pages.py
templates/ # HTML/Jinja 及原有事件属性
static/css/ # theme.css 共享令牌;chat/admin/admin_login 页面样式
static/js/ # chat.js、admin.js、admin_login.js,经典脚本
scripts/ # 可独立运行的维护 CLI
tests/ # 按业务模块组织的回归
模块边界与依赖方向
- 路由只解析请求并包装响应;服务组织业务;规则模块提供确定性计算。依赖方向为
routes → services → rules / db / ai_client,下层不导入路由或根入口。 db.py统一连接、schema 和历史持久化。人工与管理业务的 SQL 放在所属服务,HTTP 路由不执行 SQL。请求及流式请求结束时关闭连接,未提交事务回滚。init_db包括客服账号、订单与留言表,首次启动只建空表;不内置账号。重复初始化保留已有数据,业务测试从真实初始化结果插入夹具,不另建缺失表。- 所有模型 HTTP 经
ai_client.post_completion。保留流式问答(5, 90)、压缩(5, 30)、追问(5, 15)三组连接/读取超时;不能因共用客户端而合并期限。流结束或取消时释放 HTTP 响应。 - 模块导入不建库、不备份、不清理附件、不访问模型。
create_app默认显式初始化运行目录、数据库、备份与旧附件清理;INITIALIZE_RUNTIME=False可禁止这些动作,此时调用方负责提供已有 schema。访问兼容入口am.app视为显式创建应用。 config.ROOT_DIR指向仓库根目录,模板/静态目录显式提供给 Flask。数据库、上传、备份、日志使用配置中的绝对路径,避免包文件移动改变数据位置。default_config用python-dotenv读取根目录.env,不修改os.environ;只读取已支持的DEEPSEEK_API_KEY,不展开${...}。显式工厂配置优先于进程环境(含空值),再使用文件值。配置在应用创建时确定,修改后重启;真实.env不纳入 Git。- 限流、输入状态由应用实例持有,不能每请求重置或跨测试应用共享。维护 CLI 和纯规则可用标准库加载,包入口延迟导入 Web 依赖。
- 单文件围绕一个职责;超过约 300–400 行时检查职责,而非按行数机械拆分。报价数据保持单一来源;兼容转发不复制字典。页面脚本按页面保留既有执行顺序和全局函数,不擅自改为 ES Modules。
- 配色、字体基线和通用控件放在
theme.css,页面布局放在对应 CSS。客户页通过body.dark覆盖主题令牌;新增可翻译文案加入chat.js的I18N,静态文案用data-i18n。调整样式后检查桌面、390px 窄屏、侧栏、聊天卡片和客服空/活动状态。 - 客户附件预览由
clearAttachment管理,轨迹展开由fillTrackCard管理。客服drafts按sid保存草稿,发送成功后只清理已确认发送的内容;常用回复仅填入草稿。renderList只在展示数据变化时重绘。 - 客户页
resetConversation统一处理新建、快捷问题和历史切换;人工路由同时绑定humanConvId与当前会话版本。旧建会话、历史、人工申请和轮询的异步结果不得覆盖新话题。三个业务快捷入口开启独立 AI 对话,联系人工入口才进入人工模式;排队/接待状态常驻输入框上方,可用「返回 AI 问答」结束人工会话。人工消息确认成功后才清空草稿,失败保留输入;服务端校验可选conv_id并拒绝已关闭会话。 - 客服工作台默认只展示会话列表和全高聊天区;统计使用原生
details收在「数据概览」。setSessionTab切换接待/排队列表,setChatView与showSessionList控制 720px 及以下的整屏导航,不结束当前会话。setToolsOpen控制默认关闭的服务资料:1200px 以上为侧栏,较窄屏为抽屉;列表入口让未选会话的手机用户也能查看留言。
后续结构调整顺序
| 阶段 | 范围 | 验收要求 |
|---|---|---|
| 1. 纯规则 | 知识、报价、运费、运单识别 | 边界结果与迁移前一致;固定时钟比较模拟轨迹;导入无运行数据副作用 |
| 2. 数据访问 | 配置、SQLite、备份、附件 | 临时目录验证 schema 兼容、事务、保留/清理时机和跨目录 CLI |
| 3. 服务/路由 | 模型、聊天、人工、应用工厂、Blueprint | URL/方法/状态/JSON/SSE 不变;保留限流、HTML/SSE 缓存头及根入口 |
| 4. 前端 | 模板与 CSS/JS | 仅迁移时对照原资源内容;主动改版时验证语法、资源 URL、加载顺序、响应式和客户/客服页交互 |
每阶段完成相关验证再推进依赖阶段。鉴权、缺表和计费的业务修复单独说明,避免在结构调整中顺带改行为。
必须保留的接口与数据约定
- SSE 字段为
t、e、card、replace、suggest、d;客户端兼容 LF/CRLF 和跨字节分段,收到d才算成功,意外 EOF 保留已收到正文并提供重试。上游缺少结束标记或因长度截断时保存中断状态;压缩、追问、流式 HTTP 响应都要关闭。首段等待 90 秒、整轮 120 秒;会话、历史及人工 JSON 请求 10 秒,上传 15 秒超时可恢复。 chat_service.create_chat_stream的订单查询使用本地order_test_data;忽略附件路径、重量、日期和三维尺寸,保留标识中的后缀,不再调用build_track生成模拟轨迹。旧模拟函数仅兼容旧导入,不进入聊天查询路径。未知单号、多条匹配和查表失败明确说明,禁止回退模型编造状态。CARD_PREFIX新增kind=order:仅包含白名单概要、申报货物汇总和订单业务状态历史,不包含姓名、地址、内部备注或操作人。子单没有独立货物数据时不继承父单总重量;COMPLETED 只表示头程订单完成,不表示快递签收。页面和模型上下文只显示订单事实,不附加测试副本声明或导入时间;旧历史订单卡片中的相关元数据也不展示。订单追问只在同一conv_id内复用最近单号,并重新查表取得手工修改后的值;仅明确指向上一票或简短字段追问可复用,新报价或其他话题不会沿用旧订单。- 订单数据仅为内部验收副本:
ORDER_DATA_TENANT_ID可固定服务器端租户范围,空值允许查询内部已导入样本。它不代替将来客户登录授权。没有管理页面或对外增删改接口;表数据在运行时 SQLite 内维护,导入脚本默认保留已有记录,只有显式--replace覆盖。源库连接凭据和快照文件均在仓库外,业务库只读,不随服务查询访问源库。 - 历史卡片以
__CARD__{json}保存;原 SQLite 表、字段、角色值和历史记录继续可读。历史正文和卡片使用存库时间,卡片恢复复制操作。切换话题或历史时取消旧流和待上传附件;等待建会话期间的新草稿不能被旧发送清空。历史刷新失败保留已有列表;删除或清空成功后先同步本地列表,并使先前的刷新失效,刷新失败或迟到均不恢复已删除记录。删除会话同步移除其人工会话及消息,迟到的模型写入不能生成孤立消息。 - 人工申请使用
conv_id,返回session_id,后续用sid。状态为waiting/active/closed,消息方向为customer/agent/system。转接将 active 改为 waiting,列表只允许主动接入。备注保存在human_sessions.note;撤回将原客服消息改为系统提示并追加带recalled_id的系统事件,轮询按原消息编号更新,重复撤回不追加事件。 - 新建会话保存一条 assistant 欢迎语并返回
welcome,前端在首次用户消息之前显示。首次提问判定只统计 user 消息。服务评价用ratings保存,并汇总到管理统计。Excel 导出依赖openpyxl,原 CSV 可用?format=csv访问。 - 计费档位、单位换算和舍入保持原样。
shipping_intent_with_context用is_shipping_followup识别渠道、重量、尺寸、单独目的地回复及重试,保留报价条件;新订单、另外一票、理赔及新的完整问题形成回溯边界,不继承上一票尺寸。尺寸支持带小数和空格,换算单位后计价。中英混写的 UK/US 按 ASCII 边界识别;目的地未确认时先询问目的国家,不默认给出欧洲报价。英国使用英国渠道和默认比价组合。明确提到美国等未覆盖目的地时不套用欧洲费率,英国按方报价不套用欧洲仓价;指定国家或仓点没有匹配时calc_warehouse_card返回空。calc_freight.total仅含基础运费;附加费尚未统一并入。知识文档与knowledge_list同步维护。 - 聊天请求的会话编号仅接受 SQLite 整数范围内的 ASCII 十进制整数或空值;字符串转换前限制长度,非法 Unicode 数字和超长数字返回 SSE 输入错误,不进入模型调用。
- 上传 URL 保留
/uploads/,默认 10MB,扩展名配置保持不变。原附件保留本地、继续忽略,目录迁移不另建一份数据。 agents、orders、tickets在应用初始化时建空表;兼容已有独立 id 列的 agents 表,不预置账号或演示数据。- 后台鉴权和会话隔离仍不完整,订单表为内部测试副本,不提供实时物流轨迹。Linux 公网验收用 Nginx 全站密码隔离访问,不代表已修复面向客户开放所需的应用权限。
验证与维护
先按 README 安装项目依赖。Windows 使用 .\.venv\Scripts\python.exe -m pytest -v 或同解释器的 -m unittest discover -s tests -v;Linux/macOS 使用 .venv/bin/python。业务测试依赖 Flask,不能用未安装依赖的全局 Python 运行整套测试。模型请求全部模拟,不代表真实 DeepSeek 联调。
路径、函数或资产移动后同步更新根 AGENTS.md、本文、知识资料和 README 目录树。仅改导航时检查路径、符号、命令;改业务时补充相关成功和失败分支,前端改动检查实际页面。