XieXing 3 hónapja
szülő
commit
ea70467d21

+ 0 - 42
@SETUP_INSTRUCTIONS.md

@@ -1,42 +0,0 @@
-# 前端BUG修复与功能调整说明
-
-## 问题描述与功能调整
-1. **BUG修复**: 在AI对话模块中,当报告输出到一半时用户切换到其他页面再切回来,会显示为空白记录。
-2. **BUG修复**: 移动端AI对话模块中,点击报告中的文件预览组件时,由于没有移动端预览组件会显示报错。
-3. **功能调整**: 暂时隐藏AI对话报告结果中的语音朗读图标。
-4. **BUG修复**: 移动端AI对话页面语音输入(STT)无法使用,提示"当前浏览器不支持语音识别"。
-
-## 修复与调整方案
-已修改 `shudao-vue-frontend/src/views/Chat.vue` 和 `shudao-vue-frontend/src/views/mobile/m-Chat.vue` 文件,实现以下改进:
-
-1. **保持流式输出状态**: 在 `onActivated`生命周期钩子中,保留正在输出的消息(`isTyping`为true),不再将其作为已完成消息处理。
-2. **显示输出内容**: 确保切换回来时,未完成的消息也能正常显示已输出的内容。
-3. **移动端PDF预览**: 在移动端引入了 `MobilePdfViewer` 组件,并在文件预览弹窗中针对 PDF 文件使用该组件进行渲染,解决了预览报错的问题。
-4. **隐藏语音朗读**: 使用 `v-if="false"` 隐藏了PC端和移动端AI对话报告结果中的语音朗读按钮。
-5. **修复语音输入**: 修正了移动端Chat页面语音输入功能的逻辑,移除了导致误判的浏览器支持性检查,现在可以正常启动语音识别。
-
-## 需要测试的功能
-1. **流式输出保持**:
-   - 开始一个AI对话,等待报告输出到一半
-   - 切换到其他功能页面(如:隐患识别、政策文档等)
-   - 切换回AI对话页面
-   - 验证:正在输出的报告内容应该保持显示,且仍在继续输出
-
-2. **移动端文件预览**:
-   - 在移动端AI对话中,生成包含PDF文件的报告
-   - 点击文件预览按钮
-   - 验证: PDF文件能够正常加载和显示,没有报错
-
-3. **语音朗读图标**:
-   - 检查PC端和移动端AI对话页面
-   - 验证: 报告结果下方的操作栏中不再显示语音朗读图标
-
-4. **移动端语音输入**:
-   - 在移动端AI对话页面点击输入框右侧的语音按钮
-   - 验证: 能够正常启动录音,并显示录音状态指示器
-
-## 注意事项
-- 本次修改仅涉及前端Vue组件
-- 不需要执行任何终端命令
-- 不需要重新编译或重启服务
-- 修改将在保存后立即生效(热更新)

+ 0 - 402
INTEGRATION_GUIDE.md

