5a26dfde2a
后端变更: - 新增 risk_config.py: 风险配置数据类,支持环境变量驱动 - 新增 risk_control.py: 风险控制控制器,管理并发和预算 - 新增 session_store.py: 匿名会话存储,基于 cookie 的 session ID - 新增 audit_store.py: API 审计日志存储,记录请求和 LLM 调用 - 新增 captcha_api.py: 验证码 API,用于验证用户操作真实性 - 新增 llm_policy.py: LLM 策略配置,管理 completion/pro/vision 模型 - main.py: 集成 middleware、risk/audit/session 模块 (+467/-7) - job_handlers.py: LLM 执行流程重构,新增 risk/audit 集成 (+207/-4) - llm.py: 异步客户端封装,新增 max_output_tokens 参数 (+78/-1) - job_system.py: stream_events 逻辑优化,支持心跳检测 (+12/-4) - pro_completions.py: SSE heartbeat 机制,防止连接超时 (+14/-4) - prompt.py: _normalize_preferences 支持 Mapping 类型 (+13/-0) - tts_asr.py: asyncio loop 初始化,router export (+10/-0) 前端变更: - src/components/CaptchaComponent.vue: 新增验证码组件 (NEW) - src/utils/cookie_policy.js: Cookie 策略工具 (NEW) - SettingsPanel.vue: 集成验证码组件,新增安全设置部分 (+59/-0) - MilkdownEditor.vue: 移除硬编码 API_KEY,新增 credentials (+32/-10) - ProBlockCrepe.vue: 样式简化,移除渐变动画 (+18/-4) - proBlockPlugin.ts: 重构 schema/serializer 引用方式,通过 Ctx 管理 (+40/-10) - api.js: 新增 credentials,重构 headers 条件逻辑 (+50/-14) - config.js: API 基址改为 https://api.imageteach.tech:8002 (+8/-4) - convert.js, docsApi.js, i18n.js: 新增 credentials 和验证码 i18n (+54/-12) - proAccept.js: 重构正则和转义处理,修复捕获组索引 (+14/-4) 配置和基础设施: - docker-compose.yml: 新增端口映射 8001:8001 (+2/-0) - docker/nginx.conf: 改为 307 redirect,优化代理配置 (+8/-6) - vite.config.js: 移除 proxy 配置,直接调用远程 API (+8/-4) - .env.example: 新增 VITE_API_BASE_URL, VITE_API_KEY (+3/-1) - backend/.env.example: 大量 RISK_*, SESSION_*, CORS_* 配置 (+54/-0) - pytest.ini: 扩展 coverage 范围到整个 backend,移除 fail_under (+3/-2) - .coveragerc: 移除 fail_under = 90 (+0/-1) - .gitignore: 新增 docker-data/ (+3/-0) - package.json: 新增 vue3-captcha 依赖 (+3/-1) - AGENTS.md, README.md: 更新 Docker 部署和前端网络约定 (+20/-5) - public/sw.js: Service Worker cache 版本从 v1 升级到 v2 (+0/-1) 测试变更: - test_main_endpoints.py: 新增 session/risk/audit reset,新增测试用例 (+63/-4) - test_main_cancel.py: 新增 reset 调用 (+6/-0) - test_pro_completions.py: 新增 preferences 序列化和测试 (+23/-0) 总计: 45 个文件变更,+1009/-280 行
152 lines
11 KiB
Markdown
152 lines
11 KiB
Markdown
# LLM in Text 仓库指引
|
||
|
||
本文件适用于整个仓库。进入更深层目录后,子目录中的 AGENTS.md 优先于本文件。
|
||
|
||
## 项目定位
|
||
|
||
- 这是一个智能 Markdown 编辑器,前端负责编辑器 UI、上传导出、补全交互和设置状态,后端负责 LLM、OCR、文件转换和 TTS 接口。
|
||
- 前端技术栈:Vue 3 + Vite + Milkdown/Crepe + Pinia + Vue Router。
|
||
- 后端技术栈:FastAPI + Python + OpenAI-compatible LLM endpoint。
|
||
|
||
## 功能块系统(核心概念)
|
||
|
||
- **统一命名**:文档块、PRO 块、上传块统称为"功能块"。
|
||
- **禁止嵌套**:所有功能块的 schema 均设 `atom: true, isolating: true`,ProseMirror 层面强制禁止互相嵌套。DocBlockCrepe.vue 的嵌套 Crepe 编辑器不注册任何功能块插件,从架构上杜绝深层嵌套。
|
||
- **无数量限制**:一篇文档可包含任意数量的功能块,彼此独立存在。
|
||
- **导入自动解析**:从 Markdown 文件导入后,各功能块语法必须通过对应的 Remark/parseMarkdown 解析器自动识别并还原为交互卡片。
|
||
- **导出可复原**:通过 toMarkdown/leafText 序列化器将功能块还原为 Markdown 语法,确保导出后再次导入能完整复原。doc_block toMarkdown 输出 legacy HTML tag,`getExportMarkdown()` 中通过 `transformLegacyDocBlocksForExport()` 转换为 fenced code block。
|
||
|
||
| 类型 | Node Type | Markdown 语法 | Plugin 文件 | Utility 文件 |
|
||
|------|-----------|---------------|-------------|--------------|
|
||
| 文档块 | `doc_block` | \`\`\`llm-file fenced code / `<doc_type=...>` legacy HTML tag | `plugins/docBlockPlugin.ts` | `utils/docBlock.js` |
|
||
| PRO 块 | `pro_block` | `[PRO]` / `[PRO]{指令}` | `plugins/proBlockPlugin.ts` | `utils/proBlock.js` |
|
||
| 上传块 | `upload_block` | `{{{}}}` / `{{{upload file type:...}}}` | `plugins/uploadBlockPlugin.ts` | `utils/uploadBlock.js` |
|
||
|
||
- **已验证**:当前代码完全符合"禁止嵌套、自动解析复原"的要求。修改功能块相关逻辑时需验证:1) schema 的 atom/isolating 属性不被移除;2) Remark/parseMarkdown/toMarkdown 解析链路完整。
|
||
- 当前代码中可以确认的主功能是:AI 补全、OCR、文档转 Markdown、TTS、Markdown/DOCX/PDF 导入导出。
|
||
- 历史文档中有一部分 TTS/ASR、Apple Silicon、Whisper、离线模式说明已经落后于当前代码;出现冲突时以实际代码和测试为准。
|
||
|
||
## 先看哪里
|
||
|
||
- 项目概览和运行说明:README.md
|
||
- 前端入口:src/main.js
|
||
- 路由:src/router/index.js
|
||
- 编辑器主组件:src/components/MilkdownEditor.vue
|
||
- AI 补全核心:src/plugins/copilotPlugin.ts
|
||
- 前端请求层:src/utils/api.js
|
||
- 前端配置:src/utils/config.js
|
||
- 设置状态:src/stores/settings.js
|
||
- 后端入口和主路由:backend/main.py
|
||
- LLM 和 OCR 调用:backend/llm.py
|
||
- Prompt 组装:backend/prompt.py
|
||
- TTS 路由:backend/tts_asr.py
|
||
- 测试配置和入口:pytest.ini、backend/tests/run_tests.py
|
||
|
||
## 稳定事实
|
||
|
||
- **功能块禁止嵌套**:`doc_block`、`pro_block`、`upload_block` 的 schema 均设 `atom: true, isolating: true`,ProseMirror 层面强制禁止互相嵌套。DocBlockCrepe.vue 的嵌套 Crepe 编辑器仅注册 copilotPlugin + hiddenText*,不注册任何功能块插件。修改时不得移除 atom/isolating 属性或在嵌套编辑器中引入功能块插件。
|
||
- **功能块导入解析**:各功能块的 Remark 插件(`docBlockRemark`, `proBlockRemark`, `uploadBlockRemark`)负责从 Markdown AST 识别对应语法并转换为节点。doc_block Remark 同时支持 fenced code (`llm-file`) 和 legacy HTML tag (`<doc_type=...>`)。解析链路必须保持完整,否则导入后无法自动复原。
|
||
- **功能块导出序列化**:doc_block 的 `toMarkdown` runner 输出 legacy HTML tag,但 `getExportMarkdown()` 中通过 `transformLegacyDocBlocksForExport()` 转换为 fenced code block。pro_block/upload_block 的 toMarkdown/leafText 直接输出标准语法。修改时需验证导出后再次导入能完整复原。
|
||
- **Store 同步格式**:`scheduleMarkdownSync()` emit markdown 不做转换(doc_block 为 legacy HTML tag),store 中始终是 legacy format。`syncInitialMarkdown()` / `getExportMarkdown()` 负责格式转换。
|
||
- **上传块生命周期**:upload_block 是临时占位符,文件上传后被替换为 image node(图片)或 doc_block(文档),不会与 pro_block 共存。
|
||
- **PRO block escape/unescape**:`escapeProBlockContent()` / `unescapeProBlockSyntax()` 处理 `\`, `]`, `}`, newline,确保指令 round-trip 正确。
|
||
- **补全接口当前不是 SSE**;前端用普通 POST 请求拿 JSON 响应。
|
||
- 前端会生成 X-Request-Id,并在请求被中止时额外调用 /v1/completions/cancel。
|
||
- 文档超过 32 KB 时,AI 补全会在前端和插件层被禁用。
|
||
- OCR 文本和文档块内容会被注入补全上下文,但这些内容属于隐藏上下文,不应被直接当作用户可见文本重复输出。
|
||
- /v1/convert 当前支持 txt、docx、pptx、pdf,非 txt 文件通过 MarkItDown 转成 Markdown,之后会清理图片标记。
|
||
- 前端存在 /v1/export/pdf 调用点,但当前后端主路由中看不到同名端点;排查 PDF 导出问题前先确认服务端是否真正提供该接口。
|
||
- 当前 tts_asr.py 主要提供 TTS 相关能力。不要直接沿用 README 或历史修复文档里关于 ASR、Whisper、MPS/offline 的描述。
|
||
|
||
## 常用命令
|
||
|
||
- 前端安装:npm install
|
||
- 前端开发:npm run dev
|
||
- 前端构建:npm run build
|
||
- 后端安装:pip install -r backend/requirements.txt
|
||
- 后端启动:python backend/main.py
|
||
- 可选启动方式:uvicorn backend.main:app --reload --port 8001
|
||
- 全量测试:pytest
|
||
- 常用窄测试:
|
||
- pytest backend/tests/test_main_endpoints.py -v
|
||
- pytest backend/tests/test_main_cancel.py -v
|
||
- pytest backend/tests/test_prompt.py -v
|
||
- pytest backend/tests/test_llm.py -v
|
||
|
||
## Docker 部署约定
|
||
|
||
- 本机部署目录固定在 `/Users/allenyuan/lit/` 下,不在仓库外再散落数据库或 Docker 持久化目录。
|
||
- 当前推荐的部署工作目录是 `/Users/allenyuan/lit/llm-in-text/`;把仓库同步到该目录后,从该目录执行 `docker compose up -d --build`。
|
||
- 不再使用 `/Volumes/New Volume/lit/` 部署本项目;迁移时可放弃旧 PostgreSQL 数据,从新部署目录初始化空数据库。
|
||
- **前端网络硬约定**:前端 API 必须调用 `https://api.imageteach.tech:8002/` 反向代理,不要让前端调用 Docker 内 `api` 服务、本机 `localhost:8001`、`localhost:8081` 或同源 `/v1` 代理。网络和反向代理由外部配置处理,除非用户明确要求,不要新增或恢复前端到 Docker 后端的代理。
|
||
- 每次修改会影响 Docker 运行效果的代码后,不能只停留在本地测试;必须同步更新当前 Docker 环境中的代码,并验证容器内代码已经变化。
|
||
- 首选更新方式:
|
||
1. 在仓库根目录执行 `docker compose up -d --build`。
|
||
2. 执行 `docker compose ps` 确认 `api`、`worker`、`frontend` 等目标服务已重新创建并处于 Up。
|
||
3. 对关键修复点执行容器内验证,例如 `docker compose exec -T worker sh -lc "python - <<'PY'\nfrom pathlib import Path\nprint('_normalize_preferences' in Path('/app/backend/prompt.py').read_text())\nPY"`。
|
||
- 如果 `docker compose build` 因 Docker Hub、镜像源、网络 token 超时等外部原因无法拉基础镜像,仍然必须更新正在运行的 Docker 环境。可用应急方式:
|
||
1. 先执行 `npm run build` 生成最新前端产物。
|
||
2. 用 `docker cp` 将改动后的后端文件复制到 `api` 和 `worker` 容器的 `/app/backend/`,必要时将 `dist/` 复制到 `frontend` 容器的 `/usr/share/nginx/html/`。
|
||
3. 执行 `docker compose restart api worker frontend` 重启受影响服务。
|
||
4. 执行 `docker commit llm-in-text-api-1 llm-in-text-api:latest`、`docker commit llm-in-text-worker-1 llm-in-text-worker:latest`;如果更新了前端,也执行 `docker commit llm-in-text-frontend-1 llm-in-text-frontend:latest`。
|
||
5. 执行 `docker compose up -d --no-build --force-recreate api worker frontend`,确保新容器来自已更新镜像。
|
||
6. 再次用 `docker compose exec -T ...` 验证容器内文件和行为,不能只看本地文件。
|
||
- Docker 持久化数据统一落在部署目录内的 `docker-data/`,包括 PostgreSQL、Redis 和任务共享临时目录。
|
||
- 容器内访问宿主机模型服务时,不要继续使用 `localhost`;应改成 `host.docker.internal` 之类的容器可达地址。
|
||
- 当前 Docker 部署默认使用轻量后端依赖集(`backend/requirements.docker.txt`),覆盖补全、OCR、转换、文档空间和队列,不默认包含本地 `torch` / TTS / ASR 模型栈。
|
||
- 修改 Docker 相关文件时,除了代码本身,还要同步检查:
|
||
- `docker-compose.yml`
|
||
- `backend/Dockerfile`
|
||
- `backend/requirements.docker.txt`
|
||
- `Dockerfile.frontend`
|
||
- `docker/nginx.conf`
|
||
- `backend/.env.example` 与实际部署用 `backend/.env`
|
||
|
||
## 代码约定
|
||
|
||
- 不要把整个仓库当成“全小写+短横线命名”项目。当前实际情况是:
|
||
- Vue 组件和视图多为 PascalCase
|
||
- 前端工具模块多为小写 .js
|
||
- 插件层使用 TypeScript
|
||
- Python 使用 snake_case
|
||
- 以就地风格为准,不要顺手做全仓格式统一。
|
||
- UI 文案和代理回复默认使用中文。
|
||
- 不要修改 milkdown-docs/,它是只读参考资料。
|
||
- 不要新增硬编码密钥、空 catch/except、as any、@ts-ignore 之类的扩散式技术债。
|
||
- 代理在这个仓库里应优先做局部、可验证的修改,不要做无关重构。
|
||
|
||
## 调试路径
|
||
|
||
- 补全问题:
|
||
src/components/MilkdownEditor.vue
|
||
-> src/plugins/copilotPlugin.ts
|
||
-> src/utils/api.js
|
||
-> backend/main.py
|
||
-> backend/prompt.py / backend/llm.py
|
||
|
||
- OCR 问题:
|
||
src/components/MilkdownEditor.vue
|
||
-> backend/main.py
|
||
-> backend/llm.py
|
||
|
||
- 文档转换问题:
|
||
src/utils/convert.js
|
||
-> backend/main.py
|
||
|
||
- TTS 问题:
|
||
src/components/TTSMenu.vue / src/components/TTSPlayer.vue / src/components/MilkdownEditor.vue
|
||
-> src/utils/api.js
|
||
-> backend/tts_asr.py
|
||
|
||
## 测试和产物
|
||
|
||
- pytest.ini 对 backend.main、backend.llm、backend.prompt、backend.geoip、backend.prompts、backend.tts_asr 设了覆盖率门槛,低于 90% 会失败。
|
||
- 默认测试目录是 backend/tests。
|
||
- 常见生成产物包括 dist、htmlcov、.pytest_cache、api_performance_report.md;它们不是源代码。
|
||
|
||
## 文档注意事项
|
||
|
||
- README.md 对产品功能有参考价值,但其中补全、TTS/ASR 和部分接口说明已经比代码旧。
|
||
- backend/TTS_ASR_MACOS_FIX.md 和 backend/tests/TESTING_GUIDE.md 更适合作为历史背景,不应在与代码冲突时被当成事实来源。
|
||
- 修改行为时,优先参考实现代码和对应测试,再决定是否同步普通文档。
|