8.2 KiB
8.2 KiB
2026-04-13
背景
- 用户确认在现有
fquiz系统内先落地 AI 聊天功能(先方案确认,再开发),要求最小改动闭环。
改动
-
后端新增聊天域(FastAPI + SQLAlchemy):
- 新增模型:
api/app/models/chat.pychat_sessionschat_messages
- 新增 Schema:
api/app/schemas/chat.py - 新增服务:
api/app/services/chat_service.py(会话/消息读写与发送主流程)api/app/services/llm_gateway.py(模型路由解析 + OpenAI-compatible 调用)
- 新增路由:
api/app/api/v1/chat.pyGET /api/v1/chat/sessionsPOST /api/v1/chat/sessionsGET /api/v1/chat/sessions/{session_id}/messagesPOST /api/v1/chat/sessions/{session_id}/messages
- 入口接入:
api/app/api/router.py挂载chat路由api/app/models/__init__.py、api/app/core/database.py注册聊天模型确保create_all生效
- 新增模型:
-
聊天模型与密钥策略:
- 复用模型管理路由规则,解析顺序:
CAPABILITY: chat.defaultGLOBAL: __global__
- 仅命中
ENABLED且存在激活密钥记录的模型。 - 运行时 key 从环境变量读取,不反解库内 hash:
LLM_PROVIDER_API_KEYS(openai=sk-...或 JSON)。
- 复用模型管理路由规则,解析顺序:
-
配置与部署模板:
api/app/core/config.py新增:llm_provider_api_keysllm_request_timeout_secondschat_context_message_limitchat_default_system_prompt
.env.example、docker-compose.yml、.github/workflows/main.yml同步新增上述变量透传。api/requirements.txt新增httpx==0.28.1。
-
RBAC 与菜单:
api/app/services/seed_service.py新增权限chat.use。- 新增后台菜单
admin.chat(/admin/chat)。 admin默认菜单绑定新增admin.chat。api/app/services/admin_service.py把admin.chat加入内置受保护菜单集合。
-
前端(Next.js App Router + TanStack Query):
- 新增页面:
web/src/app/admin/chat/page.tsx- 会话列表
- 消息列表
- 发送消息
- 错误与反馈展示
- 新增类型:
web/src/types/auth.ts(ChatSession/ChatMessage 等)。 - 后台首页增加入口卡片:
web/src/app/admin/page.tsx。 - 首页快捷入口增加
AI 聊天按钮:web/src/app/page.tsx。
- 新增页面:
验证
- 后端语法编译:
python3 -m compileall api/app通过
- 前端 lint:
npm run lint:web通过
- 前端类型检查:
cd web && npx tsc --noEmit通过
风险与备注
- 当前为非流式回复,长回答时前端等待感较明显。
- 当前默认按 OpenAI-compatible
/chat/completions调用,若其他 Provider 接口不兼容需二期扩展适配层。 - 聊天表由
create_all自动创建,适用于当前仓库口径;后续若引入正式迁移体系需补充迁移脚本。
补充记录(2026-04-13 / web 构建修复)
- 问题:
docker compose build web在RUN npm run build失败,堆栈指向web/src/app/layout.tsx中next/font/google(Space Grotesk/Manrope/JetBrains Mono)拉取fonts.googleapis.com失败。 - 处理:
web/src/app/layout.tsx移除next/font/google依赖与变量注入。web/src/app/globals.css在:root补充--font-heading/--font-body/--font-mono本地字体回退栈,保持现有样式变量接口不变。
- 验证:
cd web && npm run build通过。docker compose build web通过。
- 风险:
- 构建不再依赖外网字体下载,但渲染字体会按运行环境已安装字体回退,字形可能与 Google Fonts 原始效果有轻微差异。
补充记录(2026-04-13 / 首页类型构建修复)
- 问题:
docker compose build web在RUN npm run build的 TypeScript 阶段失败,报错集中在web/src/app/page.tsx,ButtonRootProps/InputRootProps不接受role/id/onPress等常用属性。 - 根因:
@heroui/react在当前仓库依赖组合(Next.js 16 + React 19 + TS 严格检查)下导出类型不完整,导致封装组件web/src/components/ui.tsx的Button/Input/Checkbox类型约束与页面实际用法不一致。 - 处理:
web/src/app/page.tsx:认证模式切换按钮从role="tab"+aria-selected改为aria-pressedtoggle 语义,避免不被组件类型支持的属性。web/src/app/page.tsx:将首页Button用法改为原生button,保持现有btn-*样式类不变。web/src/components/ui.tsx:Button/Input/Checkbox改为原生语义封装(保留btn-*/control约定),并为Checkbox兼容isSelected、onValueChange与布尔回调onChange。
- 验证:
cd web && npm run build通过(包含Running TypeScript ... Finished TypeScript)。
- 风险:
- 首页表单控件不再走 HeroUI 行为层,交互细节(如组件内建动画/状态样式)由本地样式类主导;当前页面功能不受影响,但若后续回切 HeroUI 需先升级或修复其类型声明。
补充记录(2026-04-13 / HeroUI 类型阻断修复-2)
- 问题:
docker compose build web在RUN npm run build的 TypeScript 阶段再次失败,先报web/src/components/ui.tsx中withDefaultButtonClass(className)参数不兼容(className可能是函数),随后暴露ListBox/Modal/Table类型不接受children。 - 根因:
@heroui/react在当前依赖组合下的导出类型与页面实际用法持续不一致,Button/Input与容器类组件(ListBox/Modal/Table)都存在声明缺口。 - 处理:
web/src/components/ui.tsx:Button/Input/TextArea/Checkbox全部切为原生语义封装,并兼容现有调用参数:Button兼容onPress、isDisabledCheckbox兼容isSelected、defaultSelected、onValueChange、布尔onChange
web/src/components/ui.tsx:ListBox/ListBoxItem/Modal/Table保持 HeroUI 运行时组件,但新增宽松 TS 包装类型,避免children和onSelectionChange的类型阻断。
- 验证:
cd web && npm run build通过(Running TypeScript ... Finished TypeScript)。
- 风险:
ListBox/Modal/Table的包装类型放宽后,编译期约束下降;后续若升级 HeroUI 并修复官方声明,建议回收宽松包装并恢复严格类型。
补充记录(2026-04-13 / HeroUI Table 集合上下文运行时修复)
- 问题:用户在前端运行时遇到
cannot be rendered outside a collection.,堆栈来自压缩产物,页面实际白屏。 - 根因:
web/src/app/admin/todos/page.tsx中Table.Header/Table.Body/Table.Column/Table.Row直接挂在Table下;当前 HeroUI 版本中Table仅是容器根节点,必须通过Table.Content承载react-aria的真正表格上下文,否则集合子节点会在运行时抛错。 - 处理:
web/src/app/admin/todos/page.tsx:将表格结构调整为Table -> Table.Content -> Table.Header/Table.Body,其余业务逻辑与样式不变。
- 验证:
npm run lint:web通过。cd web && npx tsc --noEmit通过。cd web && npm run build通过(含Generating static pages ... /admin/todos)。
- 风险:
- 仅修复
admin/todos当前命中页面;若后续新增 HeroUITable页面,仍需遵循同一组合约束避免复发。
- 仅修复
补充记录(2026-04-13 / web 字体构建回归修复)
- 问题:用户再次反馈
docker compose build web在RUN npm run build失败,堆栈指向web/src/app/layout.tsx的[next]/internal/font/google/space_grotesk...。 - 根因:
layout.tsx回归为next/font/google(Space_Grotesk/Manrope/JetBrains_Mono)编译期下载字体,受限网络环境下失败。 - 处理:
web/src/app/layout.tsx删除next/font/google导入与字体变量注入,仅保留h-full antialiased。web/src/app/globals.css在:root显式补齐--font-heading/--font-body/--font-mono本地字体回退栈。
- 验证:
cd web && npm run build通过。docker compose build web通过([builder 5/5] RUN npm run build完成,镜像fquiz-web构建成功)。
- 风险:
- 字体外观按运行环境本地字体回退,可能与 Google Fonts 设计稿存在轻微字形差异。