@@ -1,402 +0,0 @@
-# 4A统一API网关集成指南
-
-本文档说明如何在其他系统中调用4A统一API网关服务。
-
-## 服务地址
-
-| 环境 | 地址 |
-|------|------|
-| 本地开发 | http://localhost:28004 |
-| 测试环境 | http://localhost:28004 |
-| 线上环境 | https://aqai.shudaodsj.com:22000/auth |
-
-## 接口调用示例
-
-### 1. 票据获取
-
-获取SSO单点登录票据。
-
-```python
-import requests
-
-# 本地/测试环境
-url = "http://localhost:28004/api/ticket/get"
-# 线上环境
-# url = "https://aqai.shudaodsj.com:22000/auth/api/ticket/get"
-
-response = requests.post(url, json={
-    "mobile": "17800000001",  # 可选,不传使用默认值
-    "app_code": "SDJD_AQAI"   # 可选,不传使用默认值
-})
-
-result = response.json()
-# 返回: {"retCode": "1000", "ssoTicket": "..."}
-```
-
-### 2. 票据解析
-
-解析票据获取用户信息。
-
-```python
-url = "http://localhost:28004/api/ticket/analyze"
-
-response = requests.post(url, json={
-    "ticket_data": "oXlMiYSOLhJAYP3Qo7Zwps..."  # 从票据获取接口得到的ssoTicket
-})
-
-result = response.json()
-# 返回: {"retCode": "1000", "token": "...", "userInfo": {...}}
-```
-
-### 3. 票据处理+JWT生成(推荐)
-
-一步完成票据解析和JWT Token生成。
-
-```python
-url = "http://localhost:28004/api/ticket/process"
-
-response = requests.post(url, json={
-    "ticket_data": "oXlMiYSOLhJAYP3Qo7Zwps..."
-})
-
-result = response.json()
-# 返回:
-# {
-#     "retCode": "1000",
-#     "message": "处理成功",
-#     "ticket_token": "...",
-#     "username": "张三",
-#     "refresh_token": "eyJ...",
-#     "token_type": "bearer",
-#     "expires_in": 43200
-# }
-```
-
-### 4. JWT Token生成
-
-根据用户信息生成JWT Token。
-
-```python
-url = "http://localhost:28004/auth/tokens"
-
-response = requests.post(url, json={
-    "accountID": "user001",
-    "name": "张三",
-    "userCode": "N1234567",
-    "contactNumber": "13800138000"
-})
-
-result = response.json()
-# 返回:
-# {
-#     "access_token": "eyJ...",
-#     "refresh_token": "eyJ...",
-#     "token_type": "bearer",
-#     "expires_in": 43200
-# }
-```
-
-### 5. JWT Token验证
-
-验证Token是否有效。
-
-```python
-url = "http://localhost:28004/auth/verify"
-
-response = requests.post(url, json={
-    "token": "eyJ..."
-})
-
-result = response.json()
-# 返回:
-# {
-#     "valid": true,
-#     "token_type": "refresh",
-#     "accountID": "user001",
-#     "name": "张三",
-#     "userCode": "N1234567",
-#     "contactNumber": "13800138000",
-#     "exp": 1702857600
-# }
-```
-
-### 6. 账号查询
-
-分页查询从账号。
-
-```python
-url = "http://localhost:28004/api/account/query"
-
-response = requests.post(url, json={
-    "cur_page": 1,
-    "page_size": 10,
-    "user_code": "N1234567",  # 可选
-    "user_name": "张三",       # 可选,支持模糊匹配
-    "org_code": "NG5596477"   # 可选
-})
-
-result = response.json()
-# 返回: {"success": true, "data": [...], "recordsTotal": 100, ...}
-```
-
-### 7. 账号添加
-
-```python
-url = "http://localhost:28004/api/account/add"
-
-response = requests.post(url, json={
-    "user_code": "N1234567",
-    "org_code": "NG5596477",
-    "org_name": "蜀道投资集团有限责任公司"
-})
-```
-
-### 8. 账号修改
-
-```python
-url = "http://localhost:28004/api/account/modify"
-
-response = requests.post(url, json={
-    "account_id": "aizscs001",
-    "org_code": "NG5596477"
-})
-```
-
-### 9. 账号删除
-
-```python
-url = "http://localhost:28004/api/account/delete"
-
-response = requests.post(url, json={
-    "account_id": "aizscs001"
-})
-```
-
-## 线上环境注意事项
-
-线上环境通过Nginx代理,路径前缀为 `/auth`:
-
-```python
-# 本地/测试
-base_url = "http://localhost:28004"
-
-# 线上
-base_url = "https://aqai.shudaodsj.com:22000/auth"
-
-# 调用示例
-ticket_url = f"{base_url}/api/ticket/get"
-auth_url = f"{base_url}/auth/tokens"
-```
-
-## 错误处理
-
-所有接口返回统一格式:
-
-```json
-// 成功
-{"retCode": "1000", "msg": "成功", ...}
-
-// 失败
-{"detail": "错误信息"}
-```
-
-HTTP状态码:
-- 200: 成功
-- 400: 请求参数错误
-- 422: 参数验证失败
-- 500: 服务器内部错误
-
-## 健康检查
-
-```python
-response = requests.get("http://localhost:28004/health")
-# 返回: {"status": "healthy", "service": "unified-api-gateway"}
-```
-
----
-
-## Go调用示例
-
-### 1. 票据获取
-
-```go
-package main
-
-import (
-    "bytes"
-    "encoding/json"
-    "fmt"
-    "io"
-    "net/http"
-)
-
-const baseURL = "http://localhost:28004" // 线上: https://aqai.shudaodsj.com:22000/auth
-
-type TicketRequest struct {
-    Mobile  string `json:"mobile,omitempty"`
-    AppCode string `json:"app_code,omitempty"`
-}
-
-type TicketResponse struct {
-    RetCode   string `json:"retCode"`
-    SSOTicket string `json:"ssoTicket"`
-}
-
-func GetTicket() (*TicketResponse, error) {
-    reqBody, _ := json.Marshal(TicketRequest{})
-    resp, err := http.Post(baseURL+"/api/ticket/get", "application/json", bytes.NewBuffer(reqBody))
-    if err != nil {
-        return nil, err
-    }
-    defer resp.Body.Close()
-
-    body, _ := io.ReadAll(resp.Body)
-    var result TicketResponse
-    json.Unmarshal(body, &result)
-    return &result, nil
-}
-```
-
-### 2. 票据处理+JWT生成
-
-```go
-type TicketProcessRequest struct {
-    TicketData string `json:"ticket_data"`
-}
-
-type TicketProcessResponse struct {
-    RetCode      string `json:"retCode"`
-    Message      string `json:"message"`
-    TicketToken  string `json:"ticket_token"`
-    Username     string `json:"username"`
-    RefreshToken string `json:"refresh_token"`
-    TokenType    string `json:"token_type"`
-    ExpiresIn    int    `json:"expires_in"`
-}
-
-func ProcessTicket(ticketData string) (*TicketProcessResponse, error) {
-    reqBody, _ := json.Marshal(TicketProcessRequest{TicketData: ticketData})
-    resp, err := http.Post(baseURL+"/api/ticket/process", "application/json", bytes.NewBuffer(reqBody))
-    if err != nil {
-        return nil, err
-    }
-    defer resp.Body.Close()
-
-    body, _ := io.ReadAll(resp.Body)
-    var result TicketProcessResponse
-    json.Unmarshal(body, &result)
-    return &result, nil
-}
-```
-
-### 3. JWT Token生成
-
-```go
-type UserInfo struct {
-    AccountID     string `json:"accountID"`
-    Name          string `json:"name"`
-    UserCode      string `json:"userCode"`
-    ContactNumber string `json:"contactNumber"`
-}
-
-type TokenResponse struct {
-    AccessToken  string `json:"access_token"`
-    RefreshToken string `json:"refresh_token"`
-    TokenType    string `json:"token_type"`
-    ExpiresIn    int    `json:"expires_in"`
-}
-
-func CreateTokens(user UserInfo) (*TokenResponse, error) {
-    reqBody, _ := json.Marshal(user)
-    resp, err := http.Post(baseURL+"/auth/tokens", "application/json", bytes.NewBuffer(reqBody))
-    if err != nil {
-        return nil, err
-    }
-    defer resp.Body.Close()
-
-    body, _ := io.ReadAll(resp.Body)
-    var result TokenResponse
-    json.Unmarshal(body, &result)
-    return &result, nil
-}
-```
-
-### 4. JWT Token验证
-
-```go
-type VerifyRequest struct {
-    Token string `json:"token"`
-}
-
-type VerifyResponse struct {
-    Valid         bool   `json:"valid"`
-    TokenType     string `json:"token_type"`
-    AccountID     string `json:"accountID"`
-    Name          string `json:"name"`
-    UserCode      string `json:"userCode"`
-    ContactNumber string `json:"contactNumber"`
-    Exp           int64  `json:"exp"`
-}
-
-func VerifyToken(token string) (*VerifyResponse, error) {
-    reqBody, _ := json.Marshal(VerifyRequest{Token: token})
-    resp, err := http.Post(baseURL+"/auth/verify", "application/json", bytes.NewBuffer(reqBody))
-    if err != nil {
-        return nil, err
-    }
-    defer resp.Body.Close()
-
-    body, _ := io.ReadAll(resp.Body)
-    var result VerifyResponse
-    json.Unmarshal(body, &result)
-    return &result, nil
-}
-```
-
-### 5. 账号查询
-
-```go
-type AccountQueryRequest struct {
-    CurPage  int    `json:"cur_page"`
-    PageSize int    `json:"page_size"`
-    UserCode string `json:"user_code,omitempty"`
-    UserName string `json:"user_name,omitempty"`
-    OrgCode  string `json:"org_code,omitempty"`
-}
-
-func QueryAccounts(req AccountQueryRequest) (map[string]interface{}, error) {
-    reqBody, _ := json.Marshal(req)
-    resp, err := http.Post(baseURL+"/api/account/query", "application/json", bytes.NewBuffer(reqBody))
-    if err != nil {
-        return nil, err
-    }
-    defer resp.Body.Close()
-
-    body, _ := io.ReadAll(resp.Body)
-    var result map[string]interface{}
-    json.Unmarshal(body, &result)
-    return result, nil
-}
-```
-
-### 6. 完整调用示例
-
-```go
-func main() {
-    // 1. 获取票据
-    ticket, _ := GetTicket()
-    fmt.Printf("票据: %s\n", ticket.SSOTicket[:50])
-
-    // 2. 处理票据获取JWT
-    jwt, _ := ProcessTicket(ticket.SSOTicket)
-    fmt.Printf("用户: %s, Token: %s\n", jwt.Username, jwt.RefreshToken[:50])
-
-    // 3. 验证Token
-    verify, _ := VerifyToken(jwt.RefreshToken)
-    fmt.Printf("验证结果: %v, 用户: %s\n", verify.Valid, verify.Name)
-
-    // 4. 查询账号
-    accounts, _ := QueryAccounts(AccountQueryRequest{CurPage: 1, PageSize: 10})
-    fmt.Printf("账号总数: %v\n", accounts["recordsTotal"])
-}
-```

+ 0 - 110
REFACTOR_BATCH1_SUMMARY.md

