Files

17 KiB
Raw Permalink Blame History

模块导航与拆分规范

四阶段拆分已落地: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 目录树。仅改导航时检查路径、符号、命令;改业务时补充相关成功和失败分支,前端改动检查实际页面。