architecture.md 6.3 KB

架构说明

本文是项目的架构事实来源。根 CLAUDE.md 只做简短入口,深层规则都在这里。

项目定位

青浦区营商智能助手前端。Vue 3 + TypeScript + Vite,面向企业的政策匹配与办事指引: 用户自然语言提问,助手检索政策知识库,以「开场概述 + 政策卡片 + 综合说明 + 参考资料」 的形式给出有原文依据的回答;涉及具体企业时先引导用户确认公司主体,再结合工商信息作答。

容易误判的几件事

先看这几条,可以省掉不少弯路:

  • 对话走接口 POST /api/chat(SSE)。前端不直接渲染接口协议,而是经适配层 src/components/api-chat-coordinator.ts 翻译成既有渲染组件可识别的内容标记。 详见 reference/api-chat.md
  • 没有 3D 虚拟人渲染three 仅用于粒子背景(business-assistant-particle.ts); src/three-libs/ 下有且只有一个模块:asr/,是语音识别,且在用 (PC 与移动端都 import ASR from '@/three-libs/asr/index',点麦克风就走它)。 > 注:本文曾写「src/three-libs/metamaker 是未被引用的 SDK 包」——那个目录不存在, > 2026-09-18 核查时已更正。目录名 three-libs 有误导性:它与 three.js 无关。
  • 没有状态管理库(无 Vuex / Pinia)。对话状态在 useBusinessAssistantChat 组合式函数内, 会话与消息持久化到 localStorage
  • 没有 src/hooks/ 目录;也没有 stream-message-coordinator-v2.ts

技术栈

说明
框架 Vue 3(<script setup>)+ TypeScript + Vite 5
UI Ant Design Vue 4(unplugin-vue-components 按需自动引入)
状态 无状态管理库;组合式函数 + localStorage
流式 原生 fetch + ReadableStream(现行);@microsoft/fetch-event-source(旧协议,保留未用)
Markdown marked
其他 Three.js 0.143.0(粒子背景)、alloyfinger(语音相关)

主入口与页面壳

  • src/main.ts — 应用入口
  • src/App.vue — 根组件
  • src/components/BusinessAssistant.vue只做 PC / 移动端切换,不是主壳
  • src/components/BusinessAssistantPC.vue / BusinessAssistantMobile.vue — 真正的页面主壳 (输入区、消息列表、滚动与打字机联动都在这里)

目录结构

src/
├── components/
│   ├── Chat/                    消息渲染、政策卡片、补问问卷等
│   ├── Common/                  通用组件(MediaViewer、ScrollList、Toast…)
│   ├── business-assistant/      对话编排(useBusinessAssistantChat、上传、滚动等)
│   ├── api-chat-coordinator.ts  ★ 协议适配层(现行)
│   └── stream-message-coordinator.ts  旧协议实现(保留未用,勿改)
├── network/api/                 接口封装(chat-sessions、enterprise、assistant-statistics、card)
├── types/                       TypeScript 类型定义
├── utils/                       工具(runtime-config、stream-xml-filter、scope-record-rows…)
└── three-libs/asr/              语音识别

核心系统

对话协议适配层(现行)

src/components/api-chat-coordinator.ts —— 接口 POST /api/chat 的客户端。 把 SSE 事件翻译成内容标记交给既有渲染组件:

接口事件 翻译为 由谁渲染
progress / heartbeat <scope title="阶段文字"> ScopeContent("思考中"卡片)
item <!-- POLICY_TABLE {"data":[…]} --> PolicyMatch(政策卡片 + 详情面板)
source <ref_links>[…]</ref_links> 参考资料 chips + 侧边面板
interrupt <question-cards>{…}</question-cards> QuestionCard(补问问卷)
answer / summary 纯文本 TextContent(markdown)

渲染层不需要感知新协议。 这是刻意设计:协议会变,渲染层不动。

旧协议实现(保留未用)

src/components/stream-message-coordinator.ts。当前未被使用,不要改动

关键约束

接口层

  1. 请求体只接受 {thread_id, question} 两个字段,多一个返回 422。 旧协议的 transmission.files / file_pos 发不出去(这是"文件上传"功能待定的原因)。
  2. answer.textresult.response 内容相同,只能展示一次(result 是快照)。
  3. 未收到 done/error 即断流 → 按连接中断处理,不自动重试
  4. 不要用后端文案做判断。 补问形态由 kind + status 字段决定, 而不是拿 input_help 的中文措辞做正则 —— 后端改一个字判定就会失效(踩过)。

界面

  • 界面样式必须与原版一致。 新协议能力通过适配层翻译成内容标记来复用既有渲染组件, 不要新建带自有样式的 UI 组件。
  • 既有 UI 的可选项、文案、筛选逻辑不要擅自改动 —— 确需变更先取得确认。

开发环境

  • dev server 为 HTTPS(自签证书),浏览器首次访问会有证书告警,属正常现象
  • 聊天接口走同源代理 /chat-apihttp://192.168.2.23:8000(见 vite.config.ts)。 代理由服务端发起,因此局域网同事访问也不会有混合内容或跨域问题
  • 生产环境 vite 代理不生效,需由 nginx 做等价转发

环境变量

变量 用途
VITE_API 主业务 API 网关
VITE_CHAT_API 对话接口。服务前缀(/chat-apihttp://host:8000)会自动追加 /api/chat;已是完整地址则原样使用
VITE_CHAT_TARGET 聊天后端真实地址(仅 dev 用)。VITE_CHAT_API 在开发环境是代理前缀 /chat-api,代理的 target 从本变量读(见 vite.config.ts),不再硬编码在配置文件里
VITE_DMS_API / VITE_DMS_TARGET DMS 数据服务(会话/问答记录/反馈落地)。dev 走 /dms-api 代理、token 由代理注入,见 vite.config.ts
VITE_MODEL_SERVER 模型服务
VITE_ASR / VITE_STREAM_SERVER 语音识别 / 流媒体

📌 地址往 env 里放、不要写死在代码里VITE_DMS_TARGETVITE_CHAT_TARGET 都是为此加的。vite.config.ts 里保留同值兜底,但优先读 env。