@@ -1,110 +0,0 @@
-# 第一批次重构完成总结
-
-## 已完成的工作
-
-### 1. 配置模板创建 ✅
-- 创建了 `conf/app.conf.example` 配置模板文件
-- 包含所有环境配置项的详细说明
-- 为本地、测试、生产三个环境提供了配置示例
-
-### 2. 配置管理工具增强 ✅
-- 重写了 `utils/config.go`,提供统一的配置读取接口:
-  - `GetConfigString()` - 获取字符串配置(带默认值)
-  - `MustGetConfigString()` - 获取必需配置(缺失时panic)
-  - `GetBaseURL()` - 获取系统基础URL
-  - `GetProxyURL()` - 生成OSS代理URL(不再硬编码)
-  - `GetMySQLConfig()` - 获取MySQL配置
-  - `GetOSSConfig()` - 获取OSS配置
-  - `GetYOLOBaseURL()` - 获取YOLO服务地址
-  - `GetAuthAPIURL()` - 获取认证服务地址
-  - `GetKnowledgeSearchURL()` - 获取知识库搜索地址
-  - `GetDifyWorkflowURL()` - 获取Dify工作流地址
-
-### 3. 控制器硬编码替换 ✅
-已替换以下文件中的硬编码配置:
-
-#### `controllers/hazard.go`
-- ✅ 第122-126行: YOLO API地址
-- 修改前: `yoloBaseURL = "http://172.16.35.50:18080"`
-- 修改后: `yoloBaseURL := utils.GetYOLOBaseURL()`
-
-#### `controllers/shudaooss.go`
-- ✅ 第29-36行: OSS配置(bucket, access_key, secret_key, endpoint)
-- 修改前: 硬编码的全局变量
-- 修改后: 在`init()`函数中从配置读取
-
-#### `controllers/chroma.go`
-- ✅ 第9行: 添加utils包导入
-- ✅ 第94行: 知识库搜索API地址
-- 修改前: `apiURL := "https://aqai.shudaodsj.com:22000/admin/api/v1/knowledge/files/advanced-search"`
-- 修改后: `apiURL := utils.GetKnowledgeSearchURL()`
-
-#### `controllers/chat.go`
-- ✅ 第3001行: Dify工作流URL(OnlineSearch方法)
-- ✅ 第3713行: Dify工作流URL(内部方法)
-- 修改前: `"http://172.16.35.50:8000/v1/workflows/run"`
-- 修改后: `utils.GetDifyWorkflowURL()`
-
-### 4. Git配置更新 ✅
-- 更新了 `.gitignore`,将 `shudao-go-backend/conf/app.conf` 加入忽略列表
-- 确保敏感配置不会被提交到版本控制
-
-## 配置文件使用说明
-
-### 首次部署步骤:
-1. 复制配置模板:
-   ```bash
-   cp shudao-go-backend/conf/app.conf.example shudao-go-backend/conf/app.conf
-   ```
-
-2. 根据部署环境编辑 `app.conf`,填写实际配置值:
-   - 本地环境: 使用本地服务地址(127.0.0.1, localhost)
-   - 测试环境: 使用测试服务器地址
-   - 生产环境: 使用生产服务器地址
-
-3. 启动服务:
-   ```bash
-   cd shudao-go-backend
-   bee run  # 本地开发(支持热重载)
-   # 或
-   go run main.go  # 直接运行
-   ```
-
-## 待完成工作(第二批次)
-
-### 代码清理
-- [ ] 删除 `views/liushitest.vue`
-- [ ] 移动或删除 `views/*.html` 测试文件
-- [ ] 处理 `controllers/chat.go` 和 `models/chat.go`(已弃用但前端可能依赖)
-
-### 其他硬编码检查
-- [ ] 检查 `controllers/oss.go` 中的硬编码
-- [ ] 检查 `controllers/test.go` 中的硬编码
-- [ ] 全局搜索确认没有遗漏的硬编码IP地址
-
-## 注意事项
-
-⚠️ **重要提醒**:
-1. `app.conf` 文件已加入 `.gitignore`,不会被Git追踪
-2. 每个环境(本地/测试/生产)需要手动创建和维护各自的 `app.conf`
-3. 部署前务必检查配置文件是否正确填写
-4. 敏感信息(密钥、密码)不要提交到版本控制
-
-## 验证方法
-
-1. 检查配置是否生效:
-   - 启动服务后查看日志,确认连接的是正确的数据库和服务地址
-   - 测试文件上传功能,验证OSS配置
-   - 测试隐患识别功能,验证YOLO服务配置
-
-2. 检查热重载:
-   - 使用 `bee run` 启动
-   - 修改代码文件
-   - 观察是否自动重新编译
-
-## 下一步建议
-
-建议按以下顺序执行:
-1. 先在本地环境测试配置文件功能
-2. 确认所有功能正常后,再部署到测试环境
-3. 测试环境验证通过后,最后部署到生产环境

+ 0 - 55
REFACTOR_FINAL_REPORT.md

@@ -1,55 +0,0 @@
-# 后端重构完成总结报告
-
-## 1. 重构概览
-本次重构主要解决了后端项目的环境隔离问题、硬编码问题以及代码清理。现在项目已经具备了良好的配置管理机制,支持多环境无侵入切换。
-
-## 2. 已完成工作
-
-### 2.1 配置收拢 (Batch 1)
-- **配置模板**: 创建了 `conf/app.conf.example`,包含所有环境配置项及说明。
-- **配置工具**: 增强了 `utils/config.go`,提供类型安全的配置读取方法。
-- **硬编码替换**:
-  - `controllers/hazard.go`: YOLO服务地址。
-  - `controllers/shudaooss.go`: OSS配置。
-  - `controllers/chroma.go`: 知识库搜索地址。
-  - `controllers/chat.go`: Dify工作流地址。
-- **Git忽略**: 更新 `.gitignore` 忽略 `conf/app.conf`。
-
-### 2.2 代码清理与安全 (Batch 2)
-- **前端残留清理**:
-  - 移除了 `views/liushitest.vue`。
-  - 将测试HTML文件从 `views/` 移动到 `tests/test_pages/`。
-- **弃用代码标记**:
-  - `controllers/chat.go`: 添加弃用说明(核心逻辑已迁移微服务)。
-  - `models/chat.go`: 添加弃用说明。
-  - `controllers/oss.go`: 标记为弃用,建议使用 `shudaooss.go`。
-- **安全增强**:
-  - 修复了 `controllers/oss.go` 和 `controllers/test.go` 中的硬编码敏感凭据,改为从配置读取。
-
-### 2.3 文档与验证 (Batch 3)
-- **部署文档**: 创建了 `DEPLOY.md`,指导新环境部署。
-- **重构计划**: `REFACTOR_PLAN.md` 记录了规划过程。
-
-## 3. 验证指南
-
-### 3.1 本地验证
-1. 复制配置: `cp shudao-go-backend/conf/app.conf.example shudao-go-backend/conf/app.conf`
-2. 填写本地配置(如数据库连本地,OSS连测试环境)。
-3. 运行: `bee run`
-4. 验证接口: 调用 `/api/health` 或其他基础接口。
-
-### 3.2 关键检查点
-- [x] **OSS上传**: 确认 `shudaooss.go` 能正确读取配置并上传文件。
-- [x] **隐患识别**: 确认 `hazard.go` 能正确调用配置的YOLO服务。
-- [x] **联网搜索**: 确认 `chat.go` 能正确调用配置的Dify工作流。
-
-## 4. 遗留事项与建议
-- **前端路由**: `controllers/frontend.go` 中的测试页面路由目前指向新的测试文件位置,如果需要使用这些测试页面,请确保Beego能找到它们(可能需要调整ViewPath或恢复文件位置仅供开发使用)。建议后续完全移除这些后端渲染的测试页面,改用Postman或独立前端测试工具。
-- **弃用代码**: 待前端完全切换到微服务后,应彻底删除 `controllers/chat.go` 和 `models/chat.go`。
-
-## 5. 交付物清单
-- `REFACTOR_PLAN.md`: 重构规划
-- `REFACTOR_BATCH1_SUMMARY.md`: 第一批次总结
-- `DEPLOY.md`: 部署指南
-- `shudao-go-backend/conf/app.conf.example`: 配置模板
-- 修改后的源代码文件

