{"repo": "alansonder/ai-assistant", "files": {"README.md": {"21aff4283e4de41af9e3fe71334b29e780105958": {"t": 1785746433.6459394, "n": 7461, "h": "d066369510fc0898", "c": "# AI-Assistant\n\n模块化 AI 助手应用,集成大语言模型(LLM)、OCR 文字识别、智能翻译等核心能力,支持多提供商(本地 / DeepSeek)灵活切换。同时包含一个 Vue 3 Web 前端和一个 Python 桌面截图翻译工具。\n\n| 属性 | 说明 |\n|------|------|\n| 构建工具 | Maven 3.x(Wrapper)+ npm |\n| Java / Spring Boot | 21 / 3.5.13 |\n| Spring AI | 1.1.4(已排除自动配置,使用自定义 LLM 调用) |\n| 前端 | Vue 3.5 + Element Plus 2.13 + Vite 8 + TypeScript |\n| Python 桌面端 | tkinter + mss + Pillow + Tesseract/PaddleOCR |\n| 服务端口 | 9090(后端)/ 5173(前端开发) |\n\n## 项目结构\n\n```\nai-app ─── 启动入口,依赖所有子模块\n ├── ai-common 公共模块(统一响应体、全局异常处理、WebClient)\n ├── ai-llm LLM 多提供商调用封装(文本/Vision/流式)\n ├── ai-translator 多模态翻译(文本/图片/语音)+ SSE 流式\n └── ai-agent 智能体框架(预留模块)\n\nui ─── Vue 3 Web 前端(翻译界面 + LLM 提供商切换)\n\nscreen-translator ─── Python 桌面截图翻译工具(独立运行,无需后端)\n```\n\n---\n\n## 快速开始\n\n### 环境要求\n\n- JDK 21+(项目使用 Maven Toolchains,无需修改全局 JAVA_HOME)、Node.js 18+、Maven 3.x\n- PostgreSQL 14+(需安装 pgvector 扩展)\n- LM Studio 或其他 OpenAI 兼容 LLM 服务(本地部署时)\n- Tesseract OCR 引擎(可选,screen-translator 本地 OCR 使用)\n\n### 后端启动\n\n```bash\n# 构建所有模块\n.\\mvnw.cmd install -DskipTests\n\n# 启动 Spring Boot\n.\\mvnw.cmd spring-boot:run -pl ai-app\n```\n\n### 前端启动\n\n```bash\ncd ui\nnpm install\nnpm run dev\n```\n\n前端开发服务器在 `http://localhost:5173`,`/api` 请求自动代理到后端 `9090`。\n\n### 一键管理(start.ps1)\n\n项目提供 PowerShell 管理脚本,支持前后端启停、重启、状态查看、日志查看等:\n\n```powershell\n.\\start.ps1 start # 启动后端 + 前端\n.\\start.ps1 stop # 停止后端 + 前端\n.\\start.ps1 restart # 重启后端 + 前端\n.\\start.ps1 start-backend # 仅启动后端\n.\\start.ps1 start-frontend # 仅启动前端\n.\\start.ps1 status # 查看运行状态\n.\\start.ps1 build # 构建后端\n.\\start.ps1 menu # 交互式菜单\n```\n\n### screen-translator 启动\n\n```bash\ncd screen-translator\npip install -r requirements.txt\npython main.py\n```\n\n详细配置见 [screen-translator](#screen-translator) 章节。\n\n---\n\n## 多 Provider 配置\n\n项目支持同时配置多个 LLM 提供商,通过 `active-provider` 切换当前使用的提供商,每个提供商可配置多个模型。\n\n### application.yml\n\n```yaml\nai:\n llm:\n active-provider: ${LLM_ACTIVE_PROVIDER:local}\n default-model: ${LLM_DEFAULT_MODEL:qwen}\n timeout: ${LLM_TIMEOUT:60000}\n max-retries: ${LLM_MAX_RETRIES:3}\n temperature: ${LLM_TEMPERATURE:0.3}\n top-p: ${LLM_TOP_P:0.9}\n max-tokens: ${LLM_MAX_TOKENS:4096}\n providers:\n local:\n base-url: ${LLM_LOCAL_URL:http://localhost:1234/v1}\n api-key: ${LLM_LOCAL_KEY:sk-lm-local}\n models: [qwen, llama]\n deepseek:\n base-url: ${LLM_DEEPSEEK_URL:https://api.deepseek.com}\n api-key: ${LLM_DEEPSEEK_KEY:your-api-key}\n models: [deepseek-v4-pro, deepseek-v4-flash]\n vision-enabled: false\n thinking:\n enabled: ${LLM_DEEPSEEK_THINKING:false}\n reasoning-effort: ${LLM_DEEPSEEK_REASONING:high}\n```\n\n### 运行时切换\n\n- **API 方式**:通过 `/api/v1/llm/providers/activate` 接口切换提供商和模型(见 API 文档)\n- **前端方式**:页面右上角 `LlmSelector` 组件可直接切换提供商、模型,以及 DeepSeek 思考模式开关\n- **自动匹配**:切换模型时自动定位其所属的 Provider 并切换\n\n### DeepSeek 思考模式\n\n当 `active-provider` 为 `deepseek` 时,可开启思考模式(`thinking`),模型会先输出推理过程再输出最终结果。`reasoning-effort` 控制推理深度(`low` / `medium` / `high`)。Vision 请求不支持思考模式参数,仅在纯文本场景生效。\n\n---\n\n## API 接口\n\n### 翻译接口(SSE 流式)\n\n| 方法 | 路径 | 说明 | 请求类型 |\n|------|------|------|----------|\n| POST | `/api/v1/translate/text/stream` | 文本翻译(流式) | JSON |\n| POST | `/api/v1/translate/image/stream` | 图片翻译(流式) | Multipart |\n| POST | `/api/v1/translate/audio/stream` | 语音翻译(流式) | Multipart |\n\n**文本翻译请求示例**:\n\n```json\n{\n \"text\": \"Hello, world!\",\n \"from\": \"English\",\n \"to\": \"Chinese\",\n \"domain\": \"general\",\n \"style\": \"neutral\"\n}\n```\n\n**文本翻译 SSE 响应**:\n\n```\nevent: message\ndata: {\"text\":\"你好,\",\"done\":false}\n\nevent: done\ndata: {\"text\":\"\",\"done\":true}\n```\n\n**图片翻译**(`multipart/form-data`):\n\n- `file` — 图片文件(JPG/PNG/GIF/WEBP,最大 50MB)\n- `from` — 源语言(如 `Japanese`)\n- `to` — 目标语言(如 `Chinese`)\n\n> 图片翻译依赖 Vision 能力,当前 Provider 需设置 `vision-enabled: true`(如 local)。\n\n**语音翻译**(`multipart/form-data`):\n\n- `file` — 音频文件(MP3/WAV/M4A/OGG/FLAC,最大 50MB)\n- `from` / `to` — 语言参数\n\nSSE 事件类型:`asr`(语音识别完成)→ `translation`(翻译流式块)→ `done`(完成)\n\n### LLM 管理接口\n\n| 方法 | 路径 | 说明 |\n|------|------|------|\n| GET | `/api/v1/llm/providers` | 获取所有提供商及模型列表 |\n| POST | `/api/v1/llm/providers/activate` | 切换提供商和/或模型 |\n| POST | `/api/v1/llm/thinking` | 切换 DeepSeek 思考模式 |\n\n**切换提供商请求**:\n\n```json\n{\n \"provider\": \"deepseek\",\n \"model\": \"deepseek-v4-flash\"\n}\n```\n\n**切换思考模式请求**:\n\n```json\n{ \"enabled\": true }\n```\n\n### 错误响应格式\n\n```json\n{\n \"code\": 400,\n \"message\": \"参数验证失败: 翻译文本不能为空\",\n \"data\": null,\n \"timestamp\": 1713763200000\n}\n```\n\n---\n\n## screen-translator\n\n独立的 Python 桌面截图翻译工具,**无需 Spring Boot 后端**,直接调用 LLM API。\n\n### 功能\n\n- 系统托盘图标 + 全局热键(默认 `Ctrl+Q`)触发截图\n- 全屏选区(类似 Snipaste),悬停选框可保存截图或翻译\n- 翻译结果实时流式显示在覆盖层上\n- 支持运行时切换 LLM 提供商/模型、OCR 引擎、字体、语言\n\n### 双模式翻译\n\n根据当前 Provider 是否支持 Vision 自动选择:\n\n| 模式 | 适用 Provider | 流程 |\n|------|--------------|------|\n| Vision 模式 | local | 截图 → LLM Vision API(直接视觉翻译) |\n| OCR 模式 | deepseek 等非 Vision | 截图 → 本地 OCR 识别 → LLM 文字翻译 |\n\nOCR 引擎支持 **Tesseract**(轻量快速,默认)和 **PaddleOCR**(精度更高)。\n\n### config.yaml 关键配置\n\n```yaml\nllm:\n active_provider: \"deepseek\" # local / deepseek\n default_model: \"deepseek-v4-flash\"\n\nocr:\n engine: \"tesseract\" # tesseract / paddle\n lang: \"ch\" # 识别语言\n\ntranslate:\n from: \"Japanese\"\n to: \"Chinese\"\n\nhotkey: \"ctrl+Q\" # 全局热键\n```\n\n---\n\n## 开发说明\n\n### 模块构建\n\n```bash\n# 构建全部模块\n.\\mvnw.cmd clean install -DskipTests\n\n# 仅构建指定模块及其依赖\n.\\mvnw.cmd install -DskipTests -pl ai-translator -am\n```\n\n### 目录结构\n\n```\nAI-Assistant/\n├── ai-app/src/main/java/com/alan/aiassistant/\n│ └── AiAssistantApplication.java # 启动类\n├── ai-common/src/main/java/com/alan/aicommon/\n│ ├── config/WebClientConfig.java # WebClient Bean\n│ ├── dto/ApiResponse.java # 统一响应体\n│ └── exception/\n│ ├── GlobalExceptionHandler.java # 全局异常处理\n│ ├── LlmException.java\n│ └── TranslationException.java\n├── ai-llm/src/main/java/com/alan/aillm/\n│ ├── config/LlmConfig.java # 多 Provider 配置\n│ ├── controller/LlmController.java # LLM 管理接口\n│ ├── dto/request/ChatRequest.java # 含 thinking/reasoningEffort\n│ ├── dto/response/ChatResponse.java\n│ └── service/LlmService.java # 核心 LLM 服务\n├── ai-translator/src/main/java/com/alan/aitranslator/\n│ ├── config/TranslatorConfig.java # 翻译配置\n│ ├── controller/TranslateController.java\n│ ├── service/\n│ │ ├── TranslateService.java # 文本翻译 + 缓存 + 分段\n│ │ ├── ImageTranslateService.java # 图片翻译(Vision/OCR 降级)\n│ │ ├── AudioTranslateService.java # 语音翻译\n│ │ └── AsrService.java # Whisper ASR\n│ └── util/TextPreprocessor.java\n├── ui/src/\n│ ├── App.vue # 主页面(翻译 + SSE)\n│ └── components/LlmSelector.vue # Provider/Model 切换器\n└── screen-translator/\n ├── main.py # 入口(Tk + 系统托盘)\n ├── llm_client.py # 独立 LLM 客户端\n ├── tesseract_service.py # Tesseract OCR\n ├── ocr_service.py # PaddleOCR\n ├── overlay.py # 翻译结果覆盖层\n ├── region_selector.py # 全屏选区\n ├── selection_frame.py # 悬停选框\n ├── tray.py # 系统托盘 + 热键\n └── config.yaml # 配置文件\n```\n\n### 已知限制\n\n- 文本翻译接口(`text/stream`)实际为同步调用 LLM 后分块发送 SSE,非真正的 LLM 流式输出\n- `TranslateService.buildSystemPrompt()` 中 `domain` 和 `style` 参数传入但未在提示词模板中使用(仅 2 个 `%s` 占位符)\n- `AsrService` 的 API 地址从当前激活 Provider 的 `baseUrl` 拼接,不支持独立配置\n- 缺少单元测试覆盖和 API 文档(Swagger/OpenAPI)\n- `extra_body` 透传仅在测试类中实现,未集成到 `LlmService`\n"}, "692fd9f27006b351adf497237ccff3603de3910c": {"t": 1785764150.1530025, "n": 7461, "h": "d066369510fc0898", "c": "# AI-Assistant\n\n模块化 AI 助手应用,集成大语言模型(LLM)、OCR 文字识别、智能翻译等核心能力,支持多提供商(本地 / DeepSeek)灵活切换。同时包含一个 Vue 3 Web 前端和一个 Python 桌面截图翻译工具。\n\n| 属性 | 说明 |\n|------|------|\n| 构建工具 | Maven 3.x(Wrapper)+ npm |\n| Java / Spring Boot | 21 / 3.5.13 |\n| Spring AI | 1.1.4(已排除自动配置,使用自定义 LLM 调用) |\n| 前端 | Vue 3.5 + Element Plus 2.13 + Vite 8 + TypeScript |\n| Python 桌面端 | tkinter + mss + Pillow + Tesseract/PaddleOCR |\n| 服务端口 | 9090(后端)/ 5173(前端开发) |\n\n## 项目结构\n\n```\nai-app ─── 启动入口,依赖所有子模块\n ├── ai-common 公共模块(统一响应体、全局异常处理、WebClient)\n ├── ai-llm LLM 多提供商调用封装(文本/Vision/流式)\n ├── ai-translator 多模态翻译(文本/图片/语音)+ SSE 流式\n └── ai-agent 智能体框架(预留模块)\n\nui ─── Vue 3 Web 前端(翻译界面 + LLM 提供商切换)\n\nscreen-translator ─── Python 桌面截图翻译工具(独立运行,无需后端)\n```\n\n---\n\n## 快速开始\n\n### 环境要求\n\n- JDK 21+(项目使用 Maven Toolchains,无需修改全局 JAVA_HOME)、Node.js 18+、Maven 3.x\n- PostgreSQL 14+(需安装 pgvector 扩展)\n- LM Studio 或其他 OpenAI 兼容 LLM 服务(本地部署时)\n- Tesseract OCR 引擎(可选,screen-translator 本地 OCR 使用)\n\n### 后端启动\n\n```bash\n# 构建所有模块\n.\\mvnw.cmd install -DskipTests\n\n# 启动 Spring Boot\n.\\mvnw.cmd spring-boot:run -pl ai-app\n```\n\n### 前端启动\n\n```bash\ncd ui\nnpm install\nnpm run dev\n```\n\n前端开发服务器在 `http://localhost:5173`,`/api` 请求自动代理到后端 `9090`。\n\n### 一键管理(start.ps1)\n\n项目提供 PowerShell 管理脚本,支持前后端启停、重启、状态查看、日志查看等:\n\n```powershell\n.\\start.ps1 start # 启动后端 + 前端\n.\\start.ps1 stop # 停止后端 + 前端\n.\\start.ps1 restart # 重启后端 + 前端\n.\\start.ps1 start-backend # 仅启动后端\n.\\start.ps1 start-frontend # 仅启动前端\n.\\start.ps1 status # 查看运行状态\n.\\start.ps1 build # 构建后端\n.\\start.ps1 menu # 交互式菜单\n```\n\n### screen-translator 启动\n\n```bash\ncd screen-translator\npip install -r requirements.txt\npython main.py\n```\n\n详细配置见 [screen-translator](#screen-translator) 章节。\n\n---\n\n## 多 Provider 配置\n\n项目支持同时配置多个 LLM 提供商,通过 `active-provider` 切换当前使用的提供商,每个提供商可配置多个模型。\n\n### application.yml\n\n```yaml\nai:\n llm:\n active-provider: ${LLM_ACTIVE_PROVIDER:local}\n default-model: ${LLM_DEFAULT_MODEL:qwen}\n timeout: ${LLM_TIMEOUT:60000}\n max-retries: ${LLM_MAX_RETRIES:3}\n temperature: ${LLM_TEMPERATURE:0.3}\n top-p: ${LLM_TOP_P:0.9}\n max-tokens: ${LLM_MAX_TOKENS:4096}\n providers:\n local:\n base-url: ${LLM_LOCAL_URL:http://localhost:1234/v1}\n api-key: ${LLM_LOCAL_KEY:sk-lm-local}\n models: [qwen, llama]\n deepseek:\n base-url: ${LLM_DEEPSEEK_URL:https://api.deepseek.com}\n api-key: ${LLM_DEEPSEEK_KEY:your-api-key}\n models: [deepseek-v4-pro, deepseek-v4-flash]\n vision-enabled: false\n thinking:\n enabled: ${LLM_DEEPSEEK_THINKING:false}\n reasoning-effort: ${LLM_DEEPSEEK_REASONING:high}\n```\n\n### 运行时切换\n\n- **API 方式**:通过 `/api/v1/llm/providers/activate` 接口切换提供商和模型(见 API 文档)\n- **前端方式**:页面右上角 `LlmSelector` 组件可直接切换提供商、模型,以及 DeepSeek 思考模式开关\n- **自动匹配**:切换模型时自动定位其所属的 Provider 并切换\n\n### DeepSeek 思考模式\n\n当 `active-provider` 为 `deepseek` 时,可开启思考模式(`thinking`),模型会先输出推理过程再输出最终结果。`reasoning-effort` 控制推理深度(`low` / `medium` / `high`)。Vision 请求不支持思考模式参数,仅在纯文本场景生效。\n\n---\n\n## API 接口\n\n### 翻译接口(SSE 流式)\n\n| 方法 | 路径 | 说明 | 请求类型 |\n|------|------|------|----------|\n| POST | `/api/v1/translate/text/stream` | 文本翻译(流式) | JSON |\n| POST | `/api/v1/translate/image/stream` | 图片翻译(流式) | Multipart |\n| POST | `/api/v1/translate/audio/stream` | 语音翻译(流式) | Multipart |\n\n**文本翻译请求示例**:\n\n```json\n{\n \"text\": \"Hello, world!\",\n \"from\": \"English\",\n \"to\": \"Chinese\",\n \"domain\": \"general\",\n \"style\": \"neutral\"\n}\n```\n\n**文本翻译 SSE 响应**:\n\n```\nevent: message\ndata: {\"text\":\"你好,\",\"done\":false}\n\nevent: done\ndata: {\"text\":\"\",\"done\":true}\n```\n\n**图片翻译**(`multipart/form-data`):\n\n- `file` — 图片文件(JPG/PNG/GIF/WEBP,最大 50MB)\n- `from` — 源语言(如 `Japanese`)\n- `to` — 目标语言(如 `Chinese`)\n\n> 图片翻译依赖 Vision 能力,当前 Provider 需设置 `vision-enabled: true`(如 local)。\n\n**语音翻译**(`multipart/form-data`):\n\n- `file` — 音频文件(MP3/WAV/M4A/OGG/FLAC,最大 50MB)\n- `from` / `to` — 语言参数\n\nSSE 事件类型:`asr`(语音识别完成)→ `translation`(翻译流式块)→ `done`(完成)\n\n### LLM 管理接口\n\n| 方法 | 路径 | 说明 |\n|------|------|------|\n| GET | `/api/v1/llm/providers` | 获取所有提供商及模型列表 |\n| POST | `/api/v1/llm/providers/activate` | 切换提供商和/或模型 |\n| POST | `/api/v1/llm/thinking` | 切换 DeepSeek 思考模式 |\n\n**切换提供商请求**:\n\n```json\n{\n \"provider\": \"deepseek\",\n \"model\": \"deepseek-v4-flash\"\n}\n```\n\n**切换思考模式请求**:\n\n```json\n{ \"enabled\": true }\n```\n\n### 错误响应格式\n\n```json\n{\n \"code\": 400,\n \"message\": \"参数验证失败: 翻译文本不能为空\",\n \"data\": null,\n \"timestamp\": 1713763200000\n}\n```\n\n---\n\n## screen-translator\n\n独立的 Python 桌面截图翻译工具,**无需 Spring Boot 后端**,直接调用 LLM API。\n\n### 功能\n\n- 系统托盘图标 + 全局热键(默认 `Ctrl+Q`)触发截图\n- 全屏选区(类似 Snipaste),悬停选框可保存截图或翻译\n- 翻译结果实时流式显示在覆盖层上\n- 支持运行时切换 LLM 提供商/模型、OCR 引擎、字体、语言\n\n### 双模式翻译\n\n根据当前 Provider 是否支持 Vision 自动选择:\n\n| 模式 | 适用 Provider | 流程 |\n|------|--------------|------|\n| Vision 模式 | local | 截图 → LLM Vision API(直接视觉翻译) |\n| OCR 模式 | deepseek 等非 Vision | 截图 → 本地 OCR 识别 → LLM 文字翻译 |\n\nOCR 引擎支持 **Tesseract**(轻量快速,默认)和 **PaddleOCR**(精度更高)。\n\n### config.yaml 关键配置\n\n```yaml\nllm:\n active_provider: \"deepseek\" # local / deepseek\n default_model: \"deepseek-v4-flash\"\n\nocr:\n engine: \"tesseract\" # tesseract / paddle\n lang: \"ch\" # 识别语言\n\ntranslate:\n from: \"Japanese\"\n to: \"Chinese\"\n\nhotkey: \"ctrl+Q\" # 全局热键\n```\n\n---\n\n## 开发说明\n\n### 模块构建\n\n```bash\n# 构建全部模块\n.\\mvnw.cmd clean install -DskipTests\n\n# 仅构建指定模块及其依赖\n.\\mvnw.cmd install -DskipTests -pl ai-translator -am\n```\n\n### 目录结构\n\n```\nAI-Assistant/\n├── ai-app/src/main/java/com/alan/aiassistant/\n│ └── AiAssistantApplication.java # 启动类\n├── ai-common/src/main/java/com/alan/aicommon/\n│ ├── config/WebClientConfig.java # WebClient Bean\n│ ├── dto/ApiResponse.java # 统一响应体\n│ └── exception/\n│ ├── GlobalExceptionHandler.java # 全局异常处理\n│ ├── LlmException.java\n│ └── TranslationException.java\n├── ai-llm/src/main/java/com/alan/aillm/\n│ ├── config/LlmConfig.java # 多 Provider 配置\n│ ├── controller/LlmController.java # LLM 管理接口\n│ ├── dto/request/ChatRequest.java # 含 thinking/reasoningEffort\n│ ├── dto/response/ChatResponse.java\n│ └── service/LlmService.java # 核心 LLM 服务\n├── ai-translator/src/main/java/com/alan/aitranslator/\n│ ├── config/TranslatorConfig.java # 翻译配置\n│ ├── controller/TranslateController.java\n│ ├── service/\n│ │ ├── TranslateService.java # 文本翻译 + 缓存 + 分段\n│ │ ├── ImageTranslateService.java # 图片翻译(Vision/OCR 降级)\n│ │ ├── AudioTranslateService.java # 语音翻译\n│ │ └── AsrService.java # Whisper ASR\n│ └── util/TextPreprocessor.java\n├── ui/src/\n│ ├── App.vue # 主页面(翻译 + SSE)\n│ └── components/LlmSelector.vue # Provider/Model 切换器\n└── screen-translator/\n ├── main.py # 入口(Tk + 系统托盘)\n ├── llm_client.py # 独立 LLM 客户端\n ├── tesseract_service.py # Tesseract OCR\n ├── ocr_service.py # PaddleOCR\n ├── overlay.py # 翻译结果覆盖层\n ├── region_selector.py # 全屏选区\n ├── selection_frame.py # 悬停选框\n ├── tray.py # 系统托盘 + 热键\n └── config.yaml # 配置文件\n```\n\n### 已知限制\n\n- 文本翻译接口(`text/stream`)实际为同步调用 LLM 后分块发送 SSE,非真正的 LLM 流式输出\n- `TranslateService.buildSystemPrompt()` 中 `domain` 和 `style` 参数传入但未在提示词模板中使用(仅 2 个 `%s` 占位符)\n- `AsrService` 的 API 地址从当前激活 Provider 的 `baseUrl` 拼接,不支持独立配置\n- 缺少单元测试覆盖和 API 文档(Swagger/OpenAPI)\n- `extra_body` 透传仅在测试类中实现,未集成到 `LlmService`\n"}, "7f654192dd07ebe9320ae22bfe7f2a3666497bc6": {"t": 1785764152.3332696, "n": 23711, "h": "bd2e3f8cdb58ba7d", "c": "# AI-Assistant 项目深度分析文档\n\n## 一、项目概述\n\n**AI-Assistant** 是一个基于 **Spring Boot 3.5.13** 构建的模块化 AI 助手应用,采用 **Maven 多模块架构**设计。项目集成了大语言模型(LLM)、光学字符识别(OCR)、智能翻译等核心 AI 能力,通过本地化的 LLM 服务(如 LM Studio)提供智能对话、文本翻译、图片翻译(Vision)、语音翻译等功能。\n\n项目同时包含一个基于 **Vue 3 + Element Plus + Vite** 的前端界面(`ui` 模块),支持流式(SSE)输出,提供良好的用户体验。\n\n| 属性 | 说明 |\n| ------------------ | ------------------ |\n| **项目名称** | ai-assistant |\n| **版本** | 0.0.1-SNAPSHOT |\n| **构建工具** | Maven 3.x(Wrapper) |\n| **Java 版本** | 17 |\n| **Spring Boot 版本** | 3.5.13 |\n| **Spring AI 版本** | 1.1.4 |\n| **前端框架** | Vue 3 + Vite + Element Plus |\n| **服务端口** | 9090(后端)/ 5173(前端开发) |\n\n***\n\n## 二、项目架构\n\n### 2.1 模块依赖图\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│ ai-app (启动入口) │\n│ Spring Boot Web 应用 │\n│ 端口: 9090 │\n└──────────┬──────────────────────────────────────────────────┘\n │ 依赖所有子模块\n ▼\n┌──────────────┬──────────────┬──────────────┬──────────────┐\n│ ai-common │ ai-llm │ ai-ocr │ ai-translator│\n│ (公共模块) │ (LLM调用) │ (文字识别) │ (翻译服务) │\n├──────────────┼──────────────┼──────────────┼──────────────┤\n│ • WebClient │ • 纯文本对话 │ • Tesseract │ • 文本翻译 │\n│ • 全局异常处理│ • Vision图片 │ • 图片文字提取│ • 图片翻译 │\n│ • 统一响应体 │ • 流式输出 │ │ • 语音翻译 │\n│ │ • 图片压缩 │ │ • 缓存机制 │\n│ │ • 重试机制 │ │ • SSE流式 │\n└──────────────┴──────────────┴──────────────┴──────────────┘\n ▲\n┌──────────┴──────────────────────────────────────────────────┐\n│ ui (Vue.js 前端界面) │\n│ Vue 3 + TypeScript + Element Plus + Vite + Axios │\n│ 端口: 5173 (dev),代理 /api 到后端 9090 │\n└─────────────────────────────────────────────────────────────┘\n ▲\n┌──────────┴──────────────────────────────────────────────────┐\n│ ai-agent (智能体框架) │\n│ 当前为占位模块,预留扩展 │\n└─────────────────────────────────────────────────────────────┘\n```\n\n### 2.2 模块职责说明\n\n| 模块 | 职责 | 被依赖方 |\n| --------------- | ------------------------------------- | ------------------------------- |\n| `ai-common` | 公共工具类、全局异常处理、统一 API 响应格式、WebClient 配置 | 所有模块 |\n| `ai-llm` | 大语言模型调用封装(纯文本/Vision/流式)、图片压缩 | ai-translator, ai-agent |\n| `ai-ocr` | 基于 Tesseract 的光学字符识别服务 | (当前未被 translator 直接使用) |\n| `ai-translator` | 多模态翻译服务(文本/图片/语音)、SSE 流式输出、缓存管理 | ai-app |\n| `ai-agent` | 智能体框架(当前为预留模块) | ai-app |\n| `ai-app` | 应用启动入口、配置聚合、依赖组装 | - |\n| `ui` | Vue 3 前端界面,流式翻译交互 | - |\n\n***\n\n## 三、核心模块详解\n\n### 3.1 ai-common(公共模块)\n\n**包结构**: `com.alan.aicommon`\n\n#### 3.1.1 统一响应体(ApiResponse)\n\n位于 `dto/ApiResponse.java`,采用泛型设计,提供标准化的 API 返回格式:\n\n```json\n{\n \"code\": 200,\n \"message\": \"success\",\n \"data\": { ... },\n \"timestamp\": 1713763200000\n}\n```\n\n**工厂方法**:\n\n- `success(T data)` - 成功响应\n- `success(String message, T data)` - 带自定义消息的成功响应\n- `error(int code, String message)` - 错误响应\n- `badRequest(String message)` - 400 错误\n- `serverError(String message)` - 500 错误\n\n#### 3.1.2 全局异常处理(GlobalExceptionHandler)\n\n基于 `@RestControllerAdvice` 的全局异常拦截器,覆盖以下异常类型:\n\n| 异常类型 | HTTP 状态码 | 处理逻辑 |\n| ----------------------------------------- | -------- | --------------- |\n| `LlmException` | 500 | AI 模型调用失败 |\n| `TranslationException` | 400 | 翻译业务异常 |\n| `MethodArgumentNotValidException` | 400 | 参数校验失败(JSR-303) |\n| `HttpMessageNotReadableException` | 400 | 请求体解析失败 |\n| `MissingServletRequestParameterException` | 400 | 缺少必需参数 |\n| `HttpRequestMethodNotSupportedException` | 405 | 不支持的 HTTP 方法 |\n| `NoResourceFoundException` | 404 | 资源未找到 |\n| `MaxUploadSizeExceededException` | 413 | 文件上传超限 |\n| `Exception` | 500 | 兜底异常处理 |\n\n#### 3.1.3 自定义异常\n\n- **LlmException**: LLM 调用过程中的运行时异常\n- **TranslationException**: 翻译业务异常,支持错误码(`errorCode`)\n\n#### 3.1.4 WebClient 配置\n\n提供响应式 HTTP 客户端 `WebClient` Bean,用于异步 HTTP 调用。\n\n***\n\n### 3.2 ai-llm(大语言模型模块)\n\n**包结构**: `com.alan.aillm`\n\n`LlmService` 是整个项目的核心服务,统一提供以下四大能力:\n\n1. **纯文本对话**(同步 + 流式)\n2. **Vision 图片内容理解**(图片翻译、文字提取)\n3. **图片压缩处理**(自动压缩大图用于 LLM 传输)\n4. **流式输出**(SSE / Flux)\n\n所有请求均调用相同的 `/chat/completions` 接口,区别仅在于 messages 的格式:\n- 文本消息使用 `ChatRequest.Message`(含 system/user/assistant 角色)\n- 含图片消息使用 `ChatRequest.VisionMessage`(包含 base64 图片数据)\n\n#### 3.2.1 配置类(LlmConfig)\n\n通过 `@ConfigurationProperties(prefix = \"ai.llm\")` 绑定配置:\n\n| 配置项 | 默认值 | 说明 |\n| ------------- | -------------------------- | ----------------------- |\n| `base-url` | `http://localhost:1234/v1` | LLM API 基础地址(兼容 OpenAI) |\n| `model` | `qwen` | 默认模型名称 |\n| `api-key` | `\"\"` | API 密钥 |\n| `timeout` | 30000ms | 连接/读取超时 |\n| `max-retries` | 3 | 最大重试次数 |\n| `temperature` | 0.3 | 采样温度 |\n| `topP` | 0.9 | 核采样参数 |\n| `max-tokens` | 4096 | 最大生成令牌数 |\n| `stream` | false | 文本请求是否流式(Vision 请求始终为 true) |\n\n**配置示例**(支持环境变量覆盖):\n\n```yaml\nai:\n llm:\n base-url: ${LLM_BASE_URL:http://localhost:1234/v1}\n model: ${LLM_MODEL:qwen}\n api-key: ${LLM_API_KEY:your-api-key}\n timeout: ${LLM_TIMEOUT:60000}\n max-retries: ${LLM_MAX_RETRIES:3}\n temperature: ${LLM_TEMPERATURE:0.3}\n topP: ${LLM_TOP_P:0.9}\n max-tokens: ${LLM_MAX_TOKENS:4096}\n stream: ${LLM_STREAM:false}\n```\n\n#### 3.2.2 LlmService 核心方法\n\n**纯文本对话**:\n\n- `chat(String systemPrompt, String userPrompt)` - 单轮对话(同步)\n- `chat(List messages)` - 多消息对话(同步)\n- `chatWithHistory(String systemPrompt, String userPrompt, List history)` - 带历史记录的对话\n- `chatStream(String systemPrompt, String userPrompt)` - 单轮流式对话,返回 `Flux`\n- `chatStream(List messages)` - 多轮流式对话\n\n**Vision 图片翻译**:\n\n- `translateImage(byte[] imageBytes, String from, String to, String domain, String style)` - 图片翻译(同步),自动压缩图片后调用 Vision LLM\n- `translateImageBase64(String base64Image, String from, String to, String domain, String style)` - 使用已有 Base64 图片翻译\n- `translateImageStream(byte[] imageBytes, String from, String to, String domain, String style)` - 图片翻译(流式),返回 `Flux`\n\n**图片文字提取**:\n\n- `extractTextFromImage(byte[] imageBytes)` - 纯 OCR 识别,使用 Vision LLM 提取图片中的文字(不翻译)\n\n**技术特性**:\n\n- 使用 `WebClient`(响应式)进行 HTTP 调用\n- **Vision 请求自动强制流式**(`stream: true`),通过解析 SSE 行来提取最终结果\n- 支持 **Spring Retry** 重试机制(`@Retryable`),对 `WebClientResponseException` 自动重试\n- 指数退避策略:`delay = 1000ms`,`multiplier = 2`\n- 完善的日志记录(请求耗时、模型名称、异常详情)\n- 响应内容安全校验(空响应、空 choices、空内容检查)\n- 图片自动压缩:大于 50KB 的图片自动缩放(最大边 1024px)并转 JPEG\n- 流式解析同时支持 `content` 和 `reasoning`(推理内容)字段\n\n#### 3.2.3 请求/响应 DTO\n\n**ChatRequest** (位于 `dto/request/ChatRequest.java`):\n\n- `Message` 内部类:纯文本消息(role + content),含 `system()` / `user()` / `assistant()` 工厂方法\n- `VisionMessage` 内部类:多模态消息(role + List\\),含图片+文本混合内容\n- `Content` 内部类:支持 `text` 和 `image_url` 两种类型\n\n**ChatResponse** (位于 `dto/response/ChatResponse.java`):\n\n- 解析 OpenAI 标准响应格式(含 `choices`/`usage`/`delta` 等字段)\n- 支持非流式和流式两种模式的响应结构\n\n***\n\n### 3.3 ai-ocr(光学字符识别模块)\n\n**包结构**: `com.alan.aiocr`\n\n#### 3.3.1 OCR 服务(OcrService)\n\n基于 **Tess4J**(Tesseract OCR 的 Java 封装)实现图片文字提取:\n\n**依赖**: `net.sourceforge.tess4j:tess4j:5.8.0`\n\n**核心方法**:\n\n- `extractText(MultipartFile imageFile)` - 默认语言识别\n- `extractText(MultipartFile imageFile, String language)` - 指定语言识别\n\n**技术细节**:\n\n- 页面分割模式设置为 `PSM_AUTO`(`setPageSegMode(1)`)\n- 支持常见图片格式(通过 `ImageIO` 自动识别)\n- 异常处理:图片读取失败、OCR 识别失败均有明确异常提示\n\n> **注意**: 当前图片翻译功能已改用 LLM Vision 实现(通过 `LlmService.translateImage()`),\n> OcrService 主要用于独立的文字识别需求,不再被 `ImageTranslateService` 直接调用。\n\n#### 3.3.2 自定义异常\n\n- **OcrException**: OCR 识别过程中的运行时异常\n\n***\n\n### 3.4 ai-translator(智能翻译模块)\n\n**包结构**: `com.alan.aitranslator`\n\n#### 3.4.1 配置类(TranslatorConfig)\n\n通过 `@ConfigurationProperties(prefix = \"ai.translator\")` 绑定配置:\n\n| 配置项 | 默认值 | 说明 |\n| -------------------- | ------- | ------------ |\n| `max-text-length` | 50000 | 最大翻译文本长度 |\n| `max-segment-length` | 3000 | 长文本分段长度 |\n| `enable-cache` | true | 是否启用翻译缓存 |\n| `cache-size` | 10000 | 缓存最大条目数 |\n| `cache-ttl-minutes` | 1440 | 缓存过期时间(24小时) |\n| `default-domain` | general | 默认翻译领域 |\n| `default-style` | neutral | 默认翻译风格 |\n\n**配置示例**:\n\n```yaml\nai:\n translator:\n max-text-length: 50000\n max-segment-length: 3000\n enable-cache: true\n cache-size: 10000\n cache-ttl-minutes: 1440\n default-domain: general\n default-style: neutral\n```\n\n#### 3.4.2 翻译服务(TranslateService)\n\n基于 LLM 的高质量翻译引擎,支持多领域、多风格翻译:\n\n**核心特性**:\n\n1. **缓存机制**: 使用 **Caffeine Cache** 实现本地缓存\n - 缓存键:`{from}_{to}_{domain}_{style}_{length}_{hash}`\n - 统计功能:记录命中率\n2. **长文本处理**: 超过 `maxSegmentLength` 的文本自动分段翻译\n - 按段落分割,保持上下文连贯性\n - 前一段内容作为下一段的上下文参考\n3. **领域适配**: 支持 6 种领域(含通用)\n - `general` - 通用领域\n - `tech` - 技术领域(计算机、软件工程)\n - `medical` - 医学领域\n - `legal` - 法律领域\n - `business` - 商业领域\n - `literary` - 文学领域\n4. **风格适配**: 支持 4 种翻译风格\n - `neutral` - 中性风格\n - `formal` - 正式书面语\n - `casual` - 口语化风格\n - `academic` - 学术严谨风格\n5. **XML 标签隔离**: 使用 ``/`` XML 标签包裹待翻译内容和上下文,有效防止本地小模型的\"提示词注入(Prompt Injection)\"问题\n\n#### 3.4.3 图片翻译服务(ImageTranslateService)\n\n**流程**: 图片上传 → LLM Vision 识别并翻译 → 流式返回结果\n\n> **注意**: 当前实现直接使用 LLM Vision 能力,不再经过 Tesseract OCR。\n\n**方法**:\n\n- `translateImageStream(MultipartFile imageFile, String from, String to)` - 流式图片翻译,返回 `Flux`\n\n**校验规则**:\n\n- 文件类型必须为 `image/*`\n- 文件大小限制 50MB\n- 使用 `TranslatorConfig` 中的 `defaultDomain` 和 `defaultStyle`\n\n#### 3.4.4 语音翻译服务(AudioTranslateService)\n\n**流程**: 音频上传 → ASR 语音识别 → 文本翻译(流式)→ SSE 返回结果\n\n**方法**:\n\n- `translateAudioStream(MultipartFile audioFile, String from, String to, ObjectMapper objectMapper)` - 流式语音翻译,返回 `SseEmitter`\n\n**SSE 事件类型**:\n\n- `asr` - ASR 识别完成事件(含 `recognizedText` 和 `asrDuration`)\n- `translation` - 翻译流式块(含 `text` 和 `done` 标志)\n- `done` - 完成事件(含 `recognizedText`/`translatedText`/`totalDuration`/`audioDuration`)\n\n**技术细节**:\n\n- 临时文件管理:上传后创建临时文件,处理完成后自动清理\n- 音频时长计算:通过 `javax.sound.sampled` 获取音频时长\n- 流式翻译:使用 `llmService.chatStream()` 获取 Flux,通过 Rx 订阅发送 SSE 事件\n\n#### 3.4.5 ASR 服务(AsrService)\n\n调用 OpenAI Whisper 兼容 API 进行语音识别:\n\n- 模型:`whisper-1`\n- 响应格式:`text`\n- 支持语言参数指定\n- API 地址自动从 `LlmConfig.baseUrl` 拼接 `/audio/transcriptions`\n\n#### 3.4.6 文本预处理(TextPreprocessor)\n\n翻译前的文本清洗工具:\n\n- 去除 HTML 标签\n- 合并多余空格\n- 合并多余换行(超过 2 个换行合并为 2 个)\n\n#### 3.4.7 自定义异常\n\n- **AsrException**: 语音识别过程中的运行时异常\n\n***\n\n### 3.5 ai-agent(智能体模块)\n\n**包结构**: `com.alan.aiagent`\n\n当前为**预留模块**,仅包含占位类 `AgentModuleInfo`,用于:\n\n- 确保目录被 Git 跟踪\n- 为后续智能体框架(Agent Framework)扩展预留空间\n\n**未来可扩展方向**:\n\n- ReAct 智能体模式\n- 工具调用(Function Calling)编排\n- 多智能体协作\n- 记忆管理(Memory)\n\n***\n\n### 3.6 ai-app(应用启动模块)\n\n**包结构**: `com.alan.aiassistant`\n\n#### 3.6.1 启动类(AiAssistantApplication)\n\n```java\n@SpringBootApplication(exclude = {\n OpenAiAudioSpeechAutoConfiguration.class,\n OpenAiAudioTranscriptionAutoConfiguration.class,\n OpenAiChatAutoConfiguration.class,\n OpenAiEmbeddingAutoConfiguration.class,\n OpenAiImageAutoConfiguration.class,\n OpenAiModerationAutoConfiguration.class,\n PgVectorStoreAutoConfiguration.class\n})\n@EnableRetry\n@ComponentScan(basePackages = {\"com.alan.aiassistant\", \"com.alan.aicommon\",\n \"com.alan.aitranslator\", \"com.alan.aillm\", \"com.alan.aiocr\", \"com.alan.aiagent\"})\npublic class AiAssistantApplication { ... }\n```\n\n**关键注解**:\n\n- `@EnableRetry`: 启用 Spring Retry 重试机制\n- `@ComponentScan`: 显式扫描所有模块的包路径(解决多模块包扫描问题)\n- `@SpringBootApplication(exclude = {...})`: 排除 Spring AI 的自动配置,因为项目使用自定义的 LLM 调用实现\n\n#### 3.6.2 应用配置(application.yml)\n\n```yaml\nspring:\n application:\n name: ai-assistant\n datasource:\n url: jdbc:postgresql://localhost:5432/ai_assistant\n username: postgres\n password: 123456\n driver-class-name: org.postgresql.Driver\n servlet:\n multipart:\n max-file-size: 50MB\n max-request-size: 50MB\n\nai:\n llm:\n base-url: ${LLM_BASE_URL:http://localhost:1234/v1}\n model: ${LLM_MODEL:qwen}\n api-key: ${LLM_API_KEY:sk-lm-zmU7SpEW:2wED8QUaU6JFaPKTbs6t}\n timeout: ${LLM_TIMEOUT:60000}\n max-retries: ${LLM_MAX_RETRIES:3}\n temperature: ${LLM_TEMPERATURE:0.3}\n topP: ${LLM_TOP_P:0.9}\n max-tokens: ${LLM_MAX_TOKENS:4096}\n translator:\n max-text-length: 50000\n max-segment-length: 3000\n enable-cache: true\n cache-size: 10000\n cache-ttl-minutes: 1440\n default-domain: general\n default-style: neutral\n\nserver:\n port: 9090\n```\n\n**基础设施**:\n\n- **数据库**: PostgreSQL(用于向量存储 `pgvector`)\n- **LLM 服务**: 本地 LM Studio(端口 1234)\n- **文件上传**: 最大 50MB\n\n**安全配置说明**:\n\n- 所有敏感配置(API Key、密码)支持通过环境变量覆盖\n- 格式:`${ENV_VAR:default_value}`,环境变量不存在时使用默认值\n- 生产环境建议设置对应的环境变量,避免使用默认值\n\n***\n\n### 3.7 ui(Vue.js 前端模块)\n\n**技术栈**: Vue 3 + TypeScript + Element Plus + Vite + Axios\n\n#### 3.7.1 功能特性\n\n- **三模式翻译**: 文本翻译 / 图片翻译 / 语音翻译,通过标签页切换\n- **流式输出(SSE)**: 所有翻译均采用 SSE 流式输出,实时显示翻译进度\n- **领域与风格选择**: 支持 6 种领域 × 4 种风格组合\n- **文件拖拽上传**: 图片和音频支持拖拽上传\n- **复制翻译结果**: 一键复制到剪贴板\n- **响应式布局**: 适配桌面端和移动端\n\n#### 3.7.2 技术细节\n\n- Vite 开发服务器端口:`5173`\n- 代理配置:`/api` → `http://localhost:9090`\n- SSE 流式解析:手动实现 SSE 协议解析(`fetch` + `ReadableStream`)\n- 时长展示:显示翻译耗时(毫秒)\n\n***\n\n## 四、API 接口清单\n\n### 4.1 翻译接口(v1 版本,全部流式)\n\n所有接口均返回 SSE(Server-Sent Events)流式响应。\n\n| 方法 | 路径 | 说明 | 请求类型 | 流式格式 |\n| ---- | ------------------------------ | -------- | ------------ | -------- |\n| POST | `/api/v1/translate/text/stream` | 文本翻译(流式) | JSON | SSE |\n| POST | `/api/v1/translate/image/stream` | 图片翻译(流式) | Multipart | SSE (text/event-stream) |\n| POST | `/api/v1/translate/audio/stream` | 语音翻译(流式) | Multipart | SSE |\n\n### 4.2 请求/响应示例\n\n#### 文本翻译(流式)\n\n**请求**:\n\n```json\n{\n \"text\": \"Hello, world!\",\n \"from\": \"English\",\n \"to\": \"Chinese\",\n \"domain\": \"general\",\n \"style\": \"neutral\",\n \"contextText\": \"可选的上下文内容\"\n}\n```\n\n**SSE 流式响应**:\n\n```\nevent: message\ndata: {\"text\":\"你\",\"done\":false}\n\nevent: message\ndata: {\"text\":\"好,\",\"done\":false}\n\nevent: message\ndata: {\"text\":\"世界!\",\"done\":false}\n\nevent: done\ndata: {\"text\":\"\",\"done\":true}\n```\n\n#### 图片翻译(流式)\n\n**请求** (multipart/form-data):\n\n- `file` - 图片文件(JPG/PNG/GIF/WEBP,最大 50MB)\n- `from` - 源语言代码\n- `to` - 目标语言代码\n\n**响应**: SSE 流(`text/event-stream`),每行为 `data: {\"choices\":[{\"delta\":{\"content\":\"...\"}}]}`\n\n> **语言参数说明**: 前端使用明确的语言名称(如 `Chinese`、`English`、`Japanese`),\n> 后端通过 `.toLowerCase()` 转换后传入 LLM(如 `chinese`、`english`、`japanese`)。\n\n#### 语音翻译(流式)\n\n**请求** (multipart/form-data):\n\n- `file` - 音频文件(MP3/WAV/M4A/OGG/FLAC,最大 50MB)\n- `from` - 源语言代码\n- `to` - 目标语言代码\n\n**SSE 流式响应**:\n\n```\nevent: asr\ndata: {\"type\":\"asr_result\",\"recognizedText\":\"Hello world\",\"asrDuration\":1250}\n\nevent: translation\ndata: {\"text\":\"你\",\"done\":false}\n\nevent: translation\ndata: {\"text\":\"好世\",\"done\":false}\n\nevent: translation\ndata: {\"text\":\"界\",\"done\":false}\n\nevent: done\ndata: {\"type\":\"done\",\"recognizedText\":\"Hello world\",\"translatedText\":\"你好世界\",\"totalDuration\":5250,\"audioDuration\":15000}\n```\n\n### 4.3 错误响应示例\n\n```json\n{\n \"code\": 400,\n \"message\": \"参数验证失败: 翻译文本不能为空; 源语言不能为空\",\n \"data\": null,\n \"timestamp\": 1713763200000\n}\n```\n\n***\n\n## 五、技术栈分析\n\n### 5.1 核心框架与库\n\n| 技术 | 版本 | 用途 |\n| ------------------ | ------ | ----------------- |\n| Spring Boot | 3.5.13 | 应用框架 |\n| Spring AI | 1.1.4 | AI 抽象框架(向量存储,自动配置已排除) |\n| Spring Retry | - | 重试机制 |\n| Spring Validation | - | 参数校验(JSR-303) |\n| Spring WebFlux | - | 响应式 HTTP 客户端和流式处理 |\n| Lombok | - | 代码简化 |\n| Tess4J | 5.8.0 | OCR 引擎 |\n| Caffeine | - | 本地缓存 |\n| PostgreSQL | - | 关系型数据库 |\n| pgvector | - | 向量扩展 |\n| Vue 3 | 3.5.32 | 前端框架 |\n| Element Plus | 2.13.7 | UI 组件库 |\n| Vite | 8.0.9 | 前端构建工具 |\n| Axios | 1.15.2 | HTTP 客户端 |\n| Jackson | - | JSON 解析(后端流式 SSE 解析) |\n\n### 5.2 设计模式应用\n\n| 模式 | 应用位置 | 说明 |\n| --------- | ------------------ | ------------------------ |\n| **模板方法** | `LlmService` | 对话/Vision 流程标准化(构建请求→调用API→解析响应) |\n| **策略模式** | `TranslateService` | 不同领域/风格的翻译策略通过 prompt 切换 |\n| **建造者模式** | DTO 类 | `@Builder` 注解生成流式构建器 |\n| **单例模式** | `OcrService` | Tesseract 引擎单例管理 |\n| **工厂模式** | `ApiResponse` | 静态工厂方法创建响应对象 |\n| **观察者模式** | 流式处理 | WebFlux Flux/SSE 事件订阅处理 |\n\n### 5.3 异常处理策略\n\n项目采用**分层异常处理**架构:\n\n1. **模块自定义异常**: 各模块定义自己的异常类型(`LlmException`, `TranslationException`, `OcrException`, `AsrException`)\n2. **异常转换**: 底层异常在模块边界处转换为业务异常\n3. **统一拦截**: `GlobalExceptionHandler` 集中处理所有异常,统一返回格式\n4. **日志分级**: WARN 处理客户端错误,ERROR 处理服务端错误\n\n***\n\n## 六、数据流分析\n\n### 6.1 文本翻译流程(流式)\n\n```\n用户请求 (SSE)\n │\n ▼\n┌─────────────────────┐\n│ TranslateController │\n│ POST /api/v1/translate/text/stream │\n│ @Valid 参数校验 │\n└──────┬──────────────┘\n │\n ▼\n┌─────────────────────┐\n│ TextPreprocessor │\n│ • 文本预处理 │\n└──────┬──────────────┘\n │\n ▼\n┌─────────────────────┐\n│ LlmService.chat() │\n│ • 构建请求体 │\n│ • WebClient 同步调用 │\n│ • 解析响应 │\n└──────┬──────────────┘\n │\n ▼\n 分块发送 SSE 事件\n (10字符/块, 间隔50ms)\n │\n ▼\n 发送 done 事件\n```\n\n### 6.2 图片翻译流程(流式)\n\n```\n用户上传图片\n │\n ▼\n┌──────────────────────────┐\n│ ImageTranslateService │\n│ • 图片格式/大小校验 │\n│ POST /api/v1/translate/image/stream │\n└──────┬───────────────────┘\n │\n ▼\n┌──────────────────────────┐\n│ LlmService.translateImageStream() │\n│ • 图片自动压缩(>50KB→1024px)│\n│ • Base64 编码 │\n│ • 构建 Vision 请求体 │\n│ • WebClient Flux 流式调用 │\n│ • Vision LLM 识别+翻译 │\n└──────┬───────────────────┘\n │\n ▼\n SSE 流式返回翻译结果\n```\n\n### 6.3 语音翻译流程(流式)\n\n```\n用户上传音频\n │\n ▼\n┌──────────────────────────┐\n│ AudioTranslateService │\n│ • 音频格式/大小校验 │\n│ • 创建临时文件 │\n│ • 计算音频时长 │\n│ POST /api/v1/translate/audio/stream │\n└──────┬───────────────────┘\n │\n ▼\n┌──────────────────────────┐\n│ AsrService.recognize() │\n│ • 调用 Whisper API │\n│ • 语音识别 │\n└──────┬───────────────────┘\n │\n ▼ SSE event: asr\n 发送识别结果事件\n │\n ▼\n┌──────────────────────────┐\n│ LlmService.chatStream() │\n│ • 文本翻译(流式 Flux) │\n└──────┬───────────────────┘\n │\n ▼ SSE event: translation (多次)\n 流式发送翻译块\n │\n ▼ SSE event: done\n 发送完成事件 + 清理临时文件\n```\n\n***\n\n## 七、构建与部署\n\n### 7.1 Maven 构建\n\n```bash\n# 使用 Maven Wrapper 构建\n./mvnw clean package\n\n# 运行应用\n./mvnw spring-boot:run -pl ai-app\n```\n\n### 7.2 前端构建\n\n```bash\n# 进入 ui 目录\ncd ui\n\n# 安装依赖\nnpm install\n\n# 开发模式(热重载)\nnpm run dev\n\n# 生产构建\nnpm run build\n```\n\n### 7.3 一键启动\n\n项目提供了 `start.bat` 脚本:\n\n```batch\nmvnw.cmd clean package\nmvnw.cmd spring-boot:run -pl ai-app\n```\n\n### 7.4 模块构建配置\n\n- 所有模块均配置 `maven-compiler-plugin`,启用 Lombok 注解处理器\n- `ai-app` 模块使用 `spring-boot-maven-plugin` 打包可执行 JAR\n- 打包时排除 Lombok 依赖\n\n### 7.5 运行环境要求\n\n| 依赖 | 版本 | 说明 |\n| ----------- | --- | --------------------------- |\n| JDK | 17+ | Java 运行时 |\n| Node.js | 18+ | 前端构建 |\n| PostgreSQL | 14+ | 数据库,需安装 pgvector 扩展(当前未使用) |\n| LM Studio | - | 本地 LLM 服务,端口 1234 |\n| Tesseract | - | OCR 引擎(安装语言包,可选) |\n\n### 7.6 环境变量配置(生产环境推荐)\n\n```bash\n# LLM 配置\nexport LLM_BASE_URL=http://localhost:1234/v1\nexport LLM_MODEL=qwen\nexport LLM_API_KEY=your-secure-api-key\nexport LLM_TIMEOUT=60000\n\n# 数据库配置\nexport DB_URL=jdbc:postgresql://localhost:5432/ai_assistant\nexport DB_USERNAME=postgres\nexport DB_PASSWORD=your-secure-password\n```\n\n***\n\n## 八、扩展性分析\n\n### 8.1 当前扩展点\n\n1. **新领域翻译**: 在 `TranslateService` 和 `LlmService.buildImageTranslatePrompt()` 中添加新的 domain case\n2. **新风格翻译**: 添加新的 style case\n3. **新 OCR 语言**: 通过 `OcrService.extractText(file, language)` 指定 Tesseract 语言包\n4. **缓存策略**: 调整 `TranslatorConfig` 中的缓存参数\n5. **前端多语言**: 扩展 `LANGUAGE_OPTIONS` 常量\n6. **extra_body 参数**: 通过扩展 `LlmService` 透传额外 LLM 参数(如 `enable_thinking`,当前仅在测试类中实现)\n\n### 8.2 架构优势\n\n1. **模块化设计**: 各模块职责清晰,可独立演进\n2. **依赖倒置**: `ai-app` 作为组装模块,业务模块之间通过接口解耦\n3. **配置外部化**: 所有 AI 参数通过 `application.yml` 配置,支持环境变量覆盖\n4. **异常隔离**: 各模块自定义异常,避免错误传播污染\n5. **流式优先**: 所有翻译接口均采用 SSE 流式输出,用户体验好\n6. **前后端分离**: Vue.js 独立开发,通过 Vite proxy 与后端通信\n\n### 8.3 待完善方向\n\n1. **ai-agent 模块**: 当前为空,建议实现 ReAct/Plan-and-Execute 智能体框架\n2. **向量存储**: 已引入 `spring-ai-starter-vector-store-pgvector`,但排除自动配置,未在业务中使用\n3. **传统 REST 端点**: 当前只有流式端点,可添加非流式 API 作为降级方案\n4. **多模态支持**: 可扩展视频翻译、文档翻译等能力\n5. **用户管理**: 当前无认证授权机制\n6. **限流熔断**: 建议引入 Sentinel/Resilience4j\n7. **单元测试**: 当前测试覆盖不足(仅一个默认测试),需补充 Service/Controller 层测试\n8. **API 文档**: 建议引入 Swagger/OpenAPI 自动生成接口文档\n9. **前端状态管理**: 可引入 Pinia 管理复杂状态\n\n***\n\n## 九、代码质量评估\n\n### 9.1 优点\n\n- ✅ 统一的 API 响应格式,前后端交互规范\n- ✅ 完善的全局异常处理,错误信息友好\n- ✅ 日志记录详尽,便于问题排查\n- ✅ 参数校验完善(`@Valid`, `@NotBlank`, `@Size`)\n- ✅ 缓存机制提升性能(Caffeine)\n- ✅ 重试机制增强稳定性(Spring Retry)\n- ✅ 临时文件自动清理,避免磁盘泄漏\n- ✅ 配置外部化,支持环境变量注入\n- ✅ 敏感配置默认支持环境变量覆盖\n- ✅ 流式 SSE 输出,实时反馈翻译进度\n- ✅ Vision LLM 直接处理图片翻译,无需 OCR 中间步骤\n- ✅ 图片自动压缩优化,减少数据传输量\n- ✅ XML 标签隔离防提示词注入\n- ✅ Vue 3 前端实现完整,支持拖拽上传和流式显示\n\n### 9.2 改进建议\n\n- ⚠️ `application.yml` 中数据库密码和 API Key 仍有默认值,生产环境务必通过环境变量覆盖\n- ⚠️ `AsrService` 中 API URL 从 `LlmConfig` 拼接待改进,建议使用独立配置\n- ⚠️ `OcrService` 中 Tesseract 数据路径未配置,可能依赖系统环境\n- ⚠️ 缺少单元测试覆盖(仅有一个默认的 `AiAssistantApplicationTests`)\n- ⚠️ 缺少 API 文档(如 Swagger/OpenAPI)\n- ⚠️ `TranslateController.text/stream` 实际上是同步调用后分块发送,并非真正的流式 LLM 调用\n- ⚠️ `TranslateService.buildSystemPrompt()` 中 `domain` 和 `style` 参数虽传入但未在提示词中使用(4 参数仅 2 个 `%s` 占位符)\n- ⚠️ `extra_body` 透传(如 `enable_thinking`)仅在测试类 `ChatCompletionsTest` 中实现,未集成到生产代码 `LlmService`\n\n***\n\n## 十、版本变更记录\n\n### v0.0.1-SNAPSHOT (当前版本)\n\n**新增功能**:\n\n- 多模态翻译支持(文本/图片/语音)\n- 所有翻译接口改为 SSE 流式输出\n- LLM Vision 图片翻译(替代 OCR 流程)\n- 图片自动压缩优化\n- 翻译缓存机制(Caffeine)\n- 长文本自动分段翻译\n- 领域和风格适配(tech/medical/legal/business/literary/formal/casual/academic)\n- 全局异常处理与统一响应格式\n- Spring Retry 重试机制\n- 配置外部化(支持环境变量)\n- Vue 3 前端界面(Element Plus + Vite)\n- XML 标签隔离防提示词注入\n- `extra_body` 透传支持\n\n**架构变更**:\n\n- 清理重复模块(app、translator)\n- API 路径规范化(`/api/v1/translate/*/stream`)\n- 模块依赖关系优化\n- `LlmService` 重构:从 `RestTemplate` 迁移到 `WebClient`,统一文本/Vision 调用\n- 排除 Spring AI 自动配置(使用自定义 LLM 调用)\n- 图片翻译从 OCR+翻译 流程改为 Vision LLM 直接处理\n\n***\n\n## 十一、总结\n\nAI-Assistant 是一个架构清晰、模块化的 Spring Boot AI 应用,通过 Maven 多模块方式组织了 LLM、OCR、翻译等核心能力,并提供了 Vue 3 前端界面。项目采用**本地化 LLM 方案**(LM Studio),降低了对外部云服务的依赖,适合私有化部署场景。\n\n核心设计亮点:\n\n1. **统一 LLM 服务层**: `LlmService` 统一封装文本对话、Vision 识别、图片翻译、流式输出四大能力\n2. **流式优先架构**: 所有翻译接口均采用 SSE 流式输出,提供实时反馈\n3. **分层异常处理**: 模块异常 → 业务异常 → 统一拦截 → 标准化响应\n4. **Prompt 工程**: 领域/风格适配 + XML 标签隔离 + Vision 系统提示词\n5. **多模态翻译**: 文本/图片/语音三种输入方式的统一翻译能力\n6. **性能优化**: Caffeine 缓存 + 长文本分段处理 + 图片自动压缩\n7. **配置安全**: 敏感配置支持环境变量覆盖\n8. **前后端分离**: Vue 3 独立前端,Vite 代理通信\n\n项目当前处于 **MVP 阶段**,核心功能已可用,后续可在智能体框架、向量检索、非流式降级等方向持续演进。\n"}, "6316ad783ca1d7603123b1630cdebccc07d4a6e9": {"t": 1785764155.910998, "n": 17835, "h": "ffc3b85932a63971", "c": "# AI-Assistant 项目深度分析文档\n\n## 一、项目概述\n\n**AI-Assistant** 是一个基于 **Spring Boot 3.5.13** 构建的模块化 AI 助手应用,采用 **Maven 多模块架构**设计。项目集成了大语言模型(LLM)、光学字符识别(OCR)、智能翻译等核心 AI 能力,通过本地化的 LLM 服务(如 LM Studio)提供智能对话、文本翻译、图片翻译、语音翻译等功能。\n\n| 属性 | 说明 |\n| ------------------ | ------------------ |\n| **项目名称** | ai-assistant |\n| **版本** | 0.0.1-SNAPSHOT |\n| **构建工具** | Maven 3.x(Wrapper) |\n| **Java 版本** | 17 |\n| **Spring Boot 版本** | 3.5.13 |\n| **Spring AI 版本** | 1.1.4 |\n| **服务端口** | 9090 |\n\n***\n\n## 二、项目架构\n\n### 2.1 模块依赖图\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│ ai-app (启动入口) │\n│ Spring Boot Web 应用 │\n│ 端口: 9090 │\n└──────────┬──────────────────────────────────────────────────┘\n │ 依赖所有子模块\n ▼\n┌──────────────┬──────────────┬──────────────┬──────────────┐\n│ ai-common │ ai-llm │ ai-ocr │ ai-translator│\n│ (公共模块) │ (LLM调用) │ (文字识别) │ (翻译服务) │\n├──────────────┼──────────────┼──────────────┼──────────────┤\n│ • WebClient │ • OpenAI API │ • Tesseract │ • 文本翻译 │\n│ • 全局异常处理│ • 对话服务 │ • 图片文字提取│ • 图片翻译 │\n│ • 统一响应体 │ • 重试机制 │ │ • 语音翻译 │\n│ │ • 配置外部化 │ │ • 缓存机制 │\n└──────────────┴──────────────┴──────────────┴──────────────┘\n ▲\n┌──────────┴──────────────────────────────────────────────────┐\n│ ai-agent (智能体框架) │\n│ 当前为占位模块,预留扩展 │\n└─────────────────────────────────────────────────────────────┘\n```\n\n### 2.2 模块职责说明\n\n| 模块 | 职责 | 被依赖方 |\n| --------------- | ------------------------------------- | ------------------------------- |\n| `ai-common` | 公共工具类、全局异常处理、统一 API 响应格式、WebClient 配置 | 所有模块 |\n| `ai-llm` | 大语言模型调用封装、对话服务、OpenAI 兼容 API 交互 | ai-ocr, ai-translator, ai-agent |\n| `ai-ocr` | 基于 Tesseract 的光学字符识别服务 | ai-translator |\n| `ai-translator` | 多模态翻译服务(文本/图片/语音)、缓存管理 | ai-app |\n| `ai-agent` | 智能体框架(当前为预留模块) | ai-app |\n| `ai-app` | 应用启动入口、配置聚合、依赖组装 | - |\n\n***\n\n## 三、核心模块详解\n\n### 3.1 ai-common(公共模块)\n\n**包结构**: `com.alan.aicommon`\n\n#### 3.1.1 统一响应体(ApiResponse)\n\n位于 `dto/ApiResponse.java`,采用泛型设计,提供标准化的 API 返回格式:\n\n```java\n{\n \"code\": 200,\n \"message\": \"success\",\n \"data\": { ... },\n \"timestamp\": 1713763200000\n}\n```\n\n**工厂方法**:\n\n- `success(T data)` - 成功响应\n- `success(String message, T data)` - 带自定义消息的成功响应\n- `error(int code, String message)` - 错误响应\n- `badRequest(String message)` - 400 错误\n- `serverError(String message)` - 500 错误\n\n#### 3.1.2 全局异常处理(GlobalExceptionHandler)\n\n基于 `@RestControllerAdvice` 的全局异常拦截器,覆盖以下异常类型:\n\n| 异常类型 | HTTP 状态码 | 处理逻辑 |\n| ----------------------------------------- | -------- | --------------- |\n| `LlmException` | 500 | AI 模型调用失败 |\n| `TranslationException` | 400 | 翻译业务异常 |\n| `MethodArgumentNotValidException` | 400 | 参数校验失败(JSR-303) |\n| `HttpMessageNotReadableException` | 400 | 请求体解析失败 |\n| `MissingServletRequestParameterException` | 400 | 缺少必需参数 |\n| `HttpRequestMethodNotSupportedException` | 405 | 不支持的 HTTP 方法 |\n| `NoResourceFoundException` | 404 | 资源未找到 |\n| `MaxUploadSizeExceededException` | 413 | 文件上传超限 |\n| `Exception` | 500 | 兜底异常处理 |\n\n#### 3.1.3 自定义异常\n\n- **LlmException**: LLM 调用过程中的运行时异常\n- **TranslationException**: 翻译业务异常,支持错误码(errorCode)\n\n#### 3.1.4 WebClient 配置\n\n提供响应式 HTTP 客户端 `WebClient` Bean,用于异步 HTTP 调用。\n\n***\n\n### 3.2 ai-llm(大语言模型模块)\n\n**包结构**: `com.alan.aillm`\n\n#### 3.2.1 配置类(LlmConfig)\n\n通过 `@ConfigurationProperties(prefix = \"ai.llm\")` 绑定配置:\n\n| 配置项 | 默认值 | 说明 |\n| ------------- | -------------------------- | ----------------------- |\n| `base-url` | `http://localhost:1234/v1` | LLM API 基础地址(LM Studio) |\n| `model` | `qwen` | 默认模型名称 |\n| `api-key` | `\"\"` | API 密钥 |\n| `timeout` | 30000ms | 连接/读取超时 |\n| `max-retries` | 3 | 最大重试次数 |\n| `temperature` | 0.3 | 采样温度 |\n| `topP` | 0.9 | 核采样参数(YAML 中使用 `topP`) |\n| `max-tokens` | 4096 | 最大生成令牌数 |\n| `stream` | false | 是否流式输出 |\n\n**配置示例**(支持环境变量覆盖):\n\n```yaml\nai:\n llm:\n base-url: ${LLM_BASE_URL:http://localhost:1234/v1}\n model: ${LLM_MODEL:qwen}\n api-key: ${LLM_API_KEY:your-api-key}\n timeout: ${LLM_TIMEOUT:60000}\n max-retries: ${LLM_MAX_RETRIES:3}\n temperature: ${LLM_TEMPERATURE:0.3}\n topP: ${LLM_TOP_P:0.9}\n max-tokens: ${LLM_MAX_TOKENS:4096}\n```\n\n#### 3.2.2 对话服务(LlmService)\n\n核心服务类,提供与 OpenAI 兼容 API 的交互能力:\n\n**核心方法**:\n\n- `chat(String systemPrompt, String userPrompt)` - 单轮对话\n- `chat(List messages)` - 多消息对话\n- `chatWithHistory(String systemPrompt, String userPrompt, List history)` - 带历史记录的对话\n\n**技术特性**:\n\n- 使用 `RestTemplate` 进行同步 HTTP 调用\n- 支持 **Spring Retry** 重试机制(`@Retryable`),对 `ResourceAccessException` 和 `HttpServerErrorException` 自动重试\n- 指数退避策略:`delay = 1000ms`,`multiplier = 2`\n- 完善的日志记录(请求耗时、模型名称、异常详情)\n- 响应内容安全校验(空响应、空 choices、空内容检查)\n\n**请求/响应 DTO**:\n\n- `ChatRequest`: 兼容 OpenAI Chat Completions API 的请求体(含 temperature/topP/maxTokens/stream)\n- `ChatResponse`: 解析 OpenAI 标准响应格式(含 choices/usage/delta 等字段)\n\n***\n\n### 3.3 ai-ocr(光学字符识别模块)\n\n**包结构**: `com.alan.aiocr`\n\n#### 3.3.1 OCR 服务(OcrService)\n\n基于 **Tess4J**(Tesseract OCR 的 Java 封装)实现图片文字提取:\n\n**依赖**: `net.sourceforge.tess4j:tess4j:5.8.0`\n\n**核心方法**:\n\n- `extractText(MultipartFile imageFile)` - 默认语言识别\n- `extractText(MultipartFile imageFile, String language)` - 指定语言识别\n\n**技术细节**:\n\n- 页面分割模式设置为 `PSM_AUTO`(`setPageSegMode(1)`)\n- 支持常见图片格式(通过 `ImageIO` 自动识别)\n- 异常处理:图片读取失败、OCR 识别失败均有明确异常提示\n\n***\n\n### 3.4 ai-translator(智能翻译模块)\n\n**包结构**: `com.alan.aitranslator`\n\n#### 3.4.1 配置类(TranslatorConfig)\n\n通过 `@ConfigurationProperties(prefix = \"ai.translator\")` 绑定配置:\n\n| 配置项 | 默认值 | 说明 |\n| -------------------- | ------- | ------------ |\n| `max-text-length` | 10000 | 最大翻译文本长度 |\n| `max-segment-length` | 3000 | 长文本分段长度 |\n| `enable-cache` | true | 是否启用翻译缓存 |\n| `cache-size` | 10000 | 缓存最大条目数 |\n| `cache-ttl-minutes` | 1440 | 缓存过期时间(24小时) |\n| `default-domain` | general | 默认翻译领域 |\n| `default-style` | neutral | 默认翻译风格 |\n\n**配置示例**:\n\n```yaml\nai:\n translator:\n max-text-length: 10000\n max-segment-length: 3000\n enable-cache: true\n cache-size: 10000\n cache-ttl-minutes: 1440\n default-domain: general\n default-style: neutral\n```\n\n#### 3.4.2 翻译服务(TranslateService)\n\n基于 LLM 的高质量翻译引擎,支持多领域、多风格翻译:\n\n**核心特性**:\n\n1. **缓存机制**: 使用 **Caffeine Cache** 实现本地缓存\n - 缓存键:`{from}_{to}_{domain}_{style}_{length}_{hash}`\n - 统计功能:记录命中率\n2. **长文本处理**: 超过 `maxSegmentLength` 的文本自动分段翻译\n - 按段落分割,保持上下文连贯性\n - 前一段摘要作为下一段的上下文参考\n3. **领域适配**: 支持 5 种专业领域\n - `general` - 通用领域\n - `tech` - 技术领域(计算机、软件工程)\n - `medical` - 医学领域\n - `legal` - 法律领域\n - `business` - 商业领域\n - `literary` - 文学领域\n4. **风格适配**: 支持 3 种翻译风格\n - `neutral` - 中性风格\n - `formal` - 正式书面语\n - `casual` - 口语化风格\n - `academic` - 学术严谨风格\n5. **系统提示词工程**: 通过精心设计的 system prompt 约束 LLM 输出,确保翻译质量\n\n#### 3.4.3 图片翻译服务(ImageTranslateService)\n\n**流程**: 图片上传 → OCR 文字提取 → 文本翻译 → 返回结果\n\n**接口**: `POST /api/v1/translate/image` (multipart/form-data)\n\n**参数**:\n\n- `file` - 图片文件(JPG/PNG/GIF/WEBP,最大 50MB)\n- `from` - 源语言\n- `to` - 目标语言\n\n#### 3.4.4 语音翻译服务(AudioTranslateService)\n\n**流程**: 音频上传 → ASR 语音识别 → 文本翻译 → 返回结果\n\n**接口**: `POST /api/v1/translate/audio` (multipart/form-data)\n\n**参数**:\n\n- `file` - 音频文件(MP3/WAV/M4A/OGG/FLAC,最大 50MB)\n- `from` - 源语言\n- `to` - 目标语言\n\n**技术细节**:\n\n- 临时文件管理:上传后创建临时文件,处理完成后自动清理\n- 音频时长计算:通过 `javax.sound.sampled` 获取音频时长\n- ASR 服务:调用兼容 OpenAI 的 `/v1/audio/transcriptions` API\n\n#### 3.4.5 ASR 服务(AsrService)\n\n调用 OpenAI Whisper 兼容 API 进行语音识别:\n\n- 模型:`whisper-1`\n- 响应格式:`text`\n- 支持语言参数指定\n\n#### 3.4.6 文本预处理(TextPreprocessor)\n\n翻译前的文本清洗工具:\n\n- 去除 HTML 标签\n- 合并多余空格\n- 合并多余换行(超过 2 个换行合并为 2 个)\n\n***\n\n### 3.5 ai-agent(智能体模块)\n\n**包结构**: `com.alan.aiagent`\n\n当前为**预留模块**,仅包含占位类 `AgentModuleInfo`,用于:\n\n- 确保目录被 Git 跟踪\n- 为后续智能体框架(Agent Framework)扩展预留空间\n\n**未来可扩展方向**:\n\n- ReAct 智能体模式\n- 工具调用(Function Calling)编排\n- 多智能体协作\n- 记忆管理(Memory)\n\n***\n\n### 3.6 ai-app(应用启动模块)\n\n**包结构**: `com.alan.aiassistant`\n\n#### 3.6.1 启动类(AiAssistantApplication)\n\n```java\n@SpringBootApplication\n@EnableRetry\n@ComponentScan(basePackages = {\"com.alan.aiassistant\", \"com.alan.aicommon\", \n \"com.alan.aitranslator\", \"com.alan.aillm\", \"com.alan.aiocr\", \"com.alan.aiagent\"})\n```\n\n**关键注解**:\n\n- `@EnableRetry`: 启用 Spring Retry 重试机制\n- `@ComponentScan`: 显式扫描所有模块的包路径(解决多模块包扫描问题)\n\n#### 3.6.2 应用配置(application.yml)\n\n```yaml\nspring:\n application:\n name: ai-assistant\n datasource:\n url: jdbc:postgresql://localhost:5432/ai_assistant\n username: postgres\n password: 123456\n ai:\n openai:\n api-key: ${OPENAI_API_KEY:sk-lm-zmU7SpEW:2wED8QUaU6JFaPKTbs6t}\n base-url: http://localhost:1234/v1\n servlet:\n multipart:\n max-file-size: 50MB\n max-request-size: 50MB\n\nai:\n llm:\n base-url: ${LLM_BASE_URL:http://localhost:1234/v1}\n model: ${LLM_MODEL:qwen}\n api-key: ${LLM_API_KEY:sk-lm-zmU7SpEW:2wED8QUaU6JFaPKTbs6t}\n timeout: ${LLM_TIMEOUT:60000}\n max-retries: ${LLM_MAX_RETRIES:3}\n temperature: ${LLM_TEMPERATURE:0.3}\n topP: ${LLM_TOP_P:0.9}\n max-tokens: ${LLM_MAX_TOKENS:4096}\n translator:\n max-text-length: 10000\n max-segment-length: 3000\n enable-cache: true\n cache-size: 10000\n cache-ttl-minutes: 1440\n default-domain: general\n default-style: neutral\n\nserver:\n port: 9090\n```\n\n**基础设施**:\n\n- **数据库**: PostgreSQL(用于向量存储 `pgvector`)\n- **LLM 服务**: 本地 LM Studio(端口 1234)\n- **文件上传**: 最大 50MB\n\n**安全配置说明**:\n\n- 所有敏感配置(API Key、密码)支持通过环境变量覆盖\n- 格式:`${ENV_VAR:default_value}`,环境变量不存在时使用默认值\n- 生产环境建议设置对应的环境变量,避免使用默认值\n\n***\n\n## 四、API 接口清单\n\n### 4.1 翻译接口(v1 版本)\n\n| 方法 | 路径 | 说明 | 请求类型 |\n| ---- | ------------------------- | ---- | --------- |\n| POST | `/api/v1/translate/text` | 文本翻译 | JSON |\n| POST | `/api/v1/translate/image` | 图片翻译 | Multipart |\n| POST | `/api/v1/translate/audio` | 语音翻译 | Multipart |\n\n### 4.2 请求/响应示例\n\n#### 文本翻译\n\n**请求**:\n\n```json\n{\n \"text\": \"Hello, world!\",\n \"from\": \"en\",\n \"to\": \"zh\",\n \"domain\": \"general\",\n \"style\": \"neutral\",\n \"contextText\": \"可选的上下文内容\"\n}\n```\n\n**响应**:\n\n```json\n{\n \"code\": 200,\n \"message\": \"success\",\n \"data\": {\n \"originalText\": \"Hello, world!\",\n \"translatedText\": \"你好,世界!\",\n \"from\": \"en\",\n \"to\": \"zh\",\n \"domain\": \"general\",\n \"style\": \"neutral\",\n \"durationMs\": 1250,\n \"cached\": false\n },\n \"timestamp\": 1713763200000\n}\n```\n\n#### 图片翻译\n\n**请求** (multipart/form-data):\n\n- `file` - 图片文件\n- `from` - 源语言代码\n- `to` - 目标语言代码\n\n**响应**:\n\n```json\n{\n \"code\": 200,\n \"message\": \"success\",\n \"data\": {\n \"extractedText\": \"图片中提取的原文\",\n \"translatedText\": \"翻译后的文本\",\n \"from\": \"en\",\n \"to\": \"zh\",\n \"durationMs\": 3250\n },\n \"timestamp\": 1713763200000\n}\n```\n\n#### 语音翻译\n\n**请求** (multipart/form-data):\n\n- `file` - 音频文件\n- `from` - 源语言代码\n- `to` - 目标语言代码\n\n**响应**:\n\n```json\n{\n \"code\": 200,\n \"message\": \"success\",\n \"data\": {\n \"recognizedText\": \"语音识别结果\",\n \"translatedText\": \"翻译后的文本\",\n \"from\": \"en\",\n \"to\": \"zh\",\n \"durationMs\": 5250,\n \"audioDurationMs\": 15000\n },\n \"timestamp\": 1713763200000\n}\n```\n\n### 4.3 错误响应示例\n\n```json\n{\n \"code\": 400,\n \"message\": \"参数验证失败: 翻译文本不能为空; 源语言不能为空\",\n \"data\": null,\n \"timestamp\": 1713763200000\n}\n```\n\n***\n\n## 五、技术栈分析\n\n### 5.1 核心框架与库\n\n| 技术 | 版本 | 用途 |\n| ----------------- | ------ | ------------- |\n| Spring Boot | 3.5.13 | 应用框架 |\n| Spring AI | 1.1.4 | AI 抽象框架(向量存储) |\n| Spring Retry | - | 重试机制 |\n| Spring Validation | - | 参数校验(JSR-303) |\n| Lombok | - | 代码简化 |\n| Tess4J | 5.8.0 | OCR 引擎 |\n| Caffeine | - | 本地缓存 |\n| PostgreSQL | - | 关系型数据库 |\n| pgvector | - | 向量扩展 |\n\n### 5.2 设计模式应用\n\n| 模式 | 应用位置 | 说明 |\n| --------- | ------------------ | ------------------------ |\n| **模板方法** | `LlmService` | 对话流程标准化(构建请求→调用API→提取内容) |\n| **策略模式** | `TranslateService` | 不同领域/风格的翻译策略通过 prompt 切换 |\n| **建造者模式** | DTO 类 | `@Builder` 注解生成流式构建器 |\n| **单例模式** | `OcrService` | Tesseract 引擎单例管理 |\n| **工厂模式** | `ApiResponse` | 静态工厂方法创建响应对象 |\n\n### 5.3 异常处理策略\n\n项目采用**分层异常处理**架构:\n\n1. **模块自定义异常**: 各模块定义自己的异常类型(`LlmException`, `TranslationException`, `OcrException`, `AsrException`)\n2. **异常转换**: 底层异常在模块边界处转换为业务异常\n3. **统一拦截**: `GlobalExceptionHandler` 集中处理所有异常,统一返回格式\n4. **日志分级**: WARN 处理客户端错误,ERROR 处理服务端错误\n\n***\n\n## 六、数据流分析\n\n### 6.1 文本翻译流程\n\n```\n用户请求\n │\n ▼\n┌─────────────┐\n│ TranslateController │\n│ @Valid 参数校验 │\n│ 路径: /api/v1/translate/text │\n└──────┬──────┘\n │\n ▼\n┌─────────────┐\n│ TranslateService │\n│ • 文本预处理 │\n│ • 缓存查询 │\n│ • 长文本分段 │\n│ • 领域/风格适配 │\n└──────┬──────┘\n │\n ▼\n┌─────────────┐\n│ LlmService │\n│ • 构建请求体 │\n│ • HTTP 调用 │\n│ • 重试机制 │\n│ • 响应解析 │\n└──────┬──────┘\n │\n ▼\n LLM API\n │\n ▼\n 返回翻译结果\n```\n\n### 6.2 图片翻译流程\n\n```\n用户上传图片\n │\n ▼\n┌─────────────┐\n│ ImageTranslateService │\n│ • 图片格式/大小校验 │\n│ 路径: /api/v1/translate/image │\n└──────┬──────┘\n │\n ▼\n┌─────────────┐\n│ OcrService │\n│ • ImageIO 读取│\n│ • Tesseract │\n│ 文字提取 │\n└──────┬──────┘\n │\n ▼\n┌─────────────┐\n│ TranslateService │\n│ • 文本翻译 │\n└──────┬──────┘\n │\n ▼\n 返回 {extractedText, translatedText}\n```\n\n### 6.3 语音翻译流程\n\n```\n用户上传音频\n │\n ▼\n┌─────────────┐\n│ AudioTranslateService │\n│ • 音频格式/大小校验 │\n│ • 创建临时文件 │\n│ • 计算音频时长 │\n│ 路径: /api/v1/translate/audio │\n└──────┬──────┘\n │\n ▼\n┌─────────────┐\n│ AsrService │\n│ • 调用 Whisper API │\n│ • 语音识别 │\n└──────┬──────┘\n │\n ▼\n┌─────────────┐\n│ TranslateService │\n│ • 文本翻译 │\n└──────┬──────┘\n │\n ▼\n 清理临时文件\n │\n ▼\n 返回 {recognizedText, translatedText, audioDurationMs}\n```\n\n***\n\n## 七、构建与部署\n\n### 7.1 Maven 构建\n\n```bash\n# 使用 Maven Wrapper 构建\n./mvnw clean package\n\n# 运行应用\n./mvnw spring-boot:run -pl ai-app\n```\n\n### 7.2 模块构建配置\n\n- 所有模块均配置 `maven-compiler-plugin`,启用 Lombok 注解处理器\n- `ai-app` 模块使用 `spring-boot-maven-plugin` 打包可执行 JAR\n- 打包时排除 Lombok 依赖\n\n### 7.3 运行环境要求\n\n| 依赖 | 版本 | 说明 |\n| ---------- | --- | ------------------- |\n| JDK | 17+ | Java 运行时 |\n| PostgreSQL | 14+ | 数据库,需安装 pgvector 扩展 |\n| LM Studio | - | 本地 LLM 服务,端口 1234 |\n| Tesseract | - | OCR 引擎(需安装语言包) |\n\n### 7.4 环境变量配置(生产环境推荐)\n\n```bash\n# LLM 配置\nexport LLM_BASE_URL=http://localhost:1234/v1\nexport LLM_MODEL=qwen\nexport LLM_API_KEY=your-secure-api-key\nexport LLM_TIMEOUT=60000\n\n# OpenAI 配置(Spring AI 使用)\nexport OPENAI_API_KEY=your-secure-api-key\n\n# 数据库配置\nexport DB_URL=jdbc:postgresql://localhost:5432/ai_assistant\nexport DB_USERNAME=postgres\nexport DB_PASSWORD=your-secure-password\n```\n\n***\n\n## 八、扩展性分析\n\n### 8.1 当前扩展点\n\n1. **新领域翻译**: 在 `TranslateService.buildSystemPrompt()` 中添加新的 domain case\n2. **新风格翻译**: 在 `TranslateService.buildSystemPrompt()` 中添加新的 style case\n3. **新 OCR 语言**: 通过 `OcrService.extractText(file, language)` 指定 Tesseract 语言包\n4. **缓存策略**: 调整 `TranslatorConfig` 中的缓存参数\n\n### 8.2 架构优势\n\n1. **模块化设计**: 各模块职责清晰,可独立演进\n2. **依赖倒置**: `ai-app` 作为组装模块,业务模块之间通过接口解耦\n3. **配置外部化**: 所有 AI 参数通过 `application.yml` 配置,支持环境变量覆盖,无需改代码\n4. **异常隔离**: 各模块自定义异常,避免错误传播污染\n\n### 8.3 待完善方向\n\n1. **ai-agent 模块**: 当前为空,建议实现 ReAct/Plan-and-Execute 智能体框架\n2. **向量存储**: 已引入 `spring-ai-starter-vector-store-pgvector`,但未在业务中使用\n3. **流式输出**: `LlmService` 中 `stream=false` 写死,可扩展 SSE 流式接口\n4. **多模态支持**: 可扩展视频翻译、文档翻译等能力\n5. **用户管理**: 当前无认证授权机制\n6. **限流熔断**: 建议引入 Sentinel/Resilience4j\n7. **单元测试**: 当前测试覆盖不足,需补充 Service/Controller 层测试\n8. **API 文档**: 建议引入 Swagger/OpenAPI 自动生成接口文档\n\n***\n\n## 九、代码质量评估\n\n### 9.1 优点\n\n- ✅ 统一的 API 响应格式,前后端交互规范\n- ✅ 完善的全局异常处理,错误信息友好\n- ✅ 日志记录详尽,便于问题排查\n- ✅ 参数校验完善(`@Valid`, `@NotBlank`, `@Size`)\n- ✅ 缓存机制提升性能\n- ✅ 重试机制增强稳定性\n- ✅ 临时文件自动清理,避免磁盘泄漏\n- ✅ 配置外部化,支持环境变量注入\n- ✅ 敏感配置默认支持环境变量覆盖\n\n### 9.2 改进建议\n\n- ⚠️ `application.yml` 中数据库密码仍有默认值,生产环境务必通过环境变量覆盖\n- ⚠️ `AsrService` 中 ASR API URL 硬编码,建议提取到配置\n- ⚠️ `OcrService` 中 Tesseract 数据路径未配置,可能依赖系统环境\n- ⚠️ 缺少单元测试覆盖(仅有一个默认的 `AiAssistantApplicationTests`)\n- ⚠️ 缺少 API 文档(如 Swagger/OpenAPI)\n\n***\n\n## 十、版本变更记录\n\n### v0.0.1-SNAPSHOT (当前版本)\n\n**新增功能**:\n\n- 多模态翻译支持(文本/图片/语音)\n- 翻译缓存机制(Caffeine)\n- 长文本自动分段翻译\n- 领域和风格适配(tech/medical/legal/business/literary/formal/casual/academic)\n- 全局异常处理与统一响应格式\n- Spring Retry 重试机制\n- 配置外部化(支持环境变量)\n\n**架构变更**:\n\n- 清理重复模块(app、translator)\n- API 路径规范化(`/api/v1/translate/*`)\n- 模块依赖关系优化\n\n***\n\n## 十一、总结\n\nAI-Assistant 是一个架构清晰、模块化的 Spring Boot AI 应用,通过 Maven 多模块方式组织了 LLM、OCR、翻译等核心能力。项目采用**本地化 LLM 方案**(LM Studio),降低了对外部云服务的依赖,适合私有化部署场景。\n\n核心设计亮点:\n\n1. **分层异常处理**: 模块异常 → 业务异常 → 统一拦截 → 标准化响应\n2. **Prompt 工程**: 通过精细的系统提示词控制翻译质量\n3. **多模态翻译**: 文本/图片/语音三种输入方式的统一翻译能力\n4. **性能优化**: Caffeine 缓存 + 长文本分段处理\n5. **配置安全**: 敏感配置支持环境变量覆盖\n\n项目当前处于 **MVP 阶段**,核心功能已可用,后续可在智能体框架、向量检索、流式输出等方向持续演进。\n"}, "a529eca927fc7271e5c9400867ddaba3ba754f70": {"t": 1785764157.6639109, "n": 18886, "h": "33d3b040d83b7a90", "c": "# AI-Assistant 项目深度分析文档\n\n## 一、项目概述\n\n**AI-Assistant** 是一个基于 **Spring Boot 3.5.13** 构建的模块化 AI 助手应用,采用 **Maven 多模块架构**设计。项目集成了大语言模型(LLM)、光学字符识别(OCR)、智能翻译等核心 AI 能力,通过本地化的 LLM 服务(如 LM Studio)提供智能对话、文本翻译、图片翻译、语音翻译等功能。\n\n| 属性 | 说明 |\n| ------------------ | ------------------ |\n| **项目名称** | ai-assistant |\n| **版本** | 0.0.1-SNAPSHOT |\n| **构建工具** | Maven 3.x(Wrapper) |\n| **Java 版本** | 17 |\n| **Spring Boot 版本** | 3.5.13 |\n| **Spring AI 版本** | 1.1.4 |\n| **服务端口** | 9090 |\n\n***\n\n## 二、项目架构\n\n### 2.1 模块依赖图\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│ ai-app (启动入口) │\n│ Spring Boot Web 应用 │\n│ 端口: 9090 │\n└──────────┬──────────────────────────────────────────────────┘\n │ 依赖所有子模块\n ▼\n┌──────────────┬──────────────┬──────────────┬──────────────┐\n│ ai-common │ ai-llm │ ai-ocr │ ai-translator│\n│ (公共模块) │ (LLM调用) │ (文字识别) │ (翻译服务) │\n├──────────────┼──────────────┼──────────────┼──────────────┤\n│ • WebClient │ • OpenAI API │ • Tesseract │ • 文本翻译 │\n│ • 全局异常处理│ • 对话服务 │ • 图片文字提取│ • 图片翻译 │\n│ • 统一响应体 │ • 重试机制 │ │ • 语音翻译 │\n│ │ • 配置外部化 │ │ • 缓存机制 │\n└──────────────┴──────────────┴──────────────┴──────────────┘\n ▲\n┌──────────┴──────────────────────────────────────────────────┐\n│ ai-agent (智能体框架) │\n│ 当前为占位模块,预留扩展 │\n└─────────────────────────────────────────────────────────────┘\n```\n\n### 2.2 模块职责说明\n\n| 模块 | 职责 | 被依赖方 |\n| --------------- | ------------------------------------- | ------------------------------- |\n| `ai-common` | 公共工具类、全局异常处理、统一 API 响应格式、WebClient 配置 | 所有模块 |\n| `ai-llm` | 大语言模型调用封装、对话服务、OpenAI 兼容 API 交互 | ai-ocr, ai-translator, ai-agent |\n| `ai-ocr` | 基于 Tesseract 的光学字符识别服务 | ai-translator |\n| `ai-translator` | 多模态翻译服务(文本/图片/语音)、缓存管理 | ai-app |\n| `ai-agent` | 智能体框架(当前为预留模块) | ai-app |\n| `ai-app` | 应用启动入口、配置聚合、依赖组装 | - |\n\n***\n\n## 三、核心模块详解\n\n### 3.1 ai-common(公共模块)\n\n**包结构**: `com.alan.aicommon`\n\n#### 3.1.1 统一响应体(ApiResponse)\n\n位于 `dto/ApiResponse.java`,采用泛型设计,提供标准化的 API 返回格式:\n\n```java\n{\n \"code\": 200,\n \"message\": \"success\",\n \"data\": { ... },\n \"timestamp\": 1713763200000\n}\n```\n\n**工厂方法**:\n\n- `success(T data)` - 成功响应\n- `success(String message, T data)` - 带自定义消息的成功响应\n- `error(int code, String message)` - 错误响应\n- `badRequest(String message)` - 400 错误\n- `serverError(String message)` - 500 错误\n\n#### 3.1.2 全局异常处理(GlobalExceptionHandler)\n\n基于 `@RestControllerAdvice` 的全局异常拦截器,覆盖以下异常类型:\n\n| 异常类型 | HTTP 状态码 | 处理逻辑 |\n| ----------------------------------------- | -------- | --------------- |\n| `LlmException` | 500 | AI 模型调用失败 |\n| `TranslationException` | 400 | 翻译业务异常 |\n| `MethodArgumentNotValidException` | 400 | 参数校验失败(JSR-303) |\n| `HttpMessageNotReadableException` | 400 | 请求体解析失败 |\n| `MissingServletRequestParameterException` | 400 | 缺少必需参数 |\n| `HttpRequestMethodNotSupportedException` | 405 | 不支持的 HTTP 方法 |\n| `NoResourceFoundException` | 404 | 资源未找到 |\n| `MaxUploadSizeExceededException` | 413 | 文件上传超限 |\n| `Exception` | 500 | 兜底异常处理 |\n\n#### 3.1.3 自定义异常\n\n- **LlmException**: LLM 调用过程中的运行时异常\n- **TranslationException**: 翻译业务异常,支持错误码(errorCode)\n\n#### 3.1.4 WebClient 配置\n\n提供响应式 HTTP 客户端 `WebClient` Bean,用于异步 HTTP 调用。\n\n***\n\n### 3.2 ai-llm(大语言模型模块)\n\n**包结构**: `com.alan.aillm`\n\n#### 3.2.1 配置类(LlmConfig)\n\n通过 `@ConfigurationProperties(prefix = \"ai.llm\")` 绑定配置:\n\n| 配置项 | 默认值 | 说明 |\n| ------------- | -------------------------- | ----------------------- |\n| `base-url` | `http://localhost:1234/v1` | LLM API 基础地址(LM Studio) |\n| `model` | `qwen` | 默认模型名称 |\n| `api-key` | `\"\"` | API 密钥 |\n| `timeout` | 30000ms | 连接/读取超时 |\n| `max-retries` | 3 | 最大重试次数 |\n| `temperature` | 0.3 | 采样温度 |\n| `topP` | 0.9 | 核采样参数(YAML 中使用 `topP`) |\n| `max-tokens` | 4096 | 最大生成令牌数 |\n| `stream` | false | 是否流式输出 |\n\n**配置示例**(支持环境变量覆盖):\n\n```yaml\nai:\n llm:\n base-url: ${LLM_BASE_URL:http://localhost:1234/v1}\n model: ${LLM_MODEL:qwen}\n api-key: ${LLM_API_KEY:your-api-key}\n timeout: ${LLM_TIMEOUT:60000}\n max-retries: ${LLM_MAX_RETRIES:3}\n temperature: ${LLM_TEMPERATURE:0.3}\n topP: ${LLM_TOP_P:0.9}\n max-tokens: ${LLM_MAX_TOKENS:4096}\n```\n\n#### 3.2.2 对话服务(LlmService)\n\n核心服务类,提供与 OpenAI 兼容 API 的交互能力:\n\n**核心方法**:\n\n- `chat(String systemPrompt, String userPrompt)` - 单轮对话\n- `chat(List messages)` - 多消息对话\n- `chatWithHistory(String systemPrompt, String userPrompt, List history)` - 带历史记录的对话\n\n**技术特性**:\n\n- 使用 `RestTemplate` 进行同步 HTTP 调用\n- 支持 **Spring Retry** 重试机制(`@Retryable`),对 `ResourceAccessException` 和 `HttpServerErrorException` 自动重试\n- 指数退避策略:`delay = 1000ms`,`multiplier = 2`\n- 完善的日志记录(请求耗时、模型名称、异常详情)\n- 响应内容安全校验(空响应、空 choices、空内容检查)\n\n**请求/响应 DTO**:\n\n- `ChatRequest`: 兼容 OpenAI Chat Completions API 的请求体(含 temperature/topP/maxTokens/stream)\n- `ChatResponse`: 解析 OpenAI 标准响应格式(含 choices/usage/delta 等字段)\n\n***\n\n### 3.3 ai-ocr(光学字符识别模块)\n\n**包结构**: `com.alan.aiocr`\n\n#### 3.3.1 OCR 服务(OcrService)\n\n基于 **Tess4J**(Tesseract OCR 的 Java 封装)实现图片文字提取:\n\n**依赖**: `net.sourceforge.tess4j:tess4j:5.8.0`\n\n**核心方法**:\n\n- `extractText(MultipartFile imageFile)` - 默认语言识别\n- `extractText(MultipartFile imageFile, String language)` - 指定语言识别\n\n**技术细节**:\n\n- 页面分割模式设置为 `PSM_AUTO`(`setPageSegMode(1)`)\n- 支持常见图片格式(通过 `ImageIO` 自动识别)\n- 异常处理:图片读取失败、OCR 识别失败均有明确异常提示\n\n***\n\n### 3.4 ai-translator(智能翻译模块)\n\n**包结构**: `com.alan.aitranslator`\n\n#### 3.4.1 配置类(TranslatorConfig)\n\n通过 `@ConfigurationProperties(prefix = \"ai.translator\")` 绑定配置:\n\n| 配置项 | 默认值 | 说明 |\n| -------------------- | ------- | ------------ |\n| `max-text-length` | 10000 | 最大翻译文本长度 |\n| `max-segment-length` | 3000 | 长文本分段长度 |\n| `enable-cache` | true | 是否启用翻译缓存 |\n| `cache-size` | 10000 | 缓存最大条目数 |\n| `cache-ttl-minutes` | 1440 | 缓存过期时间(24小时) |\n| `default-domain` | general | 默认翻译领域 |\n| `default-style` | neutral | 默认翻译风格 |\n\n**配置示例**:\n\n```yaml\nai:\n translator:\n max-text-length: 10000\n max-segment-length: 3000\n enable-cache: true\n cache-size: 10000\n cache-ttl-minutes: 1440\n default-domain: general\n default-style: neutral\n```\n\n#### 3.4.2 翻译服务(TranslateService)\n\n基于 LLM 的高质量翻译引擎,支持多领域、多风格翻译:\n\n**核心特性**:\n\n1. **缓存机制**: 使用 **Caffeine Cache** 实现本地缓存\n - 缓存键:`{from}_{to}_{domain}_{style}_{length}_{hash}`\n - 统计功能:记录命中率\n2. **长文本处理**: 超过 `maxSegmentLength` 的文本自动分段翻译\n - 按段落分割,保持上下文连贯性\n - 前一段摘要作为下一段的上下文参考\n3. **领域适配**: 支持 5 种专业领域\n - `general` - 通用领域\n - `tech` - 技术领域(计算机、软件工程)\n - `medical` - 医学领域\n - `legal` - 法律领域\n - `business` - 商业领域\n - `literary` - 文学领域\n4. **风格适配**: 支持 3 种翻译风格\n - `neutral` - 中性风格\n - `formal` - 正式书面语\n - `casual` - 口语化风格\n - `academic` - 学术严谨风格\n5. **系统提示词工程**: 通过精心设计的 system prompt 约束 LLM 输出,确保翻译质量\n\n#### 3.4.3 图片翻译服务(ImageTranslateService)\n\n**流程**: 图片上传 → OCR 文字提取 → 文本翻译 → 返回结果\n\n**接口**: `POST /api/v1/translate/image` (multipart/form-data)\n\n**参数**:\n\n- `file` - 图片文件(JPG/PNG/GIF/WEBP,最大 50MB)\n- `from` - 源语言\n- `to` - 目标语言\n\n#### 3.4.4 语音翻译服务(AudioTranslateService)\n\n**流程**: 音频上传 → ASR 语音识别 → 文本翻译 → 返回结果\n\n**接口**: `POST /api/v1/translate/audio` (multipart/form-data)\n\n**参数**:\n\n- `file` - 音频文件(MP3/WAV/M4A/OGG/FLAC,最大 50MB)\n- `from` - 源语言\n- `to` - 目标语言\n\n**技术细节**:\n\n- 临时文件管理:上传后创建临时文件,处理完成后自动清理\n- 音频时长计算:通过 `javax.sound.sampled` 获取音频时长\n- ASR 服务:调用兼容 OpenAI 的 `/v1/audio/transcriptions` API\n\n#### 3.4.5 ASR 服务(AsrService)\n\n调用 OpenAI Whisper 兼容 API 进行语音识别:\n\n- 模型:`whisper-1`\n- 响应格式:`text`\n- 支持语言参数指定\n\n#### 3.4.6 文本预处理(TextPreprocessor)\n\n翻译前的文本清洗工具:\n\n- 去除 HTML 标签\n- 合并多余空格\n- 合并多余换行(超过 2 个换行合并为 2 个)\n\n***\n\n### 3.5 ai-agent(智能体模块)\n\n**包结构**: `com.alan.aiagent`\n\n当前为**预留模块**,仅包含占位类 `AgentModuleInfo`,用于:\n\n- 确保目录被 Git 跟踪\n- 为后续智能体框架(Agent Framework)扩展预留空间\n\n**未来可扩展方向**:\n\n- ReAct 智能体模式\n- 工具调用(Function Calling)编排\n- 多智能体协作\n- 记忆管理(Memory)\n\n***\n\n### 3.6 ai-app(应用启动模块)\n\n**包结构**: `com.alan.aiassistant`\n\n#### 3.6.1 启动类(AiAssistantApplication)\n\n```java\n@SpringBootApplication\n@EnableRetry\n@ComponentScan(basePackages = {\"com.alan.aiassistant\", \"com.alan.aicommon\", \n \"com.alan.aitranslator\", \"com.alan.aillm\", \"com.alan.aiocr\", \"com.alan.aiagent\"})\n```\n\n**关键注解**:\n\n- `@EnableRetry`: 启用 Spring Retry 重试机制\n- `@ComponentScan`: 显式扫描所有模块的包路径(解决多模块包扫描问题)\n\n#### 3.6.2 应用配置(application.yml)\n\n```yaml\nspring:\n application:\n name: ai-assistant\n datasource:\n url: jdbc:postgresql://localhost:5432/ai_assistant\n username: postgres\n password: 123456\n ai:\n openai:\n api-key: ${OPENAI_API_KEY:sk-lm-zmU7SpEW:2wED8QUaU6JFaPKTbs6t}\n base-url: http://localhost:1234/v1\n servlet:\n multipart:\n max-file-size: 50MB\n max-request-size: 50MB\n\nai:\n llm:\n base-url: ${LLM_BASE_URL:http://localhost:1234/v1}\n model: ${LLM_MODEL:qwen}\n api-key: ${LLM_API_KEY:sk-lm-zmU7SpEW:2wED8QUaU6JFaPKTbs6t}\n timeout: ${LLM_TIMEOUT:60000}\n max-retries: ${LLM_MAX_RETRIES:3}\n temperature: ${LLM_TEMPERATURE:0.3}\n topP: ${LLM_TOP_P:0.9}\n max-tokens: ${LLM_MAX_TOKENS:4096}\n translator:\n max-text-length: 10000\n max-segment-length: 3000\n enable-cache: true\n cache-size: 10000\n cache-ttl-minutes: 1440\n default-domain: general\n default-style: neutral\n\nserver:\n port: 9090\n```\n\n**基础设施**:\n\n- **数据库**: PostgreSQL(用于向量存储 `pgvector`)\n- **LLM 服务**: 本地 LM Studio(端口 1234)\n- **文件上传**: 最大 50MB\n\n**安全配置说明**:\n\n- 所有敏感配置(API Key、密码)支持通过环境变量覆盖\n- 格式:`${ENV_VAR:default_value}`,环境变量不存在时使用默认值\n- 生产环境建议设置对应的环境变量,避免使用默认值\n\n***\n\n## 四、API 接口清单\n\n### 4.1 翻译接口(v1 版本)\n\n| 方法 | 路径 | 说明 | 请求类型 |\n| ---- | ------------------------- | ---- | --------- |\n| POST | `/api/v1/translate/text` | 文本翻译 | JSON |\n| POST | `/api/v1/translate/image` | 图片翻译 | Multipart |\n| POST | `/api/v1/translate/audio` | 语音翻译 | Multipart |\n\n### 4.2 请求/响应示例\n\n#### 文本翻译\n\n**请求**:\n\n```json\n{\n \"text\": \"Hello, world!\",\n \"from\": \"en\",\n \"to\": \"zh\",\n \"domain\": \"general\",\n \"style\": \"neutral\",\n \"contextText\": \"可选的上下文内容\"\n}\n```\n\n**响应**:\n\n```json\n{\n \"code\": 200,\n \"message\": \"success\",\n \"data\": {\n \"originalText\": \"Hello, world!\",\n \"translatedText\": \"你好,世界!\",\n \"from\": \"en\",\n \"to\": \"zh\",\n \"domain\": \"general\",\n \"style\": \"neutral\",\n \"durationMs\": 1250,\n \"cached\": false\n },\n \"timestamp\": 1713763200000\n}\n```\n\n#### 图片翻译\n\n**请求** (multipart/form-data):\n\n- `file` - 图片文件\n- `from` - 源语言代码\n- `to` - 目标语言代码\n\n**响应**:\n\n```json\n{\n \"code\": 200,\n \"message\": \"success\",\n \"data\": {\n \"extractedText\": \"图片中提取的原文\",\n \"translatedText\": \"翻译后的文本\",\n \"from\": \"en\",\n \"to\": \"zh\",\n \"durationMs\": 3250\n },\n \"timestamp\": 1713763200000\n}\n```\n\n#### 语音翻译\n\n**请求** (multipart/form-data):\n\n- `file` - 音频文件\n- `from` - 源语言代码\n- `to` - 目标语言代码\n\n**响应**:\n\n```json\n{\n \"code\": 200,\n \"message\": \"success\",\n \"data\": {\n \"recognizedText\": \"语音识别结果\",\n \"translatedText\": \"翻译后的文本\",\n \"from\": \"en\",\n \"to\": \"zh\",\n \"durationMs\": 5250,\n \"audioDurationMs\": 15000\n },\n \"timestamp\": 1713763200000\n}\n```\n\n### 4.3 错误响应示例\n\n```json\n{\n \"code\": 400,\n \"message\": \"参数验证失败: 翻译文本不能为空; 源语言不能为空\",\n \"data\": null,\n \"timestamp\": 1713763200000\n}\n```\n\n***\n\n## 五、技术栈分析\n\n### 5.1 核心框架与库\n\n| 技术 | 版本 | 用途 |\n| ----------------- | ------ | ------------- |\n| Spring Boot | 3.5.13 | 应用框架 |\n| Spring AI | 1.1.4 | AI 抽象框架(向量存储) |\n| Spring Retry | - | 重试机制 |\n| Spring Validation | - | 参数校验(JSR-303) |\n| Lombok | - | 代码简化 |\n| Tess4J | 5.8.0 | OCR 引擎 |\n| Caffeine | - | 本地缓存 |\n| PostgreSQL | - | 关系型数据库 |\n| pgvector | - | 向量扩展 |\n\n### 5.2 设计模式应用\n\n| 模式 | 应用位置 | 说明 |\n| --------- | ------------------ | ------------------------ |\n| **模板方法** | `LlmService` | 对话流程标准化(构建请求→调用API→提取内容) |\n| **策略模式** | `TranslateService` | 不同领域/风格的翻译策略通过 prompt 切换 |\n| **建造者模式** | DTO 类 | `@Builder` 注解生成流式构建器 |\n| **单例模式** | `OcrService` | Tesseract 引擎单例管理 |\n| **工厂模式** | `ApiResponse` | 静态工厂方法创建响应对象 |\n\n### 5.3 异常处理策略\n\n项目采用**分层异常处理**架构:\n\n1. **模块自定义异常**: 各模块定义自己的异常类型(`LlmException`, `TranslationException`, `OcrException`, `AsrException`)\n2. **异常转换**: 底层异常在模块边界处转换为业务异常\n3. **统一拦截**: `GlobalExceptionHandler` 集中处理所有异常,统一返回格式\n4. **日志分级**: WARN 处理客户端错误,ERROR 处理服务端错误\n\n***\n\n## 六、数据流分析\n\n### 6.1 文本翻译流程\n\n```\n用户请求\n │\n ▼\n┌─────────────┐\n│ TranslateController │\n│ @Valid 参数校验 │\n│ 路径: /api/v1/translate/text │\n└──────┬──────┘\n │\n ▼\n┌─────────────┐\n│ TranslateService │\n│ • 文本预处理 │\n│ • 缓存查询 │\n│ • 长文本分段 │\n│ • 领域/风格适配 │\n└──────┬──────┘\n │\n ▼\n┌─────────────┐\n│ LlmService │\n│ • 构建请求体 │\n│ • HTTP 调用 │\n│ • 重试机制 │\n│ • 响应解析 │\n└──────┬──────┘\n │\n ▼\n LLM API\n │\n ▼\n 返回翻译结果\n```\n\n### 6.2 图片翻译流程\n\n```\n用户上传图片\n │\n ▼\n┌─────────────┐\n│ ImageTranslateService │\n│ • 图片格式/大小校验 │\n│ 路径: /api/v1/translate/image │\n└──────┬──────┘\n │\n ▼\n┌─────────────┐\n│ OcrService │\n│ • ImageIO 读取│\n│ • Tesseract │\n│ 文字提取 │\n└──────┬──────┘\n │\n ▼\n┌─────────────┐\n│ TranslateService │\n│ • 文本翻译 │\n└──────┬──────┘\n │\n ▼\n 返回 {extractedText, translatedText}\n```\n\n### 6.3 语音翻译流程\n\n```\n用户上传音频\n │\n ▼\n┌─────────────┐\n│ AudioTranslateService │\n│ • 音频格式/大小校验 │\n│ • 创建临时文件 │\n│ • 计算音频时长 │\n│ 路径: /api/v1/translate/audio │\n└──────┬──────┘\n │\n ▼\n┌─────────────┐\n│ AsrService │\n│ • 调用 Whisper API │\n│ • 语音识别 │\n└──────┬──────┘\n │\n ▼\n┌─────────────┐\n│ TranslateService │\n│ • 文本翻译 │\n└──────┬──────┘\n │\n ▼\n 清理临时文件\n │\n ▼\n 返回 {recognizedText, translatedText, audioDurationMs}\n```\n\n***\n\n## 七、构建与部署\n\n### 7.1 Maven 构建\n\n```bash\n# 使用 Maven Wrapper 构建\n./mvnw clean package\n\n# 运行应用\n./mvnw spring-boot:run -pl ai-app\n```\n\n### 7.2 模块构建配置\n\n- 所有模块均配置 `maven-compiler-plugin`,启用 Lombok 注解处理器\n- `ai-app` 模块使用 `spring-boot-maven-plugin` 打包可执行 JAR\n- 打包时排除 Lombok 依赖\n\n### 7.3 运行环境要求\n\n| 依赖 | 版本 | 说明 |\n| ---------- | --- | ------------------- |\n| JDK | 17+ | Java 运行时 |\n| PostgreSQL | 14+ | 数据库,需安装 pgvector 扩展 |\n| LM Studio | - | 本地 LLM 服务,端口 1234 |\n| Tesseract | - | OCR 引擎(需安装语言包) |\n\n### 7.4 环境变量配置(生产环境推荐)\n\n```bash\n# LLM 配置\nexport LLM_BASE_URL=http://localhost:1234/v1\nexport LLM_MODEL=qwen\nexport LLM_API_KEY=your-secure-api-key\nexport LLM_TIMEOUT=60000\n\n# OpenAI 配置(Spring AI 使用)\nexport OPENAI_API_KEY=your-secure-api-key\n\n# 数据库配置\nexport DB_URL=jdbc:postgresql://localhost:5432/ai_assistant\nexport DB_USERNAME=postgres\nexport DB_PASSWORD=your-secure-password\n```\n\n***\n\n## 八、扩展性分析\n\n### 8.1 当前扩展点\n\n1. **新领域翻译**: 在 `TranslateService.buildSystemPrompt()` 中添加新的 domain case\n2. **新风格翻译**: 在 `TranslateService.buildSystemPrompt()` 中添加新的 style case\n3. **新 OCR 语言**: 通过 `OcrService.extractText(file, language)` 指定 Tesseract 语言包\n4. **缓存策略**: 调整 `TranslatorConfig` 中的缓存参数\n\n### 8.2 架构优势\n\n1. **模块化设计**: 各模块职责清晰,可独立演进\n2. **依赖倒置**: `ai-app` 作为组装模块,业务模块之间通过接口解耦\n3. **配置外部化**: 所有 AI 参数通过 `application.yml` 配置,支持环境变量覆盖,无需改代码\n4. **异常隔离**: 各模块自定义异常,避免错误传播污染\n\n### 8.3 待完善方向\n\n1. **ai-agent 模块**: 当前为空,建议实现 ReAct/Plan-and-Execute 智能体框架\n2. **向量存储**: 已引入 `spring-ai-starter-vector-store-pgvector`,但未在业务中使用\n3. **流式输出**: `LlmService` 中 `stream=false` 写死,可扩展 SSE 流式接口\n4. **多模态支持**: 可扩展视频翻译、文档翻译等能力\n5. **用户管理**: 当前无认证授权机制\n6. **限流熔断**: 建议引入 Sentinel/Resilience4j\n7. **单元测试**: 当前测试覆盖不足,需补充 Service/Controller 层测试\n8. **API 文档**: 建议引入 Swagger/OpenAPI 自动生成接口文档\n\n***\n\n## 九、代码质量评估\n\n### 9.1 优点\n\n- ✅ 统一的 API 响应格式,前后端交互规范\n- ✅ 完善的全局异常处理,错误信息友好\n- ✅ 日志记录详尽,便于问题排查\n- ✅ 参数校验完善(`@Valid`, `@NotBlank`, `@Size`)\n- ✅ 缓存机制提升性能\n- ✅ 重试机制增强稳定性\n- ✅ 临时文件自动清理,避免磁盘泄漏\n- ✅ 配置外部化,支持环境变量注入\n- ✅ 敏感配置默认支持环境变量覆盖\n\n### 9.2 改进建议\n\n- ⚠️ `application.yml` 中数据库密码仍有默认值,生产环境务必通过环境变量覆盖\n- ⚠️ `AsrService` 中 ASR API URL 硬编码,建议提取到配置\n- ⚠️ `OcrService` 中 Tesseract 数据路径未配置,可能依赖系统环境\n- ⚠️ 缺少单元测试覆盖(仅有一个默认的 `AiAssistantApplicationTests`)\n- ⚠️ 缺少 API 文档(如 Swagger/OpenAPI)\n\n***\n\n## 十、版本变更记录\n\n### v0.0.1-SNAPSHOT (当前版本)\n\n**新增功能**:\n\n- 多模态翻译支持(文本/图片/语音)\n- 翻译缓存机制(Caffeine)\n- 长文本自动分段翻译\n- 领域和风格适配(tech/medical/legal/business/literary/formal/casual/academic)\n- 全局异常处理与统一响应格式\n- Spring Retry 重试机制\n- 配置外部化(支持环境变量)\n\n**架构变更**:\n\n- 清理重复模块(app、translator)\n- API 路径规范化(`/api/v1/translate/*`)\n- 模块依赖关系优化\n\n***\n\n## 十一、总结\n\nAI-Assistant 是一个架构清晰、模块化的 Spring Boot AI 应用,通过 Maven 多模块方式组织了 LLM、OCR、翻译等核心能力。项目采用**本地化 LLM 方案**(LM Studio),降低了对外部云服务的依赖,适合私有化部署场景。\n\n核心设计亮点:\n\n1. **分层异常处理**: 模块异常 → 业务异常 → 统一拦截 → 标准化响应\n2. **Prompt 工程**: 通过精细的系统提示词控制翻译质量\n3. **多模态翻译**: 文本/图片/语音三种输入方式的统一翻译能力\n4. **性能优化**: Caffeine 缓存 + 长文本分段处理\n5. **配置安全**: 敏感配置支持环境变量覆盖\n\n项目当前处于 **MVP 阶段**,核心功能已可用,后续可在智能体框架、向量检索、流式输出等方向持续演进。\n\n
\n\n
\n\n你是一个资深前端工程师,正在为本“桌面 AI 助手”项目开发第一阶段 UI。\n\n技术栈要求:\n\n- Vue 3(script setup)\n- TypeScript\n- Vite\n- Element Plus\n- Axios\n- 使用 Pinia(但当前页面可以不复杂使用)\n\n目标:\\\n实现一个“翻译控制台页面”,用于调用后端翻译接口。\n\n***\n\n请生成一个完整的 Vue 页面组件(.vue),要求如下:\n\n一、页面结构(UI)\\\n使用 Element Plus 实现,布局简洁现代:\n\n1. 顶部:\n\n- 标题:AI 翻译助手\n- 显示模型状态(固定写:LM Studio 已连接)\n\n1. 输入区:\n\n- 多行输入框(textarea)\n- placeholder:请输入要翻译的内容\n- 支持自动高度\n\n1. 语言选择区:\n\n- from:源语言(默认 auto)\n- to:目标语言(默认 en)\n- 使用 el-select\n\n语言选项:\n\n- auto(自动检测)\n- zh(中文)\n- en(英文)\n- ja(日文)\n\n1. 操作按钮:\n\n- “翻译”按钮(primary)\n- “清空”按钮\n- 翻译时按钮 loading\n\n1. 输出区:\n\n- 卡片样式\n- 显示翻译结果\n- 支持复制按钮\n\n***\n\n二、功能要求\n\n1. 点击“翻译”:\n\n- 调用 后端接口,支持文本,图片,音频输入,分别调用对应的后端接口\n- 使用 axios\n- 显示 loading 状态\n- 成功后展示结果\n- 失败时弹出 error 提示(ElMessage)\n\n1. 输入校验:\n\n- 为空时禁止翻译\n- 给出提示\n\n1. 清空按钮:\n\n- 清空输入和结果\n\n1. 复制功能:\n\n- 点击复制结果到剪贴板\n- 成功提示\n\n***\n\n三、代码要求\n\n- 使用\n- 使用 ref/reactive 管理状态\n- axios 封装为简单函数(可写在当前文件中)\n- 代码结构清晰,有适当注释\n- 不要过度拆组件(单文件即可)\n\n***\n\n四、样式要求\n\n- 使用 scoped style\n- 页面居中(最大宽度 800px)\n- 留白舒适(padding)\n- 卡片阴影\n- 不要复杂 UI,但要“像产品”\n\n***\n\n五、额外要求(重要)\n\n- 代码必须可直接运行\n- 不要省略 import\n- 不要写伪代码\n- 输出完整代码\n\n***\n\n现在开始生成代码。\n"}}, "ai-app/src/main/resources/application.yml": {"21aff4283e4de41af9e3fe71334b29e780105958": {"t": 1785746951.8719914, "n": 1324, "h": "be88e3b2940437c3", "c": "spring:\n application:\n name: ai-assistant\n datasource:\n url: jdbc:postgresql://localhost:5432/ai_assistant\n username: postgres\n password: 123456\n driver-class-name: org.postgresql.Driver\n servlet:\n multipart:\n max-file-size: 50MB\n max-request-size: 50MB\n\nai:\n llm:\n active-provider: ${LLM_ACTIVE_PROVIDER:local}\n default-model: ${LLM_DEFAULT_MODEL:qwen}\n timeout: ${LLM_TIMEOUT:60000}\n max-retries: ${LLM_MAX_RETRIES:3}\n temperature: ${LLM_TEMPERATURE:0.3}\n top-p: ${LLM_TOP_P:0.9}\n max-tokens: ${LLM_MAX_TOKENS:4096}\n providers:\n local:\n base-url: ${LLM_LOCAL_URL:http://localhost:1234/v1}\n api-key: ${LLM_LOCAL_KEY:sk-lm-local}\n models:\n - qwen\n - llama\n deepseek:\n base-url: ${LLM_DEEPSEEK_URL:https://api.deepseek.com}\n api-key: ${LLM_DEEPSEEK_KEY:}\n models:\n - deepseek-v4-pro\n - deepseek-v4-flash\n vision-enabled: false\n thinking:\n enabled: ${LLM_DEEPSEEK_THINKING:false}\n reasoning-effort: ${LLM_DEEPSEEK_REASONING:high}\n\n translator:\n max-text-length: 50000\n max-segment-length: 3000\n enable-cache: true\n cache-size: 10000\n cache-ttl-minutes: 1440\n default-domain: general\n default-style: neutral\n\nserver:\n port: 9090\n\n"}, "af5e7d3d21cf392d9f78273cf703a55e0bc6e909": {"t": 1785764149.836176, "n": 1324, "h": "be88e3b2940437c3", "c": "spring:\n application:\n name: ai-assistant\n datasource:\n url: jdbc:postgresql://localhost:5432/ai_assistant\n username: postgres\n password: 123456\n driver-class-name: org.postgresql.Driver\n servlet:\n multipart:\n max-file-size: 50MB\n max-request-size: 50MB\n\nai:\n llm:\n active-provider: ${LLM_ACTIVE_PROVIDER:local}\n default-model: ${LLM_DEFAULT_MODEL:qwen}\n timeout: ${LLM_TIMEOUT:60000}\n max-retries: ${LLM_MAX_RETRIES:3}\n temperature: ${LLM_TEMPERATURE:0.3}\n top-p: ${LLM_TOP_P:0.9}\n max-tokens: ${LLM_MAX_TOKENS:4096}\n providers:\n local:\n base-url: ${LLM_LOCAL_URL:http://localhost:1234/v1}\n api-key: ${LLM_LOCAL_KEY:sk-lm-local}\n models:\n - qwen\n - llama\n deepseek:\n base-url: ${LLM_DEEPSEEK_URL:https://api.deepseek.com}\n api-key: ${LLM_DEEPSEEK_KEY:}\n models:\n - deepseek-v4-pro\n - deepseek-v4-flash\n vision-enabled: false\n thinking:\n enabled: ${LLM_DEEPSEEK_THINKING:false}\n reasoning-effort: ${LLM_DEEPSEEK_REASONING:high}\n\n translator:\n max-text-length: 50000\n max-segment-length: 3000\n enable-cache: true\n cache-size: 10000\n cache-ttl-minutes: 1440\n default-domain: general\n default-style: neutral\n\nserver:\n port: 9090\n\n"}, "7f654192dd07ebe9320ae22bfe7f2a3666497bc6": {"t": 1785764151.4725099, "n": 1359, "h": "bd46700ef2e1c0c8", "c": "spring:\n application:\n name: ai-assistant\n datasource:\n url: jdbc:postgresql://localhost:5432/ai_assistant\n username: postgres\n password: 123456\n driver-class-name: org.postgresql.Driver\n servlet:\n multipart:\n max-file-size: 50MB\n max-request-size: 50MB\n\nai:\n llm:\n active-provider: ${LLM_ACTIVE_PROVIDER:local}\n default-model: ${LLM_DEFAULT_MODEL:qwen}\n timeout: ${LLM_TIMEOUT:60000}\n max-retries: ${LLM_MAX_RETRIES:3}\n temperature: ${LLM_TEMPERATURE:0.3}\n top-p: ${LLM_TOP_P:0.9}\n max-tokens: ${LLM_MAX_TOKENS:4096}\n providers:\n local:\n base-url: ${LLM_LOCAL_URL:http://localhost:1234/v1}\n api-key: ${LLM_LOCAL_KEY:sk-lm-local}\n models:\n - qwen\n - llama\n deepseek:\n base-url: ${LLM_DEEPSEEK_URL:https://api.deepseek.com}\n api-key: ${LLM_DEEPSEEK_KEY:sk-2ce14ae2234947709419a377083cb91b}\n models:\n - deepseek-v4-pro\n - deepseek-v4-flash\n vision-enabled: false\n thinking:\n enabled: ${LLM_DEEPSEEK_THINKING:false}\n reasoning-effort: ${LLM_DEEPSEEK_REASONING:high}\n\n translator:\n max-text-length: 50000\n max-segment-length: 3000\n enable-cache: true\n cache-size: 10000\n cache-ttl-minutes: 1440\n default-domain: general\n default-style: neutral\n\nserver:\n port: 9090\n\n"}, "1c60a0dd38b5a3740ea3b868051b4ee68ea8fe6b": {"t": 1785764152.9581316, "n": 842, "h": "467c1f717c506d86", "c": "spring:\n application:\n name: ai-assistant\n datasource:\n url: jdbc:postgresql://localhost:5432/ai_assistant\n username: postgres\n password: 123456\n driver-class-name: org.postgresql.Driver\n servlet:\n multipart:\n max-file-size: 50MB\n max-request-size: 50MB\n\nai:\n llm:\n base-url: ${LLM_BASE_URL:http://localhost:1234/v1}\n model: ${LLM_MODEL:qwen}\n api-key: ${LLM_API_KEY:sk-lm-zmU7SpEW:2wED8QUaU6JFaPKTbs6t}\n timeout: ${LLM_TIMEOUT:60000}\n max-retries: ${LLM_MAX_RETRIES:3}\n temperature: ${LLM_TEMPERATURE:0.3}\n topP: ${LLM_TOP_P:0.9}\n max-tokens: ${LLM_MAX_TOKENS:4096}\n translator:\n max-text-length: 50000\n max-segment-length: 3000\n enable-cache: true\n cache-size: 10000\n cache-ttl-minutes: 1440\n default-domain: general\n default-style: neutral\n\nserver:\n port: 9090"}, "118f9ef34444e80a1f8b01389ddef647ccb67cd4": {"t": 1785764154.4231207, "n": 842, "h": "10ad9a099dd4a779", "c": "spring:\n application:\n name: ai-assistant\n datasource:\n url: jdbc:postgresql://localhost:5432/ai_assistant\n username: postgres\n password: 123456\n driver-class-name: org.postgresql.Driver\n servlet:\n multipart:\n max-file-size: 50MB\n max-request-size: 50MB\n\nai:\n llm:\n base-url: ${LLM_BASE_URL:http://localhost:1234/v1}\n model: ${LLM_MODEL:qwen}\n api-key: ${LLM_API_KEY:sk-lm-zmU7SpEW:2wED8QUaU6JFaPKTbs6t}\n timeout: ${LLM_TIMEOUT:60000}\n max-retries: ${LLM_MAX_RETRIES:3}\n temperature: ${LLM_TEMPERATURE:0.3}\n topP: ${LLM_TOP_P:0.9}\n max-tokens: ${LLM_MAX_TOKENS:4096}\n translator:\n max-text-length: 10000\n max-segment-length: 3000\n enable-cache: true\n cache-size: 10000\n cache-ttl-minutes: 1440\n default-domain: general\n default-style: neutral\n\nserver:\n port: 9090"}, "274d7f8e23780eb8a947f34c117e8728ce718b4e": {"t": 1785764155.98013, "n": 971, "h": "f0c03b98ea680d17", "c": "spring:\n application:\n name: ai-assistant\n datasource:\n url: jdbc:postgresql://localhost:5432/ai_assistant\n username: postgres\n password: 123456\n driver-class-name: org.postgresql.Driver\n ai:\n openai:\n api-key: ${OPENAI_API_KEY:sk-lm-zmU7SpEW:2wED8QUaU6JFaPKTbs6t}\n base-url: http://localhost:1234/v1\n servlet:\n multipart:\n max-file-size: 50MB\n max-request-size: 50MB\n\nai:\n llm:\n base-url: ${LLM_BASE_URL:http://localhost:1234/v1}\n model: ${LLM_MODEL:qwen}\n api-key: ${LLM_API_KEY:sk-lm-zmU7SpEW:2wED8QUaU6JFaPKTbs6t}\n timeout: ${LLM_TIMEOUT:60000}\n max-retries: ${LLM_MAX_RETRIES:3}\n temperature: ${LLM_TEMPERATURE:0.3}\n topP: ${LLM_TOP_P:0.9}\n max-tokens: ${LLM_MAX_TOKENS:4096}\n translator:\n max-text-length: 10000\n max-segment-length: 3000\n enable-cache: true\n cache-size: 10000\n cache-ttl-minutes: 1440\n default-domain: general\n default-style: neutral\n\nserver:\n port: 9090\n"}, "aba7982ccc230063540d14dd20f4cc8a93d2a31a": {"t": 1785764157.5308654, "n": 628, "h": "04723c6043d0cb7c", "c": "spring:\n application:\n name: ai-assistant\n datasource:\n url: jdbc:postgresql://localhost:5432/ai_assistant\n username: postgres\n password: 123456\n driver-class-name: org.postgresql.Driver\n ai:\n openai:\n api-key: sk-lm-zmU7SpEW:2wED8QUaU6JFaPKTbs6t\n base-url: http://localhost:1234/v1\n servlet:\n multipart:\n max-file-size: 50MB\n max-request-size: 50MB\n\nai:\n llm:\n base-url: http://localhost:1234/v1\n model: qwen\n api-key: sk-lm-zmU7SpEW:2wED8QUaU6JFaPKTbs6t\n timeout: 60000\n max-retries: 3\n temperature: 0.3\n top-p: 0.9\n max-tokens: 4096\n\nserver:\n port: 9090\n"}, "78a5329adc00125114fbe63b20f7f427a3d66090": {"t": 1785764160.0406945, "n": 296, "h": "ff591ef3f31cf4a7", "c": "spring:\n application:\n name: ai-assistant\n datasource:\n url: jdbc:postgresql://localhost:5432/ai_assistant\n username: postgres\n password: 123456\n driver-class-name: org.postgresql.Driver\n\n ai:\n openai:\n api-key: sk-lm-zmU7SpEW:2wED8QUaU6JFaPKTbs6t\n\nserver:\n port: 9090\n"}}}}