Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/alansonder_ai-assistant.json
T

1 line
120 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"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<ChatRequest.Message> messages)` - 多消息对话(同步)\n- `chatWithHistory(String systemPrompt, String userPrompt, List<ChatRequest.Message> history)` - 带历史记录的对话\n- `chatStream(String systemPrompt, String userPrompt)` - 单轮流式对话,返回 `Flux<String>`\n- `chatStream(List<ChatRequest.Message> 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<String>`\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\\<Content\\>),含图片+文本混合内容\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 标签隔离**: 使用 `<text>`/`<context>` 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<String>`\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<Message> messages)` - 多消息对话\n- `chatWithHistory(String systemPrompt, String userPrompt, List<Message> 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<Message> messages)` - 多消息对话\n- `chatWithHistory(String systemPrompt, String userPrompt, List<Message> 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<br />\n\n<br />\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"}}}}