+ 0 - 151
REFACTOR_PLAN.md

@@ -1,151 +0,0 @@
-# 后端重构与环境隔离规划
-
-## 1. 技术锐评 (Technical Review)
-
-### 1.1 架构层面
-*   **环境隔离缺失**:当前主要依赖在 `app.conf` 中手动注释/取消注释代码块来切换环境(如 MySQL 配置、认证地址)。这种方式极易出错,且难以在 CI/CD 流程中自动化。
-*   **硬编码泛滥**:
-    *   `utils/config.go` 中直接硬编码了生产环境 URL (`https://aqai.shudaodsj.com:22000`)。
-    *   `controllers/` 下多个文件(`shudaooss.go`, `hazard.go`, `chroma.go` 等)硬编码了 IP 地址和端口(如 `172.16.17.52:8060`, `172.16.35.50:18080`)。
-    *   这导致代码与特定部署环境强耦合,本地开发和测试环境极易连接到错误的服务(如本地连上了生产库)。
-*   **部署差异**:由于配置散落在代码中,部署到新环境(如测试环境)需要修改源码并重新编译,违反了 "Build Once, Run Anywhere" 原则。
-
-### 1.2 代码层面
-*   **配置管理混乱**:没有统一的配置加载层。有的配置在 `app.conf`,有的在 `utils`,有的直接在 `controllers` 的常量或变量中。
-*   **代码位置不当**:
-    *   `views/` 目录下存在 `.vue` 文件 (`liushitest.vue`) 和测试 HTML 文件,这些是前端源码或临时测试文件,不应出现在 Go 后端项目的构建目录中。
-    *   `chat.go` 被标记为已弃用但仍存在于项目中,造成维护困扰。
-*   **可测试性差**:由于依赖硬编码的外部服务地址,单元测试难以在隔离环境下运行(必须有网络且对应 IP 可达)。
-
-### 1.3 重构难度评估
-*   **成本**:**中等**。主要工作量在于全局搜索硬编码字符串并替换为配置读取逻辑。
-*   **风险**:**低**。只要严格遵循"只读配置,不改逻辑"的原则,业务逻辑不会受影响。主要风险在于遗漏某些隐蔽的硬编码值。
-
----
-
-## 2. 重构方案 (Refactoring Strategy)
-
-### 2.1 核心原则
-1.  **单一数据源**:所有可变参数必须且只能在 `conf/app.conf` 中定义。代码中严禁出现 IP、端口、URL、密钥等字面量。
-2.  **环境无侵入**:代码不感知当前是 "dev" 还是 "prod",它只管读取配置。环境差异由 `app.conf` 的内容决定。
-3.  **本地热重载**:利用 Beego 框架自带的 `bee run` 命令实现本地开发热重载。
-
-### 2.2 配置文件管理策略
-根据您的要求,采用 **"单文件 + 模板"** 策略:
-
-1.  **`conf/app.conf`**:
-    *   **加入 `.gitignore`**。
-    *   这是实际生效的配置文件,由开发者/运维在部署时手动创建和维护。
-2.  **`conf/app.conf.example`** (新增):
-    *   **加入版本控制 (Git)**。
-    *   包含所有必要的配置项 Key,Value 留空或设为默认占位符。
-    *   包含详细的注释,说明每个配置项在不同环境(本地、测试、生产)应填写的典型值。
-
-### 2.3 目录结构调整建议
-```text
-shudao-go-backend/
-├── conf/
-│   ├── app.conf          (被 git 忽略,实际配置)
-│   └── app.conf.example  (新增,配置模板,含所有环境说明)
-├── utils/
-│   └── config.go         (增强,提供类型安全的配置读取方法)
-├── controllers/          (移除硬编码,改为调用 utils.GetConfig)
-├── views/                (清理 .vue 和测试 html)
-└── ...
-```
-
----
-
-## 3. 执行批次 (Execution Batches)
-
-### 第一批次:配置收拢与标准化 (Configuration Centralization)
-**目标**:消除代码中的硬编码,建立统一配置读取机制。
-
-1.  **创建配置模板 `conf/app.conf.example`**:
-    *   整理所有散落在 `app.conf` 和代码中的配置项。
-    *   为 MySQL, Redis, OSS, YOLO, Chroma, DeepSeek, Qwen 等所有外部服务定义标准的 Key 命名(如 `oss_endpoint`, `yolo_base_url`)。
-    *   添加注释说明本地、测试、生产环境的推荐值。
-2.  **增强 `utils/config.go`**:
-    *   封装 Beego 的 `AppConfig`,提供如 `GetString(key)`, `MustGetString(key)` 等方法,确保配置缺失时能快速报错(Fail Fast)。
-    *   **修正**:修改 `GetProxyURL` 方法,不再硬编码域名,而是从配置读取 `base_url`。
-3.  **替换 Controller 硬编码**:
-    *   `controllers/shudaooss.go`: 替换 `ossEndpoint` 为配置读取。
-    *   `controllers/hazard.go`: 替换 `yoloBaseURL` 为配置读取。
-    *   `controllers/chroma.go`: 替换 `apiURL` 为配置读取。
-    *   `controllers/chat.go`: 替换 `http://172.16.35.50:8000` 等硬编码地址。
-
-### 第二批次:代码清理与环境准备 (Cleanup & Environment Setup)
-**目标**:清理废弃代码和无关文件,确保项目纯净。
-
-1.  **清理前端残留**:
-    *   删除 `views/liushitest.vue`。
-    *   移动或删除 `views/*.html` 测试文件(如果必须保留,移至 `tests/test_data/` 或类似目录,不要混在视图层)。
-2.  **处理弃用代码**:
-    *   将 `controllers/chat.go` 和 `models/chat.go` 移动到 `_deprecated/` 目录(或直接删除,如果确认无用),并在文件名加 `_deprecated` 后缀,防止误引用。
-    *   *注意:如果前端仍依赖某些接口路径,需确认微服务网关是否已接管这些路径。如果后端仍需保留接口定义但转发流量,需重写为代理模式(Proxy)。鉴于您提到"前端有用",建议先保留文件但清理内部逻辑,或确认前端调用地址已变更。*
-3.  **本地热重载验证**:
-    *   确认开发环境安装了 `bee` 工具。
-    *   使用 `bee run` 启动项目,验证修改文件后是否自动重新编译。
-
-### 第三批次:验证与文档 (Verification)
-**目标**:确保重构后各环境功能正常。
-
-1.  **本地环境验证**:
-    *   复制 `app.conf.example` 为 `app.conf`。
-    *   配置为本地参数(连接本地/开发库)。
-    *   启动服务,验证基础接口。
-2.  **测试/生产环境验证指南**:
-    *   编写 `DEPLOY.md`,说明在新环境部署时如何准备 `app.conf`。
-
----
-
-## 4. 风险点与检查清单 (Risks & Checklist)
-
-*   [ ] **风险**:`app.conf` 中的 Key 命名变更导致旧代码读取失败。
-    *   **对策**:在 `utils/config.go` 中使用 `MustGet` 类方法,如果配置缺失直接 Panic,避免静默失败。
-*   [ ] **风险**:OSS 或第三方服务的 URL 拼接逻辑错误(如多加了 `/`)。
-    *   **对策**:统一使用 `strings.TrimRight(url, "/")` 处理配置项。
-*   [ ] **风险**:`chat.go` 删除导致前端旧版本报错。
-    *   **对策**:暂时保留 `chat.go` 文件,但将其内部逻辑标记为 `Deprecated`,并确认前端请求是否已路由到微服务。
-
-## 5. 附录:app.conf.example 预览
-
-```ini
-appname = shudao-chat-go
-httpport = 22001
-runmode = dev
-
-# ==========================================
-# 基础配置 (Base Config)
-# ==========================================
-# 本地: https://127.0.0.1:22000
-# 生产: https://aqai.shudaodsj.com:22000
-base_url = "https://aqai.shudaodsj.com:22000"
-
-# ==========================================
-# 数据库配置 (Database)
-# ==========================================
-mysql_user = "root"
-mysql_pass = "password"
-mysql_urls = "127.0.0.1"
-mysql_port = "3306"
-mysql_db   = "shudao"
-
-# ==========================================
-# 外部服务 (External Services)
-# ==========================================
-# 认证服务
-auth_api_url = "http://127.0.0.1:28004/api/auth/verify"
-
-# OSS 配置
-oss_endpoint = "http://172.16.17.52:8060"
-oss_access_key = "..."
-oss_secret_key = "..."
-oss_bucket = "gdsc-ai-aqzs"
-
-# 模型服务
-deepseek_api_url = "https://api.deepseek.com"
-deepseek_api_key = "..."
-
-yolo_base_url = "http://172.16.35.50:18080"
-```

