Compare commits

...
2 Commits
Author SHA1 Message Date
eaiadmin 9de09dfa72 Merge branch 'main' of gitea: keep local product name eai_agentplatform_app
Resolved conflict in docs/微趣MyGPT调研与办公智能体架构对比.md:
kept HEAD (local) product name eai_agentplatform_app over remote eaisalestrain_app
2026-09-14 01:03:29 +08:00
eaiadminandClaude Code 0455f064ac feat: 新增语音转文字(ASR)功能
- 后端:新增 /api/audio/transcribe 接口,调用 Ollama whisper 进行语音识别
- 前端:新增 AudioTranscribePage.vue 页面,支持 MP3/WAV/M4A/OGG/FLAC 等格式
- 注册路由、工具卡片、智能助手欢迎语更新

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-14 00:53:36 +08:00
299 changed files with 818 additions and 433 deletions
+8 -5
View File
@@ -1,4 +1,4 @@
# eaisalestrain_app 博昇内部培训平台 — 编码与调试最高准则
# eai_agentplatform_app 博昇内部培训平台 — 编码与调试最高准则
> **版本:V1.0**
> **日期:2026-08-15**
@@ -16,7 +16,7 @@
# 第一部分:通用开发规则
> **适用范围**:适用于 eaisalestrain_app 及 EAIHub 下其他涉及 FastAPI/Vue3/AI 的项目。
> **适用范围**:适用于 eai_agentplatform_app 及 EAIHub 下其他涉及 FastAPI/Vue3/AI 的项目。
> **使用方式**:新任务开始前应先通读本部分;项目专用规则(P)在遵守本部分基础上叠加。
## 索引
@@ -112,10 +112,13 @@
## G06 原则:AI 助手行为规范
1. **任务启动预读**:AI 助手在接收到新任务后的第一步操作中,必须读取本项目根目录下的 `CODING_RULES.md` 与 `eaisalestrain_app/CLAUDE.md`。
1. **任务启动预读**:AI 助手在接收到新任务后的第一步操作中,必须读取本项目根目录下的 `CODING_RULES.md` 与 `eai_agentplatform_app/CLAUDE.md`。
2. **持续追踪**:直到问题完全解决并经由日志或接口验证通过前,不得结束任务。
3. **新对话启动仪式**:新对话必须先读 `eaisalestrain_app/PROJECT_STATE.md` → `CODING_RULES.md`,再开始干活。
3. **新对话启动仪式**:新对话必须先读 `eai_agentplatform_app/PROJECT_STATE.md` → `CODING_RULES.md`,再开始干活。
4. **发现规则与实现冲突时**,优先提醒并修正,不得静默忽略。
5. **Git 同步状态必须用 `-sb` 显式确认**:首次执行 git 相关操作时,必须使用 `git status -sb` 或 `git status -v` 而非简短版本,确保能清晰看到本地与远端的 ahead/behind 关系。禁止依赖 `git diff HEAD origin/HEAD` 单条链式命令判断,因其 `&&` 链在中间出错时会导致后续输出丢失。
6. **Git 检查必须指定分支名**:使用 `origin/<branch>`(如 `origin/main`)而非 `origin/HEAD`,避免 `origin/HEAD` 歧义。
7. **验证输出后再总结**:在给出 git 状态结论前,必须确认所有关键信息(ahead/behind、clean/dirty、branch)均已成功读取,不得在未确认完整性的情况下返回结论。
---
@@ -138,7 +141,7 @@
---
# 第二部分:eaisalestrain_app 项目专用规则
# 第二部分:eai_agentplatform_app 项目专用规则
> **适用范围**:仅适用于博昇内部培训平台项目。
> **使用方式**:本部分在通用规则之上叠加。若两者看似冲突,应先检查是否为项目专用规则对通用规则的场景化收敛。
@@ -55,22 +55,22 @@
### 品牌与布局
- `eaisalestrain_app/frontend/src/layout/SideNav.vue`
- `eaisalestrain_app/frontend/src/layout/SectionTabs.vue`
- `eaisalestrain_app/frontend/src/views/Login.vue`
- `eaisalestrain_app/frontend/src/views/home/HomePage.vue`
- `eaisalestrain_app/frontend/src/views/exam/MyCertificates.vue`
- `eai_agentplatform_app/frontend/src/layout/SideNav.vue`
- `eai_agentplatform_app/frontend/src/layout/SectionTabs.vue`
- `eai_agentplatform_app/frontend/src/views/Login.vue`
- `eai_agentplatform_app/frontend/src/views/home/HomePage.vue`
- `eai_agentplatform_app/frontend/src/views/exam/MyCertificates.vue`
### 导航与路由
- `eaisalestrain_app/frontend/src/config/navigation.js`
- `eaisalestrain_app/frontend/src/router/index.js`
- `eai_agentplatform_app/frontend/src/config/navigation.js`
- `eai_agentplatform_app/frontend/src/router/index.js`
### 系统配置页面
- `eaisalestrain_app/frontend/src/views/system/CompanyConfigPage.vue`
- `eaisalestrain_app/frontend/src/views/system/SystemConfigPage.vue`
- `eaisalestrain_app/frontend/src/views/system/AiUsage.vue`
- `eai_agentplatform_app/frontend/src/views/system/CompanyConfigPage.vue`
- `eai_agentplatform_app/frontend/src/views/system/SystemConfigPage.vue`
- `eai_agentplatform_app/frontend/src/views/system/AiUsage.vue`
## 当前状态
@@ -12,7 +12,7 @@
## 1. 项目定位
**eaisalestrain_app**(博昇内部培训平台)是一个纯内网本地化部署的内部专属员工培训系统,并以此为基础演进为知识库中心化的智能体平台。
**eai_agentplatform_app**(博昇内部培训平台)是一个纯内网本地化部署的内部专属员工培训系统,并以此为基础演进为知识库中心化的智能体平台。
**核心价值(V1 已交付):**
- 新人快速了解公司文化和业务
@@ -19,8 +19,8 @@
相关参考文档:
- [SY03_Knowledge_Centric_Agent_Platform_Strategy.md](file:///home/eaiadmin/eaifiles/codebase/pj0231-eaisalestraining/docs/01_System_Overall/SY03_Knowledge_Centric_Agent_Platform_Strategy.md)
- [09_Research/wechat/叶小钗](file:///home/eaiadmin/eaifiles/codebase/pj0231-eaisalestraining/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97)(专家/专家团、任务系统、生产级 Agent 工程清单)
- [SY03_Knowledge_Centric_Agent_Platform_Strategy.md](file:///home/eaiadmin/eaifiles/codebase/pj0231-eai_agentplatforming/docs/01_System_Overall/SY03_Knowledge_Centric_Agent_Platform_Strategy.md)
- [09_Research/wechat/叶小钗](file:///home/eaiadmin/eaifiles/codebase/pj0231-eai_agentplatforming/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97)(专家/专家团、任务系统、生产级 Agent 工程清单)
- [SY15_Terminology_Benchmark_Ontology_Semantic_Layer_Object_Layer.md](file:///home/eaiadmin/eaifiles/codebase/pj0235-eai_agentplatform/docs/01_System_Overall/SY15_Terminology_Benchmark_Ontology_Semantic_Layer_Object_Layer.md)
- [SY16_Ontology_Generalizes_Data_Actions_And_Workflows.md](file:///home/eaiadmin/eaifiles/codebase/pj0235-eai_agentplatform/docs/01_System_Overall/SY16_Ontology_Generalizes_Data_Actions_And_Workflows.md)
@@ -339,6 +339,6 @@ SY03 在业务方向上提出“知识底座 + 智能体矩阵 + 半定制工坊
- 本文档:SY04(平台升级分析、分层、UI、落地路线)
- 研究材料已入库:
- [09_Research/wechat/叶小钗](file:///home/eaiadmin/eaifiles/codebase/pj0231-eaisalestraining/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97)
- [生产级Agent实践指南/PAG00](file:///home/eaiadmin/eaifiles/codebase/pj0231-eaisalestraining/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/%E7%94%9F%E4%BA%A7%E7%BA%A7Agent%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/PAG00_%E5%90%88%E9%9B%86%E6%80%BB%E8%A7%88_%E6%91%98%E8%A6%81%E4%B8%8E%E5%B7%A5%E7%A8%8B%E6%A3%80%E6%9F%A5%E5%8D%95_01-14.md)
- [PAG14](file:///home/eaiadmin/eaifiles/codebase/pj0231-eaisalestraining/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/%E7%94%9F%E4%BA%A7%E7%BA%A7Agent%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/PAG14_%E7%AC%AC14%E7%AF%87_%E5%A4%9AAagent%E7%BC%96%E6%8E%92%E4%B8%8E%E4%BB%BB%E5%8A%A1%E7%B3%BB%E7%BB%9F_%E4%BB%8E%E4%B8%80%E6%AC%A1%E5%A7%94%E6%B4%BE%E5%88%B0%E4%BB%BB%E5%8A%A1%E5%B7%A5%E4%BD%9C%E6%B5%81.md)
- [09_Research/wechat/叶小钗](file:///home/eaiadmin/eaifiles/codebase/pj0231-eai_agentplatforming/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97)
- [生产级Agent实践指南/PAG00](file:///home/eaiadmin/eaifiles/codebase/pj0231-eai_agentplatforming/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/%E7%94%9F%E4%BA%A7%E7%BA%A7Agent%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/PAG00_%E5%90%88%E9%9B%86%E6%80%BB%E8%A7%88_%E6%91%98%E8%A6%81%E4%B8%8E%E5%B7%A5%E7%A8%8B%E6%A3%80%E6%9F%A5%E5%8D%95_01-14.md)
- [PAG14](file:///home/eaiadmin/eaifiles/codebase/pj0231-eai_agentplatforming/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/%E7%94%9F%E4%BA%A7%E7%BA%A7Agent%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/PAG14_%E7%AC%AC14%E7%AF%87_%E5%A4%9AAagent%E7%BC%96%E6%8E%92%E4%B8%8E%E4%BB%BB%E5%8A%A1%E7%B3%BB%E7%BB%9F_%E4%BB%8E%E4%B8%80%E6%AC%A1%E5%A7%94%E6%B4%BE%E5%88%B0%E4%BB%BB%E5%8A%A1%E5%B7%A5%E4%BD%9C%E6%B5%81.md)
+1 -1
View File
@@ -81,7 +81,7 @@ from fastapi import FastAPI
from app.api import auth, company_train, product, sales_train
from app.api import exam, media, ai_chat, system
app = FastAPI(title="eaisalestrain_app", version="1.1.0")
app = FastAPI(title="eai_agentplatform_app", version="1.1.0")
# 异常处理器
@app.exception_handler(AppError)
+4 -4
View File
@@ -80,7 +80,7 @@ location /api/ {
# 媒体文件预览(仅内部)
location /media/ {
alias /opt/eaisalestrain/backend/data/media/;
alias /opt/eai_agentplatform/backend/data/media/;
internal;
}
@@ -95,8 +95,8 @@ services:
mysql:
image: mysql:8.0
environment:
MYSQL_DATABASE: eaisalestrain
MYSQL_USER: eaisalestrain
MYSQL_DATABASE: eai_agentplatform
MYSQL_USER: eai_agentplatform
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
@@ -104,7 +104,7 @@ services:
backend:
build: ./backend
environment:
DATABASE_URL: mysql+pymysql://eaisalestrain:${DB_PASSWORD}@mysql:3306/eaisalestrain
DATABASE_URL: mysql+pymysql://eai_agentplatform:${DB_PASSWORD}@mysql:3306/eai_agentplatform
JWT_SECRET: ${JWT_SECRET}
LLM_BASE_URL: http://llm-server:11434/v1
volumes:
@@ -22,7 +22,7 @@
## 2. 完整目录结构(定稿)
```
eaisalestrain_app/
eai_agentplatform_app/
├── docs/
│ └── knowledge_source/ # 知识源文档(权威源,纳入 git 版本管理)
│ ├── README.md # 格式契约 + 答案契约 + 审批状态机
@@ -1,7 +1,7 @@
# 工作流画布交互设计调研报告
> **版本:V2.0 | 最后更新:2026-08-17**
> **目标产品:eaisalestrain-app · 数字员工平台 · 工坊(Studio)**
> **目标产品:eai_agentplatform-app · 数字员工平台 · 工坊(Studio)**
---
+4 -4
View File
@@ -11,10 +11,10 @@
## 已整理
- [RE01_AgentScope_WorkBuddy_专家与专家团机制_2026-08-12.md](file:///home/eaiadmin/eaifiles/codebase/pj0231-eaisalestraining/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/RE01_AgentScope_WorkBuddy_%E4%B8%93%E5%AE%B6%E4%B8%8E%E4%B8%93%E5%AE%B6%E5%9B%A2%E6%9C%BA%E5%88%B6_2026-08-12.md)
- [RE02_mini-openclaw_多Agent编排与任务系统_delegate_task_2026-08-15.md](file:///home/eaiadmin/eaifiles/codebase/pj0231-eaisalestraining/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/RE02_mini-openclaw_%E5%A4%9AAagent%E7%BC%96%E6%8E%92%E4%B8%8E%E4%BB%BB%E5%8A%A1%E7%B3%BB%E7%BB%9F_delegate_task_2026-08-15.md)
- [RE03_WorkBuddy培训复盘_业务团队崛起产研紧张_日期未提供.md](file:///home/eaiadmin/eaifiles/codebase/pj0231-eaisalestraining/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/RE03_WorkBuddy%E5%9F%B9%E8%AE%AD%E5%A4%8D%E7%9B%98_%E4%B8%9A%E5%8A%A1%E5%9B%A2%E9%98%9F%E5%B4%9B%E8%B5%B7%E4%BA%A7%E7%A0%94%E7%B4%A7%E5%BC%A0_%E6%97%A5%E6%9C%9F%E6%9C%AA%E6%8F%90%E4%BE%9B.md)
- [RE01_AgentScope_WorkBuddy_专家与专家团机制_2026-08-12.md](file:///home/eaiadmin/eaifiles/codebase/pj0231-eai_agentplatforming/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/RE01_AgentScope_WorkBuddy_%E4%B8%93%E5%AE%B6%E4%B8%8E%E4%B8%93%E5%AE%B6%E5%9B%A2%E6%9C%BA%E5%88%B6_2026-08-12.md)
- [RE02_mini-openclaw_多Agent编排与任务系统_delegate_task_2026-08-15.md](file:///home/eaiadmin/eaifiles/codebase/pj0231-eai_agentplatforming/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/RE02_mini-openclaw_%E5%A4%9AAagent%E7%BC%96%E6%8E%92%E4%B8%8E%E4%BB%BB%E5%8A%A1%E7%B3%BB%E7%BB%9F_delegate_task_2026-08-15.md)
- [RE03_WorkBuddy培训复盘_业务团队崛起产研紧张_日期未提供.md](file:///home/eaiadmin/eaifiles/codebase/pj0231-eai_agentplatforming/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/RE03_WorkBuddy%E5%9F%B9%E8%AE%AD%E5%A4%8D%E7%9B%98_%E4%B8%9A%E5%8A%A1%E5%9B%A2%E9%98%9F%E5%B4%9B%E8%B5%B7%E4%BA%A7%E7%A0%94%E7%B4%A7%E5%BC%A0_%E6%97%A5%E6%9C%9F%E6%9C%AA%E6%8F%90%E4%BE%9B.md)
## 合集
- 生产级 Agent 实践指南:[README.md](file:///home/eaiadmin/eaifiles/codebase/pj0231-eaisalestraining/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/%E7%94%9F%E4%BA%A7%E7%BA%A7Agent%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/README.md)
- 生产级 Agent 实践指南:[README.md](file:///home/eaiadmin/eaifiles/codebase/pj0231-eai_agentplatforming/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/%E7%94%9F%E4%BA%A7%E7%BA%A7Agent%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/README.md)
@@ -15,7 +15,7 @@
## 清单
- [PAG00_合集总览_摘要与工程检查单_01-14.md](file:///home/eaiadmin/eaifiles/codebase/pj0231-eaisalestraining/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/%E7%94%9F%E4%BA%A7%E7%BA%A7Agent%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/PAG00_%E5%90%88%E9%9B%86%E6%80%BB%E8%A7%88_%E6%91%98%E8%A6%81%E4%B8%8E%E5%B7%A5%E7%A8%8B%E6%A3%80%E6%9F%A5%E5%8D%95_01-14.md)
- [PAG00_合集总览_摘要与工程检查单_01-14.md](file:///home/eaiadmin/eaifiles/codebase/pj0231-eai_agentplatforming/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/%E7%94%9F%E4%BA%A7%E7%BA%A7Agent%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/PAG00_%E5%90%88%E9%9B%86%E6%80%BB%E8%A7%88_%E6%91%98%E8%A6%81%E4%B8%8E%E5%B7%A5%E7%A8%8B%E6%A3%80%E6%9F%A5%E5%8D%95_01-14.md)
- PAG01_第01篇_Agent的定义与环境搭建_2026-05-31.md
- PAG02_第02篇_一次LLM_API调用_2026-06-02.md
- PAG03_第03篇_FunctionCalling原理_2026-06-06.md
@@ -29,4 +29,4 @@
- PAG11_第11篇_上下文压缩_长会话持续工作.md
- PAG12_第12篇_Agent记忆_长期记忆与短期记忆.md
- PAG13_第13篇_多Agent_协作原理与任务委派实现.md
- [PAG14_第14篇_多Agent编排与任务系统_从一次委派到任务工作流.md](file:///home/eaiadmin/eaifiles/codebase/pj0231-eaisalestraining/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/%E7%94%9F%E4%BA%A7%E7%BA%A7Agent%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/PAG14_%E7%AC%AC14%E7%AF%87_%E5%A4%9AAagent%E7%BC%96%E6%8E%92%E4%B8%8E%E4%BB%BB%E5%8A%A1%E7%B3%BB%E7%BB%9F_%E4%BB%8E%E4%B8%80%E6%AC%A1%E5%A7%94%E6%B4%BE%E5%88%B0%E4%BB%BB%E5%8A%A1%E5%B7%A5%E4%BD%9C%E6%B5%81.md)
- [PAG14_第14篇_多Agent编排与任务系统_从一次委派到任务工作流.md](file:///home/eaiadmin/eaifiles/codebase/pj0231-eai_agentplatforming/docs/09_Research/wechat/%E5%8F%B6%E5%B0%8F%E9%92%97/%E7%94%9F%E4%BA%A7%E7%BA%A7Agent%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/PAG14_%E7%AC%AC14%E7%AF%87_%E5%A4%9AAagent%E7%BC%96%E6%8E%92%E4%B8%8E%E4%BB%BB%E5%8A%A1%E7%B3%BB%E7%BB%9F_%E4%BB%8E%E4%B8%80%E6%AC%A1%E5%A7%94%E6%B4%BE%E5%88%B0%E4%BB%BB%E5%8A%A1%E5%B7%A5%E4%BD%9C%E6%B5%81.md)
+1 -1
View File
@@ -1,4 +1,4 @@
# eaisalestrain_app 博昇内部培训平台 — 产品需求文档
# eai_agentplatform_app 博昇内部培训平台 — 产品需求文档
> **版本:V1.1 最终版(V1 培训底座基线)| 纯本地化部署 | 极简架构 | 全功能闭环**
> **最后更新:2026-08-15**
+2 -2
View File
@@ -1,4 +1,4 @@
# eaisalestrain_app — API 文档
# eai_agentplatform_app — API 文档
> **版本:V1.1 | 协议:HTTP/JSON | 认证:JWT Bearer**
> **最后更新:2026-08-15**
@@ -570,7 +570,7 @@ data: {"type": "done"}
```json
{
"status": "ok",
"service": "eaisalestrain-app",
"service": "eai_agentplatform-app",
"version": "1.1.0"
}
```
+4 -4
View File
@@ -1,4 +1,4 @@
# eaisalestrain_app — 变更日志
# eai_agentplatform_app — 变更日志
> **最后更新:2026-08-16**
@@ -122,9 +122,9 @@
**目录重构 + 全功能联调测试 + 修复 1 个缺陷。**
### 变更
- `docs/`(设计文档)从 `eaisalestrain_app/` 移出到仓库根 `pj0231-eaisalestraining/docs/`,与 `CODING_RULES.md` 平级
- `docs/`(设计文档)从 `eai_agentplatform_app/` 移出到仓库根 `pj0231-eai_agentplatforming/docs/`,与 `CODING_RULES.md` 平级
- `knowledge_source/`(知识源运行时数据)从 `docs/` 移入 `backend-go/knowledge_source/`,归后端
- 后端 `KNOWLEDGE_SOURCE_DIR` 默认值 `../docs/knowledge_source` → `knowledge_source`;部署路径 `/opt/eaisalestrain/knowledge_source`
- 后端 `KNOWLEDGE_SOURCE_DIR` 默认值 `../docs/knowledge_source` → `knowledge_source`;部署路径 `/opt/eai_agentplatform/knowledge_source`
- 前后端全功能联调测试通过(认证/权限边界/产品/课程/考试/素材审批/知识入库/AI)
- 素材存储目录 `data/media` → `data/kb_data`,子目录三态化:`approved/`(已审批公开)、
`pending/`(待审批)、`rejected/`(已驳回);环境变量 `MEDIA_DIR` → `KB_DATA_DIR`。
@@ -145,7 +145,7 @@
- 旧 Python 后端目录 `backend/` 已整体删除,Go 后端为唯一后端
- 认证:JWT(golang-jwt)+ bcrypt;文档转换:LibreOffice + pdftotext(裸进程)
- 部署:裸进程 + systemd + Clonezilla 整盘克隆,Go 单二进制交付(无 Docker、无源码交付)
- 文件存储路径:`backend/data/media` → `data/media`(Go 后端工作目录下,部署为 `/opt/eaisalestrain/data/media`)
- 文件存储路径:`backend/data/media` → `data/media`(Go 后端工作目录下,部署为 `/opt/eai_agentplatform/data/media`)
### 说明
- `docs/` 下历史设计文档(SY/AR/BE/设计稿)中残留的 `backend/`、`backend/data/media`、
+1 -1
View File
@@ -1,4 +1,4 @@
# eaisalestrain_app — 数据库 Schema
# eai_agentplatform_app — 数据库 Schema
> **版本:V1.2 | 引擎:MySQL 8.0(关系数据)+ FAISS(向量检索)| ORM:GORM**
> **最后更新:2026-08-16**
+23 -23
View File
@@ -1,4 +1,4 @@
# eaisalestrain_app — 部署文档
# eai_agentplatform_app — 部署文档
> **版本:V1.2 | 部署模式:纯本地离线 · Go 单二进制 · MySQL 8.0 + FAISS · systemd · Clonezilla 整盘克隆**
> **最后更新:2026-08-16**
@@ -25,7 +25,7 @@
│ │
┌─────▼──────────────┐ ┌──────▼───────┐
│ Go 单二进制 │ │ Vue 静态打包 │
│ eaisalestrain- │ │ /usr/share/ │
│ eai_agentplatform- │ │ /usr/share/ │
│ server :8080 │ │ nginx/html │
│ (Gin + GORM) │ └──────────────┘
└──┬─────┬─────┬─────┘
@@ -55,7 +55,7 @@
| 服务 | 端口 | 说明 |
|------|------|------|
| Nginx | 80/443 | HTTP 反代 + 前端静态资源托管 |
| eaisalestrain-server | 8080 | Go 单二进制后端(Gin + GORM) |
| eai_agentplatform-server | 8080 | Go 单二进制后端(Gin + GORM) |
| MySQL | 3306 | MySQL 8.0 关系数据(systemd 托管 mysqld) |
| FAISS | 内嵌 | 向量索引,由 Go 后端 cgo 内嵌,索引文件 `data/faiss/` |
| LibreOffice + pdftotext | 进程内调用 | 裸进程,非容器,文档转文本 |
@@ -68,8 +68,8 @@
## 目录布局
```
/opt/eaisalestrain/
├── eaisalestrain-server # 单二进制(CGO 关闭,静态链接,约 38MB)
/opt/eai_agentplatform/
├── eai_agentplatform-server # 单二进制(CGO 关闭,静态链接,约 38MB)
├── .env # JWT 密钥、LLM 配置等
├── data/
│ ├── faiss/ # FAISS 向量索引(embedding 向量)
@@ -93,9 +93,9 @@ apt update && apt install -y nginx mysql-server libreoffice poppler-utils
> MySQL 初始化库与账号(FAISS 向量索引内嵌于后端,无需独立服务):
>
> ```sql
> CREATE DATABASE eaisalestrain DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
> CREATE USER 'eaisalestrain'@'127.0.0.1' IDENTIFIED BY '<随机密码>';
> GRANT ALL PRIVILEGES ON eaisalestrain.* TO 'eaisalestrain'@'127.0.0.1';
> CREATE DATABASE eai_agentplatform DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
> CREATE USER 'eai_agentplatform'@'127.0.0.1' IDENTIFIED BY '<随机密码>';
> GRANT ALL PRIVILEGES ON eai_agentplatform.* TO 'eai_agentplatform'@'127.0.0.1';
> FLUSH PRIVILEGES;
> ```
@@ -103,37 +103,37 @@ apt update && apt install -y nginx mysql-server libreoffice poppler-utils
```bash
# 2.1 拷贝二进制 + 建服务账号
sudo install -m 0755 eaisalestrain-server /opt/eaisalestrain/eaisalestrain-server
sudo useradd -r -s /usr/sbin/nologin eaisalestrain
sudo mkdir -p /opt/eaisalestrain/data/kb_data /opt/eaisalestrain/docs/knowledge_source
sudo chown -R eaisalestrain:eaisalestrain /opt/eaisalestrain
sudo install -m 0755 eai_agentplatform-server /opt/eai_agentplatform/eai_agentplatform-server
sudo useradd -r -s /usr/sbin/nologin eai_agentplatform
sudo mkdir -p /opt/eai_agentplatform/data/kb_data /opt/eai_agentplatform/docs/knowledge_source
sudo chown -R eai_agentplatform:eai_agentplatform /opt/eai_agentplatform
# 2.2 生成 .env(JWT 密钥随机)
sudo -u eaisalestrain cp deploy/eaisalestrain.env /opt/eaisalestrain/.env
sudo -u eai_agentplatform cp deploy/eai_agentplatform.env /opt/eai_agentplatform/.env
NEW_SECRET=$(python3 -c "import secrets; print(secrets.token_urlsafe(48))")
sudo sed -i "s|^JWT_SECRET=.*|JWT_SECRET=$NEW_SECRET|" /opt/eaisalestrain/.env
sudo sed -i "s|^JWT_SECRET=.*|JWT_SECRET=$NEW_SECRET|" /opt/eai_agentplatform/.env
# 2.3 安装 systemd 单元并启动
sudo install -m 0644 deploy/eaisalestrain.service /etc/systemd/system/eaisalestrain.service
sudo install -m 0644 deploy/eai_agentplatform.service /etc/systemd/system/eai_agentplatform.service
sudo systemctl daemon-reload
sudo systemctl enable --now eaisalestrain
sudo systemctl enable --now eai_agentplatform
# 2.4 验证
curl http://127.0.0.1:8080/api/health # {"status":"ok","service":"eaisalestrain-app",...}
curl http://127.0.0.1:8080/api/health # {"status":"ok","service":"eai_agentplatform-app",...}
```
`.env` 关键项:
```bash
PORT=8080
DB_DSN=eaisalestrain:<随机密码>@tcp(127.0.0.1:3306)/eaisalestrain?charset=utf8mb4&parseTime=True&loc=Local
DB_DSN=eai_agentplatform:<随机密码>@tcp(127.0.0.1:3306)/eai_agentplatform?charset=utf8mb4&parseTime=True&loc=Local
JWT_SECRET=<48 字符随机串,交付前生成>
LLM_BASE_URL=http://127.0.0.1:11434/v1
LLM_MODEL=qwen2.5:7b
EMBED_MODEL=bge-m3
FAISS_INDEX_DIR=data/faiss
KB_DATA_DIR=data/kb_data
KNOWLEDGE_SOURCE_DIR=/opt/eaisalestrain/docs/knowledge_source
KNOWLEDGE_SOURCE_DIR=/opt/eai_agentplatform/docs/knowledge_source
LIBREOFFICE_BIN=/usr/bin/libreoffice
PDFTOTEXT_BIN=/usr/bin/pdftotext
```
@@ -205,10 +205,10 @@ python -m vllm.entrypoints.openai.api_server \
## 启动/停止
```bash
sudo systemctl restart eaisalestrain # 重启
sudo systemctl stop eaisalestrain # 停止
sudo systemctl status eaisalestrain # 状态 / 日志
journalctl -u eaisalestrain -f # 实时日志
sudo systemctl restart eai_agentplatform # 重启
sudo systemctl stop eai_agentplatform # 停止
sudo systemctl status eai_agentplatform # 状态 / 日志
journalctl -u eai_agentplatform -f # 实时日志
```
---
+2 -2
View File
@@ -1,4 +1,4 @@
eaisalestrain_app 博昇内部培训平台
eai_agentplatform_app 博昇内部培训平台
最终完整定稿 PRD(可直接交付 AI 生成前后端代码)
版本:V1.1 最终版 | 纯本地化部署 | 极简架构 | 全功能闭环
@@ -71,7 +71,7 @@ V1.0 → V1.1(修复内部不自洽):
2. 项目目录结构(最终强制规范)
plaintext
eaisalestrain_app/ # 项目根目录(所有代码集中此处)
eai_agentplatform_app/ # 项目根目录(所有代码集中此处)
├── docs/ # 独立文档目录(只放文档,不放代码)
│ ├── PRD.md
│ ├── db_schema.md
@@ -1,4 +1,4 @@
# pj0231-eaisalestraining 完整分析报告(对比 + 差距 + 路线图 + 设计稿)
# pj0231-eai_agentplatforming 完整分析报告(对比 + 差距 + 路线图 + 设计稿)
> 版本:V1.0 | 日期:2026-08-16
> 对比对象:pj006-zhilianyuan2(智练猿)
@@ -47,7 +47,7 @@
## A3. 重要前提:pj0231 文档已过时
- `docs/PRD.md` 写「FastAPI + MySQL + 不做向量检索」;实际代码是 **Go + Gin + GORM + SQLite**,检索已实现**向量(brute-force 余弦 + bge-m3)**。
- 本项目权威信息以 `eaisalestrain_app/CLAUDE.md` 与**实际代码**为准。
- 本项目权威信息以 `eai_agentplatform_app/CLAUDE.md` 与**实际代码**为准。
---
@@ -1,4 +1,4 @@
# pj0231-eaisalestraining vs pj006-zhilianyuan2 能力对比分析
# pj0231-eai_agentplatforming vs pj006-zhilianyuan2 能力对比分析
> 生成日期:2026-08-16
> 范围:知识库能力、考试能力、测试/自测能力、岗位与知识对应能力
@@ -132,10 +132,10 @@
## 7. 关键文件索引(证据)
**pj0231**(本项,实际代码为准):
- 数据模型:`eaisalestrain_app/backend-go/internal/model/`(11 张表)
- 检索:`eaisalestrain_app/backend-go/internal/ai/retrieve.go`(混合检索)
- 考试:`eaisalestrain_app/backend-go/internal/api/exam.go`(组卷 / 判分 / 存档)
- AI 聊天:`eaisalestrain_app/backend-go/internal/api/ai_chat.go`(PathCoach + 3 快捷动作)
- 数据模型:`eai_agentplatform_app/backend-go/internal/model/`(11 张表)
- 检索:`eai_agentplatform_app/backend-go/internal/ai/retrieve.go`(混合检索)
- 考试:`eai_agentplatform_app/backend-go/internal/api/exam.go`(组卷 / 判分 / 存档)
- AI 聊天:`eai_agentplatform_app/backend-go/internal/api/ai_chat.go`(PathCoach + 3 快捷动作)
**pj006**(对比项):
- 数据模型:`zlyapp/backend/app/db/schema.py`(v23,40+ 表,含 `orgs` 多租户根)
@@ -730,7 +730,7 @@ MyGPT = 强底座 + 强场景(博昇的底座 + AionUi 的场景)
## 四、博昇 pj0235 实读结果
- **当前产品名**:eaisalestrain_app(博昇内部员工培训平台)
- **当前产品名**:eai_agentplatform_app(博昇内部员工培训平台)
- **技术栈**:Vue3 + Vite + Element Plus / Go + Gin + GORM + SQLite / Ollama bge-m3 / LibreOffice + pdftotext
- **已落地模块**:
- 知识库全套(上传→审批→摄入→混合检索→导出)
@@ -154,7 +154,7 @@ CREATE INDEX IF NOT EXISTS idx_pk_domain ON position_knowledge(domain);
### 4.3 改动:`user` 加岗位列
在 [user.go](eaisalestrain_app/backend-go/internal/model/user.go) 的 `User` 中追加:
在 [user.go](eai_agentplatform_app/backend-go/internal/model/user.go) 的 `User` 中追加:
```go
PositionID *uint `gorm:"index" json:"position_id"` // 所属岗位,可空(历史用户/管理员可为空)
@@ -162,7 +162,7 @@ CREATE INDEX IF NOT EXISTS idx_pk_domain ON position_knowledge(domain);
### 4.4 改动:`exam_paper` 加岗位列
在 [exam_paper.go](eaisalestrain_app/backend-go/internal/model/exam_paper.go) 的 `ExamPaper` 中追加:
在 [exam_paper.go](eai_agentplatform_app/backend-go/internal/model/exam_paper.go) 的 `ExamPaper` 中追加:
```go
PositionID *uint `gorm:"index" json:"position_id"` // 关联岗位考试,可空;设置后按岗位知识映射抽题
@@ -238,7 +238,7 @@ var validLevels = map[string]bool{LevelL1: true, LevelL2: true, LevelL3: true, L
## 6. 岗位驱动考试组卷(核心算法改动)
修改 [exam.go](eaisalestrain_app/backend-go/internal/api/exam.go) 的 `pickQuestions`,在原有 `domain` 抽题之前,先判断 `p.PositionID` 是否为空:
修改 [exam.go](eai_agentplatform_app/backend-go/internal/api/exam.go) 的 `pickQuestions`,在原有 `domain` 抽题之前,先判断 `p.PositionID` 是否为空:
```go
// pickQuestions 按 paper 抽题:优先按岗位知识映射圈定题池,否则回退 domain 抽题
@@ -1,4 +1,4 @@
# eaisalestrain_app 博昇内部培训平台
# eai_agentplatform_app 博昇内部培训平台
纯内网本地化、内部专属员工培训系统。
用于新人入职培训、公司认知、产品知识学习、销售能力培训、统一考试验收。
@@ -18,7 +18,7 @@
## 目录结构
```
pj0231-eaisalestraining/ # 工作区根(仓库根)
pj0231-eai_agentplatforming/ # 工作区根(仓库根)
├── CODING_RULES.md # 编码与调试最高准则
├── start_dev_10231_10232.sh # 开发启动脚本
├── docs/ # 设计文档(项目级,与代码分离)
@@ -33,9 +33,9 @@ pj0231-eaisalestraining/ # 工作区根(仓库根)
│ ├── api.md # API 文档
│ ├── deploy.md # 部署文档
│ ├── changelog.md # 变更日志
│ ├── eaisalestrain_app设计稿.md # 完整 PRD 中文原稿
│ ├── eai_agentplatform_app设计稿.md # 完整 PRD 中文原稿
│ └── 博昇产品与渠道合作表.md # 知识源权威数据
└── eaisalestrain_app/ # 应用代码
└── eai_agentplatform_app/ # 应用代码
├── backend-go/ # Go 后端(正式,唯一后端)
│ ├── cmd/ internal/ # Go 源码
│ ├── knowledge_source/ # 知识源 Markdown(运行时数据)
@@ -5,7 +5,7 @@
## 1. 项目是什么
**eaisalestrain_app** — 博昇内部培训平台。
**eai_agentplatform_app** — 博昇内部培训平台。
纯内网本地化、内部专属员工培训系统,用于新人入职培训、公司认知、产品知识学习、
销售能力培训、统一考试验收。配套全局 AI 助教 PathCoach。
@@ -68,7 +68,7 @@
| 文档 | 路径 | 说明 |
|------|------|------|
| PRD | `../docs/PRD.md` | 产品需求文档(V1.1 最终版) |
| 设计稿 | `../docs/eaisalestrain_app设计稿.md` | 完整 PRD 中文原稿 |
| 设计稿 | `../docs/eai_agentplatform_app设计稿.md` | 完整 PRD 中文原稿 |
| DB Schema | `../docs/db_schema.md` | 9 张核心表字段设计 |
| API 文档 | `../docs/api.md` | API 接口定义 |
| 部署文档 | `../docs/deploy.md` | 部署架构与步骤 |
@@ -81,7 +81,7 @@
## 5. 目录结构(当前)
```
pj0231-eaisalestraining/ # 工作区根(仓库根)
pj0231-eai_agentplatforming/ # 工作区根(仓库根)
├── CODING_RULES.md # 编码与调试最高准则
├── start_dev_10231_10232.sh # 开发启动脚本
├── docs/ # 设计文档(项目级,与代码分离)
@@ -92,9 +92,9 @@ pj0231-eaisalestraining/ # 工作区根(仓库根)
│ ├── 06_Product_Lines/ # 产品线与前端设计
│ ├── 08_Design_Rules/ # UI/UX 设计规范
│ ├── PRD.md / db_schema.md / api.md / deploy.md / changelog.md
│ ├── eaisalestrain_app设计稿.md # 完整 PRD 中文原稿
│ ├── eai_agentplatform_app设计稿.md # 完整 PRD 中文原稿
│ └── 博昇产品与渠道合作表.md # 知识源权威数据
└── eaisalestrain_app/ # 应用代码
└── eai_agentplatform_app/ # 应用代码
├── backend-go/ # Go 后端(正式,唯一后端,已完成)
│ ├── cmd/ internal/ # Go 源码
│ ├── knowledge_source/ # 知识源 Markdown(运行时数据)
@@ -47,7 +47,7 @@ func main() {
resetStuck := flag.Bool("reset-stuck", false, "reset stuck running state for the given task")
flag.Parse()
dbPath := `d:\traecode\pj0235-eai_agentplatform\eai_ap_app\backend-go\data\eaisalestrain.db`
dbPath := `d:\traecode\pj0235-eai_agentplatform\eai_ap_app\backend-go\data\eai_agentplatform.db`
db, err := sql.Open("sqlite", dbPath)
if err != nil {
log.Fatal(err)
@@ -6,11 +6,11 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/api"
"eaisalestrain/backend/internal/auth"
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eai_agentplatform/backend/internal/api"
"eai_agentplatform/backend/internal/auth"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
)
func main() {
@@ -36,16 +36,16 @@ func main() {
api.RegisterRoutes(r, cfg)
log.Printf("eaisalestrain 后端启动,端口 :%s", cfg.Port)
log.Printf("eai_agentplatform 后端启动,端口 :%s", cfg.Port)
if err := r.Run(":" + cfg.Port); err != nil {
log.Fatalf("启动失败: %v", err)
}
}
// resetAdmin 交付前重置管理员密码:eaisalestrain-server -reset-admin <新密码>
// resetAdmin 交付前重置管理员密码:eai_agentplatform-server -reset-admin <新密码>
func resetAdmin(args []string) {
if len(args) < 1 || args[0] == "" {
log.Fatal("用法: eaisalestrain-server -reset-admin <新密码>")
log.Fatal("用法: eai_agentplatform-server -reset-admin <新密码>")
}
cfg := config.Load()
if _, err := store.Init(cfg.DBPath); err != nil {
@@ -1 +1 @@
{"agent_routes": {"embed_gen": "embed_route_openrouter_text_v3", "image_gen": "image_route_openrouter_gpt_image_2", "path_coach": "chat_route_openrouter_deepseek_v4_flash", "title_gen": "chat_route_openrouter_deepseek_v4_flash"}, "chat_routes": {"chat_route_ollama_qwen": {"description": "本地 Ollama Qwen2.5:7b", "endpoint": "/chat/completions", "max_tokens": 2048, "model": "qwen2.5:7b", "provider": "ollama", "temperature": 0.7}, "chat_route_ollama_qwen_fast": {"description": "本地快速对话 (Ollama Qwen2.5:7b 轻量)", "endpoint": "/chat/completions", "max_tokens": 512, "model": "qwen2.5:7b", "provider": "ollama", "temperature": 0.3}, "chat_route_openrouter_deepseek_v3": {"description": "DeepSeek V3.2 (OpenRouter)", "endpoint": "/chat/completions", "max_tokens": 4096, "model": "deepseek/deepseek-v3.2", "provider": "openrouter", "temperature": 0.6}, "chat_route_openrouter_deepseek_v4_flash": {"description": "DeepSeek V4 Flash (OpenRouter)", "endpoint": "/chat/completions", "max_tokens": 4096, "model": "deepseek/deepseek-v4-flash", "provider": "openrouter", "temperature": 0.7}, "chat_route_openrouter_gpt_5": {"description": "GPT 5.4 (OpenRouter)", "endpoint": "/chat/completions", "max_tokens": 8192, "model": "openai/gpt-5.4", "provider": "openrouter", "temperature": 0.7}, "chat_route_openrouter_grok_4": {"description": "Grok 4.20 (OpenRouter)", "endpoint": "/chat/completions", "max_tokens": 4096, "model": "x-ai/grok-4.20", "provider": "openrouter", "temperature": 0.6}}, "default_embed_route": "embed_route_openrouter_text_v3", "default_route": "chat_route_openrouter_deepseek_v4_flash", "description": "eaisalestrain AI 路由配置 — 按场景分类定义多条路由,支持 provider/模型切换", "embed_routes": {"embed_route_ollama_bge_m3": {"description": "本地 Ollama bge-m3", "endpoint": "/embeddings", "model": "bge-m3", "provider": "ollama"}, "embed_route_openrouter_text_v3": {"description": "OpenAI text-embedding-3-small (OpenRouter)", "endpoint": "/embeddings", "model": "openai/text-embedding-3-small", "provider": "openrouter"}}, "fallback_routes": {"chat_route_openrouter_deepseek_v3": ["chat_route_openrouter_grok_4", "chat_route_ollama_qwen"], "chat_route_openrouter_deepseek_v4_flash": ["chat_route_openrouter_deepseek_v3", "chat_route_openrouter_grok_4", "chat_route_ollama_qwen"], "chat_route_openrouter_grok_4": ["chat_route_ollama_qwen"], "embed_route_ollama_bge_m3": ["embed_route_openrouter_text_v3"], "embed_route_openrouter_text_v3": ["embed_route_ollama_bge_m3"]}, "image_routes": {"image_route_ollama_llava": {"description": "本地 Ollama LLaVA", "endpoint": "/chat/completions", "max_tokens": 2048, "model": "llava", "provider": "ollama", "temperature": 0.7}, "image_route_openrouter_flux": {"description": "FLUX 1.1 Pro (OpenRouter)", "endpoint": "/images/generations", "max_tokens": 1024, "model": "black-forest-labs/flux-1.1-pro", "provider": "openrouter", "temperature": 1}, "image_route_openrouter_gpt_image_2": {"description": "GPT 5.4 Image 2 (OpenRouter)", "endpoint": "/images/generations", "max_tokens": 4096, "model": "openai/gpt-5.4-image-2", "provider": "openrouter", "temperature": 1}}, "version": "2.1.0"}
{"agent_routes": {"embed_gen": "embed_route_openrouter_text_v3", "image_gen": "image_route_openrouter_gpt_image_2", "path_coach": "chat_route_openrouter_deepseek_v4_flash", "title_gen": "chat_route_openrouter_deepseek_v4_flash"}, "chat_routes": {"chat_route_ollama_qwen": {"description": "本地 Ollama Qwen2.5:7b", "endpoint": "/chat/completions", "max_tokens": 2048, "model": "qwen2.5:7b", "provider": "ollama", "temperature": 0.7}, "chat_route_ollama_qwen_fast": {"description": "本地快速对话 (Ollama Qwen2.5:7b 轻量)", "endpoint": "/chat/completions", "max_tokens": 512, "model": "qwen2.5:7b", "provider": "ollama", "temperature": 0.3}, "chat_route_openrouter_deepseek_v3": {"description": "DeepSeek V3.2 (OpenRouter)", "endpoint": "/chat/completions", "max_tokens": 4096, "model": "deepseek/deepseek-v3.2", "provider": "openrouter", "temperature": 0.6}, "chat_route_openrouter_deepseek_v4_flash": {"description": "DeepSeek V4 Flash (OpenRouter)", "endpoint": "/chat/completions", "max_tokens": 4096, "model": "deepseek/deepseek-v4-flash", "provider": "openrouter", "temperature": 0.7}, "chat_route_openrouter_gpt_5": {"description": "GPT 5.4 (OpenRouter)", "endpoint": "/chat/completions", "max_tokens": 8192, "model": "openai/gpt-5.4", "provider": "openrouter", "temperature": 0.7}, "chat_route_openrouter_grok_4": {"description": "Grok 4.20 (OpenRouter)", "endpoint": "/chat/completions", "max_tokens": 4096, "model": "x-ai/grok-4.20", "provider": "openrouter", "temperature": 0.6}}, "default_embed_route": "embed_route_openrouter_text_v3", "default_route": "chat_route_openrouter_deepseek_v4_flash", "description": "eai_agentplatform AI 路由配置 — 按场景分类定义多条路由,支持 provider/模型切换", "embed_routes": {"embed_route_ollama_bge_m3": {"description": "本地 Ollama bge-m3", "endpoint": "/embeddings", "model": "bge-m3", "provider": "ollama"}, "embed_route_openrouter_text_v3": {"description": "OpenAI text-embedding-3-small (OpenRouter)", "endpoint": "/embeddings", "model": "openai/text-embedding-3-small", "provider": "openrouter"}}, "fallback_routes": {"chat_route_openrouter_deepseek_v3": ["chat_route_openrouter_grok_4", "chat_route_ollama_qwen"], "chat_route_openrouter_deepseek_v4_flash": ["chat_route_openrouter_deepseek_v3", "chat_route_openrouter_grok_4", "chat_route_ollama_qwen"], "chat_route_openrouter_grok_4": ["chat_route_ollama_qwen"], "embed_route_ollama_bge_m3": ["embed_route_openrouter_text_v3"], "embed_route_openrouter_text_v3": ["embed_route_ollama_bge_m3"]}, "image_routes": {"image_route_ollama_llava": {"description": "本地 Ollama LLaVA", "endpoint": "/chat/completions", "max_tokens": 2048, "model": "llava", "provider": "ollama", "temperature": 0.7}, "image_route_openrouter_flux": {"description": "FLUX 1.1 Pro (OpenRouter)", "endpoint": "/images/generations", "max_tokens": 1024, "model": "black-forest-labs/flux-1.1-pro", "provider": "openrouter", "temperature": 1}, "image_route_openrouter_gpt_image_2": {"description": "GPT 5.4 Image 2 (OpenRouter)", "endpoint": "/images/generations", "max_tokens": 4096, "model": "openai/gpt-5.4-image-2", "provider": "openrouter", "temperature": 1}}, "version": "2.1.0"}
@@ -1,6 +1,6 @@
{
"name": "博昇内部培训平台",
"short_name": "eaisalestrain",
"short_name": "eai_agentplatform",
"version": "1.1.0",
"build_time": "2026-08-15",
"company": "博昇",
@@ -9,11 +9,11 @@
| 文件 | 说明 |
|------|------|
| `eaisalestrain-server` | 单二进制(CGO 关闭,静态链接,约 38MB,无任何运行时依赖) |
| `eaisalestrain.service` | systemd 单元文件 |
| `eaisalestrain.env` | 环境变量样例 |
| `eai_agentplatform-server` | 单二进制(CGO 关闭,静态链接,约 38MB,无任何运行时依赖) |
| `eai_agentplatform.service` | systemd 单元文件 |
| `eai_agentplatform.env` | 环境变量样例 |
| `clonezilla-cleanup.sh` | 克隆前清理脚本(DRY-RUN 默认) |
| `data/eaisalestrain.db` | SQLite 数据库(首启自动建表) |
| `data/eai_agentplatform.db` | SQLite 数据库(首启自动建表) |
| `data/kb_data/` | 已审批素材目录 |
| `knowledge_source/` | 知识源 Markdown(待入库,由管理员审批) |
@@ -24,11 +24,11 @@
## 1. 目录布局(客户机器最终形态)
```
/opt/eaisalestrain/
├── eaisalestrain-server # 单二进制
/opt/eai_agentplatform/
├── eai_agentplatform-server # 单二进制
├── .env # JWT 密钥等(交付前生成,勿提交源码库)
├── data/
│ ├── eaisalestrain.db # SQLite(首启自动建)
│ ├── eai_agentplatform.db # SQLite(首启自动建)
│ └── kb_data/ # 素材 + 提取缓存
├── knowledge_source/ # 知识源 Markdown
└── (前端静态资源由 Nginx 托管,见 ../docs/deploy.md)
@@ -41,24 +41,24 @@
```bash
# 2.1 构建静态二进制(开发机执行,产物拷贝到原型机)
export PATH=$HOME/go-sdk/go/bin:$PATH CGO_ENABLED=0 GOPROXY=https://goproxy.cn,direct
go build -o bin/eaisalestrain-server ./cmd/server
go build -o bin/eai_agentplatform-server ./cmd/server
# 校验:file 输出应为 "statically linked",ldd 应为 "not a dynamic executable"
# 2.2 拷贝到原型机 + 建账号 + 装 systemd 单元
sudo install -m 0755 eaisalestrain-server /opt/eaisalestrain/eaisalestrain-server
sudo useradd -r -s /usr/sbin/nologin eaisalestrain
sudo mkdir -p /opt/eaisalestrain/data/kb_data /opt/eaisalestrain/knowledge_source
sudo chown -R eaisalestrain:eaisalestrain /opt/eaisalestrain
sudo install -m 0644 deploy/eaisalestrain.service /etc/systemd/system/eaisalestrain.service
sudo install -m 0755 eai_agentplatform-server /opt/eai_agentplatform/eai_agentplatform-server
sudo useradd -r -s /usr/sbin/nologin eai_agentplatform
sudo mkdir -p /opt/eai_agentplatform/data/kb_data /opt/eai_agentplatform/knowledge_source
sudo chown -R eai_agentplatform:eai_agentplatform /opt/eai_agentplatform
sudo install -m 0644 deploy/eai_agentplatform.service /etc/systemd/system/eai_agentplatform.service
# 2.3 生成 .env(含随机 JWT 密钥)
sudo -u eaisalestrain cp deploy/eaisalestrain.env /opt/eaisalestrain/.env
sudo -u eai_agentplatform cp deploy/eai_agentplatform.env /opt/eai_agentplatform/.env
NEW_SECRET=$(python3 -c "import secrets; print(secrets.token_urlsafe(48))")
sudo sed -i "s|^JWT_SECRET=.*|JWT_SECRET=$NEW_SECRET|" /opt/eaisalestrain/.env
sudo sed -i "s|^JWT_SECRET=.*|JWT_SECRET=$NEW_SECRET|" /opt/eai_agentplatform/.env
# 2.4 启动验证
sudo systemctl daemon-reload
sudo systemctl enable --now eaisalestrain
sudo systemctl enable --now eai_agentplatform
curl http://127.0.0.1:8080/api/health # {"status":"ok",...}
```
@@ -82,8 +82,8 @@ sudo bash clonezilla-cleanup.sh --confirm # 确认后真实清理
| # | 动作 | 命令 |
|---|------|------|
| A | **重置管理员密码** | `sudo -u eaisalestrain /opt/eaisalestrain/eaisalestrain-server -reset-admin '<强密码>'` |
| B | **确认 JWT 密钥随机** | `grep -c '__CHANGE_ME__' /opt/eaisalestrain/.env`(应为 0) |
| A | **重置管理员密码** | `sudo -u eai_agentplatform /opt/eai_agentplatform/eai_agentplatform-server -reset-admin '<强密码>'` |
| B | **确认 JWT 密钥随机** | `grep -c '__CHANGE_ME__' /opt/eai_agentplatform/.env`(应为 0) |
| C | **清空测试数据** | Web 后台删除演示用户/素材/考试记录,或用 sqlite3(见第 4 节) |
> 默认种子账号为 `admin / admin123`,**克隆前必须改密**(A 项),否则客户拿到默认口令。
@@ -94,7 +94,7 @@ sudo bash clonezilla-cleanup.sh --confirm # 确认后真实清理
```bash
# 若需彻底清库只保留结构 + admin:
sqlite3 /opt/eaisalestrain/data/eaisalestrain.db <<'SQL'
sqlite3 /opt/eai_agentplatform/data/eai_agentplatform.db <<'SQL'
-- 先停服务
DELETE FROM exam_record;
DELETE FROM knowledge_chunk;
@@ -125,9 +125,9 @@ SQL
## 6. 交付红线(每次克隆前过一遍)
- [ ] `ldd eaisalestrain-server` 输出 `not a dynamic executable`
- [ ] `find /opt/eaisalestrain -name '*.go' -o -name 'go.mod'` 无结果
- [ ] `/opt/eaisalestrain/.env` 无 `__CHANGE_ME__`
- [ ] `ldd eai_agentplatform-server` 输出 `not a dynamic executable`
- [ ] `find /opt/eai_agentplatform -name '*.go' -o -name 'go.mod'` 无结果
- [ ] `/opt/eai_agentplatform/.env` 无 `__CHANGE_ME__`
- [ ] 管理员密码非 `admin123`
- [ ] `.bash_history` 已清空、无 `.git`
- [ ] 测试账号(zhangsan 等)、演示素材、演示考试记录已删除
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# ============================================================
# eaisalestrain — Clonezilla 整盘克隆前的清理脚本
# eai_agentplatform — Clonezilla 整盘克隆前的清理脚本
# 目标:交付给客户的设备上「无源代码、无开发痕迹、无测试数据、无默认口令」。
#
# 用法(在交付原型机上以 root 执行):
@@ -11,7 +11,7 @@
# ============================================================
set -euo pipefail
APP_DIR="/opt/eaisalestrain"
APP_DIR="/opt/eai_agentplatform"
CONFIRM="${1:-}"
log() { echo -e "\033[1;32m[OK]\033[0m $*"; }
@@ -45,7 +45,7 @@ echo " - 提示:测试用户 zhangsan / 演示素材 / 演示考试记录等
echo " 或在克隆前用 sqlite3 执行(见 DELIVERY.md 第 4 节)。脚本不自动清库,避免误删正式数据。"
step "4. 清空日志与 shell 历史"
for f in "$APP_DIR/logs" "$APP_DIR"/*.log /var/log/eaisalestrain*.log; do
for f in "$APP_DIR/logs" "$APP_DIR"/*.log /var/log/eai_agentplatform*.log; do
if compgen -G "$f" >/dev/null 2>&1; then
echo " 将清空: $f"
[[ $DRY -eq 0 ]] && find "$f" -type f -name '*.log' -exec truncate -s 0 {} \; 2>/dev/null || true
@@ -61,11 +61,11 @@ done
step "5. 提示:以下必须手工完成(脚本无法替你决定口令)"
cat <<'EOF'
[A] 重置管理员密码:
sudo -u eaisalestrain /opt/eaisalestrain/eaisalestrain-server -reset-admin '<新强密码>'
[B] 重新生成 JWT 密钥(写回 /opt/eaisalestrain/.env):
sudo -u eai_agentplatform /opt/eai_agentplatform/eai_agentplatform-server -reset-admin '<新强密码>'
[B] 重新生成 JWT 密钥(写回 /opt/eai_agentplatform/.env):
python3 -c "import secrets; print('JWT_SECRET='+secrets.token_urlsafe(48))"
[C] 确认 .env 内无 __CHANGE_ME__ 占位符:
grep -n '__CHANGE_ME__' /opt/eaisalestrain/.env && echo '!! 存在未替换占位符' || echo '无占位符'
grep -n '__CHANGE_ME__' /opt/eai_agentplatform/.env && echo '!! 存在未替换占位符' || echo '无占位符'
EOF
step "6. 移除本清理脚本自身(交付物不含脚本)"
@@ -1,11 +1,11 @@
# eaisalestrain 后端环境变量(交付样例,实际值在 Clonezilla 清理时生成)
# eai_agentplatform 后端环境变量(交付样例,实际值在 Clonezilla 清理时生成)
# systemd 通过 EnvironmentFile 读取;system_config 表可覆盖 LLM 相关字段。
# 监听端口(Nginx 反代到 127.0.0.1:8080)
PORT=8080
# SQLite 数据文件(相对 WorkingDirectory=/opt/eaisalestrain)
DB_PATH=data/eaisalestrain.db
# SQLite 数据文件(相对 WorkingDirectory=/opt/eai_agentplatform)
DB_PATH=data/eai_agentplatform.db
# JWT 签名密钥 —— 交付前必须随机生成(见 DELIVERY.md)
JWT_SECRET=__CHANGE_ME__GENERATE_48_CHARS_RANDOM__
@@ -19,7 +19,7 @@ EMBED_MODEL=bge-m3
# 数据目录
KB_DATA_DIR=data/kb_data
KNOWLEDGE_SOURCE_DIR=/opt/eaisalestrain/knowledge_source
KNOWLEDGE_SOURCE_DIR=/opt/eai_agentplatform/knowledge_source
# 上传大小限制(字节)
FILE_MAX_SIZE_DOC=209715200
@@ -1,15 +1,15 @@
[Unit]
Description=eaisalestrain 博昇内部培训平台后端
Description=eai_agentplatform 博昇内部培训平台后端
After=network.target
Wants=network.target
[Service]
Type=simple
User=eaisalestrain
Group=eaisalestrain
WorkingDirectory=/opt/eaisalestrain
EnvironmentFile=-/opt/eaisalestrain/.env
ExecStart=/opt/eaisalestrain/eaisalestrain-server
User=eai_agentplatform
Group=eai_agentplatform
WorkingDirectory=/opt/eai_agentplatform
EnvironmentFile=-/opt/eai_agentplatform/.env
ExecStart=/opt/eai_agentplatform/eai_agentplatform-server
Restart=always
RestartSec=3
@@ -17,7 +17,7 @@ RestartSec=3
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/eaisalestrain/data
ReadWritePaths=/opt/eai_agentplatform/data
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=true
@@ -1,4 +1,4 @@
module eaisalestrain/backend
module eai_agentplatform/backend
go 1.25.0
@@ -5,8 +5,8 @@ import (
"gorm.io/gorm"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
)
// ──────────────────────────────────────────────
@@ -9,7 +9,7 @@ import (
"strings"
"time"
"eaisalestrain/backend/internal/config"
"eai_agentplatform/backend/internal/config"
)
type KnowledgeClassifyResult struct {
@@ -10,9 +10,9 @@ import (
"strings"
"time"
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
)
// ──────────────────────────────────────────────
@@ -5,9 +5,9 @@ import (
"sort"
"strings"
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
)
// Retrieve 混合检索:向量 brute-force 余弦 + 关键词兜底,去重合并取 topK
@@ -6,8 +6,8 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/web"
)
// ──────────────────────────────────────────────
@@ -9,11 +9,11 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/ai"
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/ai"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/web"
)
// checkBalance 调用前校验用户算力点余额(不扣点的能力直接放行)
@@ -6,10 +6,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// ──────────────────────────────────────────────
@@ -0,0 +1,183 @@
package api
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
"eai_agentplatform/backend/internal/ai"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// AudioTranscribeResult 语音转录结果
type AudioTranscribeResult struct {
Text string `json:"text"` // 转录文字
Language string `json:"language"` // 语言
Duration float64 `json:"duration"` // 时长(秒)
CreatedAt string `json:"created_at"` // 时间
}
// TranscribeAudio POST /api/audio/transcribe —— 语音转文字
func TranscribeAudio(c *gin.Context) {
user := middleware.CurrentUser(c)
if user == nil {
web.Fail(c, web.NewAuthError("未登录"))
return
}
// 解析 multipart 表单
file, fileHeader, err := c.Request.FormFile("file")
if err != nil {
web.Fail(c, web.NewBadRequest("请上传音频文件"))
return
}
// 检查扩展名
ext := extractExt(fileHeader.Filename)
if ext == "" {
ext = "mp3"
}
allowedExt := map[string]bool{
"mp3": true, "wav": true, "m4a": true,
"ogg": true, "flac": true, "aac": true, "wma": true,
}
if !allowedExt[ext] {
web.Fail(c, web.NewBadRequest("不支持的音频格式,仅支持 MP3/WAV/M4A/OGG/FLAC"))
return
}
language := c.PostForm("language")
if language == "" {
language = "zh" // 默认中文
}
// 读取文件内容
fileData, err := io.ReadAll(file)
if err != nil {
web.Fail(c, web.NewBadRequest("读取音频文件失败"))
return
}
file.Close()
result := transcribeAudio(fileData, ext, language)
logTranscription(user.ID, fileHeader.Filename, result)
web.OK(c, result)
}
// extractExt 从文件名提取扩展名
func extractExt(filename string) string {
for i := len(filename) - 1; i >= 0; i-- {
if filename[i] == '.' {
return strings.ToLower(filename[i+1:])
}
}
return ""
}
// transcribeAudio 调用 Ollama whisper 进行语音转录
func transcribeAudio(fileData []byte, ext, language string) AudioTranscribeResult {
// 尝试从路由配置获取 LLM baseURL,降级到 Ollama 默认
baseURL := "http://127.0.0.1:11434"
if r, err := config.GetRoute("title_gen"); err == nil && r != nil && r.BaseURL != "" {
baseURL = r.BaseURL
// 去掉 /v1 后缀,确保路径正确
baseURL = strings.TrimSuffix(baseURL, "/v1")
}
// 调用 Ollama /v1/audio/transcriptions
url := baseURL + "/v1/audio/transcriptions"
// 构建 multipart body
buf := bytes.NewBuffer(nil)
w := multipart.NewWriter(buf)
// model field
modelField, _ := w.CreateFormField("model")
modelField.Write([]byte("whisper"))
// language field
langField, _ := w.CreateFormField("language")
langField.Write([]byte(language))
// audio file
filePart, _ := w.CreateFormFile("file", "audio."+ext)
filePart.Write(fileData)
w.Close()
req, err := http.NewRequest("POST", url, buf)
if err != nil {
return AudioTranscribeResult{
Text: "请求构建失败",
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
}
}
req.Header.Set("Content-Type", w.FormDataContentType())
req.Header.Set("Authorization", "Bearer placeholder") // Ollama 通常不需要 key
client := &http.Client{Timeout: 120 * time.Second}
resp, err := client.Do(req)
if err != nil {
return AudioTranscribeResult{
Text: fmt.Sprintf("Ollama 服务不可达 (%s),请确认 whisper 模型已加载", baseURL),
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
}
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return AudioTranscribeResult{
Text: "读取响应失败",
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
}
}
if resp.StatusCode != http.StatusOK {
return AudioTranscribeResult{
Text: fmt.Sprintf("转录失败 (HTTP %d): %s", resp.StatusCode, string(body)),
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
}
}
// 解析 {"text": "..."}
var out struct {
Text string `json:"text"`
}
if err := json.Unmarshal(body, &out); err != nil {
return AudioTranscribeResult{
Text: "响应解析失败",
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
}
}
return AudioTranscribeResult{
Text: out.Text,
Language: language,
Duration: 0, // Ollama whisper 不返回时长
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
}
}
// logTranscription 记录语音转录日志
func logTranscription(userID uint, filename string, result AudioTranscribeResult) {
store.DB.Create(&model.AiCallLog{
UserID: userID,
Capability: "audio_transcribe",
Status: "success",
})
_ = filename
_ = ai.GenerateWithFallback
_ = result
}
@@ -3,11 +3,11 @@ package api
import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/auth"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/auth"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
type loginRequest struct {
@@ -7,11 +7,11 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/ai"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/ai"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// BatchExtractRequest POST /api/batch/extract —— 批量字段提取请求
@@ -6,10 +6,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// issueCertificate 正式考试通过后颁发证书(幂等:同一 exam_record 只发一张)。
@@ -9,10 +9,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// GetCompanyTrain GET /api/company-train
@@ -6,8 +6,8 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/connector"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/connector"
"eai_agentplatform/backend/internal/web"
)
// ListConnectors GET /api/connectors
@@ -6,11 +6,11 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/ai"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/ai"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// ContractReviewRequest POST /api/contract/review
@@ -7,10 +7,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// CopyProofreadingRequest POST /api/copy/proofread 文案校对请求
@@ -5,9 +5,9 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// courseView 课程详情视图(含绑定产品)
@@ -7,9 +7,9 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// ListDepartments GET /api/departments?status= —— 部门字典列表(含成员数)
@@ -10,12 +10,12 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/ai"
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/ai"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// DocumentTranslateRequest POST /api/document/translate 文档翻译请求
@@ -6,8 +6,8 @@ import (
"strings"
"time"
"eaisalestrain/backend/internal/ai"
"eaisalestrain/backend/internal/config"
"eai_agentplatform/backend/internal/ai"
"eai_agentplatform/backend/internal/config"
)
// gradeEssay 调 LLM 按评分标准对简答题作答打分,返回 0~1 得分率与一句话评语。
@@ -13,11 +13,11 @@ import (
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
"eaisalestrain/backend/internal/auth"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/auth"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// Option 题目选项
@@ -5,7 +5,7 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/web"
)
// parseID 解析路径中的 uint id,失败返回 false 并已写入错误响应
@@ -11,10 +11,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// ============ 扫描 ============
@@ -9,9 +9,9 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// ============ 知识库导出 ============
@@ -7,9 +7,9 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// ListKnowledgeFAQs GET /api/knowledge/faqs?knowledge_space_key=&status=&keyword=&page=&size=
@@ -6,10 +6,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/ai"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/ai"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
var knowledgeIndexRebuildLock sync.Mutex
@@ -9,10 +9,10 @@ import (
"gorm.io/gorm"
"eaisalestrain/backend/internal/ai"
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eai_agentplatform/backend/internal/ai"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
)
const (
@@ -8,9 +8,9 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
type spaceMetrics struct {
@@ -5,10 +5,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
var validItemTypes = map[string]bool{"company": true, "product": true, "course": true}
@@ -16,10 +16,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
var allowedExt = map[string]bool{
@@ -6,10 +6,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
var validNoteItemTypes = map[string]bool{"company": true, "product": true, "course": true}
@@ -5,10 +5,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// notifyUser 给单个用户发站内通知(userID=0 忽略)。
@@ -6,8 +6,8 @@ import (
"sort"
"strings"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
)
func loadOfficialAccountArticle(taskID uint) (*model.OfficialAccountArticle, error) {
@@ -13,11 +13,11 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/ai"
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/ai"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/web"
)
type officialAccountSection struct {
@@ -10,10 +10,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
func officialAccountGeneratedImageDir() string {
@@ -17,8 +17,8 @@ import (
"golang.org/x/net/html/charset"
"gorm.io/gorm/clause"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
)
type officialAccountFetchedHotspot struct {
@@ -9,12 +9,12 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/ai"
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/ai"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
const (
@@ -6,10 +6,10 @@ import (
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// —— 积分规则(游戏化成长值,集中一处便于调整,见 docs/changelog.md 待确认项)——
@@ -5,10 +5,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// ============ 岗位 CRUD(管理员) ============
@@ -3,9 +3,9 @@ package api
import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// ListProducts GET /api/products?category=&status=
@@ -5,10 +5,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// domainLabels 能力雷达维度(正式考试按域聚合的掌握度)。
@@ -8,12 +8,12 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/ai"
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/ai"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// ReportGenRequest POST /api/report/generate 报告生成请求
@@ -6,8 +6,8 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/middleware"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/middleware"
)
// Cfg 全局配置,RegisterRoutes 时注入
@@ -28,7 +28,7 @@ func RegisterRoutes(r *gin.Engine, cfg *config.Config) {
if p, err := config.LoadPlatformConfig(); err == nil {
ver = p.Version
}
c.JSON(200, gin.H{"status": "ok", "service": "eaisalestrain-app", "version": ver})
c.JSON(200, gin.H{"status": "ok", "service": "eai_agentplatform-app", "version": ver})
})
auth := r.Group("/api/auth")
@@ -135,6 +135,9 @@ func RegisterRoutes(r *gin.Engine, cfg *config.Config) {
r.POST("/api/batch/files", middleware.Auth(cfg), ExtractFromFiles)
r.POST("/api/assistant/chat", middleware.Auth(cfg), Chat)
// 语音工具
r.POST("/api/audio/transcribe", middleware.Auth(cfg), TranscribeAudio)
// 管理员维护
admin := r.Group("/api")
admin.Use(middleware.Auth(cfg), middleware.RequireAdmin())
@@ -1,8 +1,8 @@
package api
import (
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/web"
"github.com/gin-gonic/gin"
)
@@ -5,11 +5,11 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/ai"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/ai"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// SmartAssistantRequest POST /api/assistant/chat —— 智能助手请求
@@ -5,10 +5,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// ListSpecialists GET /api/specialists?tier=&state=&market_tag=
@@ -6,9 +6,9 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// round1 保留 1 位小数
@@ -9,10 +9,10 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/auth"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/auth"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// ============ 用户管理(管理员) ============
@@ -7,10 +7,10 @@ import (
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
func WorkbenchOverview(c *gin.Context) {
@@ -10,13 +10,13 @@ import (
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"eaisalestrain/backend/internal/ai"
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/connector"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/ai"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/connector"
"eai_agentplatform/backend/internal/middleware"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
type workerTaskReq struct {
@@ -46,7 +46,7 @@ func Load() *Config {
return &Config{
Port: getenv("PORT", "8080"),
DBPath: getenv("DB_PATH", filepath.Join(baseDir, "data", "eaisalestrain.db")),
DBPath: getenv("DB_PATH", filepath.Join(baseDir, "data", "eai_agentplatform.db")),
JWTSecret: getenv("JWT_SECRET", "change-this-to-a-strong-secret-in-production"),
JWTExpireMin: getenvInt("JWT_EXPIRE_MINUTES", 480),
@@ -12,7 +12,7 @@ import (
"strings"
"time"
"eaisalestrain/backend/internal/config"
"eai_agentplatform/backend/internal/config"
)
type KingdeeConnector struct {
@@ -4,7 +4,7 @@ import (
"context"
"testing"
"eaisalestrain/backend/internal/config"
"eai_agentplatform/backend/internal/config"
)
func TestKingdeeDefinitionDefaultsToDemo(t *testing.T) {
@@ -6,7 +6,7 @@ import (
"strings"
"time"
"eaisalestrain/backend/internal/config"
"eai_agentplatform/backend/internal/config"
)
var ErrConnectorNotFound = errors.New("connector not found")
@@ -4,7 +4,7 @@ import (
"context"
"strings"
"eaisalestrain/backend/internal/config"
"eai_agentplatform/backend/internal/config"
)
type Definition struct {
@@ -9,11 +9,11 @@ import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/auth"
"eaisalestrain/backend/internal/config"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
"eai_agentplatform/backend/internal/auth"
"eai_agentplatform/backend/internal/config"
"eai_agentplatform/backend/internal/model"
"eai_agentplatform/backend/internal/store"
"eai_agentplatform/backend/internal/web"
)
// Auth 解析 JWT → 校验用户 → 注入 current_user

Some files were not shown because too many files have changed in this diff Show More