+ 739 - 0
api-docs.html

@@ -0,0 +1,739 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>蜀道安全AI系统 - API接口文档</title>
+    <style>
+        * { margin: 0; padding: 0; box-sizing: border-box; }
+        body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #fafafa; color: #3b4151; }
+        .header { background: linear-gradient(135deg, #1f8a70 0%, #2d5a4a 100%); color: white; padding: 20px 30px; }
+        .header h1 { font-size: 28px; margin-bottom: 5px; }
+        .header p { opacity: 0.9; font-size: 14px; }
+        .container { max-width: 1800px; margin: 0 auto; padding: 20px; }
+        .api-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; }
+        .api-card { background: white; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.12); overflow: hidden; }
+        .api-card-header { padding: 12px 15px; display: flex; align-items: center; gap: 10px; border-bottom: 1px solid #eee; }
+        .method { padding: 4px 10px; border-radius: 4px; font-size: 11px; font-weight: 700; color: white; text-transform: uppercase; }
+        .method.get { background: #61affe; }
+        .method.post { background: #49cc90; }
+        .api-path { font-family: monospace; font-size: 13px; color: #3b4151; word-break: break-all; }
+        .api-card-body { padding: 12px 15px; }
+        .api-title { font-size: 14px; font-weight: 600; color: #3b4151; margin-bottom: 8px; }
+        .api-desc { font-size: 12px; color: #6b7280; line-height: 1.5; margin-bottom: 10px; }
+        .params-title { font-size: 11px; font-weight: 600; color: #1f8a70; margin-bottom: 5px; text-transform: uppercase; }
+        .param-item { font-size: 11px; color: #4b5563; padding: 3px 0; border-bottom: 1px dashed #e5e7eb; }
+        .param-item:last-child { border-bottom: none; }
+        .param-name { font-family: monospace; color: #1f8a70; font-weight: 500; }
+        .param-type { color: #9ca3af; font-size: 10px; }
+        .section-title { font-size: 18px; font-weight: 600; color: #1f8a70; margin: 25px 0 15px; padding-bottom: 8px; border-bottom: 2px solid #1f8a70; }
+        .tag { display: inline-block; padding: 2px 6px; background: #e0f2f1; color: #1f8a70; border-radius: 3px; font-size: 10px; margin-right: 5px; }
+        .response-tag { background: #fef3c7; color: #92400e; }
+        @media (max-width: 1200px) { .api-grid { grid-template-columns: repeat(2, 1fr); } }
+        @media (max-width: 768px) { .api-grid { grid-template-columns: 1fr; } }
+    </style>
+</head>
+<body>
+    <div class="header">
+        <h1>🛡️ 蜀道安全AI系统 API文档</h1>
+        <p>ShuDao SafeAI Backend API v1.0 | 基础路径: /apiv1</p>
+    </div>
+    <div class="container">
+
+        <!-- 认证接口 -->
+        <h2 class="section-title">🔐 认证接口</h2>
+        <div class="api-grid">
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/auth/local_login</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">本地登录</div>
+                    <div class="api-desc">用户名密码登录,返回JWT Token(需配置enable_local_login=true)</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">username</span> <span class="param-type">string</span> - 用户名</div>
+                    <div class="param-item"><span class="param-name">password</span> <span class="param-type">string</span> - 密码</div>
+                    <div class="params-title" style="margin-top:8px">响应</div>
+                    <div class="param-item"><span class="tag response-tag">200</span> token, userInfo</div>
+                </div>
+            </div>
+        </div>
+
+        <!-- AI对话接口 -->
+        <h2 class="section-title">💬 AI对话接口</h2>
+        <div class="api-grid">
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/send_deepseek_message</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">发送DeepSeek消息</div>
+                    <div class="api-desc">发送消息到AI模型,支持安全培训PPT生成、AI写作等业务类型</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">message</span> <span class="param-type">string</span> - 用户消息</div>
+                    <div class="param-item"><span class="param-name">ai_conversation_id</span> <span class="param-type">uint64</span> - 对话ID(可选)</div>
+                    <div class="param-item"><span class="param-name">business_type</span> <span class="param-type">int</span> - 业务类型(1:安全培训,2:AI写作)</div>
+                    <div class="param-item"><span class="param-name">exam_name</span> <span class="param-type">string</span> - 考试名称(可选)</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/stream/chat</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">流式聊天 (SSE)</div>
+                    <div class="api-desc">流式输出AI回复,支持RAG检索增强生成</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">message</span> <span class="param-type">string</span> - 用户消息</div>
+                    <div class="param-item"><span class="param-name">model</span> <span class="param-type">string</span> - 模型名称(可选)</div>
+                    <div class="params-title" style="margin-top:8px">响应</div>
+                    <div class="param-item"><span class="tag">SSE</span> text/event-stream</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/stream/chat-with-db</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">流式聊天(数据库集成)</div>
+                    <div class="api-desc">流式聊天并自动保存对话记录到数据库</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">message</span> <span class="param-type">string</span> - 用户消息</div>
+                    <div class="param-item"><span class="param-name">ai_conversation_id</span> <span class="param-type">uint64</span> - 对话ID</div>
+                    <div class="param-item"><span class="param-name">business_type</span> <span class="param-type">int</span> - 业务类型</div>
+                    <div class="param-item"><span class="param-name">online_search_content</span> <span class="param-type">string</span> - 联网搜索内容</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/get_history_record</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取历史记录</div>
+                    <div class="api-desc">获取当前用户的AI对话历史记录列表</div>
+                    <div class="params-title">请求参数</div>
+                    <div class="param-item">无参数,从Token获取用户ID</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/delete_conversation</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">删除对话</div>
+                    <div class="api-desc">删除指定的AI对话</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">ai_conversation_id</span> <span class="param-type">uint64</span> - 对话ID</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/delete_history_record</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">删除历史记录</div>
+                    <div class="api-desc">删除指定的历史记录</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">id</span> <span class="param-type">uint64</span> - 记录ID</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/intent_recognition</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">意图识别</div>
+                    <div class="api-desc">识别用户输入的意图类型</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">message</span> <span class="param-type">string</span> - 用户消息</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/get_chromadb_document</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取ChromaDB文档</div>
+                    <div class="api-desc">从向量数据库检索相关文档并生成回答</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">query</span> <span class="param-type">string</span> - 查询内容</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/guess_you_want</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">猜你想问</div>
+                    <div class="api-desc">根据上下文推荐相关问题</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">context</span> <span class="param-type">string</span> - 上下文内容</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/get_user_recommend_question</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">用户输入推荐问题</div>
+                    <div class="api-desc">用户输入时实时返回推荐问题</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">input</span> <span class="param-type">string</span> - 用户输入内容</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/online_search</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">联网搜索</div>
+                    <div class="api-desc">执行联网搜索获取实时信息</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">query</span> <span class="param-type">string</span> - 搜索关键词</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/save_online_search_result</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">保存联网搜索结果</div>
+                    <div class="api-desc">将联网搜索结果存入AIMessage表</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">content</span> <span class="param-type">string</span> - 搜索结果内容</div>
+                    <div class="param-item"><span class="param-name">ai_message_id</span> <span class="param-type">uint64</span> - 消息ID</div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 考试相关接口 -->
+        <h2 class="section-title">📝 考试相关接口</h2>
+        <div class="api-grid">
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/exam/build_prompt</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">生成考试提示词</div>
+                    <div class="api-desc">根据考试配置生成AI提示词</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">exam_config</span> <span class="param-type">object</span> - 考试配置对象</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/exam/build_single_prompt</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">单题生成提示词</div>
+                    <div class="api-desc">为单个题目重新生成提示词</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">question_type</span> <span class="param-type">string</span> - 题目类型</div>
+                    <div class="param-item"><span class="param-name">context</span> <span class="param-type">string</span> - 上下文</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/re_modify_question</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">修改考试题目</div>
+                    <div class="api-desc">修改已生成的考试题目内容</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">ai_conversation_id</span> <span class="param-type">uint64</span> - 对话ID</div>
+                    <div class="param-item"><span class="param-name">content</span> <span class="param-type">string</span> - 新内容</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/re_produce_single_question</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">重新生成单题</div>
+                    <div class="api-desc">重新生成指定的单个考试题目</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">question_id</span> <span class="param-type">uint64</span> - 题目ID</div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 隐患识别接口 -->
+        <h2 class="section-title">🔍 隐患识别接口</h2>
+        <div class="api-grid">
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/hazard</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">隐患识别</div>
+                    <div class="api-desc">使用YOLO模型识别图片中的安全隐患,返回标注后的图片</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">scene_name</span> <span class="param-type">string</span> - 场景名称(模型类型)</div>
+                    <div class="param-item"><span class="param-name">image</span> <span class="param-type">string</span> - 图片OSS链接</div>
+                    <div class="param-item"><span class="param-name">date</span> <span class="param-type">string</span> - 日期</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/save_step</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">保存步骤</div>
+                    <div class="api-desc">保存PPT生成步骤、JSON文件和封面图</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">ai_conversation_id</span> <span class="param-type">uint64</span> - 对话ID</div>
+                    <div class="param-item"><span class="param-name">step</span> <span class="param-type">int</span> - 步骤编号</div>
+                    <div class="param-item"><span class="param-name">ppt_json_url</span> <span class="param-type">string</span> - PPT JSON URL</div>
+                    <div class="param-item"><span class="param-name">cover_image</span> <span class="param-type">string</span> - 封面图URL</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/get_history_recognition_record</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取识别历史记录</div>
+                    <div class="api-desc">获取当前用户的隐患识别历史记录</div>
+                    <div class="params-title">请求参数</div>
+                    <div class="param-item">无参数,从Token获取用户ID</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/get_recognition_record_detail</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取识别记录详情</div>
+                    <div class="api-desc">获取指定识别记录的详细信息</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">recognition_record_id</span> <span class="param-type">int64</span> - 记录ID</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/delete_recognition_record</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">删除识别记录</div>
+                    <div class="api-desc">删除指定的隐患识别历史记录</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">id</span> <span class="param-type">uint64</span> - 记录ID</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/submit_evaluation</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">提交点评</div>
+                    <div class="api-desc">用户对识别结果提交点评反馈</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">id</span> <span class="param-type">uint</span> - 记录ID</div>
+                    <div class="param-item"><span class="param-name">scene_match</span> <span class="param-type">int</span> - 场景匹配度</div>
+                    <div class="param-item"><span class="param-name">tip_accuracy</span> <span class="param-type">int</span> - 提示准确度</div>
+                    <div class="param-item"><span class="param-name">effect_evaluation</span> <span class="param-type">int</span> - 效果评价</div>
+                    <div class="param-item"><span class="param-name">user_remark</span> <span class="param-type">string</span> - 用户备注</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/get_latest_recognition_record</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取最新识别记录</div>
+                    <div class="api-desc">查询用户最新的一条识别记录是否已点评</div>
+                    <div class="params-title">请求参数</div>
+                    <div class="param-item">无参数,从Token获取用户ID</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/get_third_scene_example_image</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取三级场景示例图</div>
+                    <div class="api-desc">获取隐患识别三级场景的正确和错误示例图</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">third_scene_name</span> <span class="param-type">string</span> - 三级场景名称</div>
+                </div>
+            </div>
+        </div>
+
+        <!-- OSS文件上传接口 -->
+        <h2 class="section-title">📁 OSS文件上传接口</h2>
+        <div class="api-grid">
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/oss/upload</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取上传凭证</div>
+                    <div class="api-desc">生成S3预签名上传凭证,用于前端直传OSS</div>
+                    <div class="params-title">响应</div>
+                    <div class="param-item"><span class="param-name">url</span> - 上传地址</div>
+                    <div class="param-item"><span class="param-name">fields</span> - 签名字段</div>
+                    <div class="param-item"><span class="param-name">expire</span> - 过期时间</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/oss/shudao/upload_image</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">上传图片</div>
+                    <div class="api-desc">上传图片到OSS,自动压缩到200KB以下</div>
+                    <div class="params-title">请求参数 (FormData)</div>
+                    <div class="param-item"><span class="param-name">image</span> <span class="param-type">file</span> - 图片文件(≤10MB)</div>
+                    <div class="params-title" style="margin-top:8px">响应</div>
+                    <div class="param-item"><span class="param-name">fileUrl</span> - 代理访问URL</div>
+                    <div class="param-item"><span class="param-name">fileName</span> - 文件名</div>
+                    <div class="param-item"><span class="param-name">fileSize</span> - 文件大小</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/oss/shudao/upload_json</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">上传PPT JSON文件</div>
+                    <div class="api-desc">上传PPT配置JSON文件到OSS</div>
+                    <div class="params-title">请求参数 (FormData)</div>
+                    <div class="param-item"><span class="param-name">json</span> <span class="param-type">file</span> - JSON文件(≤50MB)</div>
+                    <div class="params-title" style="margin-top:8px">响应</div>
+                    <div class="param-item"><span class="param-name">fileUrl</span> - 代理访问URL</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/oss/parse</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">OSS代理解析</div>
+                    <div class="api-desc">代理转发OSS URL请求,解密并获取文件内容</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">url</span> <span class="param-type">string</span> - 加密的OSS URL</div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 通用功能接口 -->
+        <h2 class="section-title">🔧 通用功能接口</h2>
+        <div class="api-grid">
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/recommend_question</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取推荐问题</div>
+                    <div class="api-desc">随机返回推荐问题列表</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">limit</span> <span class="param-type">int</span> - 数量(默认5)</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/get_function_card</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取功能卡片</div>
+                    <div class="api-desc">随机返回4条功能卡片</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">function_type</span> <span class="param-type">int</span> - 类型(0:AI问答,1:安全培训)</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/get_hot_question</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取热点问题</div>
+                    <div class="api-desc">随机返回4条热点问题</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">question_type</span> <span class="param-type">int</span> - 类型(0:AI问答,1:安全培训)</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/submit_feedback</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">提交意见反馈</div>
+                    <div class="api-desc">用户提交意见反馈信息</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">content</span> <span class="param-type">string</span> - 反馈内容</div>
+                    <div class="param-item"><span class="param-name">contact</span> <span class="param-type">string</span> - 联系方式</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/like_and_dislike</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">点赞/踩</div>
+                    <div class="api-desc">对AI回复进行点赞或踩的反馈</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">id</span> <span class="param-type">uint</span> - 消息ID</div>
+                    <div class="param-item"><span class="param-name">user_feedback</span> <span class="param-type">int</span> - 反馈(1:赞,-1:踩)</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/get_user_data_id</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取用户数据ID</div>
+                    <div class="api-desc">根据account_id获取用户数据主键ID</div>
+                    <div class="params-title">请求参数</div>
+                    <div class="param-item">无参数,从Token获取account_id</div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 政策文件接口 -->
+        <h2 class="section-title">📄 政策文件接口</h2>
+        <div class="api-grid">
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/get_policy_file</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取政策文件列表</div>
+                    <div class="api-desc">分页获取政策文件列表,支持类型筛选和搜索</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">policy_type</span> <span class="param-type">int</span> - 政策类型(0:全部)</div>
+                    <div class="param-item"><span class="param-name">search</span> <span class="param-type">string</span> - 搜索关键词</div>
+                    <div class="param-item"><span class="param-name">page</span> <span class="param-type">int</span> - 页码</div>
+                    <div class="param-item"><span class="param-name">pageSize</span> <span class="param-type">int</span> - 每页数量</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/download_file</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">下载文件</div>
+                    <div class="api-desc">从OSS链接下载文件并返回给前端</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">pdf_oss_download_link</span> <span class="param-type">string</span> - OSS下载链接</div>
+                    <div class="param-item"><span class="param-name">file_name</span> <span class="param-type">string</span> - 自定义文件名(可选)</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/policy_file_count</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">政策文件统计</div>
+                    <div class="api-desc">政策文件查看和下载次数+1</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">policy_file_id</span> <span class="param-type">int</span> - 政策文件ID</div>
+                    <div class="param-item"><span class="param-name">action_type</span> <span class="param-type">int</span> - 操作类型(1:查看,2:下载)</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/get_file_link</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取文件链接</div>
+                    <div class="api-desc">根据文件名从数据库查找对应的OSS链接</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">file_name</span> <span class="param-type">string</span> - 文件名</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/knowledge/files/advanced-search</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">知识库高级搜索</div>
+                    <div class="api-desc">从ChromaDB向量数据库进行高级文件搜索</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">query_str</span> <span class="param-type">string</span> - 查询字符串</div>
+                    <div class="param-item"><span class="param-name">n_results</span> <span class="param-type">int</span> - 结果数量(默认50)</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/save_ppt_outline</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">保存PPT大纲</div>
+                    <div class="api-desc">保存AI生成的PPT大纲内容</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">ai_conversation_id</span> <span class="param-type">uint64</span> - 对话ID</div>
+                    <div class="param-item"><span class="param-name">outline</span> <span class="param-type">string</span> - 大纲内容</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/save_edit_document</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">保存编辑文档</div>
+                    <div class="api-desc">AI写作保存编辑后的文档内容</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">ai_message_id</span> <span class="param-type">uint64</span> - 消息ID</div>
+                    <div class="param-item"><span class="param-name">content</span> <span class="param-type">string</span> - 文档内容</div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 积分系统接口 -->
+        <h2 class="section-title">💰 积分系统接口</h2>
+        <div class="api-grid">
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/points/balance</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取积分余额</div>
+                    <div class="api-desc">获取当前用户的积分余额</div>
+                    <div class="params-title">请求参数</div>
+                    <div class="param-item">无参数,从Token获取用户ID</div>
+                    <div class="params-title" style="margin-top:8px">响应</div>
+                    <div class="param-item"><span class="param-name">points</span> - 积分余额</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/points/consume</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">消费积分</div>
+                    <div class="api-desc">消费积分下载文件(每次10积分)</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">file_name</span> <span class="param-type">string</span> - 文件名</div>
+                    <div class="param-item"><span class="param-name">file_url</span> <span class="param-type">string</span> - 文件URL</div>
+                    <div class="params-title" style="margin-top:8px">响应</div>
+                    <div class="param-item"><span class="param-name">new_balance</span> - 新余额</div>
+                    <div class="param-item"><span class="param-name">points_consumed</span> - 消费积分</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/points/history</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取消费记录</div>
+                    <div class="api-desc">分页获取用户的积分消费历史记录</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">page</span> <span class="param-type">int</span> - 页码(默认1)</div>
+                    <div class="param-item"><span class="param-name">pageSize</span> <span class="param-type">int</span> - 每页数量(默认10)</div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 埋点记录接口 -->
+        <h2 class="section-title">📊 埋点记录接口</h2>
+        <div class="api-grid">
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/tracking/record</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">记录埋点数据</div>
+                    <div class="api-desc">记录用户行为埋点数据</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">api_path</span> <span class="param-type">string</span> - 接口路径</div>
+                    <div class="param-item"><span class="param-name">method</span> <span class="param-type">string</span> - 请求方法</div>
+                    <div class="param-item"><span class="param-name">extra_data</span> <span class="param-type">string</span> - 额外数据(可选)</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/tracking/records</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取埋点记录</div>
+                    <div class="api-desc">分页获取埋点记录列表</div>
+                    <div class="params-title">请求参数 (Query)</div>
+                    <div class="param-item"><span class="param-name">user_id</span> <span class="param-type">int</span> - 用户ID(可选)</div>
+                    <div class="param-item"><span class="param-name">api_path</span> <span class="param-type">string</span> - 接口路径(可选)</div>
+                    <div class="param-item"><span class="param-name">page</span> <span class="param-type">int</span> - 页码(默认1)</div>
+                    <div class="param-item"><span class="param-name">page_size</span> <span class="param-type">int</span> - 每页数量(默认20)</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method post">POST</span>
+                    <span class="api-path">/apiv1/tracking/api_mapping</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">添加接口映射</div>
+                    <div class="api-desc">添加接口路径到名称的映射关系</div>
+                    <div class="params-title">请求参数 (Body JSON)</div>
+                    <div class="param-item"><span class="param-name">api_path</span> <span class="param-type">string</span> - 接口路径</div>
+                    <div class="param-item"><span class="param-name">api_name</span> <span class="param-type">string</span> - 接口名称</div>
+                    <div class="param-item"><span class="param-name">api_desc</span> <span class="param-type">string</span> - 接口描述(可选)</div>
+                </div>
+            </div>
+            <div class="api-card">
+                <div class="api-card-header">
+                    <span class="method get">GET</span>
+                    <span class="api-path">/apiv1/tracking/api_mappings</span>
+                </div>
+                <div class="api-card-body">
+                    <div class="api-title">获取接口映射列表</div>
+                    <div class="api-desc">获取所有接口路径映射关系</div>
+                    <div class="params-title">请求参数</div>
+                    <div class="param-item">无参数</div>
+                </div>
+            </div>
+        </div>
+
+        <div style="text-align:center; padding:30px; color:#9ca3af; font-size:12px;">
+            <p>蜀道安全AI系统 API文档 v1.0 | 共 <strong>45</strong> 个接口</p>
+            <p>基础路径: <code>/apiv1</code> | 认证方式: JWT Token (Header: Authorization)</p>
+            <p>生成时间: 2024年12月</p>
+        </div>
+    </div>
+</body>
+</html>

+ 1 - 1
shudao-vue-frontend/src/services/audioTranscription.js

@@ -43,7 +43,7 @@ export async function transcribeAudio({ file, userId }) {
     formData.append('user_id', userId)
   }
 
-  const response = await audioClient.post('/audio_to_text', formData, {
+  const response = await audioClient.post('', formData, {
     headers: {
       'Content-Type': 'multipart/form-data'
     }

+ 0 - 63
移动客户端与H5对接规范.md

@@ -1,63 +0,0 @@
-# 移动客户端与H5对接规范
-
-# 一、概述
-
-在移动互联网技术发展成熟的今天,为了更好的满足app快速研发、及时更新、模块分离等需要;在原生应用中集成H5页面也越来越重要和常见。因此需要制定良好的规范以提高软件整体质量及研发效率。
-
-# 二、集成形式及系统环境
-
-## (一) 集成形式
-
-简单来说,就是把H5放到客户端中加载。为了更好的提升体验,客户端要保证H5容器的稳定和性能,
-
-客户端需要为H5提供加载容器及基本的能力支持,如:上传文件、定位、错误处理。
-
-## (二) 宿主系统环境
-
-Android:最低支持Android 8.0 系统,浏览器内核为Chrome;
-
-iOS:最低支持iOS 13系统,浏览器内核为WebKit。
-
-针对上述宿主环境,H5业务系统需要做兼容性适配。
-
-# 三、集成要求
-
-## (一) 单点登录
-
-1. app访问H5业务系统时,首先调用该系统接口获取授权token,然后按照该业务系统要求携带相关参数访问业务系统h5链接,实现单点登录。
-
-2. 针对业务系统无权限用户,需要返回给app单独的错误码和错误提示信息。
-
-3. 如使用4a作为认证,在访问业务系统时,无权限账户要进行友好提示。
-
-## (二) 导航栏设计
-
-1. 建议使用app原生导航栏,app会监听h5页面标题的变化并进行展示。
-
-2. 如受到业务系统限制不能使用app原生导航栏,需要调用交互关闭导航栏。
-
-3. H5页面自定义导航栏的情况下,需要适配安全区并且需要增加关闭原生页面的交互。
-
-## (三)  H5与app交互
-
-为了保证业务系统功能完善、性能优良,对接时往往需要支持多种交互。
-
-### 3.1 返回上一级与关闭页面
-
-在使用app原生导航栏的情况下,建议同时添加“返回webGoBack()”和“关闭页面(nativeClosePage())”这两个交互来实现返回上一级、关闭页面的功能;如业务系统评估不需要增加,则app根据webview返回栈调用返回和关闭。
-
-### 3.2 当前支持的交互
-
-当前支持的交互内容如下表所列,H5业务系统可以按照需要使用;如需要增加新的交互,可协商添加。
-
-|序号|功能|交互名称|动作(需求)表述|交互集成建议|备注|
-|---|---|---|---|---|---|
-|1|返回与关闭|webGoBack()|H5提供JS返回方法,供原生调用|建议集成|点击原生返回按钮时调用,由h5执行返回逻辑|
-|||finishPage()|JS调用原生交互关闭当前页面|建议集成||
-|2|原生导航控制|showNativeNav(show)|JS调用原生方法关闭/显示导航栏|按需|参数show:0隐藏,1显示|
-|3|下载文件|downloadFile(url)|JS调用原生方法下载文件;下载后自动预览|按需|对于H5不支持查看(或需要下载)的文件,需要通知原生进行下载查看。参数url:下载地址的全路径。|
-|4|扫描二维码|startScan()|JS调用原生方法扫描二维码|按需||
-|5||setScanResult(String result)|原生将扫码结果传递给h5|按需||
-|6|请求定位权限|requestLocPerm()|JS调用原生方法请求获取定位权限|按需||
-|||getLocationCallback()|原生通知定位权限获取成功|按需||
-|7|打电话|callPhone(tel)|JS调用原生方法拨打电话|按需||