mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-23 15:43:54 +08:00
Compare commits
216
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0475251b76 | ||
|
|
1b5c00231a | ||
|
|
95acba1126 | ||
|
|
1e6f0fd1be | ||
|
|
eb571fae57 | ||
|
|
2946be7284 | ||
|
|
425cb1d6bd | ||
|
|
cf9b0ec712 | ||
|
|
1b053dc9c8 | ||
|
|
d7ad656bd0 | ||
|
|
7dae67a57b | ||
|
|
7b0f59a747 | ||
|
|
2eaa5bbb11 | ||
|
|
c693ff1564 | ||
|
|
e9bf006d9d | ||
|
|
bef96f36e2 | ||
|
|
bebb7eac69 | ||
|
|
a787130b74 | ||
|
|
8b7f16b9c2 | ||
|
|
9ed66ec013 | ||
|
|
05c22cdf2a | ||
|
|
4bc0b67cd7 | ||
|
|
0a6f811448 | ||
|
|
5aeb55fffd | ||
|
|
c33ee9442e | ||
|
|
4670ad2925 | ||
|
|
b542388053 | ||
|
|
a71ce53a68 | ||
|
|
dd88107131 | ||
|
|
8b847a3826 | ||
|
|
036b89f24e | ||
|
|
354280d430 | ||
|
|
e2d16ec8d4 | ||
|
|
6a0192de27 | ||
|
|
ac6eeb5c1f | ||
|
|
23e213f6ea | ||
|
|
382c948482 | ||
|
|
a67d938523 | ||
|
|
26aca54f4b | ||
|
|
4717b8beac | ||
|
|
cd580b6f81 | ||
|
|
70740af7a6 | ||
|
|
7b30c25923 | ||
|
|
7db13b8be2 | ||
|
|
a0df41ac24 | ||
|
|
a432c295d3 | ||
|
|
ab8a35e233 | ||
|
|
160b67197f | ||
|
|
3510282cd5 | ||
|
|
bdf7c7facf | ||
|
|
151a0c1b99 | ||
|
|
52af722463 | ||
|
|
fa91c97685 | ||
|
|
a92d6ccdfb | ||
|
|
f5ce755fea | ||
|
|
606a42cfb2 | ||
|
|
f85e863144 | ||
|
|
550397de98 | ||
|
|
ff66b815a5 | ||
|
|
8c18e48b97 | ||
|
|
4acd02e2b0 | ||
|
|
ddfbacc717 | ||
|
|
2a4dbdb69b | ||
|
|
e9a2489e48 | ||
|
|
ce13a7e3e6 | ||
|
|
8a156e99f4 | ||
|
|
4313216816 | ||
|
|
8c0899415a | ||
|
|
3736a5845a | ||
|
|
dc7615c008 | ||
|
|
b03f9374ea | ||
|
|
cacfc9bfee | ||
|
|
ce3c8a2bd8 | ||
|
|
e1a7e50e1f | ||
|
|
90888de0ba | ||
|
|
ad4d32a05d | ||
|
|
08d6bb4056 | ||
|
|
1f0db7dc47 | ||
|
|
6f52d004e8 | ||
|
|
0681550bab | ||
|
|
97b9c95c2d | ||
|
|
6111c3b5a0 | ||
|
|
123c1e8880 | ||
|
|
6ce4503b22 | ||
|
|
b209de36f5 | ||
|
|
fc3e0869fd | ||
|
|
3436d50b43 | ||
|
|
7a58c04df3 | ||
|
|
150be65436 | ||
|
|
bacf4cd5e8 | ||
|
|
7049e8cce7 | ||
|
|
61f137ce4b | ||
|
|
35ea14b95b | ||
|
|
b7d07f92a2 | ||
|
|
d2cbec0981 | ||
|
|
6348f12d60 | ||
|
|
11caf6bc8a | ||
|
|
3cae9e3c32 | ||
|
|
0161e642d0 | ||
|
|
d41938fe07 | ||
|
|
e20c59e3df | ||
|
|
fbaf28de5c | ||
|
|
2daf492e00 | ||
|
|
ac9083cfc7 | ||
|
|
f36e605aed | ||
|
|
c1b836aaed | ||
|
|
07170f09eb | ||
|
|
8211de242f | ||
|
|
eea6807355 | ||
|
|
0ba7e81438 | ||
|
|
703c707b4c | ||
|
|
3ab14578c2 | ||
|
|
a15efa3090 | ||
|
|
8af8930997 | ||
|
|
ad01b05940 | ||
|
|
a0497fdc48 | ||
|
|
9634f84a98 | ||
|
|
27e5e1e9d7 | ||
|
|
8fd92729f2 | ||
|
|
736ffd80bf | ||
|
|
3783351f5d | ||
|
|
2cd9484c54 | ||
|
|
0f1e0d0d2e | ||
|
|
0e23672be7 | ||
|
|
a6904f6ebd | ||
|
|
784ba359f2 | ||
|
|
e08eb48d9a | ||
|
|
b9a1b154b7 | ||
|
|
64630e1b4e | ||
|
|
7dcc014ce4 | ||
|
|
389e8559aa | ||
|
|
c5f82369e5 | ||
|
|
52e63706a4 | ||
|
|
a42a8b2b4b | ||
|
|
11142104af | ||
|
|
a9f5f1ab81 | ||
|
|
a8f68c42fc | ||
|
|
1d3afb3c9a | ||
|
|
943622969a | ||
|
|
9d39168a35 | ||
|
|
61ab7f25d7 | ||
|
|
140fcd5887 | ||
|
|
3c2024d00d | ||
|
|
2aee1bf567 | ||
|
|
d89a26889c | ||
|
|
d611b2db73 | ||
|
|
b0e911b248 | ||
|
|
fb3b7830ee | ||
|
|
10eeffdf31 | ||
|
|
17847188dd | ||
|
|
7b2bfc087d | ||
|
|
24a8839753 | ||
|
|
64d25533d9 | ||
|
|
6f6c788cd5 | ||
|
|
8aa12d0961 | ||
|
|
d770632152 | ||
|
|
a30903b644 | ||
|
|
5469168d18 | ||
|
|
3c31231781 | ||
|
|
cc2e30205f | ||
|
|
f01de027cd | ||
|
|
fb195fc57b | ||
|
|
cc504fe542 | ||
|
|
fd93116d69 | ||
|
|
5622a13735 | ||
|
|
079c8630d9 | ||
|
|
11830b2f22 | ||
|
|
861b4dee4c | ||
|
|
603fa67824 | ||
|
|
4d8279d916 | ||
|
|
f91c4acb8f | ||
|
|
1342eccf86 | ||
|
|
87f9ab7bb4 | ||
|
|
94cc8564aa | ||
|
|
8fc2d05c99 | ||
|
|
1a6d9d7490 | ||
|
|
6c19f1bd26 | ||
|
|
6d89ae1c66 | ||
|
|
2a49f0804c | ||
|
|
d64bb36606 | ||
|
|
852e097e0d | ||
|
|
3aecb99f70 | ||
|
|
6eecf5d0cb | ||
|
|
a4d02ca2ab | ||
|
|
7ef5a67119 | ||
|
|
1c5dacd2d5 | ||
|
|
7732b7b1b9 | ||
|
|
6e7b938f51 | ||
|
|
52f5859b1f | ||
|
|
73d174bc4a | ||
|
|
9512fe642c | ||
|
|
0ef3a60a4c | ||
|
|
f40dc4a658 | ||
|
|
4747e54f6c | ||
|
|
9278fdb016 | ||
|
|
5b23804954 | ||
|
|
b2ed5eb2c0 | ||
|
|
07113dc4d2 | ||
|
|
1a5dd2d9d9 | ||
|
|
8a01432e9d | ||
|
|
7a39fd0152 | ||
|
|
0d2cb7b3c9 | ||
|
|
9123a174da | ||
|
|
2e165747d6 | ||
|
|
3bdf634e37 | ||
|
|
20ac6f3f96 | ||
|
|
818ac1eefb | ||
|
|
980930cd42 | ||
|
|
956ae37e56 | ||
|
|
15731892ad | ||
|
|
d6d50e0432 | ||
|
|
286079c93a | ||
|
|
860cbc36fd | ||
|
|
bcf03a0378 | ||
|
|
4f615b3807 | ||
|
|
c2b95ca896 |
@@ -149,6 +149,7 @@ tmp
|
||||
.history
|
||||
.DS_Store
|
||||
main/xiaozhi-server/data
|
||||
main/xiaozhi-server/.claude
|
||||
|
||||
main/manager-web/node_modules
|
||||
.config.yaml
|
||||
|
||||
@@ -214,8 +214,8 @@ Websocket接口地址: wss://2662r3426b.vicp.fun/xiaozhi/v1/
|
||||
|:---:|:---:|:---:|
|
||||
| ASR(语音识别) | FunASR(本地) | 👍XunfeiStreamASR(讯飞流式) |
|
||||
| LLM(大模型) | glm-4-flash(智谱) | 👍qwen-flash(阿里百炼) |
|
||||
| VLLM(视觉大模型) | glm-4v-flash(智谱) | 👍qwen2.5-vl-3b-instructh(阿里百炼) |
|
||||
| TTS(语音合成) | ✅LinkeraiTTS(灵犀流式) | 👍HuoshanDoubleStreamTTS(火山流式) |
|
||||
| VLLM(视觉大模型) | glm-4v-flash(智谱) | 👍qwen3.5-flash(阿里百炼) |
|
||||
| TTS(语音合成) | EdgeTTS(微软) | 👍HuoshanDoubleStreamTTS(火山流式) |
|
||||
| Intent(意图识别) | function_call(函数调用) | function_call(函数调用) |
|
||||
| Memory(记忆功能) | mem_local_short(本地短期记忆) | mem_local_short(本地短期记忆) |
|
||||
|
||||
|
||||
+2
-2
@@ -212,8 +212,8 @@ Websocket-Schnittstellenadresse: wss://2662r3426b.vicp.fun/xiaozhi/v1/
|
||||
|:---:|:---:|:---:|
|
||||
| ASR (Spracherkennung) | FunASR (Lokal) | 👍XunfeiStreamASR (Xunfei-Streaming) |
|
||||
| LLM (Großes Modell) | glm-4-flash (Zhipu) | 👍qwen-flash (Alibaba Bailian) |
|
||||
| VLLM (Vision Large Model) | glm-4v-flash (Zhipu) | 👍qwen2.5-vl-3b-instructh (Alibaba Bailian) |
|
||||
| TTS (Sprachsynthese) | ✅LinkeraiTTS (Lingxi-Streaming) | 👍HuoshanDoubleStreamTTS (Volcano-Streaming) |
|
||||
| VLLM (Vision Large Model) | glm-4v-flash (Zhipu) | 👍qwen3.5-flash (Alibaba Bailian) |
|
||||
| TTS (Sprachsynthese) | EdgeTTS (Microsoft) | 👍HuoshanDoubleStreamTTS (Volcano-Streaming) |
|
||||
| Intent (Absichtserkennung) | function_call (Funktionsaufruf) | function_call (Funktionsaufruf) |
|
||||
| Memory (Gedächtnisfunktion) | mem_local_short (Lokales Kurzzeitgedächtnis) | mem_local_short (Lokales Kurzzeitgedächtnis) |
|
||||
|
||||
|
||||
+2
-2
@@ -212,8 +212,8 @@ Websocket Interface Address: wss://2662r3426b.vicp.fun/xiaozhi/v1/
|
||||
|:---:|:---:|:---:|
|
||||
| ASR(Speech Recognition) | FunASR(Local) | 👍XunfeiStreamASR(Xunfei Streaming) |
|
||||
| LLM(Large Model) | glm-4-flash(Zhipu) | 👍qwen-flash(Alibaba Bailian) |
|
||||
| VLLM(Vision Large Model) | glm-4v-flash(Zhipu) | 👍qwen2.5-vl-3b-instructh(Alibaba Bailian) |
|
||||
| TTS(Speech Synthesis) | ✅LinkeraiTTS(Lingxi streaming) | 👍HuoshanDoubleStreamTTS(Volcano Streaming) |
|
||||
| VLLM(Vision Large Model) | glm-4v-flash(Zhipu) | 👍qwen3.5-flash(Alibaba Bailian) |
|
||||
| TTS(Speech Synthesis) | EdgeTTS(Microsoft) | 👍HuoshanDoubleStreamTTS(Volcano Streaming) |
|
||||
| Intent(Intent Recognition) | function_call(Function calling) | function_call(Function calling) |
|
||||
| Memory(Memory function) | mem_local_short(Local short-term memory) | mem_local_short(Local short-term memory) |
|
||||
|
||||
|
||||
+2
-2
@@ -212,8 +212,8 @@ Endereço da Interface WebSocket: wss://2662r3426b.vicp.fun/xiaozhi/v1/
|
||||
|:---:|:---:|:---:|
|
||||
| ASR(Reconhecimento de Fala) | FunASR(Local) | 👍XunfeiStreamASR(Xunfei Streaming) |
|
||||
| LLM(Modelo de Linguagem) | glm-4-flash(Zhipu) | 👍qwen-flash(Alibaba Bailian) |
|
||||
| VLLM(Modelo de Visão) | glm-4v-flash(Zhipu) | 👍qwen2.5-vl-3b-instructh(Alibaba Bailian) |
|
||||
| TTS(Síntese de Voz) | ✅LinkeraiTTS(Lingxi streaming) | 👍HuoshanDoubleStreamTTS(Volcano Streaming) |
|
||||
| VLLM(Modelo de Visão) | glm-4v-flash(Zhipu) | 👍qwen3.5-flash(Alibaba Bailian) |
|
||||
| TTS(Síntese de Voz) | EdgeTTS(Microsoft) | 👍HuoshanDoubleStreamTTS(Volcano Streaming) |
|
||||
| Intent(Reconhecimento de Intenção) | function_call(Chamada de função) | function_call(Chamada de função) |
|
||||
| Memory(Função de Memória) | mem_local_short(Memória local de curto prazo) | mem_local_short(Memória local de curto prazo) |
|
||||
|
||||
|
||||
+2
-2
@@ -213,8 +213,8 @@ Công cụ kiểm tra dịch vụ: https://2662r3426b.vicp.fun/test/
|
||||
|:---:|:---:|:---:|
|
||||
| ASR(Nhận dạng giọng nói) | FunASR(Local) | 👍XunfeiStreamASR(Xunfei Streaming) |
|
||||
| LLM(Mô hình lớn) | glm-4-flash(Zhipu) | 👍qwen-flash(Alibaba Bailian) |
|
||||
| VLLM(Mô hình lớn thị giác) | glm-4v-flash(Zhipu) | 👍qwen2.5-vl-3b-instructh(Alibaba Bailian) |
|
||||
| TTS(Tổng hợp giọng nói) | ✅LinkeraiTTS(Lingxi streaming) | 👍HuoshanDoubleStreamTTS(Volcano Streaming) |
|
||||
| VLLM(Mô hình lớn thị giác) | glm-4v-flash(Zhipu) | 👍qwen3.5-flash(Alibaba Bailian) |
|
||||
| TTS(Tổng hợp giọng nói) | EdgeTTS(Microsoft) | 👍HuoshanDoubleStreamTTS(Volcano Streaming) |
|
||||
| Intent(Nhận dạng ý định) | function_call(Gọi hàm) | function_call(Gọi hàm) |
|
||||
| Memory(Chức năng bộ nhớ) | mem_local_short(Bộ nhớ ngắn hạn cục bộ) | mem_local_short(Bộ nhớ ngắn hạn cục bộ) |
|
||||
|
||||
|
||||
@@ -418,7 +418,7 @@ manager-api:
|
||||
secret: 12345678-xxxx-xxxx-xxxx-123456789000
|
||||
```
|
||||
|
||||
## 5.运行项目
|
||||
## 9.运行项目
|
||||
|
||||
```
|
||||
# 确保在xiaozhi-server目录下执行
|
||||
|
||||
+3
-2
@@ -40,8 +40,8 @@ conda install conda-forge::ffmpeg
|
||||
|:---:|:---:|:---:|
|
||||
| ASR(语音识别) | FunASR(本地) | 👍XunfeiStreamASR(讯飞流式) |
|
||||
| LLM(大模型) | glm-4-flash(智谱) | 👍qwen-flash(阿里百炼) |
|
||||
| VLLM(视觉大模型) | glm-4v-flash(智谱) | 👍qwen2.5-vl-3b-instructh(阿里百炼) |
|
||||
| TTS(语音合成) | ✅LinkeraiTTS(灵犀流式) | 👍HuoshanDoubleStreamTTS(火山流式) |
|
||||
| VLLM(视觉大模型) | glm-4v-flash(智谱) | 👍qwen3.5-flash(阿里百炼) |
|
||||
| TTS(语音合成) | EdgeTTS(微软) | 👍HuoshanDoubleStreamTTS(火山流式) |
|
||||
| Intent(意图识别) | function_call(函数调用) | function_call(函数调用) |
|
||||
| Memory(记忆功能) | mem_local_short(本地短期记忆) | mem_local_short(本地短期记忆) |
|
||||
|
||||
@@ -83,6 +83,7 @@ VAD:
|
||||
9、[知识库ragflow集成指南](./ragflow-integration.md)<br/>
|
||||
10、[如何部署上下文源](./context-provider-integration.md)<br/>
|
||||
11、[如何集成PowerMem智能记忆](./powermem-integration.md)<br/>
|
||||
12、[如何配置天气插件查询天气](./weather-integration.md)<br/>
|
||||
|
||||
### 11、语音克隆、本地语音部署相关教程
|
||||
1、[如何在智控台克隆音色](./huoshan-streamTTS-voice-cloning.md)<br/>
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# 知识库模块全量集成测试报告
|
||||
|
||||
## 1. 测试背景
|
||||
针对 `KnowledgeBaseController` 和 `KnowledgeFilesController` 共 14 个接口进行了深度集成测试。主要解决了本地影子库与 RAGFlow 远程服务之间的状态对齐、数据反序列化兼容性以及批量操作逻辑安全性问题。
|
||||
|
||||
## 2. 修复的核心 Bug 清单 (Hotfixes)
|
||||
|
||||
| 模块 | 问题类型 | 修复方案 | 验证结果 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **DTO** | `positions` 反序列化失败 | 类型从 `List<Integer>` 提升为 `Object`,支持嵌套数组 | ✅ 已验证 |
|
||||
| **DTO** | 日期格式不兼容 | 针对 RAGFlow 的 RFC 1123 格式,将 `Date` 改为 `String` 透传 | ✅ 已验证 |
|
||||
| **请求** | 检索参数 `null` 拒绝 | 增加 `@JsonInclude(NON_NULL)`,跳过可选字段的空值序列化 | ✅ 已验证 |
|
||||
| **同步** | 状态自愈死锁 | 增加 `CANCEL/FAIL` 状态的 60s 低频同步机制,防止逻辑错误锁定 | ✅ 已验证 |
|
||||
| **逻辑** | 删除守卫逻辑错误 | 将拦截条件从 `status="1"` 修正为 `run="RUNNING"` | ✅ 已验证 |
|
||||
|
||||
## 3. 全量接口测试统计
|
||||
|
||||
### KnowledgeBaseController (7/7)
|
||||
- [x] 分页查询 (`GET /datasets`)
|
||||
- [x] 详情获取 (`GET /datasets/{id}`)
|
||||
- [x] 创建知识库 (`POST /datasets`)
|
||||
- [x] 修改配置 (`PUT /datasets/{id}`)
|
||||
- [x] 物理删除 (`DELETE /datasets/{id}`)
|
||||
- [x] 批量删除 (`DELETE /datasets/batch`)
|
||||
- [x] 模型列表获取 (`GET /datasets/rag-models`)
|
||||
|
||||
### KnowledgeFilesController (7/7)
|
||||
- [x] 文档列表与同步 (`GET /datasets/{id}/documents`)
|
||||
- [x] 状态过滤查询 (`GET /datasets/{id}/documents/status/{s}`)
|
||||
- [x] 文档上传 (`POST /datasets/{id}/documents`)
|
||||
- [x] 触发解析 (`POST /datasets/{id}/chunks`)
|
||||
- [x] 切片详情 (`GET /datasets/{id}/documents/{docId}/chunks`)
|
||||
- [x] 召回测试 (`POST /datasets/{id}/retrieval-test`)
|
||||
- [x] 批量删除文档 (`DELETE /datasets/{id}/documents`)
|
||||
|
||||
## 4. 自动化审计结论
|
||||
通过执行 `comprehensive_audit.ps1` 自动化脚本,模拟了“创建->上传->解析->同步->检索->删除”的完整生产链路。
|
||||
- **解析成功率**:100%
|
||||
- **数据准确性**:DTO 转换无异常,坐标及得分提取正常
|
||||
- **系统安全性**:解析中拦截机制生效
|
||||
- **结论**:**准生产就绪 (Production Ready)**
|
||||
|
||||
---
|
||||
*报告生成时间:2026-02-13*
|
||||
*审核:dora--1206563805@qq.com*
|
||||
@@ -95,6 +95,14 @@ public class SwaggerConfig {
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public GroupedOpenApi correctWordApi() {
|
||||
return GroupedOpenApi.builder()
|
||||
.group("correct-word")
|
||||
.pathsToMatch("/correct-word/**")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OpenAPI customOpenAPI() {
|
||||
return new OpenAPI().info(new Info()
|
||||
|
||||
@@ -151,6 +151,21 @@ public interface Constant {
|
||||
*/
|
||||
String MEMORY_NO_MEM = "Memory_nomem";
|
||||
|
||||
/**
|
||||
* 仅上报聊天记录(不总结记忆)
|
||||
*/
|
||||
String MEMORY_MEM_REPORT_ONLY = "Memory_mem_report_only";
|
||||
|
||||
/**
|
||||
* Mem0AI记忆
|
||||
*/
|
||||
String MEMORY_MEM0AI = "Memory_mem0ai";
|
||||
|
||||
/**
|
||||
* PowerMem记忆
|
||||
*/
|
||||
String MEMORY_POWERMEM = "Memory_powermem";
|
||||
|
||||
/**
|
||||
* 火山引擎双声道语音克隆
|
||||
*/
|
||||
@@ -304,7 +319,7 @@ public interface Constant {
|
||||
/**
|
||||
* 版本号
|
||||
*/
|
||||
public static final String VERSION = "0.9.2";
|
||||
public static final String VERSION = "0.9.3";
|
||||
|
||||
/**
|
||||
* 无效固件URL
|
||||
|
||||
@@ -251,4 +251,13 @@ public interface ErrorCode {
|
||||
int AGENT_TAG_NOT_EXIST = 10198; // 标签不存在
|
||||
|
||||
int RAG_DOCUMENT_PARSING_DELETE_ERROR = 10199; // 文档解析中,禁止删除
|
||||
|
||||
// 智能体MCP相关错误码
|
||||
int MCP_ACCESS_POINT_ADDRESS_NO_PERMISSION = 10200; // 没有权限查看该智能体的MCP接入点地址
|
||||
int MCP_ACCESS_POINT_ADDRESS_NOT_CONFIGURED = 10201; // 请联系管理员进入参数管理配置mcp接入点地址
|
||||
int MCP_ACCESS_POINT_TOOLS_LIST_NO_PERMISSION = 10202; // 没有权限查看该智能体的MCP工具列表
|
||||
|
||||
// 替换词相关错误码
|
||||
int CORRECT_WORD_FILE_NAME_EXISTS = 10203; // 文件名已存在
|
||||
int FILE_SIZE_OVER_LIMIT = 10204; // 文件大小超过限制
|
||||
}
|
||||
|
||||
@@ -187,4 +187,5 @@ public class RedisKeys {
|
||||
public static String getOtaUploadCountKey(Long username) {
|
||||
return "ota:upload:count:" + username;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ import xiaozhi.modules.agent.service.AgentContextProviderService;
|
||||
import xiaozhi.modules.agent.service.AgentPluginMappingService;
|
||||
import xiaozhi.modules.agent.service.AgentService;
|
||||
import xiaozhi.modules.agent.service.AgentTemplateService;
|
||||
import xiaozhi.modules.correctword.service.CorrectWordFileService;
|
||||
import xiaozhi.modules.agent.vo.AgentChatHistoryUserVO;
|
||||
import xiaozhi.modules.agent.vo.AgentInfoVO;
|
||||
import xiaozhi.modules.device.entity.DeviceEntity;
|
||||
@@ -73,6 +74,7 @@ public class AgentController {
|
||||
private final AgentChatSummaryService agentChatSummaryService;
|
||||
private final RedisUtils redisUtils;
|
||||
private final AgentTagService agentTagService;
|
||||
private final CorrectWordFileService correctWordFileService;
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获取用户智能体列表")
|
||||
@@ -150,6 +152,13 @@ public class AgentController {
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/chat-title/{sessionId}/generate")
|
||||
@Operation(summary = "根据会话ID生成聊天标题")
|
||||
public Result<Void> generateAndSaveChatTitle(@PathVariable String sessionId) {
|
||||
agentChatSummaryService.generateAndSaveChatTitle(sessionId);
|
||||
return new Result<Void>().ok(null);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@Operation(summary = "更新智能体")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
@@ -170,6 +179,8 @@ public class AgentController {
|
||||
agentPluginMappingService.deleteByAgentId(id);
|
||||
// 删除关联的上下文源配置
|
||||
agentContextProviderService.deleteByAgentId(id);
|
||||
// 删除关联的替换词文件关联记录
|
||||
correctWordFileService.deleteMappingsByAgentId(id);
|
||||
// 再删除智能体
|
||||
agentService.deleteById(id);
|
||||
return new Result<>();
|
||||
|
||||
+4
-3
@@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import xiaozhi.common.exception.ErrorCode;
|
||||
import xiaozhi.common.user.UserDetail;
|
||||
import xiaozhi.common.utils.Result;
|
||||
import xiaozhi.modules.agent.service.AgentMcpAccessPointService;
|
||||
@@ -40,11 +41,11 @@ public class AgentMcpAccessPointController {
|
||||
|
||||
// 检查权限
|
||||
if (!agentService.checkAgentPermission(agentId, user.getId())) {
|
||||
return new Result<String>().error("没有权限查看该智能体的MCP接入点地址");
|
||||
return new Result<String>().error(ErrorCode.MCP_ACCESS_POINT_ADDRESS_NO_PERMISSION);
|
||||
}
|
||||
String agentMcpAccessAddress = agentMcpAccessPointService.getAgentMcpAccessAddress(agentId);
|
||||
if (agentMcpAccessAddress == null) {
|
||||
return new Result<String>().ok("请联系管理员进入参数管理配置mcp接入点地址");
|
||||
return new Result<String>().error(ErrorCode.MCP_ACCESS_POINT_ADDRESS_NOT_CONFIGURED);
|
||||
}
|
||||
return new Result<String>().ok(agentMcpAccessAddress);
|
||||
}
|
||||
@@ -58,7 +59,7 @@ public class AgentMcpAccessPointController {
|
||||
|
||||
// 检查权限
|
||||
if (!agentService.checkAgentPermission(agentId, user.getId())) {
|
||||
return new Result<List<String>>().error("没有权限查看该智能体的MCP工具列表");
|
||||
return new Result<List<String>>().error(ErrorCode.MCP_ACCESS_POINT_TOOLS_LIST_NO_PERMISSION);
|
||||
}
|
||||
List<String> agentMcpToolsList = agentMcpAccessPointService.getAgentMcpToolsList(agentId);
|
||||
return new Result<List<String>>().ok(agentMcpToolsList);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package xiaozhi.modules.agent.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
import xiaozhi.modules.agent.entity.AgentChatTitleEntity;
|
||||
|
||||
@Mapper
|
||||
public interface AgentChatTitleDao extends BaseMapper<AgentChatTitleEntity> {
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package xiaozhi.modules.agent.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import xiaozhi.common.dao.BaseDao;
|
||||
import xiaozhi.modules.agent.entity.AgentCorrectWordMappingEntity;
|
||||
|
||||
@Mapper
|
||||
public interface AgentCorrectWordMappingDao extends BaseDao<AgentCorrectWordMappingEntity> {
|
||||
|
||||
int deleteByAgentId(@Param("agentId") String agentId);
|
||||
|
||||
int deleteByFileId(@Param("fileId") String fileId);
|
||||
|
||||
int batchInsertMapping(@Param("list") List<AgentCorrectWordMappingEntity> mappings);
|
||||
|
||||
List<AgentCorrectWordMappingEntity> selectByAgentId(@Param("agentId") String agentId);
|
||||
}
|
||||
@@ -23,4 +23,9 @@ public class AgentChatSessionDTO {
|
||||
* 聊天条数
|
||||
*/
|
||||
private Integer chatCount;
|
||||
|
||||
/**
|
||||
* 会话标题
|
||||
*/
|
||||
private String title;
|
||||
}
|
||||
@@ -33,6 +33,9 @@ public class AgentUpdateDTO implements Serializable {
|
||||
@Schema(description = "大语言模型标识", example = "llm_model_02", nullable = true)
|
||||
private String llmModelId;
|
||||
|
||||
@Schema(description = "小模型标识", example = "slm_model_02", nullable = true)
|
||||
private String slmModelId;
|
||||
|
||||
@Schema(description = "VLLM模型标识", example = "vllm_model_02", required = false)
|
||||
private String vllmModelId;
|
||||
|
||||
@@ -85,6 +88,9 @@ public class AgentUpdateDTO implements Serializable {
|
||||
@Schema(description = "上下文源配置", nullable = true)
|
||||
private List<ContextProviderDTO> contextProviders;
|
||||
|
||||
@Schema(description = "替换词文件ID列表", nullable = true)
|
||||
private List<String> correctWordFileIds;
|
||||
|
||||
@Data
|
||||
@Schema(description = "插件函数信息")
|
||||
public static class FunctionInfo implements Serializable {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package xiaozhi.modules.agent.entity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@TableName(value = "ai_agent_chat_title")
|
||||
public class AgentChatTitleEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
|
||||
@TableField(value = "session_id")
|
||||
private String sessionId;
|
||||
|
||||
@TableField(value = "title")
|
||||
private String title;
|
||||
|
||||
@TableField(value = "created_at")
|
||||
private Date createdAt;
|
||||
|
||||
@TableField(value = "updated_at")
|
||||
private Date updatedAt;
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package xiaozhi.modules.agent.entity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@TableName("ai_agent_correct_word_mapping")
|
||||
@Schema(description = "智能体替换词文件关联")
|
||||
public class AgentCorrectWordMappingEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
@Schema(description = "主键")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "智能体ID")
|
||||
private String agentId;
|
||||
|
||||
@Schema(description = "替换词文件ID")
|
||||
private String fileId;
|
||||
|
||||
@Schema(description = "创建者")
|
||||
private Long creator;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date createdAt;
|
||||
|
||||
@Schema(description = "更新者")
|
||||
private Long updater;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
private Date updatedAt;
|
||||
}
|
||||
@@ -37,6 +37,9 @@ public class AgentEntity {
|
||||
@Schema(description = "大语言模型标识")
|
||||
private String llmModelId;
|
||||
|
||||
@Schema(description = "小模型标识")
|
||||
private String slmModelId;
|
||||
|
||||
@Schema(description = "VLLM模型标识")
|
||||
private String vllmModelId;
|
||||
|
||||
|
||||
+8
@@ -12,4 +12,12 @@ public interface AgentChatSummaryService {
|
||||
* @return 保存结果
|
||||
*/
|
||||
boolean generateAndSaveChatSummary(String sessionId);
|
||||
|
||||
/**
|
||||
* 根据会话ID生成聊天标题并保存
|
||||
*
|
||||
* @param sessionId 会话ID
|
||||
* @return 是否成功
|
||||
*/
|
||||
boolean generateAndSaveChatTitle(String sessionId);
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package xiaozhi.modules.agent.service;
|
||||
|
||||
import xiaozhi.modules.agent.entity.AgentChatTitleEntity;
|
||||
|
||||
public interface AgentChatTitleService {
|
||||
|
||||
void saveOrUpdateTitle(String sessionId, String title);
|
||||
|
||||
String getTitleBySessionId(String sessionId);
|
||||
}
|
||||
+1
-1
@@ -52,7 +52,7 @@ public class AgentChatHistoryBizServiceImpl implements AgentChatHistoryBizServic
|
||||
public Boolean report(AgentChatHistoryReportDTO report) {
|
||||
String macAddress = report.getMacAddress();
|
||||
Byte chatType = report.getChatType();
|
||||
Long reportTimeMillis = null != report.getReportTime() ? report.getReportTime() * 1000
|
||||
Long reportTimeMillis = null != report.getReportTime() ? report.getReportTime()
|
||||
: System.currentTimeMillis();
|
||||
log.info("小智设备聊天上报请求: macAddress={}, type={} reportTime={}", macAddress, chatType, reportTimeMillis);
|
||||
|
||||
|
||||
+7
-1
@@ -6,6 +6,7 @@ import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -26,6 +27,7 @@ import xiaozhi.modules.agent.dto.AgentChatHistoryDTO;
|
||||
import xiaozhi.modules.agent.dto.AgentChatSessionDTO;
|
||||
import xiaozhi.modules.agent.entity.AgentChatHistoryEntity;
|
||||
import xiaozhi.modules.agent.service.AgentChatHistoryService;
|
||||
import xiaozhi.modules.agent.service.AgentChatTitleService;
|
||||
import xiaozhi.modules.agent.vo.AgentChatHistoryUserVO;
|
||||
|
||||
/**
|
||||
@@ -36,9 +38,12 @@ import xiaozhi.modules.agent.vo.AgentChatHistoryUserVO;
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AgentChatHistoryServiceImpl extends ServiceImpl<AiAgentChatHistoryDao, AgentChatHistoryEntity>
|
||||
implements AgentChatHistoryService {
|
||||
|
||||
private final AgentChatTitleService agentChatTitleService;
|
||||
|
||||
@Override
|
||||
public PageData<AgentChatSessionDTO> getSessionListByAgentId(Map<String, Object> params) {
|
||||
String agentId = (String) params.get("agentId");
|
||||
@@ -61,6 +66,7 @@ public class AgentChatHistoryServiceImpl extends ServiceImpl<AiAgentChatHistoryD
|
||||
dto.setSessionId((String) map.get("session_id"));
|
||||
dto.setCreatedAt((LocalDateTime) map.get("created_at"));
|
||||
dto.setChatCount(((Number) map.get("chat_count")).intValue());
|
||||
dto.setTitle(agentChatTitleService.getTitleBySessionId(dto.getSessionId()));
|
||||
return dto;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
@@ -91,7 +97,7 @@ public class AgentChatHistoryServiceImpl extends ServiceImpl<AiAgentChatHistoryD
|
||||
if (ToolUtil.isNotEmpty(audioIds)) {
|
||||
// 每批删除1000条
|
||||
List<List<String>> batch = ListUtil.split(audioIds, 1000);
|
||||
batch.forEach(dataList->{
|
||||
batch.forEach(dataList -> {
|
||||
baseMapper.deleteAudioByIds(dataList);
|
||||
});
|
||||
}
|
||||
|
||||
+121
-23
@@ -14,6 +14,7 @@ import org.springframework.stereotype.Service;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import xiaozhi.common.constant.Constant;
|
||||
import xiaozhi.modules.agent.dto.AgentChatHistoryDTO;
|
||||
import xiaozhi.modules.agent.dto.AgentChatSummaryDTO;
|
||||
import xiaozhi.modules.agent.dto.AgentMemoryDTO;
|
||||
@@ -21,6 +22,7 @@ import xiaozhi.modules.agent.dto.AgentUpdateDTO;
|
||||
import xiaozhi.modules.agent.entity.AgentChatHistoryEntity;
|
||||
import xiaozhi.modules.agent.service.AgentChatHistoryService;
|
||||
import xiaozhi.modules.agent.service.AgentChatSummaryService;
|
||||
import xiaozhi.modules.agent.service.AgentChatTitleService;
|
||||
import xiaozhi.modules.agent.service.AgentService;
|
||||
import xiaozhi.modules.agent.vo.AgentInfoVO;
|
||||
import xiaozhi.modules.device.entity.DeviceEntity;
|
||||
@@ -41,6 +43,7 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService {
|
||||
|
||||
private final AgentChatHistoryService agentChatHistoryService;
|
||||
private final AgentService agentService;
|
||||
private final AgentChatTitleService agentChatTitleService;
|
||||
private final DeviceService deviceService;
|
||||
private final LLMService llmService;
|
||||
private final ModelConfigService modelConfigService;
|
||||
@@ -90,33 +93,40 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService {
|
||||
@Override
|
||||
public boolean generateAndSaveChatSummary(String sessionId) {
|
||||
try {
|
||||
// 1. 生成总结
|
||||
AgentChatSummaryDTO summaryDTO = generateChatSummary(sessionId);
|
||||
if (!summaryDTO.isSuccess()) {
|
||||
log.info("生成总结失败: {}", summaryDTO.getErrorMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 获取设备信息(通过会话关联的设备)
|
||||
DeviceEntity device = getDeviceBySessionId(sessionId);
|
||||
if (device == null) {
|
||||
log.info("未找到与会话 {} 关联的设备", sessionId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. 更新智能体记忆
|
||||
AgentMemoryDTO memoryDTO = new AgentMemoryDTO();
|
||||
memoryDTO.setSummaryMemory(summaryDTO.getSummary());
|
||||
String agentId = device.getAgentId();
|
||||
String memModelId = agentService.getAgentById(agentId).getMemModelId();
|
||||
|
||||
// 调用现有接口更新记忆
|
||||
agentService.updateAgentById(device.getAgentId(),
|
||||
new AgentUpdateDTO() {
|
||||
if (memModelId == null || memModelId.equals(Constant.MEMORY_MEM_REPORT_ONLY)) {
|
||||
log.info("会话 {} 使用仅上报聊天记录模式,跳过记忆总结", sessionId);
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean shouldSummarizeMemory = !memModelId.equals(Constant.MEMORY_NO_MEM)
|
||||
&& !memModelId.equals(Constant.MEMORY_MEM0AI)
|
||||
&& !memModelId.equals(Constant.MEMORY_POWERMEM);
|
||||
|
||||
if (shouldSummarizeMemory) {
|
||||
AgentChatSummaryDTO summaryDTO = generateChatSummary(sessionId);
|
||||
if (summaryDTO.isSuccess()) {
|
||||
agentService.updateAgentById(agentId, new AgentUpdateDTO() {
|
||||
{
|
||||
setSummaryMemory(summaryDTO.getSummary());
|
||||
}
|
||||
});
|
||||
log.info("成功保存会话 {} 的聊天记录总结到智能体 {}", sessionId, agentId);
|
||||
} else {
|
||||
log.info("生成总结失败: {}", summaryDTO.getErrorMessage());
|
||||
}
|
||||
} else {
|
||||
log.info("会话 {} 使用 {} 模式,跳过记忆总结", sessionId, memModelId);
|
||||
}
|
||||
|
||||
log.info("成功保存会话 {} 的聊天记录总结到智能体 {}", sessionId, device.getAgentId());
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
@@ -125,6 +135,98 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateAndSaveChatTitle(String sessionId) {
|
||||
try {
|
||||
// 自动获取agentId
|
||||
String agentId = findAgentIdBySessionId(sessionId);
|
||||
if (StringUtils.isBlank(agentId)) {
|
||||
log.warn("会话 {} 无法获取智能体信息,跳过标题生成", sessionId);
|
||||
return false;
|
||||
}
|
||||
|
||||
List<AgentChatHistoryDTO> chatHistory = getChatHistoryBySessionId(sessionId);
|
||||
if (chatHistory == null || chatHistory.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<String> meaningfulMessages = extractMeaningfulMessages(chatHistory);
|
||||
if (meaningfulMessages.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
StringBuilder conversation = new StringBuilder();
|
||||
for (int i = 0; i < meaningfulMessages.size(); i++) {
|
||||
conversation.append("消息").append(i + 1).append(": ").append(meaningfulMessages.get(i)).append("\n");
|
||||
}
|
||||
|
||||
String slmModelId = getSlmModelId(agentId);
|
||||
String title = llmService.generateTitle(conversation.toString(), slmModelId);
|
||||
|
||||
if (StringUtils.isNotBlank(title)) {
|
||||
agentChatTitleService.saveOrUpdateTitle(sessionId, title);
|
||||
log.info("成功保存会话 {} 的标题: {}", sessionId, title);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
log.error("生成会话 {} 的标题时发生错误: {}", sessionId, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private String getSlmModelId(String agentId) {
|
||||
try {
|
||||
if (StringUtils.isBlank(agentId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AgentInfoVO agentInfo = agentService.getAgentById(agentId);
|
||||
if (agentInfo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String slmModelId = agentInfo.getSlmModelId();
|
||||
if (StringUtils.isNotBlank(slmModelId)) {
|
||||
log.info("会话 {} 使用SLM模型: {}", agentId, slmModelId);
|
||||
return slmModelId;
|
||||
}
|
||||
|
||||
ModelConfigEntity defaultLlmConfig = getDefaultLLMConfig();
|
||||
if (defaultLlmConfig != null) {
|
||||
log.info("会话 {} 使用默认LLM模型: {}", agentId, defaultLlmConfig.getId());
|
||||
return defaultLlmConfig.getId();
|
||||
}
|
||||
|
||||
String llmModelId = agentInfo.getLlmModelId();
|
||||
log.info("会话 {} 使用LLM模型(最终回退): {}", agentId, llmModelId);
|
||||
return llmModelId;
|
||||
} catch (Exception e) {
|
||||
log.error("获取智能体slm模型ID失败,agentId: {}, 错误: {}", agentId, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private ModelConfigEntity getDefaultLLMConfig() {
|
||||
try {
|
||||
List<ModelConfigEntity> llmConfigs = modelConfigService.getEnabledModelsByType("LLM");
|
||||
if (llmConfigs == null || llmConfigs.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (ModelConfigEntity config : llmConfigs) {
|
||||
if (config.getIsDefault() != null && config.getIsDefault() == 1) {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
return llmConfigs.get(0);
|
||||
} catch (Exception e) {
|
||||
log.error("获取默认LLM配置失败: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据会话ID获取聊天记录
|
||||
*/
|
||||
@@ -305,15 +407,13 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService {
|
||||
*/
|
||||
private String callJavaLLMForSummaryWithHistory(String conversation, String historyMemory, String agentId) {
|
||||
try {
|
||||
// 获取智能体配置,从中提取记忆总结的模型ID
|
||||
String modelId = getMemorySummaryModelId(agentId);
|
||||
String modelId = getSlmModelId(agentId);
|
||||
|
||||
if (StringUtils.isBlank(modelId)) {
|
||||
log.info("未找到记忆总结的LLM模型配置,使用默认LLM服务");
|
||||
log.info("未找到SLM模型,使用默认LLM服务");
|
||||
return llmService.generateSummaryWithHistory(conversation, historyMemory, null, null);
|
||||
}
|
||||
|
||||
// 使用指定的模型ID调用LLM服务(支持历史记忆合并)
|
||||
String summary = llmService.generateSummaryWithHistory(conversation, historyMemory, null, modelId);
|
||||
|
||||
if (StringUtils.isNotBlank(summary) && !summary.equals("服务暂不可用") && !summary.equals("总结生成失败")) {
|
||||
@@ -333,15 +433,13 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService {
|
||||
*/
|
||||
private String callJavaLLMForSummary(String conversation, String agentId) {
|
||||
try {
|
||||
// 获取智能体配置,从中提取记忆总结的模型ID
|
||||
String modelId = getMemorySummaryModelId(agentId);
|
||||
String modelId = getSlmModelId(agentId);
|
||||
|
||||
if (StringUtils.isBlank(modelId)) {
|
||||
log.info("未找到记忆总结的LLM模型配置,使用默认LLM服务");
|
||||
log.info("未找到SLM模型,使用默认LLM服务");
|
||||
return llmService.generateSummary(conversation);
|
||||
}
|
||||
|
||||
// 使用指定的模型ID调用LLM服务
|
||||
String summary = llmService.generateSummaryWithModel(conversation, modelId);
|
||||
|
||||
if (StringUtils.isNotBlank(summary) && !summary.equals("服务暂不可用") && !summary.equals("总结生成失败")) {
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package xiaozhi.modules.agent.service.impl;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import xiaozhi.modules.agent.dao.AgentChatTitleDao;
|
||||
import xiaozhi.modules.agent.entity.AgentChatTitleEntity;
|
||||
import xiaozhi.modules.agent.service.AgentChatTitleService;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AgentChatTitleServiceImpl implements AgentChatTitleService {
|
||||
|
||||
private final AgentChatTitleDao agentChatTitleDao;
|
||||
|
||||
@Override
|
||||
public void saveOrUpdateTitle(String sessionId, String title) {
|
||||
if (StringUtils.isBlank(sessionId) || StringUtils.isBlank(title)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QueryWrapper<AgentChatTitleEntity> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("session_id", sessionId);
|
||||
|
||||
AgentChatTitleEntity existing = agentChatTitleDao.selectOne(wrapper);
|
||||
|
||||
if (existing != null) {
|
||||
existing.setTitle(title);
|
||||
existing.setUpdatedAt(new Date());
|
||||
agentChatTitleDao.updateById(existing);
|
||||
} else {
|
||||
AgentChatTitleEntity newEntity = AgentChatTitleEntity.builder()
|
||||
.id(java.util.UUID.randomUUID().toString().replace("-", ""))
|
||||
.sessionId(sessionId)
|
||||
.title(title)
|
||||
.createdAt(new Date())
|
||||
.updatedAt(new Date())
|
||||
.build();
|
||||
agentChatTitleDao.insert(newEntity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitleBySessionId(String sessionId) {
|
||||
if (StringUtils.isBlank(sessionId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
QueryWrapper<AgentChatTitleEntity> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("session_id", sessionId);
|
||||
|
||||
AgentChatTitleEntity entity = agentChatTitleDao.selectOne(wrapper);
|
||||
return entity != null ? entity.getTitle() : null;
|
||||
}
|
||||
}
|
||||
+58
-25
@@ -48,6 +48,7 @@ import xiaozhi.modules.agent.service.AgentService;
|
||||
import xiaozhi.modules.agent.service.AgentTagService;
|
||||
import xiaozhi.modules.agent.service.AgentTemplateService;
|
||||
import xiaozhi.modules.agent.vo.AgentInfoVO;
|
||||
import xiaozhi.modules.correctword.service.CorrectWordFileService;
|
||||
import xiaozhi.modules.device.entity.DeviceEntity;
|
||||
import xiaozhi.modules.device.service.DeviceService;
|
||||
import xiaozhi.modules.model.dto.ModelProviderDTO;
|
||||
@@ -74,6 +75,7 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
private final ModelProviderService modelProviderService;
|
||||
private final AgentContextProviderService agentContextProviderService;
|
||||
private final AgentTagService agentTagService;
|
||||
private final CorrectWordFileService correctWordFileService;
|
||||
|
||||
@Override
|
||||
public PageData<AgentEntity> adminAgentList(Map<String, Object> params) {
|
||||
@@ -104,6 +106,10 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
agent.setContextProviders(contextProviderEntity.getContextProviders());
|
||||
}
|
||||
|
||||
// 查询替换词文件ID列表
|
||||
List<String> correctWordFileIds = correctWordFileService.getAgentCorrectWordFileIds(id);
|
||||
agent.setCorrectWordFileIds(correctWordFileIds);
|
||||
|
||||
// 无需额外查询插件列表,已通过SQL查询出来
|
||||
return agent;
|
||||
}
|
||||
@@ -140,40 +146,32 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
QueryWrapper<AgentEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("user_id", userId).orderByDesc("created_at");
|
||||
|
||||
// 如果有搜索关键词,根据搜索类型添加相应的查询条件
|
||||
if (StringUtils.isNotBlank(keyword)) {
|
||||
if ("mac".equals(searchType)) {
|
||||
// 按MAC地址搜索:先搜索设备,再获取对应的智能体
|
||||
queryWrapper.and(w -> {
|
||||
// 按名称搜索
|
||||
w.like("agent_name", keyword);
|
||||
|
||||
// 按MAC地址搜索:先查设备,再获取对应的智能体ID
|
||||
List<DeviceEntity> devices = Optional
|
||||
.ofNullable(deviceService.searchDevicesByMacAddress(keyword, userId)).orElseGet(ArrayList::new);
|
||||
// 获取设备对应的智能体ID列表
|
||||
.ofNullable(deviceService.searchDevicesByMacAddress(keyword, userId))
|
||||
.orElseGet(ArrayList::new);
|
||||
List<String> agentIds = devices.stream()
|
||||
.map(DeviceEntity::getAgentId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
if (ToolUtil.isNotEmpty(agentIds)) {
|
||||
queryWrapper.in("id", agentIds);
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
w.or().in("id", agentIds);
|
||||
}
|
||||
} else {
|
||||
// 按名称搜索(默认):同时搜索智能体名称和标签名
|
||||
|
||||
// 按标签名搜索
|
||||
List<String> tagAgentIds = agentTagService.getAgentIdsByTagName(keyword);
|
||||
if (ToolUtil.isNotEmpty(tagAgentIds)) {
|
||||
queryWrapper.and(wrapper -> wrapper
|
||||
.like("agent_name", keyword)
|
||||
.or()
|
||||
.in("id", tagAgentIds));
|
||||
} else {
|
||||
queryWrapper.like("agent_name", keyword);
|
||||
w.or().in("id", tagAgentIds);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
List<AgentEntity> agentEntities = baseDao.selectList(queryWrapper);
|
||||
|
||||
// 转换为DTO并设置所有必要字段
|
||||
return agentEntities.stream().map(this::buildAgentDTO).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@@ -300,6 +298,9 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
if (dto.getLlmModelId() != null) {
|
||||
existingEntity.setLlmModelId(dto.getLlmModelId());
|
||||
}
|
||||
if (dto.getSlmModelId() != null) {
|
||||
existingEntity.setSlmModelId(dto.getSlmModelId());
|
||||
}
|
||||
if (dto.getVllmModelId() != null) {
|
||||
existingEntity.setVllmModelId(dto.getVllmModelId());
|
||||
}
|
||||
@@ -406,13 +407,14 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
existingEntity.setUpdatedAt(new Date());
|
||||
|
||||
// 更新记忆策略
|
||||
if (existingEntity.getMemModelId() == null || existingEntity.getMemModelId().equals(Constant.MEMORY_NO_MEM)) {
|
||||
// 删除所有记录
|
||||
// 删除所有记录
|
||||
if (existingEntity.getMemModelId() != null && existingEntity.getMemModelId().equals(Constant.MEMORY_NO_MEM)) {
|
||||
agentChatHistoryService.deleteByAgentId(existingEntity.getId(), true, true);
|
||||
existingEntity.setSummaryMemory("");
|
||||
} else if (existingEntity.getChatHistoryConf() != null && existingEntity.getChatHistoryConf() == 1) {
|
||||
// 删除音频数据
|
||||
agentChatHistoryService.deleteByAgentId(existingEntity.getId(), true, false);
|
||||
// 删除记忆
|
||||
} else if (existingEntity.getMemModelId() != null
|
||||
&& existingEntity.getMemModelId().equals(Constant.MEMORY_MEM_REPORT_ONLY)) {
|
||||
existingEntity.setSummaryMemory("");
|
||||
}
|
||||
|
||||
// 更新上下文源配置
|
||||
@@ -423,6 +425,11 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
agentContextProviderService.saveOrUpdateByAgentId(contextEntity);
|
||||
}
|
||||
|
||||
// 更新替换词文件关联
|
||||
if (dto.getCorrectWordFileIds() != null) {
|
||||
correctWordFileService.saveAgentCorrectWords(agentId, dto.getCorrectWordFileIds());
|
||||
}
|
||||
|
||||
boolean b = validateLLMIntentParams(dto.getLlmModelId(), dto.getIntentModelId());
|
||||
if (!b) {
|
||||
throw new RenException(ErrorCode.LLM_INTENT_PARAMS_MISMATCH);
|
||||
@@ -505,6 +512,13 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
entity.setLanguage(template.getLanguage());
|
||||
}
|
||||
|
||||
if (entity.getSlmModelId() == null) {
|
||||
String defaultSlmModelId = getDefaultLLMModelId();
|
||||
if (defaultSlmModelId != null) {
|
||||
entity.setSlmModelId(defaultSlmModelId);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置用户ID和创建者信息
|
||||
UserDetail user = SecurityUser.getUser();
|
||||
entity.setUserId(user.getId());
|
||||
@@ -543,4 +557,23 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
private String getDefaultLLMModelId() {
|
||||
try {
|
||||
List<ModelConfigEntity> llmConfigs = modelConfigService.getEnabledModelsByType("LLM");
|
||||
if (llmConfigs == null || llmConfigs.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (ModelConfigEntity config : llmConfigs) {
|
||||
if (config.getIsDefault() != null && config.getIsDefault() == 1) {
|
||||
return config.getId();
|
||||
}
|
||||
}
|
||||
|
||||
return llmConfigs.get(0).getId();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,4 +25,7 @@ public class AgentInfoVO extends AgentEntity
|
||||
|
||||
@Schema(description = "上下文源配置")
|
||||
private List<ContextProviderDTO> contextProviders;
|
||||
|
||||
@Schema(description = "替换词文件ID列表")
|
||||
private List<String> correctWordFileIds;
|
||||
}
|
||||
|
||||
+11
@@ -1,5 +1,7 @@
|
||||
package xiaozhi.modules.config.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -12,6 +14,7 @@ import lombok.AllArgsConstructor;
|
||||
import xiaozhi.common.utils.Result;
|
||||
import xiaozhi.common.validator.ValidatorUtils;
|
||||
import xiaozhi.modules.config.dto.AgentModelsDTO;
|
||||
import xiaozhi.modules.config.dto.CorrectWordsDTO;
|
||||
import xiaozhi.modules.config.service.ConfigService;
|
||||
|
||||
/**
|
||||
@@ -41,4 +44,12 @@ public class ConfigController {
|
||||
Object models = configService.getAgentModels(dto.getMacAddress(), dto.getSelectedModule());
|
||||
return new Result<Object>().ok(models);
|
||||
}
|
||||
|
||||
@PostMapping("correct-words")
|
||||
@Operation(summary = "获取智能体替换词")
|
||||
public Result<Object> getCorrectWords(@Valid @RequestBody CorrectWordsDTO dto) {
|
||||
ValidatorUtils.validateEntity(dto);
|
||||
List<String> list = configService.getCorrectWords(dto.getMacAddress());
|
||||
return new Result<Object>().ok(list);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package xiaozhi.modules.config.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "获取智能体替换词DTO")
|
||||
public class CorrectWordsDTO {
|
||||
|
||||
@NotBlank(message = "设备MAC地址不能为空")
|
||||
@Schema(description = "设备MAC地址")
|
||||
private String macAddress;
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
package xiaozhi.modules.config.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface ConfigService {
|
||||
/**
|
||||
* 获取服务器配置
|
||||
*
|
||||
*
|
||||
* @param isCache 是否缓存
|
||||
* @return 配置信息
|
||||
*/
|
||||
@@ -13,10 +14,18 @@ public interface ConfigService {
|
||||
|
||||
/**
|
||||
* 获取智能体模型配置
|
||||
*
|
||||
*
|
||||
* @param macAddress MAC地址
|
||||
* @param selectedModule 客户端已实例化的模型
|
||||
* @return 模型配置信息
|
||||
*/
|
||||
Map<String, Object> getAgentModels(String macAddress, Map<String, String> selectedModule);
|
||||
|
||||
/**
|
||||
* 获取智能体替换词
|
||||
*
|
||||
* @param macAddress 设备MAC地址
|
||||
* @return 替换词列表,格式如 ["模板1|模板01", "模板2|模板02"]
|
||||
*/
|
||||
List<String> getCorrectWords(String macAddress);
|
||||
}
|
||||
+37
-7
@@ -1,10 +1,12 @@
|
||||
package xiaozhi.modules.config.service.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -30,7 +32,9 @@ import xiaozhi.modules.agent.service.AgentMcpAccessPointService;
|
||||
import xiaozhi.modules.agent.service.AgentPluginMappingService;
|
||||
import xiaozhi.modules.agent.service.AgentService;
|
||||
import xiaozhi.modules.agent.service.AgentTemplateService;
|
||||
import xiaozhi.modules.correctword.service.CorrectWordFileService;
|
||||
import xiaozhi.modules.agent.vo.AgentVoicePrintVO;
|
||||
import xiaozhi.modules.correctword.vo.CorrectWordSimpleVO;
|
||||
import xiaozhi.modules.config.service.ConfigService;
|
||||
import xiaozhi.modules.device.entity.DeviceEntity;
|
||||
import xiaozhi.modules.device.service.DeviceService;
|
||||
@@ -58,6 +62,7 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
private final AgentContextProviderService agentContextProviderService;
|
||||
private final VoiceCloneService cloneVoiceService;
|
||||
private final AgentVoicePrintDao agentVoicePrintDao;
|
||||
private final CorrectWordFileService correctWordFileService;
|
||||
|
||||
@Override
|
||||
public Object getConfig(Boolean isCache) {
|
||||
@@ -99,6 +104,7 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
result,
|
||||
isCache);
|
||||
|
||||
@@ -113,7 +119,7 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
// 检查是否为管理控制台请求
|
||||
String redisKey = RedisKeys.getTmpRegisterMacKey(macAddress);
|
||||
Object isAdminRequest = redisUtils.get(redisKey);
|
||||
|
||||
|
||||
if (isAdminRequest != null && "true".equals(isAdminRequest)) {
|
||||
// 管理控制台请求,返回getConfig的结果
|
||||
redisUtils.delete(redisKey); // 使用后清理
|
||||
@@ -203,10 +209,11 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
mcpEndpoint = mcpEndpoint.replace("/mcp/", "/call/");
|
||||
result.put("mcp_endpoint", mcpEndpoint);
|
||||
}
|
||||
|
||||
|
||||
// 获取上下文源配置
|
||||
AgentContextProviderEntity contextProviderEntity = agentContextProviderService.getByAgentId(agent.getId());
|
||||
if (contextProviderEntity != null && contextProviderEntity.getContextProviders() != null && !contextProviderEntity.getContextProviders().isEmpty()) {
|
||||
if (contextProviderEntity != null && contextProviderEntity.getContextProviders() != null
|
||||
&& !contextProviderEntity.getContextProviders().isEmpty()) {
|
||||
result.put("context_providers", contextProviderEntity.getContextProviders());
|
||||
}
|
||||
|
||||
@@ -229,6 +236,7 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
agent.getAsrModelId(),
|
||||
agent.getLlmModelId(),
|
||||
agent.getVllmModelId(),
|
||||
agent.getSlmModelId(),
|
||||
agent.getTtsModelId(),
|
||||
agent.getMemModelId(),
|
||||
agent.getIntentModelId(),
|
||||
@@ -239,6 +247,18 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getCorrectWords(String macAddress) {
|
||||
DeviceEntity device = deviceService.getDeviceByMacAddress(macAddress);
|
||||
if (device == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<CorrectWordSimpleVO> items = correctWordFileService.getAllItemsByAgentId(device.getAgentId());
|
||||
return items.stream()
|
||||
.map(item -> item.getSourceWord() + "|" + item.getTargetWord())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建配置信息
|
||||
*
|
||||
@@ -410,6 +430,7 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
String asrModelId,
|
||||
String llmModelId,
|
||||
String vllmModelId,
|
||||
String slmModelId,
|
||||
String ttsModelId,
|
||||
String memModelId,
|
||||
String intentModelId,
|
||||
@@ -418,9 +439,9 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
boolean isCache) {
|
||||
Map<String, String> selectedModule = new HashMap<>();
|
||||
|
||||
String[] modelTypes = { "VAD", "ASR", "TTS", "Memory", "Intent", "LLM", "VLLM", "RAG" };
|
||||
String[] modelTypes = { "VAD", "ASR", "TTS", "Memory", "Intent", "LLM", "VLLM", "SLM", "RAG" };
|
||||
String[] modelIds = { vadModelId, asrModelId, ttsModelId, memModelId, intentModelId, llmModelId, vllmModelId,
|
||||
ragModelId };
|
||||
slmModelId, ragModelId };
|
||||
String intentLLMModelId = null;
|
||||
String memLocalShortLLMModelId = null;
|
||||
|
||||
@@ -456,7 +477,7 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
// 火山引擎声音克隆需要替换resource_id
|
||||
Map<String, Object> map = (Map<String, Object>) model.getConfigJson();
|
||||
if (Constant.VOICE_CLONE_HUOSHAN_DOUBLE_STREAM.equals(map.get("type"))) {
|
||||
// 如果voice是”S_“开头的,使用seed-icl-1.0
|
||||
// 如果voice是”S_”开头的,使用seed-icl-1.0
|
||||
if (voice != null && voice.startsWith("S_")) {
|
||||
map.put("resource_id", "seed-icl-1.0");
|
||||
}
|
||||
@@ -474,7 +495,7 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
if (map.get("functions") != null) {
|
||||
String functionStr = (String) map.get("functions");
|
||||
if (StringUtils.isNotBlank(functionStr)) {
|
||||
String[] functions = functionStr.split("\\;");
|
||||
String[] functions = functionStr.split(";");
|
||||
map.put("functions", functions);
|
||||
}
|
||||
}
|
||||
@@ -507,6 +528,15 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
typeConfig.put(memLocalShortLLM.getId(), memLocalShortLLM.getConfigJson());
|
||||
}
|
||||
}
|
||||
// LLM也返回所选的SLM,如果同名id则不重复显示
|
||||
if (StringUtils.isNotBlank(slmModelId) && !slmModelId.equals(llmModelId)) {
|
||||
if (!typeConfig.containsKey(slmModelId)) {
|
||||
ModelConfigEntity slmModel = modelConfigService.getModelByIdFromCache(slmModelId);
|
||||
if (slmModel != null && slmModel.getConfigJson() != null) {
|
||||
typeConfig.put(slmModel.getId(), slmModel.getConfigJson());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result.put(modelTypes[i], typeConfig);
|
||||
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package xiaozhi.modules.correctword.controller;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.AllArgsConstructor;
|
||||
import xiaozhi.common.constant.Constant;
|
||||
import xiaozhi.common.page.PageData;
|
||||
import xiaozhi.common.utils.Result;
|
||||
import xiaozhi.modules.correctword.dto.CorrectWordFileCreateDTO;
|
||||
import xiaozhi.modules.correctword.service.CorrectWordFileService;
|
||||
import xiaozhi.modules.correctword.vo.CorrectWordFileVO;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/correct-word")
|
||||
@Tag(name = "替换词管理")
|
||||
@AllArgsConstructor
|
||||
public class CorrectWordController {
|
||||
|
||||
private final CorrectWordFileService correctWordFileService;
|
||||
|
||||
@PostMapping("/file")
|
||||
@Operation(summary = "创建替换词文件")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<CorrectWordFileVO> createFile(@Valid @RequestBody CorrectWordFileCreateDTO dto) {
|
||||
CorrectWordFileVO vo = correctWordFileService.createFile(dto);
|
||||
return new Result<CorrectWordFileVO>().ok(vo);
|
||||
}
|
||||
|
||||
@PutMapping("/file/{fileId}")
|
||||
@Operation(summary = "修改替换词文件")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<Void> updateFile(@PathVariable String fileId, @Valid @RequestBody CorrectWordFileCreateDTO dto) {
|
||||
correctWordFileService.updateFile(fileId, dto);
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@GetMapping("/file/list")
|
||||
@Operation(summary = "分页获取当前用户替换词文件列表")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
@Parameters({
|
||||
@Parameter(name = Constant.PAGE, description = "当前页码,从1开始", required = true),
|
||||
@Parameter(name = Constant.LIMIT, description = "每页显示记录数", required = true),
|
||||
})
|
||||
public Result<PageData<CorrectWordFileVO>> listFiles(
|
||||
@Parameter(hidden = true) @RequestParam Map<String, Object> params) {
|
||||
PageData<CorrectWordFileVO> page = correctWordFileService.listFiles(params);
|
||||
return new Result<PageData<CorrectWordFileVO>>().ok(page);
|
||||
}
|
||||
|
||||
@GetMapping("/file/select")
|
||||
@Operation(summary = "智能体获取当前用户替换词文件列表")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<List<CorrectWordFileVO>> listAllFiles() {
|
||||
List<CorrectWordFileVO> list = correctWordFileService.listAllFiles();
|
||||
return new Result<List<CorrectWordFileVO>>().ok(list);
|
||||
}
|
||||
|
||||
@GetMapping("/file/download/{fileId}")
|
||||
@Operation(summary = "下载替换词文件")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public ResponseEntity<byte[]> downloadFile(@PathVariable String fileId) {
|
||||
CorrectWordFileVO vo = correctWordFileService.getFileContent(fileId);
|
||||
if (vo == null || vo.getContent() == null || vo.getContent().isEmpty()) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
byte[] bytes = String.join("\n", vo.getContent()).getBytes(StandardCharsets.UTF_8);
|
||||
String encodedFileName = URLEncoder.encode(vo.getFileName(), StandardCharsets.UTF_8).replace("+", "%20");
|
||||
String asciiFileName = vo.getFileName().replaceAll("[^\\x00-\\x7F]", "_");
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||
"attachment; filename=\"" + asciiFileName + "\"; filename*=UTF-8''" + encodedFileName)
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
.body(bytes);
|
||||
}
|
||||
|
||||
@DeleteMapping("/file/{fileId}")
|
||||
@Operation(summary = "删除替换词文件")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<Void> deleteFile(@PathVariable String fileId) {
|
||||
correctWordFileService.deleteFile(fileId);
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@PostMapping("/file/batch-delete")
|
||||
@Operation(summary = "批量删除替换词文件")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<Void> batchDeleteFiles(@RequestBody List<String> fileIds) {
|
||||
if (fileIds == null || fileIds.isEmpty()) {
|
||||
return new Result<>();
|
||||
}
|
||||
correctWordFileService.batchDeleteFiles(fileIds);
|
||||
return new Result<>();
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package xiaozhi.modules.correctword.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import xiaozhi.common.dao.BaseDao;
|
||||
import xiaozhi.modules.correctword.entity.CorrectWordFileEntity;
|
||||
|
||||
@Mapper
|
||||
public interface CorrectWordFileDao extends BaseDao<CorrectWordFileEntity> {
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package xiaozhi.modules.correctword.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import xiaozhi.common.dao.BaseDao;
|
||||
import xiaozhi.modules.correctword.entity.CorrectWordItemEntity;
|
||||
|
||||
@Mapper
|
||||
public interface CorrectWordItemDao extends BaseDao<CorrectWordItemEntity> {
|
||||
|
||||
int batchInsert(@Param("list") List<CorrectWordItemEntity> items);
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package xiaozhi.modules.correctword.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "创建替换词文件DTO")
|
||||
public class CorrectWordFileCreateDTO {
|
||||
|
||||
@NotBlank(message = "文件名不能为空")
|
||||
@Schema(description = "文件名")
|
||||
private String fileName;
|
||||
|
||||
@NotEmpty(message = "替换词内容不能为空")
|
||||
@Schema(description = "替换词内容,每条格式:原词|替换词")
|
||||
private List<String> content;
|
||||
|
||||
@Schema(description = "文件大小(字节),不能超过1MB")
|
||||
private Long fileSize;
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package xiaozhi.modules.correctword.entity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@TableName("ai_agent_correct_word_file")
|
||||
@Schema(description = "智能体替换词文件")
|
||||
public class CorrectWordFileEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
@Schema(description = "替换词文件ID")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "原始文件名")
|
||||
private String fileName;
|
||||
|
||||
@Schema(description = "替换词数量")
|
||||
private Integer wordCount;
|
||||
|
||||
@Schema(description = "文件原始内容(用于下载)")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "创建者")
|
||||
private Long creator;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date createdAt;
|
||||
|
||||
@Schema(description = "更新者")
|
||||
private Long updater;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
private Date updatedAt;
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package xiaozhi.modules.correctword.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@TableName("ai_agent_correct_word_item")
|
||||
@Schema(description = "替换词词条")
|
||||
public class CorrectWordItemEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
@Schema(description = "词条ID")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "所属文件ID")
|
||||
private String fileId;
|
||||
|
||||
@Schema(description = "原词")
|
||||
private String sourceWord;
|
||||
|
||||
@Schema(description = "替换词")
|
||||
private String targetWord;
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package xiaozhi.modules.correctword.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import xiaozhi.common.page.PageData;
|
||||
import xiaozhi.modules.correctword.dto.CorrectWordFileCreateDTO;
|
||||
import xiaozhi.modules.correctword.vo.CorrectWordFileVO;
|
||||
import xiaozhi.modules.correctword.vo.CorrectWordSimpleVO;
|
||||
|
||||
public interface CorrectWordFileService {
|
||||
|
||||
/**
|
||||
* 创建替换词文件
|
||||
*
|
||||
* @param dto 创建参数
|
||||
* @return 文件VO
|
||||
*/
|
||||
CorrectWordFileVO createFile(CorrectWordFileCreateDTO dto);
|
||||
|
||||
/**
|
||||
* 修改替换词文件(全量替换词条)
|
||||
*
|
||||
* @param fileId 文件ID
|
||||
* @param dto 修改参数
|
||||
*/
|
||||
void updateFile(String fileId, CorrectWordFileCreateDTO dto);
|
||||
|
||||
/**
|
||||
* 获取当前用户的替换词文件列表
|
||||
*
|
||||
* @param params 分页参数
|
||||
* @return 分页数据
|
||||
*/
|
||||
PageData<CorrectWordFileVO> listFiles(Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 获取当前用户的替换词文件列表(不分页,用于下拉选择)
|
||||
*
|
||||
* @return 文件列表
|
||||
*/
|
||||
List<CorrectWordFileVO> listAllFiles();
|
||||
|
||||
/**
|
||||
* 获取文件原始内容(用于下载)
|
||||
*
|
||||
* @param fileId 文件ID
|
||||
* @return 文件实体
|
||||
*/
|
||||
CorrectWordFileVO getFileContent(String fileId);
|
||||
|
||||
/**
|
||||
* 删除替换词文件及其所有词条和关联记录
|
||||
*
|
||||
* @param fileId 文件ID
|
||||
*/
|
||||
void deleteFile(String fileId);
|
||||
|
||||
/**
|
||||
* 删除智能体关联的替换词文件关联记录(不删文件本身)
|
||||
*
|
||||
* @param agentId 智能体ID
|
||||
*/
|
||||
void deleteMappingsByAgentId(String agentId);
|
||||
|
||||
/**
|
||||
* 获取智能体的所有替换词条(精简版,供设备端使用)
|
||||
*
|
||||
* @param agentId 智能体ID
|
||||
* @return 替换词列表
|
||||
*/
|
||||
List<CorrectWordSimpleVO> getAllItemsByAgentId(String agentId);
|
||||
|
||||
/**
|
||||
* 获取智能体关联的替换词文件ID列表
|
||||
*
|
||||
* @param agentId 智能体ID
|
||||
* @return 文件ID列表
|
||||
*/
|
||||
List<String> getAgentCorrectWordFileIds(String agentId);
|
||||
|
||||
/**
|
||||
* 保存智能体关联的替换词文件(全量替换)
|
||||
*
|
||||
* @param agentId 智能体ID
|
||||
* @param fileIds 文件ID列表
|
||||
*/
|
||||
void saveAgentCorrectWords(String agentId, List<String> fileIds);
|
||||
|
||||
/**
|
||||
* 批量删除替换词文件
|
||||
*
|
||||
* @param fileIds 文件ID列表
|
||||
*/
|
||||
void batchDeleteFiles(List<String> fileIds);
|
||||
}
|
||||
+296
@@ -0,0 +1,296 @@
|
||||
package xiaozhi.modules.correctword.service.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import xiaozhi.common.exception.ErrorCode;
|
||||
import xiaozhi.common.exception.RenException;
|
||||
import xiaozhi.common.page.PageData;
|
||||
import xiaozhi.common.service.impl.BaseServiceImpl;
|
||||
import xiaozhi.common.utils.ConvertUtils;
|
||||
import xiaozhi.modules.agent.dao.AgentCorrectWordMappingDao;
|
||||
import xiaozhi.modules.correctword.dao.CorrectWordFileDao;
|
||||
import xiaozhi.modules.correctword.dao.CorrectWordItemDao;
|
||||
import xiaozhi.modules.correctword.dto.CorrectWordFileCreateDTO;
|
||||
import xiaozhi.modules.agent.entity.AgentCorrectWordMappingEntity;
|
||||
import xiaozhi.modules.correctword.entity.CorrectWordFileEntity;
|
||||
import xiaozhi.modules.correctword.entity.CorrectWordItemEntity;
|
||||
import xiaozhi.modules.correctword.service.CorrectWordFileService;
|
||||
import xiaozhi.modules.correctword.vo.CorrectWordFileVO;
|
||||
import xiaozhi.modules.correctword.vo.CorrectWordSimpleVO;
|
||||
import xiaozhi.modules.security.user.SecurityUser;
|
||||
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class CorrectWordFileServiceImpl extends BaseServiceImpl<CorrectWordFileDao, CorrectWordFileEntity>
|
||||
implements CorrectWordFileService {
|
||||
|
||||
private final CorrectWordFileDao correctWordFileDao;
|
||||
private final CorrectWordItemDao correctWordItemDao;
|
||||
private final AgentCorrectWordMappingDao agentCorrectWordMappingDao;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public CorrectWordFileVO createFile(CorrectWordFileCreateDTO dto) {
|
||||
// 校验文件大小不能超过1MB
|
||||
if (dto.getFileSize() != null && dto.getFileSize() > 1024 * 1024) {
|
||||
throw new RenException(ErrorCode.FILE_SIZE_OVER_LIMIT);
|
||||
}
|
||||
|
||||
// 校验文件名是否重复
|
||||
Long userId = SecurityUser.getUserId();
|
||||
LambdaQueryWrapper<CorrectWordFileEntity> nameWrapper = new LambdaQueryWrapper<>();
|
||||
nameWrapper.eq(CorrectWordFileEntity::getCreator, userId)
|
||||
.eq(CorrectWordFileEntity::getFileName, dto.getFileName());
|
||||
if (correctWordFileDao.selectCount(nameWrapper) > 0) {
|
||||
throw new RenException(ErrorCode.CORRECT_WORD_FILE_NAME_EXISTS);
|
||||
}
|
||||
|
||||
List<CorrectWordItemEntity> items = parseContent(dto.getContent());
|
||||
|
||||
// 保存文件记录
|
||||
CorrectWordFileEntity fileEntity = new CorrectWordFileEntity();
|
||||
fileEntity.setFileName(dto.getFileName());
|
||||
fileEntity.setWordCount(items.size());
|
||||
fileEntity.setContent(String.join("\n", dto.getContent()));
|
||||
fileEntity.setCreator(SecurityUser.getUserId());
|
||||
fileEntity.setCreatedAt(new Date());
|
||||
correctWordFileDao.insert(fileEntity);
|
||||
|
||||
// 设置fileId并批量保存词条
|
||||
String fileId = fileEntity.getId();
|
||||
for (CorrectWordItemEntity item : items) {
|
||||
item.setFileId(fileId);
|
||||
}
|
||||
if (!items.isEmpty()) {
|
||||
correctWordItemDao.batchInsert(items);
|
||||
}
|
||||
|
||||
return toVO(fileEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateFile(String fileId, CorrectWordFileCreateDTO dto) {
|
||||
CorrectWordFileEntity fileEntity = correctWordFileDao.selectById(fileId);
|
||||
if (fileEntity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 校验文件名是否重复(排除自身)
|
||||
Long userId = SecurityUser.getUserId();
|
||||
LambdaQueryWrapper<CorrectWordFileEntity> nameWrapper = new LambdaQueryWrapper<>();
|
||||
nameWrapper.eq(CorrectWordFileEntity::getCreator, userId)
|
||||
.eq(CorrectWordFileEntity::getFileName, dto.getFileName())
|
||||
.ne(CorrectWordFileEntity::getId, fileId);
|
||||
if (correctWordFileDao.selectCount(nameWrapper) > 0) {
|
||||
throw new RenException("文件名已存在:" + dto.getFileName());
|
||||
}
|
||||
|
||||
// 先删除旧词条
|
||||
LambdaQueryWrapper<CorrectWordItemEntity> deleteWrapper = new LambdaQueryWrapper<>();
|
||||
deleteWrapper.eq(CorrectWordItemEntity::getFileId, fileId);
|
||||
correctWordItemDao.delete(deleteWrapper);
|
||||
|
||||
// 解析新词条并批量保存
|
||||
List<CorrectWordItemEntity> items = parseContent(dto.getContent());
|
||||
if (!items.isEmpty()) {
|
||||
for (CorrectWordItemEntity item : items) {
|
||||
item.setFileId(fileId);
|
||||
}
|
||||
correctWordItemDao.batchInsert(items);
|
||||
}
|
||||
|
||||
// 更新文件记录
|
||||
fileEntity.setFileName(dto.getFileName());
|
||||
fileEntity.setWordCount(items.size());
|
||||
fileEntity.setContent(String.join("\n", dto.getContent()));
|
||||
fileEntity.setUpdater(SecurityUser.getUserId());
|
||||
fileEntity.setUpdatedAt(new Date());
|
||||
correctWordFileDao.updateById(fileEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageData<CorrectWordFileVO> listFiles(Map<String, Object> params) {
|
||||
Long userId = SecurityUser.getUserId();
|
||||
IPage<CorrectWordFileEntity> page = getPage(params, "created_at", false);
|
||||
LambdaQueryWrapper<CorrectWordFileEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(CorrectWordFileEntity::getCreator, userId)
|
||||
.orderByDesc(CorrectWordFileEntity::getCreatedAt);
|
||||
correctWordFileDao.selectPage(page, wrapper);
|
||||
List<CorrectWordFileVO> voList = toVOList(page.getRecords());
|
||||
return new PageData<>(voList, page.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CorrectWordFileVO> listAllFiles() {
|
||||
Long userId = SecurityUser.getUserId();
|
||||
LambdaQueryWrapper<CorrectWordFileEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(CorrectWordFileEntity::getCreator, userId)
|
||||
.orderByDesc(CorrectWordFileEntity::getCreatedAt);
|
||||
List<CorrectWordFileEntity> entities = correctWordFileDao.selectList(wrapper);
|
||||
return toVOList(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CorrectWordFileVO getFileContent(String fileId) {
|
||||
CorrectWordFileEntity entity = correctWordFileDao.selectById(fileId);
|
||||
return toVO(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteFile(String fileId) {
|
||||
if (fileId == null || fileId.trim().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// 先删除关联表记录
|
||||
agentCorrectWordMappingDao.deleteByFileId(fileId);
|
||||
// 删除词条
|
||||
LambdaQueryWrapper<CorrectWordItemEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(CorrectWordItemEntity::getFileId, fileId);
|
||||
correctWordItemDao.delete(wrapper);
|
||||
// 删除文件
|
||||
correctWordFileDao.deleteById(fileId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteMappingsByAgentId(String agentId) {
|
||||
agentCorrectWordMappingDao.deleteByAgentId(agentId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CorrectWordSimpleVO> getAllItemsByAgentId(String agentId) {
|
||||
// 通过关联表获取文件ID列表
|
||||
List<AgentCorrectWordMappingEntity> mappings = agentCorrectWordMappingDao.selectByAgentId(agentId);
|
||||
if (mappings == null || mappings.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<String> fileIds = mappings.stream()
|
||||
.map(AgentCorrectWordMappingEntity::getFileId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 根据文件ID列表查询词条
|
||||
LambdaQueryWrapper<CorrectWordItemEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.in(CorrectWordItemEntity::getFileId, fileIds);
|
||||
List<CorrectWordItemEntity> entities = correctWordItemDao.selectList(wrapper);
|
||||
return ConvertUtils.sourceToTarget(entities, CorrectWordSimpleVO.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAgentCorrectWordFileIds(String agentId) {
|
||||
List<AgentCorrectWordMappingEntity> mappings = agentCorrectWordMappingDao.selectByAgentId(agentId);
|
||||
if (mappings == null || mappings.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return mappings.stream()
|
||||
.map(AgentCorrectWordMappingEntity::getFileId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveAgentCorrectWords(String agentId, List<String> fileIds) {
|
||||
// 先删除旧的关联记录
|
||||
agentCorrectWordMappingDao.deleteByAgentId(agentId);
|
||||
|
||||
if (fileIds == null || fileIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 批量插入新的关联记录
|
||||
Long userId = SecurityUser.getUserId();
|
||||
Date now = new Date();
|
||||
List<AgentCorrectWordMappingEntity> mappings = new ArrayList<>();
|
||||
for (String fileId : fileIds) {
|
||||
AgentCorrectWordMappingEntity mapping = new AgentCorrectWordMappingEntity();
|
||||
mapping.setAgentId(agentId);
|
||||
mapping.setFileId(fileId);
|
||||
mapping.setCreator(userId);
|
||||
mapping.setCreatedAt(now);
|
||||
mapping.setUpdater(userId);
|
||||
mapping.setUpdatedAt(now);
|
||||
mappings.add(mapping);
|
||||
}
|
||||
agentCorrectWordMappingDao.batchInsertMapping(mappings);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchDeleteFiles(List<String> fileIds) {
|
||||
if (fileIds == null || fileIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (String fileId : fileIds) {
|
||||
if (fileId == null || fileId.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
deleteFile(fileId.trim());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析替换词内容,每条格式:原词|替换词
|
||||
*/
|
||||
private List<CorrectWordItemEntity> parseContent(List<String> lines) {
|
||||
List<CorrectWordItemEntity> items = new ArrayList<>();
|
||||
if (lines == null || lines.isEmpty()) {
|
||||
return items;
|
||||
}
|
||||
for (String line : lines) {
|
||||
line = line.trim();
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
int idx = line.indexOf('|');
|
||||
if (idx <= 0 || idx >= line.length() - 1) {
|
||||
continue;
|
||||
}
|
||||
String sourceWord = line.substring(0, idx).trim();
|
||||
String targetWord = line.substring(idx + 1).trim();
|
||||
if (sourceWord.isEmpty() || targetWord.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
CorrectWordItemEntity item = new CorrectWordItemEntity();
|
||||
item.setSourceWord(sourceWord);
|
||||
item.setTargetWord(targetWord);
|
||||
items.add(item);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
private CorrectWordFileVO toVO(CorrectWordFileEntity entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
CorrectWordFileVO vo = new CorrectWordFileVO();
|
||||
vo.setId(entity.getId());
|
||||
vo.setFileName(entity.getFileName());
|
||||
vo.setWordCount(entity.getWordCount());
|
||||
vo.setContent(entity.getContent() != null
|
||||
? Arrays.asList(entity.getContent().split("\n"))
|
||||
: new ArrayList<>());
|
||||
vo.setCreatedAt(entity.getCreatedAt());
|
||||
vo.setUpdatedAt(entity.getUpdatedAt());
|
||||
return vo;
|
||||
}
|
||||
|
||||
private List<CorrectWordFileVO> toVOList(List<CorrectWordFileEntity> entities) {
|
||||
if (entities == null || entities.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return entities.stream().map(this::toVO).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package xiaozhi.modules.correctword.vo;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "替换词文件列表VO")
|
||||
public class CorrectWordFileVO {
|
||||
|
||||
@Schema(description = "替换词文件ID")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "原始文件名")
|
||||
private String fileName;
|
||||
|
||||
@Schema(description = "替换词数量")
|
||||
private Integer wordCount;
|
||||
|
||||
@Schema(description = "替换词内容,每行一条")
|
||||
private List<String> content;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date createdAt;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
private Date updatedAt;
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package xiaozhi.modules.correctword.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "替换词精简VO(设备端使用)")
|
||||
public class CorrectWordSimpleVO {
|
||||
|
||||
@Schema(description = "原词")
|
||||
private String sourceWord;
|
||||
|
||||
@Schema(description = "替换词")
|
||||
private String targetWord;
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
# RAGFlow API Interface Classification
|
||||
|
||||
## 1. External APIs (三方接入体系)
|
||||
**Path Prefix:** `/api/v1`
|
||||
**Authentication:** API Key (`@token_required`)
|
||||
**Primary Use:** External system integration, SDK usage.
|
||||
|
||||
| Interface Type | Python File Path | Class/Function Name | URL Pattern | Notes |
|
||||
|---|---|---|---|---|
|
||||
| **External** | `api/apps/sdk/session.py` | `agent_bot_completions` | `/api/v1/agentbots/<agent_id>/completions` | Agent Bot completion |
|
||||
| **External** | `api/apps/sdk/session.py` | `begin_inputs` | `/api/v1/agentbots/<agent_id>/inputs` | Get Agent Bot inputs |
|
||||
| **External** | `api/apps/sdk/agents.py` | `list_agents` | `/api/v1/agents` | List Agents |
|
||||
| **External** | `api/apps/sdk/agents.py` | `create_agent` | `/api/v1/agents` | Create Agent |
|
||||
| **External** | `api/apps/sdk/agents.py` | `update_agent` | `/api/v1/agents/<agent_id>` | Update Agent |
|
||||
| **External** | `api/apps/sdk/agents.py` | `delete_agent` | `/api/v1/agents/<agent_id>` | Delete Agent |
|
||||
| **External** | `api/apps/sdk/session.py` | `agent_completions` | `/api/v1/agents/<agent_id>/completions` | Agent completion |
|
||||
| **External** | `api/apps/sdk/session.py` | `create_agent_session` | `/api/v1/agents/<agent_id>/sessions` | Create Agent Session |
|
||||
| **External** | `api/apps/sdk/session.py` | `list_agent_session` | `/api/v1/agents/<agent_id>/sessions` | List Agent Sessions |
|
||||
| **External** | `api/apps/sdk/session.py` | `delete_agent_session` | `/api/v1/agents/<agent_id>/sessions` | Delete Agent Session |
|
||||
| **External** | `api/apps/sdk/session.py` | `agents_completion_openai_compatibility` | `/api/v1/agents_openai/<agent_id>/chat/completions` | OpenAI compatible Agent completion |
|
||||
| **External** | `api/apps/sdk/session.py` | `chatbot_completions` | `/api/v1/chatbots/<dialog_id>/completions` | Chatbot completion |
|
||||
| **External** | `api/apps/sdk/session.py` | `chatbots_inputs` | `/api/v1/chatbots/<dialog_id>/info` | Chatbot info |
|
||||
| **External** | `api/apps/sdk/chat.py` | `create` | `/api/v1/chats` | Create Chat |
|
||||
| **External** | `api/apps/sdk/chat.py` | `delete_chats` | `/api/v1/chats` | Delete Chat |
|
||||
| **External** | `api/apps/sdk/chat.py` | `list_chat` | `/api/v1/chats` | List Chats |
|
||||
| **External** | `api/apps/sdk/chat.py` | `update` | `/api/v1/chats/<chat_id>` | Update Chat |
|
||||
| **External** | `api/apps/sdk/session.py` | `chat_completion` | `/api/v1/chats/<chat_id>/completions` | Chat completion |
|
||||
| **External** | `api/apps/sdk/session.py` | `create` | `/api/v1/chats/<chat_id>/sessions` | Create Chat Session |
|
||||
| **External** | `api/apps/sdk/session.py` | `list_session` | `/api/v1/chats/<chat_id>/sessions` | List Chat Sessions |
|
||||
| **External** | `api/apps/sdk/session.py` | `delete` | `/api/v1/chats/<chat_id>/sessions` | Delete Chat Session |
|
||||
| **External** | `api/apps/sdk/session.py` | `update` | `/api/v1/chats/<chat_id>/sessions/<session_id>` | Update Chat Session |
|
||||
| **External** | `api/apps/sdk/session.py` | `chat_completion_openai_like` | `/api/v1/chats_openai/<chat_id>/chat/completions` | OpenAI compatible Chat completion |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `create` | `/api/v1/datasets` | Create Dataset |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `delete` | `/api/v1/datasets` | Delete Dataset |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `list_datasets` | `/api/v1/datasets` | List Datasets |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `update` | `/api/v1/datasets/<dataset_id>` | Update Dataset |
|
||||
| **External** | `api/apps/sdk/doc.py` | `parse` | `/api/v1/datasets/<dataset_id>/chunks` | Parse Document Chunks |
|
||||
| **External** | `api/apps/sdk/doc.py` | `stop_parsing` | `/api/v1/datasets/<dataset_id>/chunks` | Stop Parsing |
|
||||
| **External** | `api/apps/sdk/doc.py` | `upload` | `/api/v1/datasets/<dataset_id>/documents` | Upload Document |
|
||||
| **External** | `api/apps/sdk/doc.py` | `list_docs` | `/api/v1/datasets/<dataset_id>/documents` | List Documents |
|
||||
| **External** | `api/apps/sdk/doc.py` | `delete` | `/api/v1/datasets/<dataset_id>/documents` | Delete Document |
|
||||
| **External** | `api/apps/sdk/doc.py` | `update_doc` | `/api/v1/datasets/<dataset_id>/documents/<document_id>` | Update Document |
|
||||
| **External** | `api/apps/sdk/doc.py` | `download` | `/api/v1/datasets/<dataset_id>/documents/<document_id>` | Download Document |
|
||||
| **External** | `api/apps/sdk/doc.py` | `list_chunks` | `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks` | List Chunks |
|
||||
| **External** | `api/apps/sdk/doc.py` | `add_chunk` | `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks` | Add Chunk |
|
||||
| **External** | `api/apps/sdk/doc.py` | `update_chunk` | `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks/<chunk_id>` | Update Chunk |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `knowledge_graph` | `/api/v1/datasets/<dataset_id>/knowledge_graph` | Knowledge Graph |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `delete_knowledge_graph` | `/api/v1/datasets/<dataset_id>/knowledge_graph` | Delete Knowledge Graph |
|
||||
| **External** | `api/apps/sdk/doc.py` | `metadata_summary` | `/api/v1/datasets/<dataset_id>/metadata/summary` | Metadata Summary |
|
||||
| **External** | `api/apps/sdk/doc.py` | `metadata_batch_update` | `/api/v1/datasets/<dataset_id>/metadata/update` | Batch Update Metadata |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `run_graphrag` | `/api/v1/datasets/<dataset_id>/run_graphrag` | Run GraphRAG |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `run_raptor` | `/api/v1/datasets/<dataset_id>/run_raptor` | Run Raptor |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `trace_graphrag` | `/api/v1/datasets/<dataset_id>/trace_graphrag` | Trace GraphRAG |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `trace_raptor` | `/api/v1/datasets/<dataset_id>/trace_raptor` | Trace Raptor |
|
||||
| **External** | `api/apps/sdk/dify_retrieval.py` | `retrieval` | `/api/v1/dify/retrieval` | Dify Retrieval |
|
||||
| **External** | `api/apps/sdk/files.py` | `get_all_parent_folders` | `/api/v1/file/all_parent_folder` | Get All Parent Folders |
|
||||
| **External** | `api/apps/sdk/files.py` | `convert` | `/api/v1/file/convert` | File Convert |
|
||||
| **External** | `api/apps/sdk/files.py` | `create` | `/api/v1/file/create` | File Create |
|
||||
| **External** | `api/apps/sdk/files.py` | `download_attachment` | `/api/v1/file/download/<attachment_id>` | Download Attachment |
|
||||
| **External** | `api/apps/sdk/files.py` | `get` | `/api/v1/file/get/<file_id>` | Get File |
|
||||
| **External** | `api/apps/sdk/files.py` | `list_files` | `/api/v1/file/list` | List Files |
|
||||
| **External** | `api/apps/sdk/files.py` | `move` | `/api/v1/file/mv` | Move File |
|
||||
| **External** | `api/apps/sdk/files.py` | `get_parent_folder` | `/api/v1/file/parent_folder` | Get Parent Folder |
|
||||
| **External** | `api/apps/sdk/files.py` | `rename` | `/api/v1/file/rename` | Rename File |
|
||||
| **External** | `api/apps/sdk/files.py` | `rm` | `/api/v1/file/rm` | Remove File |
|
||||
| **External** | `api/apps/sdk/files.py` | `get_root_folder` | `/api/v1/file/root_folder` | Get Root Folder |
|
||||
| **External** | `api/apps/sdk/files.py` | `upload` | `/api/v1/file/upload` | Upload File |
|
||||
| **External** | `api/apps/sdk/doc.py` | `retrieval_test` | `/api/v1/retrieval` | Retrieval Test |
|
||||
| **External** | `api/apps/sdk/session.py` | `ask_about_embedded` | `/api/v1/searchbots/ask` | Searchbot Ask |
|
||||
| **External** | `api/apps/sdk/session.py` | `detail_share_embedded` | `/api/v1/searchbots/detail` | Searchbot Detail |
|
||||
| **External** | `api/apps/sdk/session.py` | `mindmap` | `/api/v1/searchbots/mindmap` | Searchbot Mindmap |
|
||||
| **External** | `api/apps/sdk/session.py` | `related_questions_embedded` | `/api/v1/searchbots/related_questions` | Searchbot Related Questions |
|
||||
| **External** | `api/apps/sdk/session.py` | `retrieval_test_embedded` | `/api/v1/searchbots/retrieval_test` | Searchbot Retrieval Test |
|
||||
| **External** | `api/apps/sdk/session.py` | `ask_about` | `/api/v1/sessions/ask` | Session Ask |
|
||||
| **External** | `api/apps/sdk/session.py` | `related_questions` | `/api/v1/sessions/related_questions` | Session Related Questions |
|
||||
| **External** | `api/apps/sdk/agents.py` | `webhook` | `/api/v1/webhook_test/<agent_id>` | Webhook Test |
|
||||
| **External** | `api/apps/sdk/agents.py` | `webhook_trace` | `/api/v1/webhook_trace/<agent_id>` | Webhook Trace |
|
||||
| **External** | `api/apps/sdk/doc.py` | `rm_chunk` | `/api/v1datasets/<dataset_id>/documents/<document_id>/chunks` | Remove Chunk |
|
||||
|
||||
|
||||
## 2. Internal APIs (内部前端体系)
|
||||
**Path Prefix:** `/v1/<app_name>` matches file `api/apps/<app_name>_app.py`
|
||||
**Authentication:** Session/Cookie (`@login_required`)
|
||||
**Primary Use:** RAGFlow Web Frontend.
|
||||
|
||||
**Selected Core Interfaces:**
|
||||
|
||||
| Interface Type | Python File Path | Class/Function Name | URL Pattern | Notes |
|
||||
|---|---|---|---|---|
|
||||
| Internal | `api/apps/user_app.py` | `login` | `/v1/user/login` | User Login (Frontend) |
|
||||
| Internal | `api/apps/user_app.py` | `log_out` | `/v1/user/logout` | User Logout |
|
||||
| Internal | `api/apps/user_app.py` | `user_add` | `/v1/user/register` | User Registration |
|
||||
| Internal | `api/apps/user_app.py` | `user_profile` | `/v1/user/info` | User Profile Info |
|
||||
| Internal | `api/apps/api_app.py` | `new_token` | `/v1/api/new_token` | Generate new API Token |
|
||||
| Internal | `api/apps/conversation_app.py` | `set_conversation` | `/v1/conversation/set` | Create/Update Conversation |
|
||||
| Internal | `api/apps/conversation_app.py` | `completion` | `/v1/conversation/completion` | Chat Conversation Completion |
|
||||
| Internal | `api/apps/kb_app.py` | `list_kbs` | `/v1/kb/list` | List Knowledge Bases |
|
||||
| Internal | `api/apps/kb_app.py` | `create` | `/v1/kb/create` | Create Knowledge Base |
|
||||
| Internal | `api/apps/document_app.py` | `upload` | `/v1/document/upload` | Upload Document to KB |
|
||||
| Internal | `api/apps/document_app.py` | `parse` | `/v1/document/parse` | Parse Document |
|
||||
|
||||
*(For a complete list of all 200+ internal APIs, please refer to the `api_endpoints.txt` file or the full scan results)*
|
||||
-279
@@ -1,279 +0,0 @@
|
||||
# RAGFlow Agent 与 Dify 兼容接口详解 (Agent & Dify Compatibility)
|
||||
|
||||
## 1. Dify 兼容检索 - `retrieval`
|
||||
**接口描述**: 模拟 Dify API 格式的知识库检索接口。此接口主要用于让现有的 Dify 客户端或系统能够方便地接入 RAGFlow 的知识库检索能力。它支持文本检索、混合检索以及通过元数据过滤文档。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/dify/retrieval`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| knowledge_id | string | 是 | - | **知识库 ID**。 |
|
||||
| query | string | 是 | - | **查询文本**。用户输入的检索问题。 |
|
||||
| use_kg | boolean | 否 | false | **使用知识图谱**。是否结合知识图谱进行检索。 |
|
||||
| retrieval_setting | object | 否 | {} | **检索配置**。包含相似度阈值和 Top-K。 |
|
||||
| metadata_condition | object | 否 | {} | **元数据过滤条件**。用于筛选特定文档。 |
|
||||
|
||||
#### 参数详情 (Detail Objects)
|
||||
**retrieval_setting**:
|
||||
```json
|
||||
{
|
||||
"score_threshold": 0.5, // 相似度阈值 (default: 0.0)
|
||||
"top_k": 5 // 返回数量 (default: 1024)
|
||||
}
|
||||
```
|
||||
|
||||
**metadata_condition**:
|
||||
```json
|
||||
{
|
||||
"logic": "and", // 逻辑关系 (and/or)
|
||||
"conditions": [
|
||||
{
|
||||
"name": "author", // 字段名
|
||||
"comparison_operator": "eq",// 运算符 (eq, ne, gt, lt 等)
|
||||
"value": "Alice" // 字段值
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"records": [
|
||||
{
|
||||
"content": "RAGFlow 是一个基于深度文档理解的检索增强生成引擎...",
|
||||
"score": 0.92,
|
||||
"title": "RAGFlow_Introduction.pdf",
|
||||
"metadata": {
|
||||
"doc_id": "doc_uuid_123",
|
||||
"author": "Alice",
|
||||
"publish_year": "2024"
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": "DeepDOC 模型能够精准识别复杂的表格结构...",
|
||||
"score": 0.88,
|
||||
"title": "DeepDOC_Tech_Report.pdf",
|
||||
"metadata": {
|
||||
"doc_id": "doc_uuid_456",
|
||||
"author": "Bob"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 创建 Agent 会话 - `create_agent_session`
|
||||
**接口描述**: 创建一个新的 Agent 会话 (Session)。会话是用户与 Agent 交互的上下文容器,保存了历史对话记录和 DSL(领域特定语言)状态。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/agents/<agent_id>/sessions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | **Agent ID**。 |
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| user_id | string | 否 | **用户标识**。用于区分不同终端用户的会话。若不传,默认为当前 Tenant ID。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "session_uuid_new_123",
|
||||
"agent_id": "agent_uuid_abc",
|
||||
"user_id": "user_123",
|
||||
"source": "agent",
|
||||
"dsl": { ... }, // 完整的 Agent DSL 定义
|
||||
"messages": [
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "你好!我是你的智能助手,有什么可以帮你的吗?" // Prologue (开场白)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 获取 Agent 会话列表 - `list_agent_session`
|
||||
**接口描述**: 分页获取指定 Agent 下的会话列表。支持按 ID 或 User ID 过滤。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/agents/<agent_id>/sessions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | **Agent ID**。 |
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| page | int | 否 | 1 | **页码**。 |
|
||||
| page_size | int | 否 | 30 | **每页数量**。 |
|
||||
| orderby | string | 否 | "update_time" | **排序字段**。 |
|
||||
| desc | boolean | 否 | true | **是否降序**。 |
|
||||
| id | string | 否 | - | **会话 ID**。精确筛选。 |
|
||||
| user_id | string | 否 | - | **用户标识**。筛选特定用户的会话。 |
|
||||
| dsl | boolean | 否 | true | **包含 DSL**。是否在返回结果中包含完整的 DSL 结构 (数据量较大)。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "session_uuid_123",
|
||||
"agent_id": "agent_uuid_abc",
|
||||
"user_id": "user_123",
|
||||
"create_time": 1715000000000,
|
||||
"update_time": 1715000050000,
|
||||
"source": "agent",
|
||||
"messages": [
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Hi there!"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is RAG?"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 删除 Agent 会话 - `delete_agent_session`
|
||||
**接口描述**: 批量删除 Agent 会话。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/agents/<agent_id>/sessions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | **Agent ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| ids | array<string> | 否 | **会话 ID 列表**。若不传该参数,将尝试删除(或清空)该 Agent 下的所有会话(需谨慎)。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"ids": ["session_id_1", "session_id_2"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"success_count": 2,
|
||||
"errors": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Agent 对话 (流式) - `agent_completions`
|
||||
**接口描述**: 向 Agent 发送用户问题并获取回复。这是 Agent 交互的核心接口,支持 **Server-Sent Events (SSE)** 流式响应。Agent 会根据编排好的 DSL 流程执行(可能涉及多个节点、知识库检索、LLM 推理等),并实时推送执行过程和最终结果。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/agents/<agent_id>/completions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | **Agent ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| session_id | string | 是 | - | **会话 ID**。必须是 `create_agent_session` 返回的 ID。 |
|
||||
| question | string | 是 | - | **用户问题**。 |
|
||||
| stream | boolean | 否 | true | **是否流式响应**。强烈建议设为 `true` 以获得更好的用户体验。 |
|
||||
| return_trace | boolean | 否 | false | **返回执行轨迹**。如果为 `true`,流式响应中将包含各个节点的执行过程数据 (Trace)。 |
|
||||
|
||||
### 响应参数 (Stream Response)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
响应是一个 SSE 流,每一行以 `data:` 开头,包含一个 JSON 对象。
|
||||
|
||||
**Event Types**:
|
||||
- `message`: 普通文本消息片段。
|
||||
- `node_finished`: (当 `return_trace=true` 时) 节点执行完成事件,包含节点输出数据。
|
||||
- `message_end`: 消息结束。
|
||||
- `[DONE]`: 流结束标志。
|
||||
|
||||
#### Stream Chunk Examples:
|
||||
|
||||
**1. 文本生成片段 (message)**:
|
||||
```text
|
||||
data:{"code": 0, "message": "success", "data": {"content": "Hello", "reference": {}, "id": "msg_uuid_1"}, "event": "message"}
|
||||
|
||||
data:{"code": 0, "message": "success", "data": {"content": " world", "reference": {}, "id": "msg_uuid_1"}, "event": "message"}
|
||||
```
|
||||
|
||||
**2. 节点执行轨迹 (node_finished, return_trace=true)**:
|
||||
```text
|
||||
data:{"code": 0, "message": "success", "data": {"component_id": "retrieval_node_1", "content": "...", "trace": [...]}, "event": "node_finished"}
|
||||
```
|
||||
|
||||
**3. 最终结束 (DONE)**:
|
||||
```text
|
||||
data:[DONE]
|
||||
```
|
||||
|
||||
#### Non-Stream Response (stream=false)
|
||||
如果不使用流式响应,将等待 Agent 全流程执行完毕后一次性返回 JSON。
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"content": "Hello world! This is the final answer.",
|
||||
"reference": {
|
||||
"chunk_id_1": { ... } // 引用来源
|
||||
},
|
||||
"trace": [ ... ] // 如果 return_trace=true
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,233 +0,0 @@
|
||||
## 1. 获取 Agent 列表 - `list_agents`
|
||||
**接口描述**: 分页查询当前租户下的所有 Agent 列表,支持按 ID 或标题筛选。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/agents`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| page | int | 否 | 1 | 页码 |
|
||||
| page_size | int | 否 | 30 | 每页条数 |
|
||||
| orderby | string | 否 | update_time | 排序字段 (create_time, update_time, title) |
|
||||
| desc | boolean | 否 | True | 是否降序排列 (True: 降序, False: 升序) |
|
||||
| id | string | 否 | - | 按 Agent ID 精确筛选 |
|
||||
| title | string | 否 | - | 按 Agent 标题精确筛选 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "e0d34e2c-...",
|
||||
"title": "My Assistant",
|
||||
"description": "A helpful AI assistant",
|
||||
"dsl": { ... }, // Agent 的 DSL 流程定义
|
||||
"user_id": "tenant_123",
|
||||
"avatar": "", // 头像 Base64 或 URL
|
||||
"canvas_category": "Agent",
|
||||
"create_time": 1715623400000,
|
||||
"update_time": 1715624500000
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 创建 Agent - `create_agent`
|
||||
**接口描述**: 创建一个新的 Agent,必须包含标题和 DSL 定义。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/agents`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| title | string | 是 | - | Agent 的名称 (必须唯一) |
|
||||
| dsl | object | 是 | - | Agent 的流程定义 (节点、连线配置) |
|
||||
| description | string | 否 | - | Agent 的功能描述 |
|
||||
| avatar | string | 否 | - | Agent 头像 (Base64 字符串或 URL) |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 更新 Agent - `update_agent`
|
||||
**接口描述**: 更新指定 Agent 的配置信息,支持增量更新(仅传递需要修改的字段)。
|
||||
**请求方法**: `PUT`
|
||||
**接口地址**: `/api/v1/agents/<agent_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | 要更新的 Agent ID |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| title | string | 否 | - | 新的 Agent 名称 |
|
||||
| dsl | object | 否 | - | 新的 DSL 流程定义 |
|
||||
| description | string | 否 | - | 新的功能描述 |
|
||||
| avatar | string | 否 | - | 新的头像 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 删除 Agent - `delete_agent`
|
||||
**接口描述**: 根据 ID 删除指定的 Agent。此操作不可恢复。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/agents/<agent_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | 要删除的 Agent ID |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
无
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Webhook 测试触发 - `webhook`
|
||||
**接口描述**: 用于测试 Agent 的 Webhook 触发功能。该接口模拟外部系统调用,触发 Agent 按照配置的 "Begin" 节点逻辑开始执行。支持同步等待结果或流式返回(取决于 Agent 配置)。
|
||||
**请求方法**: `POST` (支持 GET/PUT/DELETE 等,取决于 Canvas 配置)
|
||||
**接口地址**: `/api/v1/webhook_test/<agent_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | Agent 的唯一标识符 |
|
||||
|
||||
#### Query / Headers / Body Parameters
|
||||
**说明**: 此接口的参数完全动态,取决于 Agent 画布中 **"Begin" (开始)** 节点的 **Webhook** 配置。
|
||||
- 如果配置了 Query 参数验证,则需在 URL 中传递对应参数。
|
||||
- 如果配置了 Header 验证,则需传递对应 Header。
|
||||
- **Body**: 通常为 JSON 格式,包含 Agent 运行所需的变量(inputs)或上下文数据。
|
||||
|
||||
**Body Example (JSON)**:
|
||||
```json
|
||||
{
|
||||
"inputs": {
|
||||
"topic": "AI Trends",
|
||||
"style": "professional"
|
||||
},
|
||||
"query": "Start generation"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json` (或 `text/event-stream`)
|
||||
|
||||
**即时响应模式 (Immediately)**:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"content": "生成的回答内容...",
|
||||
"usage": { ... }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**流式响应模式 (SSE)**:
|
||||
如果不使用 `webhook_test` 而是生产环境 `webhook` 且配置为 SSE,则返回流式数据。但在 `webhook_test` 接口中,通常配合 `webhook_trace` 进行异步调试。
|
||||
|
||||
---
|
||||
|
||||
## 6. Webhook 执行轨迹查询 - `webhook_trace`
|
||||
**接口描述**: 轮询查询 Agent 在 Webhook 测试触发后的执行日志和中间状态。采用长轮询或游标机制,实时获取执行进度。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/webhook_trace/<agent_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | Agent 的唯一标识符 |
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| since_ts | float | 否 | 当前时间 | 起始时间戳。返回此时间之后的日志事件。首次调用可不传(获取当前时间作为游标)。 |
|
||||
| webhook_id | string | 否 | - | Webhook 会话 ID。用于锁定特定的某次执行记录。首次轮询时不传,接口会返回新生成的 ID。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"webhook_id": "YWdlbnxxxx...", // 当前追踪的会话 ID (加密串)
|
||||
"finished": false, // 执行是否已结束 (true/false)
|
||||
"next_since_ts": 1715629999.5, // 下一次轮询应使用的 since_ts
|
||||
"events": [ // 本次轮询获取到的新事件列表
|
||||
{
|
||||
"ts": 1715629998.1,
|
||||
"event": "message", // 事件类型: message, start_to_think, finished, error 等
|
||||
"data": {
|
||||
"content": "思考中...",
|
||||
"reference": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 💡 最佳实践 (调试流程)
|
||||
1. **初始化**: 调用 `GET /webhook_trace/<id>` (不带参数),获取 `next_since_ts` (记为 `T0`)。
|
||||
2. **触发**: 调用 `POST /webhook_test/<id>` 发送测试数据。
|
||||
3. **首帧捕获**: 循环调用 `GET /webhook_trace/<id>?since_ts=T0`,直到返回 `webhook_id` (记为 `WID`) 和第一批 `events`。
|
||||
4. **持续追踪**: 使用 `WID` 和响应中的 `next_since_ts` 持续轮询,直到 `data.finished == true`。
|
||||
-164
@@ -1,164 +0,0 @@
|
||||
# RAGFlow 对话交互接口详解 (Chat Completion & OpenAI Compatibility)
|
||||
|
||||
## 5. 对话助手对话 (流式) - `chat_completion`
|
||||
**接口描述**: 发送问题给对话助手 (Assistant/Chat) 并获取回复。这是 RAGFlow 最核心的原生对话接口,支持 **Server-Sent Events (SSE)** 流式响应。它会根据助手绑定的知识库进行 RAG 检索生成。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/chats/<chat_id>/completions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chat_id | string | 是 | **助手 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| session_id | string | 是 | - | **会话 ID**。从 `create_chat_session` 获取。 |
|
||||
| question | string | 是 | - | **用户问题**。 |
|
||||
| stream | boolean | 否 | true | **是否流式响应**。 |
|
||||
| quote | boolean | 否 | false | **返回引用**。是否在响应中包含检索到的引用片段。 |
|
||||
| doc_ids | string | 否 | - | **限定文档 ID**。多个 ID 用逗号分隔,仅检索指定文档。 |
|
||||
| metadata_condition | object | 否 | {} | **元数据过滤**。用于限定检索范围。 |
|
||||
|
||||
### 响应参数 (Stream Response)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
每一行数据以 `data:` 开头,包含一个 JSON 对象。
|
||||
|
||||
**Event Example**:
|
||||
```text
|
||||
data:{"code": 0, "message": "success", "data": {"answer": "Hello", "reference": {}}}
|
||||
|
||||
data:{"code": 0, "message": "success", "data": {"answer": " world!", "reference": {}}}
|
||||
|
||||
data:{"code": 0, "message": "success", "data": {"answer": "", "reference": {"chunk_1": {...}}}} // 引用数据
|
||||
```
|
||||
|
||||
### 响应参数 (Non-Stream Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"answer": "Hello world! This is the generated response.",
|
||||
"reference": {
|
||||
"chunk_id_1": {
|
||||
"content_with_weight": "Original text...",
|
||||
"doc_name": "manual.pdf"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. OpenAI 兼容对话 - `chat_completion_openai_like`
|
||||
**接口描述**: 提供与 **OpenAI API (`/v1/chat/completions`)** 完全兼容的接口。允许开发者使用 LangChain、OpenAI Python SDK 或其他支持 OpenAI 协议的工具直接调用 RAGFlow,实现无缝迁移。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/chats_openai/<chat_id>/chat/completions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chat_id | string | 是 | **助手 ID**。在此上下文中充当 "Base URL" 的一部分。 |
|
||||
|
||||
#### Body Parameters (JSON - OpenAI Standard)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| messages | array | 是 | **消息列表**。包含 `role` (system/user/assistant) 和 `content`。 |
|
||||
| model | string | 是 | **模型名称**。可以是任意非空字符串 (RAGFlow 会使用助手预设的模型)。 |
|
||||
| stream | boolean | 否 | **是否流式**。默认为 `true`。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"model": "ragflow_default",
|
||||
"messages": [
|
||||
{"role": "system", "content": "You are a helpful assistant."},
|
||||
{"role": "user", "content": "Explain quantum physics."}
|
||||
],
|
||||
"stream": true
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Stream Response - OpenAI Format)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
严格遵循 OpenAI Chunk 格式:
|
||||
|
||||
```text
|
||||
data: {"id": "chatcmpl-123", "object": "chat.completion.chunk", "created": 1715000000, "model": "model", "choices": [{"index": 0, "delta": {"role": "assistant", "content": ""}, "finish_reason": null}]}
|
||||
|
||||
data: {"id": "chatcmpl-123", "object": "chat.completion.chunk", "created": 1715000001, "model": "model", "choices": [{"index": 0, "delta": {"content": "Quantum"}, "finish_reason": null}]}
|
||||
|
||||
data: {"id": "chatcmpl-123", "object": "chat.completion.chunk", "created": 1715000002, "model": "model", "choices": [{"index": 0, "delta": {"content": " physics"}, "finish_reason": null}]}
|
||||
|
||||
data: [DONE]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 嵌入式 Chatbot 对话 - `chatbot_completions`
|
||||
**接口描述**: 专为 **嵌入式窗口 (Embed Window)** 设计的公开对话接口。它通常用于将 RAGFlow 助手作为客服窗口嵌入到第三方网站。与普通接口不同,它通过 `Authorization` Header 传递 **Beta Token** (即 API Key) 进行鉴权,且通常面向最终用户。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/chatbots/<dialog_id>/completions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dialog_id | string | 是 | **助手 ID** (Dialog ID)。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| question | string | 是 | - | **用户问题**。 |
|
||||
| stream | boolean | 否 | true | **是否流式**。 |
|
||||
| session_id | string | 否 | - | **会话 ID**。用于维持上下文。 |
|
||||
| quote | boolean | 否 | false | **返回引用**。 |
|
||||
|
||||
### 响应参数 (Stream Response)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
与 `chat_completion` 类似,返回 RAGFlow 原生 SSE 格式。
|
||||
|
||||
```text
|
||||
data:{"code": 0, "message": "success", "data": {"answer": "Here is the answer...", "reference": {}}}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Chatbot 初始化信息 - `chatbots_inputs`
|
||||
**接口描述**: 获取嵌入式 Chatbot 的初始化配置信息。通常在前端组件加载时调用,用于展示助手的头像、名称、开场白 (Prologue) 等信息。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/chatbots/<dialog_id>/info`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dialog_id | string | 是 | **助手 ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"title": "IT Support Bot", // 助手名称
|
||||
"avatar": "http://...", // 头像 URL
|
||||
"prologue": "Hi! How can I help?" // 开场白
|
||||
}
|
||||
}
|
||||
```
|
||||
-208
@@ -1,208 +0,0 @@
|
||||
# RAGFlow 聊天助手会话管理接口详解 (Chat Assistant Session Management)
|
||||
|
||||
## 1. 创建会话 - `create_chat_session`
|
||||
**接口描述**: 为指定的聊天助手 (Chat/Assistant) 创建一个新的会话。系统会自动加载该助手的开场白 (Prologue) 作为第一条消息。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/chats/<chat_id>/sessions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chat_id | string | 是 | **助手 ID** (Assistant/Dialog ID)。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| name | string | 否 | "New session" | **会话名称**。 |
|
||||
| user_id | string | 否 | - | **用户标识**。用于区分不同终端用户的会话。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"name": "Consulting regarding RAG",
|
||||
"user_id": "client_001"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "session_uuid_123",
|
||||
"chat_id": "chat_uuid_abc",
|
||||
"name": "Consulting regarding RAG",
|
||||
"user_id": "client_001",
|
||||
"create_time": 1715000000000,
|
||||
"create_date": "2024-05-01 10:00:00",
|
||||
"update_time": 1715000000000,
|
||||
"update_date": "2024-05-01 10:00:00",
|
||||
"messages": [
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Hi! I am your AI assistant. How can I help you today?" // 自动加载的开场白
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 获取会话列表 - `list_chat_session`
|
||||
**接口描述**: 分页获取指定助手下的会话列表。支持按名称或用户 ID 过滤。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/chats/<chat_id>/sessions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chat_id | string | 是 | **助手 ID**。 |
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| page | int | 否 | 1 | **页码**。 |
|
||||
| page_size | int | 否 | 30 | **每页数量**。 |
|
||||
| orderby | string | 否 | "create_time" | **排序字段**。 |
|
||||
| desc | boolean | 否 | true | **是否降序**。 |
|
||||
| name | string | 否 | - | **会话名称搜索**。 |
|
||||
| id | string | 否 | - | **会话 ID 精确筛选**。 |
|
||||
| user_id | string | 否 | - | **用户标识筛选**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "session_uuid_123",
|
||||
"chat_id": "chat_uuid_abc",
|
||||
"name": "Consulting regarding RAG",
|
||||
"user_id": "client_001",
|
||||
"create_time": 1715000000000,
|
||||
"create_date": "2024-05-01 10:00:00",
|
||||
"update_time": 1715000050000,
|
||||
"update_date": "2024-05-01 10:00:50",
|
||||
"messages": [
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Hi! I am your AI assistant. How can I help you today?"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is RAGFlow?"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "session_uuid_456",
|
||||
"chat_id": "chat_uuid_abc",
|
||||
"name": "New session",
|
||||
"user_id": "client_002",
|
||||
"create_time": 1714900000000,
|
||||
"create_date": "2024-04-30 09:00:00",
|
||||
"update_time": 1714900000000,
|
||||
"update_date": "2024-04-30 09:00:00",
|
||||
"messages": [ ... ]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 更新会话 - `update_chat_session`
|
||||
**接口描述**: 更新会话信息。目前主要用于 **重命名** 会话。注意:不能通过此接口修改消息记录 (`messages`)。
|
||||
**请求方法**: `PUT`
|
||||
**接口地址**: `/api/v1/chats/<chat_id>/sessions/<session_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chat_id | string | 是 | **助手 ID**。 |
|
||||
| session_id | string | 是 | **会话 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| name | string | 否 | **新的会话名称**。不可为空字符串。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"name": "RAG Technical Discussion"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 删除会话 - `delete_chat_session`
|
||||
**接口描述**: 批量删除指定助手下的会话。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/chats/<chat_id>/sessions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chat_id | string | 是 | **助手 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| ids | array<string> | 否 | **待删除的会话 ID 列表**。若不传该参数,将尝试删除该助手下的**所有会话**(请极其谨慎使用)。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"ids": ["session_uuid_123", "session_uuid_456"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null // 若全部删除成功
|
||||
}
|
||||
```
|
||||
|
||||
**Response (部分成功时)**:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Partially deleted 1 sessions with 1 errors",
|
||||
"data": {
|
||||
"success_count": 1,
|
||||
"errors": ["The chat doesn't own the session session_uuid_999"]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,213 +0,0 @@
|
||||
## 1. 创建助手应用 - `create`
|
||||
**接口描述**: 创建一个新的对话助手(Chat Assistant)。支持配置关联知识库、LLM 模型参数、提示词(Prompt)以及开场白等高级设置。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/chats`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| name | string | 是 | - | 助手应用名称 (租户内唯一) |
|
||||
| avatar | string | 否 | - | 助手头像 (URL 或 Base64 字符串) |
|
||||
| description | string | 否 | "A helpful Assistant" | 助手的功能描述 |
|
||||
| dataset_ids | array | 否 | [] | 关联的知识库 ID 列表 (必须是当前租户有权限访问的知识库) |
|
||||
| llm | object | 否 | - | LLM 模型生成配置 (如模型名称、温度等) |
|
||||
| prompt | object | 否 | - | 提示词引擎与检索配置 (包含 System Prompt, Opener, Rerank 等) |
|
||||
|
||||
**`llm` 对象详细结构**:
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| model_name | string | 是 | - | 模型名称 (例如: `deepseek-chat`, `gpt-4`, `qwen-turbo`) |
|
||||
| temperature | float | 否 | 0.1 | 温度系数 (0.0 ~ 1.0),越高越随机,越低越确定 |
|
||||
| top_p | float | 否 | 0.3 | 核采样概率阈值 |
|
||||
| max_tokens | int | 否 | 512 | 单次回答的最大 Token 数限制 |
|
||||
| presence_penalty | float | 否 | 0.4 | 话题新鲜度惩罚 (-2.0 ~ 2.0),正值鼓励讨论新话题 |
|
||||
| frequency_penalty | float | 否 | 0.7 | 频率惩罚 (-2.0 ~ 2.0),正值减少重复词汇 |
|
||||
|
||||
**`prompt` 对象详细结构**:
|
||||
*注意:此对象包含“提示词配置”与“检索策略配置”两部分。*
|
||||
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| prompt | string | 否 | (内置默认提示词) | **System Prompt (系统提示词)**。给大模型的角色指令,例如 "你是一个客服..."。可使用变量占位符 `{knowledge}`。 |
|
||||
| opener | string | 否 | "Hi! I'm your assistant..." | **开场白**。用户进入对话窗口时,助手自动发送的第一条欢迎语。 |
|
||||
| show_quote | boolean | 否 | true | **显示引用**。回答中是否标注来源文档 (e.g., [1])。 |
|
||||
| variables | array | 否 | `[{"key": "knowledge", "optional": false}]` | **变量列表**。定义用于填充 System Prompt 的变量。`knowledge` 为保留变量,代表检索到的知识片段。 |
|
||||
| rerank_model | string | 否 | - | **重排序模型 ID**。配置后会对检索结果进行二次精排 (如 `BAAI/bge-reranker-v2-m3`)。 |
|
||||
| keywords_similarity_weight | float | 否 | 0.7 | **关键字权重** (0.0 ~ 1.0)。控制混合检索的比例。更接近 1.0 侧重关键字匹配,更接近 0.0 侧重向量语义匹配。 |
|
||||
| similarity_threshold | float | 否 | 0.2 | **相似度阈值** (0.0 ~ 1.0)。低于此相似度的文档块将被过滤,不喂给大模型。 |
|
||||
| top_n | int | 否 | 6 | **Top N**。最终截取并输入给大模型的文档块数量。 |
|
||||
| empty_response | string | 否 | "Sorry! No relevant..." | **空结果回复**。当没有检索到相关知识库内容时的兜底回复。 |
|
||||
| tts | boolean | 否 | false | **启用 TTS**。是否将助手的文本回答自动转为语音播放。 |
|
||||
| refine_multiturn | boolean | 否 | true | **多轮对话优化**。是否根据历史上下文重写用户问题 (Query Rewrite) 以提高检索准确率。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "e0d34e2c-1234-5678-9xxx-xxxxxxxxxxxx",
|
||||
"name": "企业知识库助手",
|
||||
"avatar": "http://example.com/avatar.png",
|
||||
"description": "用于回答员工内部问题的 AI",
|
||||
"dataset_ids": ["kb_123", "kb_456"],
|
||||
"llm": {
|
||||
"model_name": "deepseek-chat",
|
||||
"temperature": 0.1,
|
||||
"top_p": 0.3,
|
||||
"max_tokens": 512,
|
||||
"presence_penalty": 0.4,
|
||||
"frequency_penalty": 0.7
|
||||
},
|
||||
"prompt": {
|
||||
"prompt": "你是一个智能助手,请根据以下知识回答问题:\n{knowledge}",
|
||||
"opener": "你好!有什么可以帮你的?",
|
||||
"show_quote": true,
|
||||
"variables": [
|
||||
{ "key": "knowledge", "optional": false }
|
||||
],
|
||||
"rerank_model": "",
|
||||
"keywords_similarity_weight": 0.7,
|
||||
"similarity_threshold": 0.2,
|
||||
"top_n": 8,
|
||||
"empty_response": "抱歉,知识库中没有找到相关答案。",
|
||||
"tts": false,
|
||||
"refine_multiturn": true
|
||||
},
|
||||
"create_time": 1715623400000,
|
||||
"update_time": 1715624500000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 获取助手列表 - `list_chat`
|
||||
**接口描述**: 获取当前租户下的所有助手应用列表。支持分页、排序及按名称/ID筛选。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/chats`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| page | int | 否 | 1 | 页码 |
|
||||
| page_size | int | 否 | 30 | 每页条数 |
|
||||
| orderby | string | 否 | create_time | 排序字段 (`create_time`, `update_time`) |
|
||||
| desc | boolean | 否 | true | 是否降序排列 (`true`: 降序, `false`: 升序) |
|
||||
| name | string | 否 | - | 按名称模糊搜索 (支持 partial match) |
|
||||
| id | string | 否 | - | 按 ID 精确筛选 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "e0d34e2c-...",
|
||||
"name": "客服机器人",
|
||||
"avatar": "http://...",
|
||||
"datasets": [
|
||||
{
|
||||
"id": "kb_1",
|
||||
"name": "产品手册",
|
||||
"avatar": "",
|
||||
"chunk_num": 100
|
||||
}
|
||||
],
|
||||
"llm": { ... }, // (结构同 create 接口响应)
|
||||
"prompt": { ... }, // (结构同 create 接口响应)
|
||||
"create_time": 1715623400000
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 更新助手配置 - `update`
|
||||
**接口描述**: 更新指定助手应用的配置信息。支持全量或增量更新部分字段。
|
||||
**请求方法**: `PUT`
|
||||
**接口地址**: `/api/v1/chats/<chat_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chat_id | string | 是 | 助手应用 ID |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
*(以下所有字段均为可选,仅传递需要修改的字段即可)*
|
||||
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
|---|---|---|---|
|
||||
| name | string | - | 新的助手名称 |
|
||||
| avatar | string | - | 新的头像 URL 或 Base64 |
|
||||
| dataset_ids | array | - | **全量替换**关联的知识库 ID 列表 |
|
||||
| llm | object | - | 更新 LLM 配置。需包含 `model_name`,其他字段覆盖更新。 |
|
||||
| prompt | object | - | 更新提示词配置。支持增量更新 (e.g. 只改 `opener`)。 |
|
||||
| show_quotation | boolean | - | 是否显示引用来源 (此字段直接位于根对象下,对应 prompt.show_quote) |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 批量删除助手 - `delete_chats`
|
||||
**接口描述**: 批量删除一个或多个助手应用。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/chats`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| ids | array<string> | 是 | 要删除的助手应用 ID 列表。**⚠️ 注意:若列表为空或不传,虽然后端有全量删除逻辑,但在实际业务中应严谨传递 ID。** |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"ids": ["chat_id_1001", "chat_id_1002"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"success_count": 2, // 成功删除的数量
|
||||
"errors": [] // 失败原因列表 (如 ID 不存在)
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,420 +0,0 @@
|
||||
## 1. 创建知识库 - `create`
|
||||
**接口描述**: 创建一个新的知识库(Dataset),用于存储和检索文档数据。支持配置嵌入模型(Embedding Model)、解析方法、权限范围等。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/datasets`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| name | string | 是 | - | **知识库名称**。在同一个租户(Tenant)内必须唯一。 |
|
||||
| avatar | string | 否 | "" | **知识库头像**。Base64 编码的图片字符串。 |
|
||||
| description | string | 否 | "" | **描述信息**。用于说明知识库的用途或内容概要。 |
|
||||
| embedding_model | string | 否 | (系统默认) | **嵌入模型名称** (例如 `BAAI/bge-large-zh-v1.5`)。若不传,则自动使用系统设置的默认 Embedding 模型。 |
|
||||
| permission | string | 否 | "me" | **可见权限**。`me`: 仅自己可见;`team`: 团队内所有成员可见。 |
|
||||
| chunk_method | string | 否 | "naive" | **默认分块解析方法**。当上传文件未指定解析方式时使用。可选值: `naive` (通用), `manual` (手动), `qa` (Q&A拆分), `table` (表格), `paper` (论文), `book` (书籍), `laws` (法律), `presentation` (PPT), `picture` (图片), `one` (单文档), `email` (邮件)。 |
|
||||
| parser_config | object | 否 | (见下文) | **解析器详细配置**。根据 `chunk_method` 的不同而变化。 |
|
||||
|
||||
**`parser_config` 默认配置参数 (Naive 通用模式)**:
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chunk_token_num | int | 512 | **切片最大 Token 数**。超过该长度会被截断到下一块。 |
|
||||
| delimiter | string | "\\n" | **分段分隔符**。用于识别段落边界。 |
|
||||
| layout_recognize | string | "DeepDOC" | **布局识别模型**。用于处理复杂文档结构 (如 `DeepDOC` 或 `Simple`)。 |
|
||||
| html4excel | boolean | false | **Excel转HTML**。是否将 Excel 表格转为 HTML 格式进行解析。 |
|
||||
| auto_keywords | int | 0 | **自动关键词抽取**。0 表示不抽取;N>0 表示为每个切片抽取 N 个关键词。 |
|
||||
| auto_questions | int | 0 | **自动问题生成**。0 表示不生成;N>0 表示为每个切片生成 N 个相关问题。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "kb_uuid_12345678",
|
||||
"name": "企业产品手册",
|
||||
"avatar": "",
|
||||
"tenant_id": "tenant_001",
|
||||
"description": "存放所有产品相关的说明文档",
|
||||
"embedding_model": "BAAI/bge-large-zh-v1.5",
|
||||
"permission": "me",
|
||||
"chunk_method": "naive",
|
||||
"parser_config": {
|
||||
"chunk_token_num": 512,
|
||||
"delimiter": "\n",
|
||||
"layout_recognize": "DeepDOC",
|
||||
"html4excel": false,
|
||||
"auto_keywords": 0,
|
||||
"auto_questions": 0
|
||||
},
|
||||
"chunk_count": 0,
|
||||
"document_count": 0,
|
||||
"create_time": 1715623400000,
|
||||
"update_time": 1715624500000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 删除知识库 - `delete`
|
||||
**接口描述**: 批量删除一个或多个知识库。删除知识库将连带删除其中的所有文档和索引数据,**不可恢复**。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/datasets`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| ids | array<string> | 是 | **ID 列表**。指定要删除的知识库 ID。如果传递 `null`,则会**清空当前租户下所有**知识库(高危操作,请谨慎使用)。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"ids": ["kb_id_101", "kb_id_102"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Successfully deleted 2 datasets, 0 failed...",
|
||||
"data": {
|
||||
"success_count": 2, // 成功删除的数量
|
||||
"errors": [] // 失败的 ID 及原因列表
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 获取知识库列表 - `list_datasets`
|
||||
**接口描述**: 获取当前用户(及团队)有权限访问的知识库列表。支持分页、排序和筛选。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| page | int | 否 | 1 | **页码**。从 1 开始。 |
|
||||
| page_size | int | 否 | 30 | **每页条数**。 |
|
||||
| orderby | string | 否 | "create_time" | **排序字段**。可选值: `create_time` (创建时间), `update_time` (更新时间), `document_count` (文档数)。 |
|
||||
| desc | boolean | 否 | true | **是否降序**。`true`: 降序 (最新的在前); `false`: 升序。 |
|
||||
| name | string | 否 | - | **名称筛选**。支持模糊匹配。 |
|
||||
| id | string | 否 | - | **ID 筛选**。精确匹配知识库 ID。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "kb_uuid_123",
|
||||
"name": "HR 政策库",
|
||||
"document_count": 12, // 包含的文档数量
|
||||
"token_num": 10240, // 总 Token 数
|
||||
"chunk_count": 150, // 总切片数
|
||||
"create_time": 1715623400000,
|
||||
"permission": "team",
|
||||
"embedding_model": "BAAI/bge-large-zh-v1.5"
|
||||
}
|
||||
],
|
||||
"total": 1 // 匹配查询条件的总记录数 (用户分页计算)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 更新知识库配置 - `update`
|
||||
**接口描述**: 更新指定知识库的配置信息。注意:如果知识库内已有解析过的切片,通常不允许修改嵌入模型 (`embedding_model`)。
|
||||
**请求方法**: `PUT`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | 知识库 ID |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
*(以下所有字段均为可选,仅传递需要修改的字段即可)*
|
||||
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
|---|---|---|---|
|
||||
| name | string | - | **新名称**。需保持租户内唯一。 |
|
||||
| avatar | string | - | **新头像**。Base64 字符串。 |
|
||||
| description | string | - | **新描述**。 |
|
||||
| permission | string | - | **新权限**。`me` 或 `team`。 |
|
||||
| embedding_model | string | - | **嵌入模型**。**注意**: 仅当知识库为空(chunk_count=0)时才允许修改。 |
|
||||
| chunk_method | string | - | **默认解析方法**。修改后将应用于后续新上传的文件 (旧文件解析方式不变)。 |
|
||||
| parser_config | object | - | **解析器配置**。全量覆盖旧配置 (结构参考 create 接口)。 |
|
||||
| pagerank | int | 0 | **PageRank 权重**。仅在使用 Elasticsearch 引擎且需调整图谱权重时设置。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "kb_uuid_...",
|
||||
"name": "新名称",
|
||||
"update_time": 1715629999000,
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 获取知识图谱数据 - `knowledge_graph`
|
||||
**接口描述**: 获取知识库构建的知识图谱数据,包含节点(Nodes)和边(Edges),用于前端可视化展示(如 ECharts 力导向图)。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/knowledge_graph`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | 知识库 ID |
|
||||
|
||||
#### Query Parameters
|
||||
无
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"graph": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node_1",
|
||||
"label": "人工智能", // 节点显示的文本
|
||||
"pagerank": 0.05, // PageRank 权重 (决定节点大小)
|
||||
"color": "#fcb", // 节点颜色
|
||||
"img": "" // 节点图标 (如有)
|
||||
},
|
||||
{
|
||||
"id": "node_2",
|
||||
"label": "机器学习",
|
||||
"pagerank": 0.03,
|
||||
"color": "#e2b"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source": "node_1", // 起始节点 ID
|
||||
"target": "node_2", // 目标节点 ID
|
||||
"weight": 0.8, // 边权重 (决定连线粗细)
|
||||
"label": "includes" // 关系名称 (显示在连线上)
|
||||
}
|
||||
]
|
||||
},
|
||||
"mind_map": { // 思维导图结构的保留字段 (通常用于脑图展示)
|
||||
"root": {
|
||||
"id": "root_node",
|
||||
"children": [...]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 清空知识图谱数据 - `delete_knowledge_graph`
|
||||
**接口描述**: 删除指定知识库中已生成的知识图谱索引数据(包括所有实体节点和关系边)。
|
||||
**注意**: 此操作**不会**删除原始文档或普通的向量索引,仅仅是重置图谱结构。如果需要重新生成图谱,请再次调用 `chunk` 相关接口或使用 `run_graphrag`。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/knowledge_graph`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | 知识库 ID |
|
||||
|
||||
#### Body Parameters
|
||||
无
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 运行/触发 GraphRAG 索引任务 - `run_graphrag`
|
||||
**接口描述**: 触发后台异步任务,对知识库中的文档进行 GraphRAG 索引构建。此过程会使用 LLM 抽取实体(Entities)和关系(Relationships),并构建全局社区摘要。
|
||||
**前提条件**: 知识库中必须包含已解析的文档。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/run_graphrag`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | 知识库 ID |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
*(Body 可为空 `{}`, 后续版本将扩展以下配置参数)*
|
||||
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
|---|---|---|---|
|
||||
| entity_types | array | ["organization", "person", "geo", "event"] | **(预留)** 指定要抽取的实体类型列表。 |
|
||||
| method | string | "light" | **(预留)** 构建模式: `light` (轻量级), `general` (标准), `complex` (深度)。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"graphrag_task_id": "task_uuid_12345678" // 异步任务 ID,用于后续追踪进度
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 运行/触发 RAPTOR 递归摘要任务 - `run_raptor`
|
||||
**接口描述**: 触发后台异步任务,对知识库中的文档运行 RAPTOR (Recursive Abstractive Processing for Tree-Organized Retrieval) 算法。
|
||||
**功能说明**: 该算法会递归地对文档块进行聚类和摘要,生成多层级的树状索引,显著提升对长文档和复杂问题的回答能力。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/run_raptor`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | 知识库 ID |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
*(Body 可为空 `{}`, 后续版本将扩展以下配置参数)*
|
||||
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
|---|---|---|---|
|
||||
| max_cluster | int | 64 | **(预留)** 最大聚类数。 |
|
||||
| prompt | string | (内置摘要提示词) | **(预留)** 用于生成摘要的 Prompt。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"raptor_task_id": "task_uuid_87654321" // 异步任务 ID
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 查询 GraphRAG 任务进度 - `trace_graphrag`
|
||||
**接口描述**: 查询指定知识库当前 **GraphRAG** 索引构建任务的实时状态。支持长轮询机制监测进度。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/trace_graphrag`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | 知识库 ID |
|
||||
|
||||
#### Query Parameters
|
||||
无
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "task_uuid_12345678", // 任务 ID
|
||||
"doc_id": "doc_uuid_...", // 当前正在处理的文档 ID (如果是多文档任务)
|
||||
"from_page": 0, // 当前处理的起始页码
|
||||
"to_page": 10, // 当前处理的结束页码
|
||||
"progress": 0.45, // **总进度** (0.0 ~ 1.0)。0.0: 未开始/刚开始; 1.0: 完成; -1.0: 失败。
|
||||
"progress_msg": "Extracting entities from chunk 25...", // **当前状态描述**。用于前端展示 Loading 提示。
|
||||
"create_time": 1715623400000,
|
||||
"update_time": 1715624500000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 查询 RAPTOR 任务进度 - `trace_raptor`
|
||||
**接口描述**: 查询指定知识库当前 **RAPTOR** 递归摘要任务的实时状态。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/trace_raptor`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | 知识库 ID |
|
||||
|
||||
#### Query Parameters
|
||||
无
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "task_uuid_87654321",
|
||||
"progress": 1.0, // 进度值。1.0 表示树构建完成。
|
||||
"progress_msg": "Tree construction completed.", // 状态消息。
|
||||
"create_time": 1715629000000
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,757 +0,0 @@
|
||||
## 1. 上传文档 - `upload`
|
||||
**接口描述**: 向指定的知识库上传一个或多个文档文件。上传后,文档将立即被存入文件系统/对象存储,并在数据库中创建记录。默认解析状态为 `UNSTART` (未开始),解析配置将继承自 KnowledgeBase 的默认设置。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
**Content-Type**: `multipart/form-data`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。指定文档归属的知识库。 |
|
||||
|
||||
#### Form Data Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file | file | 是 | **文件二进制流**。支持多文件上传 (Multiple Files)。<br>支持格式: PDF, DOCX, TXT, MD, CS, HTML, CSV, XLSX, PPTX 等。<br>单文件大小限制请参考系统配置 (默认通常为 10MB/100MB)。 |
|
||||
| parent_path | string | 否 | **父级目录路径**。类似于文件系统的文件夹结构,默认为 `/`。如果指定 (如 `/docs/v1/`),文档将在该虚拟路径下列出。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003",
|
||||
"thumbnail": null,
|
||||
"dataset_id": "d1234567890abcdef1234567890abcde",
|
||||
"chunk_method": "naive",
|
||||
"pipeline_id": null,
|
||||
"parser_config": {
|
||||
"chunk_token_num": 512,
|
||||
"delimiter": "\\n",
|
||||
"layout_recognize": "DeepDOC",
|
||||
"html4excel": false,
|
||||
"auto_keywords": 0,
|
||||
"auto_questions": 0,
|
||||
"topn_tags": 3,
|
||||
"raptor": {
|
||||
"use_raptor": false
|
||||
},
|
||||
"graphrag": {
|
||||
"use_graphrag": false
|
||||
}
|
||||
},
|
||||
"source_type": "local",
|
||||
"type": "pdf",
|
||||
"created_by": "user_id_123",
|
||||
"name": "UserGuide_v2.pdf",
|
||||
"location": "UserGuide_v2.pdf",
|
||||
"size": 102400,
|
||||
"token_count": 0,
|
||||
"chunk_count": 0,
|
||||
"progress": 0.0,
|
||||
"progress_msg": "",
|
||||
"process_begin_at": null,
|
||||
"process_duration": 0.0,
|
||||
"meta_fields": {},
|
||||
"suffix": "pdf",
|
||||
"run": "UNSTART",
|
||||
"status": "1",
|
||||
"create_time": 1715623400123,
|
||||
"create_date": "2024-05-13 10:03:20",
|
||||
"update_time": 1715623400123,
|
||||
"update_date": "2024-05-13 10:03:20"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 获取文档列表 - `list_docs`
|
||||
**接口描述**: 查询知识库下的文档列表。支持分页检索、关键词搜索、状态筛选等功能。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| page | int | 否 | 1 | **页码**。从 1 开始计数。 |
|
||||
| page_size | int | 否 | 30 | **每页数量**。 |
|
||||
| orderby | string | 否 | "create_time" | **排序字段**。支持 `create_time` (创建时间), `name` (文件名), `size` (大小) 等。 |
|
||||
| desc | boolean | 否 | true | **是否降序**。`true` (最新/最大在前), `false` (最旧/最小在前)。 |
|
||||
| id | string | 否 | - | **精确筛选 ID**。仅返回指定 ID 的文档。 |
|
||||
| name | string | 否 | - | **精确筛选文件名**。仅返回指定名称的文档。 |
|
||||
| keywords | string | 否 | - | **模糊搜索**。匹配文档名称包含该关键词的记录。 |
|
||||
| suffix | array | 否 | - | **文件后缀筛选** (如 `pdf`, `docx`)。 |
|
||||
| run | array | 否 | - | **运行状态筛选**。可选值: `UNSTART`, `RUNNING`, `CANCEL`, `DONE`, `FAIL`。 |
|
||||
| create_time_from | int | 否 | 0 | **起始时间戳** (毫秒)。查询在此时间之后创建的文档。 |
|
||||
| create_time_to | int | 否 | 0 | **结束时间戳** (毫秒)。查询在此时间之前创建的文档。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"total": 128,
|
||||
"docs": [
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003",
|
||||
"thumbnail": null,
|
||||
"dataset_id": "d1234567890abcdef1234567890abcde",
|
||||
"chunk_method": "naive",
|
||||
"pipeline_id": null,
|
||||
"parser_config": {
|
||||
"chunk_token_num": 512,
|
||||
"delimiter": "\\n",
|
||||
"layout_recognize": "DeepDOC",
|
||||
"html4excel": false,
|
||||
"auto_keywords": 0,
|
||||
"auto_questions": 0,
|
||||
"topn_tags": 3,
|
||||
"raptor": {
|
||||
"use_raptor": false
|
||||
},
|
||||
"graphrag": {
|
||||
"use_graphrag": false
|
||||
}
|
||||
},
|
||||
"source_type": "local",
|
||||
"type": "pdf",
|
||||
"created_by": "user_id_123",
|
||||
"name": "UserGuide_v2.pdf",
|
||||
"location": "UserGuide_v2.pdf",
|
||||
"size": 102400,
|
||||
"token_count": 45000,
|
||||
"chunk_count": 120,
|
||||
"progress": 1.0,
|
||||
"progress_msg": "Parsing finished",
|
||||
"process_begin_at": "2024-05-13 10:05:00",
|
||||
"process_duration": 45.2,
|
||||
"meta_fields": {
|
||||
"author": "RAGFlow Team",
|
||||
"version": "2.0"
|
||||
},
|
||||
"suffix": "pdf",
|
||||
"run": "DONE",
|
||||
"status": "1",
|
||||
"create_time": 1715623400123,
|
||||
"create_date": "2024-05-13 10:03:20",
|
||||
"update_time": 1715623450000,
|
||||
"update_date": "2024-05-13 10:05:45"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 更新文档信息 - `update_doc`
|
||||
**接口描述**: 更新文档的名称、状态或解析配置。
|
||||
**特别注意**: 如果修改了 `chunk_method` 或 `parser_config`,后端会自动将 `run` 状态重置为 `UNSTART`,并清除已有的 chunk 数据,等待重新解析。
|
||||
**请求方法**: `PUT`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents/<document_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
| document_id | string | 是 | **文档 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
*(仅需传递要修改的字段)*
|
||||
|
||||
| 参数名 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| name | string | **新文档名称**。需包含文件后缀且不能改变原始文件类型 (如从 `.pdf` 改为 `.txt` 会导致错误)。 |
|
||||
| enabled | boolean | **启用/禁用**。`true`: 启用 (DEFAULT, 对应 status="1"); `false`: 禁用 (对应 status="0")。禁用后该文档不参与检索。 |
|
||||
| chunk_method | string | **解析方法**。可选值: `naive`, `manual`, `qa`, `table`, `paper`, `book`, `laws`, `presentation`, `picture`, `one`, `knowledge_graph`, `email`。 |
|
||||
| parser_config | object | **解析器详细配置**。应与 `chunk_method` 匹配。以下列出 `naive` (通用) 方法的完整配置参数。 |
|
||||
|
||||
**parser_config (Naive 模式全量参数)**:
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chunk_token_num | int | 512 | **切片最大 Token 数**。 |
|
||||
| delimiter | string | "\\n" | **分段符**。支持转义字符。 |
|
||||
| layout_recognize | string | "DeepDOC" | **布局识别模型**。可选 `DeepDOC` 或 `Simple`。 |
|
||||
| html4excel | boolean | false | **Excel转HTML**。是否将 Excel 解析为 HTML 表格。 |
|
||||
| auto_keywords | int | 0 | **自动关键词数量**。0 表示不抽取。 |
|
||||
| auto_questions | int | 0 | **自动问题数量**。0 表示不生成。 |
|
||||
| topn_tags | int | 3 | **自动标签数量**。 |
|
||||
| raptor | object | `{ "use_raptor": false }` | **RAPTOR 配置**。设置 `use_raptor: true` 可开启递归摘要索引。 |
|
||||
| graphrag | object | `{ "use_graphrag": false }` | **GraphRAG 配置**。设置 `use_graphrag: true` 可开启图谱增强。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003",
|
||||
"thumbnail": null,
|
||||
"dataset_id": "d1234567890abcdef1234567890abcde",
|
||||
"chunk_method": "naive",
|
||||
"pipeline_id": null,
|
||||
"parser_config": {
|
||||
"chunk_token_num": 1024,
|
||||
"delimiter": "\\n",
|
||||
"layout_recognize": "DeepDOC",
|
||||
"html4excel": false,
|
||||
"auto_keywords": 0,
|
||||
"auto_questions": 0,
|
||||
"topn_tags": 3,
|
||||
"raptor": {
|
||||
"use_raptor": false
|
||||
},
|
||||
"graphrag": {
|
||||
"use_graphrag": false
|
||||
}
|
||||
},
|
||||
"source_type": "local",
|
||||
"type": "pdf",
|
||||
"created_by": "user_id_123",
|
||||
"name": "Renamed_Guide.pdf",
|
||||
"location": "UserGuide_v2.pdf",
|
||||
"size": 102400,
|
||||
"token_count": 45000,
|
||||
"chunk_count": 0,
|
||||
"progress": 0.0,
|
||||
"progress_msg": "",
|
||||
"process_begin_at": null,
|
||||
"process_duration": 0.0,
|
||||
"meta_fields": {},
|
||||
"suffix": "pdf",
|
||||
"run": "UNSTART",
|
||||
"status": "0",
|
||||
"create_time": 1715623400123,
|
||||
"create_date": "2024-05-13 10:03:20",
|
||||
"update_time": 1715629999000,
|
||||
"update_date": "2024-05-13 12:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 删除文档 - `delete`
|
||||
**接口描述**: 物理删除一个或多个文档。此操作不可恢复,将同时删除数据库记录、MinIO 中的源文件以及 Elasticsearch 中的所有相关切片索引。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| ids | array<string> | 是 | **文档 ID 列表**。必须指定要删除的文档 ID。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 下载/预览原始文件 - `download`
|
||||
**接口描述**: 获取文档的原始二进制文件流。响应头将会包含 `Content-Disposition` 字段,指示浏览器以附件形式下载。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents/<document_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
| document_id | string | 是 | **文档 ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/octet-stream`
|
||||
**Content-Disposition**: `attachment; filename="UserGuide_v2.pdf"`
|
||||
|
||||
*(直接返回文件的二进制数据流)*
|
||||
|
||||
|
||||
## 6. 触发/重试文档解析 - `parse`
|
||||
**接口描述**: 手动触发文档的解析任务。通常在上传文件后、或修改了解析配置(如 `chunk_method`)后调用此接口。支持批量触发。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/chunks`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| document_ids | array<string> | 是 | **文档 ID 列表**。指定需要(重新)解析的文档 ID。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"document_ids": ["doc_id_1", "doc_id_2"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 停止文档解析 - `stop_parsing`
|
||||
**接口描述**: 停止当前正在进行的文档解析任务。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/chunks`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| document_ids | array<string> | 是 | **文档 ID 列表**。指定要停止解析的任务。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 获取切片列表 - `list_chunks`
|
||||
**接口描述**: 获取指定文档已解析出的切片(Chunk)列表。支持分页和关键词搜索。返回结果包含文档的详细元数据和具体的切片内容。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
| document_id | string | 是 | **文档 ID**。 |
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| page | int | 否 | 1 | **页码**。 |
|
||||
| page_size | int | 否 | 30 | **每页数量**。 |
|
||||
| keywords | string | 否 | - | **搜索关键词**。在切片内容中进行全文检索。 |
|
||||
| id | string | 否 | - | **精确切片 ID**。若指定,则只返回该 ID 对应的切片。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"total": 150,
|
||||
"chunks": [
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003_0",
|
||||
"content": "RAGFlow 是一款基于深度文档理解的开源 RAG(检索增强生成)引擎。它旨在为各种规模的企业提供精简的 RAG 工作流。RAGFlow 结合了传统文档处理的稳健性与现代大语言模型(LLM)的生成能力,确保在处理复杂格式数据(如 PDF 表格、扫描件等)时依然能保持极高的召回率和准确性。",
|
||||
"document_id": "doc_uuid_123",
|
||||
"docnm_kwd": "RAGFlow_UserGuide_v2.pdf",
|
||||
"important_keywords": ["RAGFlow", "开源", "深度文档理解", "LLM"],
|
||||
"questions": ["什么是 RAGFlow?", "RAGFlow 的主要特点是什么?"],
|
||||
"image_id": "",
|
||||
"dataset_id": "kb_uuid_456",
|
||||
"available": true,
|
||||
"positions": [1]
|
||||
},
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003_1",
|
||||
"content": "主要特性:\n1. **深度文档解析**:内置 DeepDOC 识别引擎,精准还原表格、段落结构。\n2. **多路召回**:支持关键词 + 向量的混合检索。\n3. **可视化编排**:提供基于 Graph 的工作流编排能力。",
|
||||
"document_id": "doc_uuid_123",
|
||||
"docnm_kwd": "RAGFlow_UserGuide_v2.pdf",
|
||||
"important_keywords": ["DeepDOC", "混合检索", "可视化编排"],
|
||||
"questions": [],
|
||||
"image_id": "img_uuid_789",
|
||||
"dataset_id": "kb_uuid_456",
|
||||
"available": true,
|
||||
"positions": [2]
|
||||
}
|
||||
],
|
||||
"doc": {
|
||||
"id": "doc_uuid_123",
|
||||
"name": "RAGFlow_UserGuide_v2.pdf",
|
||||
"chunk_count": 150,
|
||||
"token_count": 45000,
|
||||
"chunk_method": "naive",
|
||||
"run": "DONE",
|
||||
"status": "1",
|
||||
"progress": 1.0,
|
||||
"progress_msg": "Parsing finished",
|
||||
"process_begin_at": "2024-05-13 10:05:00",
|
||||
"process_duration": 45.2,
|
||||
"meta_fields": {
|
||||
"author": "RAGFlow Team",
|
||||
"version": "2.0"
|
||||
},
|
||||
"create_time": 1715623400123,
|
||||
"create_date": "2024-05-13 10:03:20",
|
||||
"update_time": 1715623450000,
|
||||
"update_date": "2024-05-13 10:05:45",
|
||||
"dataset_id": "kb_uuid_456"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 手动新增切片 - `add_chunk`
|
||||
**接口描述**: 向指定文档中手动添加一个新的切片。系统会自动计算该切片的向量嵌入 (Embedding)。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
| document_id | string | 是 | **文档 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| content | string | 是 | **切片内容**。手动输入的文本内容。 |
|
||||
| important_keywords | array<string> | 否 | **重要关键词**。用于关键词检索增强。 |
|
||||
| questions | array<string> | 否 | **预设问题**。用于 Q&A 检索模式增强。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"chunk": {
|
||||
"id": "new_chunk_uuid_999",
|
||||
"content": "这是管理员手动添加的一条补充切片,用于修正文档中缺失的关键信息。",
|
||||
"document_id": "doc_uuid_123",
|
||||
"docnm_kwd": "RAGFlow_UserGuide_v2.pdf",
|
||||
"important_keywords": ["手动添加", "补充信息"],
|
||||
"questions": ["如何手动添加切片?"],
|
||||
"image_id": "",
|
||||
"dataset_id": "kb_uuid_456",
|
||||
"available": true,
|
||||
"positions": []
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 修改切片信息 - `update_chunk`
|
||||
**接口描述**: 修改已存在的切片内容、关键词、可用状态等。修改内容后,系统会自动重新计算向量。
|
||||
**请求方法**: `PUT`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks/<chunk_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
| document_id | string | 是 | **文档 ID**。 |
|
||||
| chunk_id | string | 是 | **切片 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
*(以下字段均为可选,仅传递需修改的字段)*
|
||||
|
||||
| 参数名 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| content | string | **新的切片内容**。 |
|
||||
| important_keywords | array<string> | **更新关键词列表**。覆盖原有列表。 |
|
||||
| available | boolean | **启用/禁用**。`true`: 启用 (默认); `false`: 禁用 (检索时将忽略此切片)。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. 删除切片 - `rm_chunk`
|
||||
**接口描述**: 批量删除文档中的指定切片。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
| document_id | string | 是 | **文档 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chunk_ids | array<string> | 是 | **切片 ID 列表**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "deleted 2 chunks",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 12. 获取元数据摘要 - `metadata_summary`
|
||||
**接口描述**: 获取知识库中所有文档的元数据摘要信息。通常用于前端展示知识库的数据分布概况,例如不同文件类型的数量统计、文件状态分布等。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/metadata/summary`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
|
||||
#### Query Parameters
|
||||
无
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"summary": {
|
||||
"total_doc_count": 120,
|
||||
"total_token_count": 500000,
|
||||
"file_type_distribution": {
|
||||
"pdf": 80,
|
||||
"docx": 30,
|
||||
"txt": 10
|
||||
},
|
||||
"status_distribution": {
|
||||
"1": 118, // 正常启用
|
||||
"0": 2 // 禁用
|
||||
},
|
||||
"custom_metadata": {
|
||||
"author": {
|
||||
"Alice": 50,
|
||||
"Bob": 30
|
||||
},
|
||||
"department": {
|
||||
"HR": 20,
|
||||
"Engineering": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. 批量更新元数据 - `metadata_batch_update`
|
||||
**接口描述**: 对知识库中的文档进行批量元数据修改。支持基于复杂的条件筛选文档,然后执行批量更新或删除元数据字段的操作。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/metadata/update`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| selector | object | 否 | **筛选器**。定义要更新哪些文档。如果不传,可能作用于全量文档(请谨慎)。 |
|
||||
| updates | array | 否 | **更新操作列表**。包含 `key` 和 `value`。 |
|
||||
| deletes | array | 否 | **删除操作列表**。包含 `key`。 |
|
||||
|
||||
**Request Example (复杂场景)**:
|
||||
```json
|
||||
{
|
||||
"selector": {
|
||||
"document_ids": ["doc_id_101", "doc_id_102"],
|
||||
"metadata_condition": {
|
||||
"logic": "and",
|
||||
"conditions": [
|
||||
{"key": "author", "value": "OldName", "operator": "eq"},
|
||||
{"key": "status", "value": "draft", "operator": "eq"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"updates": [
|
||||
{"key": "author", "value": "Admin"},
|
||||
{"key": "reviewed_by", "value": "ManagerA"}
|
||||
],
|
||||
"deletes": [
|
||||
{"key": "temp_tag"},
|
||||
{"key": "draft_flag"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"updated": 2, // 实际更新成功的文档数量
|
||||
"matched_docs": 2 // 匹配到的文档数量
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14. 检索测试 (Hit Test) - `retrieval_test`
|
||||
**接口描述**: 在指定的知识库中进行模拟检索测试。此接口用于验证分段(Chunk)质量、检索参数(相似度阈值、Top K)的效果,是调试 RAG 效果的核心工具。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/retrieval`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
**注意**: 即使是简单的查询,由于包含较多配置参数,本接口也设计为 `POST` 请求。
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| dataset_ids | array<string> | 是 | - | **目标知识库 ID 列表**。支持跨多个知识库检索。 |
|
||||
| question | string | 是 | - | **用户查询问题**。 |
|
||||
| similarity_threshold | float | 否 | 0.2 | **相似度阈值**。低于此分数的 Chunk 将被过滤。 |
|
||||
| vector_similarity_weight | float | 否 | 0.3 | **向量权重**。混合检索时,向量检索结果的权重 (0~1)。剩余权重归于关键词检索。 |
|
||||
| top_k | int | 否 | 1024 | **初筛数量**。向量检索返回的候选切片数量。 |
|
||||
| rerank_id | string | 否 | - | **重排模型 ID**。若指定,将对检索结果进行 Rerank 二次排序。 |
|
||||
| highlight | boolean | 否 | true | **高亮匹配**。是否在返回内容中高亮关键词。 |
|
||||
| keyword | boolean | 否 | false | **关键词增强**。是否使用 LLM 提取问题关键词以增强检索。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"total": 15,
|
||||
"chunks": [
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003_12",
|
||||
"content": "RAGFlow 支持多种文档解析模式,其中 DeepDOC 模式特别适合处理包含大量表格和扫描件的 PDF 文档。它使用深度学习模型识别文档布局,精准提取表格内容。",
|
||||
"document_id": "doc_uuid_123",
|
||||
"dataset_id": "kb_uuid_456",
|
||||
"document_name": "RAGFlow_UserGuide_v2.pdf",
|
||||
"document_keyword": "RAGFlow_UserGuide_v2.pdf",
|
||||
"similarity": 0.88,
|
||||
"vector_similarity": 0.85,
|
||||
"term_similarity": 0.92,
|
||||
"index": 12,
|
||||
"highlight": "RAGFlow 支持多种<em>文档解析模式</em>,其中 <em>DeepDOC</em> 模式特别适合处理包含大量表格和扫描件的 PDF 文档。",
|
||||
"important_keywords": ["DeepDOC", "PDF"],
|
||||
"questions": ["DeepDOC 模式有什么用?"],
|
||||
"image_id": "",
|
||||
"positions": [12]
|
||||
},
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003_15",
|
||||
"content": "如果文档主要由纯文本构成,建议使用 Naive 模式。该模式解析速度快,适合通用场景。",
|
||||
"document_id": "doc_uuid_123",
|
||||
"dataset_id": "kb_uuid_456",
|
||||
"document_name": "RAGFlow_UserGuide_v2.pdf",
|
||||
"document_keyword": "RAGFlow_UserGuide_v2.pdf",
|
||||
"similarity": 0.45,
|
||||
"vector_similarity": 0.40,
|
||||
"term_similarity": 0.50,
|
||||
"index": 15,
|
||||
"highlight": "如果文档主要由纯文本构成,建议使用 <em>Naive</em> 模式。",
|
||||
"important_keywords": ["Naive", "纯文本"],
|
||||
"questions": [],
|
||||
"image_id": "",
|
||||
"positions": [15]
|
||||
}
|
||||
],
|
||||
"doc_aggs": [
|
||||
{
|
||||
"doc_name": "RAGFlow_UserGuide_v2.pdf",
|
||||
"doc_id": "doc_uuid_123",
|
||||
"count": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,503 +0,0 @@
|
||||
# RAGFlow 文件管理接口详解 (File Management API)
|
||||
|
||||
## 1. 上传文件 - `upload`
|
||||
**接口描述**: 上传一个或多个文件到指定文件夹。支持多文件上传 (Multipart)。上传成功后,文件将存储在 MinIO/S3 中,并返回文件元数据列表。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/file/upload`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
**Content-Type**: `multipart/form-data`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Form Data Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file | file | 是 | **文件二进制流**。支持多文件上传。 |
|
||||
| parent_id | string | 否 | **父级目录 ID**。如果省略,默认上传到根目录 (root)。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003",
|
||||
"parent_id": "root_folder_id_123",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "user_uuid_789",
|
||||
"type": "pdf",
|
||||
"name": "ProjectReport.pdf",
|
||||
"location": "ProjectReport.pdf",
|
||||
"size": 204800,
|
||||
"source_type": "",
|
||||
"create_time": 1715623400123,
|
||||
"create_date": "2024-05-13 10:03:20",
|
||||
"update_time": 1715623400123,
|
||||
"update_date": "2024-05-13 10:03:20"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 新建文件夹 - `create`
|
||||
**接口描述**: 在指定父目录下创建一个新的文件夹(逻辑目录)。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/file/create`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| name | string | 是 | **文件夹名称**。同一目录下不可重名。 |
|
||||
| parent_id | string | 否 | **父级目录 ID**。省略则默认为根目录。 |
|
||||
| type | string | 是 | **类型**。固定值为 `FOLDER` 创建文件夹。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"name": "Year2024_Reports",
|
||||
"parent_id": "root_folder_id_123",
|
||||
"type": "FOLDER"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "folder_uuid_abc",
|
||||
"parent_id": "root_folder_id_123",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "user_uuid_789",
|
||||
"name": "Year2024_Reports",
|
||||
"location": "",
|
||||
"size": 0,
|
||||
"type": "folder",
|
||||
"source_type": "",
|
||||
"create_time": 1715623500000,
|
||||
"create_date": "2024-05-13 10:05:00",
|
||||
"update_time": 1715623500000,
|
||||
"update_date": "2024-05-13 10:05:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 获取文件列表 - `list_files`
|
||||
**接口描述**: 分页获取指定文件夹下的文件和子文件夹列表。支持按名称模糊搜索。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/file/list`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| parent_id | string | 否 | (Root) | **父级目录 ID**。指定要查看的目录 ID。 |
|
||||
| keywords | string | 否 | - | **搜索关键词**。按文件名模糊搜索。 |
|
||||
| page | int | 否 | 1 | **页码**。 |
|
||||
| page_size | int | 否 | 15 | **每页数量**。 |
|
||||
| orderby | string | 否 | "create_time" | **排序字段**。 |
|
||||
| desc | boolean | 否 | true | **是否降序**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"total": 25,
|
||||
"parent_folder": {
|
||||
"id": "root_folder_id_123",
|
||||
"parent_id": "",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "system",
|
||||
"name": "ROOT",
|
||||
"location": "",
|
||||
"size": 0,
|
||||
"type": "folder",
|
||||
"source_type": "",
|
||||
"create_time": 1710000000000,
|
||||
"create_date": "2024-03-01 00:00:00",
|
||||
"update_time": 1710000000000,
|
||||
"update_date": "2024-03-01 00:00:00"
|
||||
},
|
||||
"files": [
|
||||
{
|
||||
"id": "folder_uuid_abc",
|
||||
"parent_id": "root_folder_id_123",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "user_uuid_789",
|
||||
"name": "Year2024_Reports",
|
||||
"location": "",
|
||||
"size": 0,
|
||||
"type": "folder",
|
||||
"source_type": "",
|
||||
"create_time": 1715623500000,
|
||||
"create_date": "2024-05-13 10:05:00",
|
||||
"update_time": 1715623500000,
|
||||
"update_date": "2024-05-13 10:05:00"
|
||||
},
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003",
|
||||
"parent_id": "root_folder_id_123",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "user_uuid_789",
|
||||
"name": "ProjectReport.pdf",
|
||||
"location": "ProjectReport.pdf",
|
||||
"size": 204800,
|
||||
"type": "pdf",
|
||||
"source_type": "",
|
||||
"create_time": 1715623400123,
|
||||
"create_date": "2024-05-13 10:03:20",
|
||||
"update_time": 1715623400123,
|
||||
"update_date": "2024-05-13 10:03:20"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 获取文件流 (下载) - `get`
|
||||
**接口描述**: 通过文件 ID 下载文件内容。不同于获取元数据,该接口直接返回文件的二进制流(Octet-stream 或 Image 等)。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/file/get/<file_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file_id | string | 是 | **文件 ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/octet-stream` (或具体 MIME 类型如 `image/png`)
|
||||
|
||||
*(返回二进制文件流)*
|
||||
|
||||
---
|
||||
|
||||
## 5. 下载附件 - `download_attachment`
|
||||
**接口描述**: 这是一个通用的附件下载接口,通常用于系统内部引用或特定路径的下载。它使用 `attachment_id`(通常对应 MinIO 中的存储路径/Key)来检索文件。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/file/download/<attachment_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| attachment_id | string | 是 | **附件 ID / 存储 Key**。通常对应底层存储的唯一标识符。 |
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| ext | string | 否 | "markdown" | **文件扩展名**。用于设置响应头中的 Content-Type。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/octet-stream` (或根据 ext 参数推断)
|
||||
|
||||
*(返回二进制文件流)*
|
||||
|
||||
|
||||
## 6. 重命名文件/文件夹 - `rename`
|
||||
**接口描述**: 修改文件或文件夹的名称。对于文件,通常不允许修改扩展名(后缀)。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/file/rename`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file_id | string | 是 | **目标文件/文件夹 ID**。 |
|
||||
| name | string | 是 | **新名称**。需符合文件命名规范,且同一目录下不可重名。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"file_id": "file_uuid_123",
|
||||
"name": "New_Report_Final.pdf"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 移动文件/文件夹 - `move`
|
||||
**接口描述**: 批量移动文件或文件夹到指定的目录 (Move)。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/file/mv`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| src_file_ids | array<string> | 是 | **源文件/文件夹 ID 列表**。支持批量移动。 |
|
||||
| dest_file_id | string | 是 | **目标文件夹 ID**。必须是已存在的文件夹 ID。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"src_file_ids": ["file_id_1", "file_id_2"],
|
||||
"dest_file_id": "folder_id_target"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 删除文件/文件夹 - `rm`
|
||||
**接口描述**: 批量删除文件或文件夹。如果是文件夹,将递归删除其下的所有内容。此操作不可恢复。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/file/rm`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file_ids | array<string> | 是 | **待删除的文件/文件夹 ID 列表**。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"file_ids": ["file_uuid_to_delete_1", "folder_uuid_to_delete_2"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 文件转知识库文档 - `convert`
|
||||
**接口描述**: 将已上传的文件(File)导入到指定的知识库(Dataset)中,转换为文档(Document)并进行解析。这是一个“文件 -> 知识库”的桥接操作。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/file/convert`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file_ids | array<string> | 是 | **源文件 ID 列表**。必须是已存在于文件管理系统中的 ID。 |
|
||||
| kb_ids | array<string> | 是 | **目标知识库 ID 列表**。文件将被同时导入到这些知识库中。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"file_ids": ["file_uuid_pdf_1", "file_uuid_txt_2"],
|
||||
"kb_ids": ["dataset_uuid_A"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "mapping_uuid_1",
|
||||
"file_id": "file_uuid_pdf_1",
|
||||
"document_id": "doc_uuid_created_in_kb_A",
|
||||
"create_time": 1715623600123,
|
||||
"create_date": "2024-05-13 10:06:40",
|
||||
"update_time": 1715623600123,
|
||||
"update_date": "2024-05-13 10:06:40"
|
||||
},
|
||||
{
|
||||
"id": "mapping_uuid_2",
|
||||
"file_id": "file_uuid_txt_2",
|
||||
"document_id": "doc_uuid_created_in_kb_A",
|
||||
"create_time": 1715623600124,
|
||||
"create_date": "2024-05-13 10:06:40",
|
||||
"update_time": 1715623600124,
|
||||
"update_date": "2024-05-13 10:06:40"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 10. 获取根目录信息 - `get_root_folder`
|
||||
**接口描述**: 获取当前用户的根目录文件夹信息。每个用户(Tenant)都有且仅有一个系统自动创建的根目录。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/file/root_folder`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Query Parameters
|
||||
无
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"root_folder": {
|
||||
"id": "root_folder_id_123",
|
||||
"parent_id": "",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "system",
|
||||
"name": "ROOT",
|
||||
"location": "",
|
||||
"size": 0,
|
||||
"type": "folder",
|
||||
"source_type": "",
|
||||
"create_time": 1710000000000,
|
||||
"create_date": "2024-03-01 00:00:00",
|
||||
"update_time": 1710000000000,
|
||||
"update_date": "2024-03-01 00:00:00"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. 获取父目录信息 - `get_parent_folder`
|
||||
**接口描述**: 获取指定文件或文件夹的直接父级目录信息。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/file/parent_folder`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file_id | string | 是 | **当前文件/文件夹 ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"parent_folder": {
|
||||
"id": "root_folder_id_123",
|
||||
"parent_id": "",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "system",
|
||||
"name": "ROOT",
|
||||
"location": "",
|
||||
"size": 0,
|
||||
"type": "folder",
|
||||
"source_type": "",
|
||||
"create_time": 1710000000000,
|
||||
"create_date": "2024-03-01 00:00:00",
|
||||
"update_time": 1710000000000,
|
||||
"update_date": "2024-03-01 00:00:00"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. 获取完整路径 (面包屑) - `get_all_parent_folders`
|
||||
**接口描述**: 获取指定文件或文件夹的所有上级目录列表,形成完整的路径链。返回的列表顺序通常是从根目录到直接父目录(有序)。此接口常用于前端展示“面包屑导航” (Breadcrumbs)。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/file/all_parent_folder`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file_id | string | 是 | **目标文件/文件夹 ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"parent_folders": [
|
||||
{
|
||||
"id": "root_folder_id_123",
|
||||
"parent_id": "",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "system",
|
||||
"name": "ROOT",
|
||||
"location": "",
|
||||
"size": 0,
|
||||
"type": "folder",
|
||||
"source_type": "",
|
||||
"create_time": 1710000000000,
|
||||
"create_date": "2024-03-01 00:00:00",
|
||||
"update_time": 1710000000000,
|
||||
"update_date": "2024-03-01 00:00:00"
|
||||
},
|
||||
{
|
||||
"id": "folder_project_a_id",
|
||||
"parent_id": "root_folder_id_123",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "user_id_001",
|
||||
"name": "Project A Docs",
|
||||
"location": "",
|
||||
"size": 0,
|
||||
"type": "folder",
|
||||
"source_type": "",
|
||||
"create_time": 1715000000000,
|
||||
"create_date": "2024-05-01 09:00:00",
|
||||
"update_time": 1715000000000,
|
||||
"update_date": "2024-05-01 09:00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
-228
@@ -1,228 +0,0 @@
|
||||
# RAGFlow 搜索机器人 & AgentBot 接口详解 (SearchBot & AgentBot)
|
||||
|
||||
## 1. 搜索机器人对话 - `ask_about_embedded`
|
||||
**接口描述**: 面向 **SearchBot (搜索机器人)** 的核心对话接口,通常用于嵌入式知识库问答场景。与普通 Chat 不同,它更侧重于从指定的 `kb_ids` 中直接检索答案,且鉴权使用 `Authorization: Bearer <Beta_Token>` (即 API Key)。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/searchbots/ask`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| question | string | 是 | - | **用户问题**。 |
|
||||
| kb_ids | array<string> | 是 | - | **知识库 ID 列表**。限定从哪些知识库中检索。 |
|
||||
| search_id | string | 否 | - | **搜索应用 ID**。如果指定,将使用该搜索应用的配置 (Search App Config)。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"question": "What is the refund policy?",
|
||||
"kb_ids": ["dataset_uuid_1", "dataset_uuid_2"],
|
||||
"search_id": "search_app_uuid_abc"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Stream Response)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
```text
|
||||
data:{"code": 0, "message": "", "data": {"answer": "According to the ", "reference": {}}}
|
||||
|
||||
data:{"code": 0, "message": "", "data": {"answer": "policy, refunds are processed within 7 days.", "reference": {"chunk_1": {"content_with_weight": "Refunds...", "doc_name": "policy.pdf"}}}}
|
||||
|
||||
data:{"code": 0, "message": "", "data": true} // 结束标志
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 获取思维导图 - `mindmap`
|
||||
**接口描述**: 根据用户的查询或对话上下文,生成用于前端展示的思维导图数据结构。这通常用于帮助用户梳理复杂的搜索结果或知识结构。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/searchbots/mindmap`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| question | string | 是 | **用户问题/主题**。 |
|
||||
| kb_ids | array<string> | 是 | **知识库 ID 列表**。 |
|
||||
| search_id | string | 否 | **搜索应用 ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"root": {
|
||||
"text": "Refund Policy", // 根节点文本
|
||||
"children": [
|
||||
{
|
||||
"text": "Conditions",
|
||||
"children": [
|
||||
{ "text": "Product defect" },
|
||||
{ "text": "Shipping error" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "Timeline",
|
||||
"children": [
|
||||
{ "text": "7-14 business days" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 获取相关推荐问题 - `related_questions_embedded`
|
||||
**接口描述**: 根据用户当前的问题,生成一组相关的推荐问题 (Suggest Questions)。常用于搜索结果页底部的“猜你想问”。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/searchbots/related_questions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| question | string | 是 | **用户当前问题**。 |
|
||||
| search_id | string | 否 | **搜索应用 ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
"How to apply for a refund online?",
|
||||
"What items are non-refundable?",
|
||||
"Contact customer support"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 获取 AgentBot 输入项 - `begin_inputs`
|
||||
**接口描述**: 获取 **AgentBot** (嵌入式 Agent) 的初始化信息,特别是前置输入项 (Prolog/Inputs)。这用于在用户开始对话前,展示一个表单让用户输入必要信息(如姓名、邮箱、API Key 等),这些信息会被传递给 Agent 的 `Begin` 节点。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/agentbots/<agent_id>/inputs`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | **Agent ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"title": "Booking Assistant",
|
||||
"avatar": "http://...",
|
||||
"prologue": "Welcome! Please tell me your details.",
|
||||
"inputs": { // `Begin` 节点定义的输入变量
|
||||
"user_name": {
|
||||
"type": "string",
|
||||
"description": "Your Name",
|
||||
"required": true
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"description": "Contact Email",
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
"mode": "chat"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. AgentBot 对话交互 - `agent_bot_completions`
|
||||
**接口描述**: 面向 **AgentBot** 的嵌入式对话接口。与 `agent_completions` 类似,但它专为无需登录的 C 端用户设计,通过 API Key 鉴权。它支持完整的 Agent 流程执行和流式响应。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/agentbots/<agent_id>/completions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | **Agent ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| session_id | string | 是 | **会话 ID**。 |
|
||||
| inputs | object | 否 | **前置输入值**。对应 `begin_inputs` 中定义的变量,如 `{"user_name": "Alice"}`。 |
|
||||
| query | string | 否 | **用户输入**。 |
|
||||
| stream | boolean | 否 | **是否流式**。默认 `true`。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"session_id": "session_uuid_123",
|
||||
"inputs": {
|
||||
"user_name": "Bob"
|
||||
},
|
||||
"query": "I want to book a room.",
|
||||
"stream": true
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Stream Response)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
```text
|
||||
data:{"event": "message", "data": {"content": "Hello Bob, ", "reference": {}}}
|
||||
|
||||
data:{"event": "message", "data": {"content": "when do you want to check in?", "reference": {}}}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Agent OpenAI 兼容接口 - `agents_completion_openai_compatibility`
|
||||
**接口描述**: 专门针对 Agent 的 **OpenAI 兼容** 接口。这使得外部工具可以像调用 OpenAI Chat Completion 一样调用 RAGFlow 配置好的复杂 Agent。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/agents_openai/<agent_id>/chat/completions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | **Agent ID**。 |
|
||||
|
||||
#### Body Parameters (OpenAI Standard)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| messages | array | 是 | 包含 `role`, `content` 的消息数组。 |
|
||||
| model | string | 是 | 占位符,任意字符串。 |
|
||||
| stream | boolean | 否 | 默认 `true`。 |
|
||||
|
||||
### 响应参数 (Stream Response - OpenAI Format)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
```text
|
||||
data: {"id": "agent-chat-uuid", "object": "chat.completion.chunk", "created": 1715000000, "model": "ragflow_agent", "choices": [{"index": 0, "delta": {"role": "assistant", "content": ""}, "finish_reason": null}]}
|
||||
|
||||
data: {"id": "agent-chat-uuid", "object": "chat.completion.chunk", "created": 1715000001, "model": "ragflow_agent", "choices": [{"index": 0, "delta": {"content": "Processing your request..."}, "finish_reason": null}]}
|
||||
|
||||
data: [DONE]
|
||||
```
|
||||
-168
@@ -1,168 +0,0 @@
|
||||
# RAGFlow SearchBot 补充与通用会话接口详解 (Session Extras)
|
||||
|
||||
## 1. 获取引用详情 - `detail_share_embedded`
|
||||
**接口描述**: 当用户点击 SearchBot 回复中的引用标号 (e.g., [1]) 时,调用此接口获取该引用的详细内容(包括原文片段、来源文档名等)。此接口通常用于前端展示“引用来源”侧边栏或弹窗。它使用 API Key (Beta Token) 进行鉴权。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/searchbots/detail`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| search_id | string | 是 | **搜索应用/SearchBot ID**。此接口需要验证调用者是否有权访问该 SearchBot。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "search_app_uuid_123",
|
||||
"title": "IT Knowledge Base",
|
||||
"description": "Tech support search bot",
|
||||
"kb_ids": ["kb_uuid_1", "kb_uuid_2"],
|
||||
"search_config": {
|
||||
"top_k": 5,
|
||||
"similarity_threshold": 0.5
|
||||
},
|
||||
// 注意:此接口目前主要返回 Search App 的详情配置,
|
||||
// 前端通常使用 search_config 或其他信息来辅助展示引用。
|
||||
// 具体引用内容的文本通常已包含在 `ask` 接口的 `reference` 字段中。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. SearchBot 检索测试 - `retrieval_test_embedded`
|
||||
**接口描述**: 面向 SearchBot 的**检索效果测试**接口。它不通过 LLM 生成答案,而是直接返回 RAG 检索到的文档片段 (`chunks`)。这用于调试 SearchBot 的检索参数(如相似度阈值、Top-K)是否合理。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/searchbots/retrieval_test`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| kb_id | string/array | 是 | - | **知识库 ID** (或列表)。支持单个 ID 字符串或 ID 列表。 |
|
||||
| question | string | 是 | - | **测试查询词**。 |
|
||||
| page | int | 否 | 1 | **页码**。 |
|
||||
| size | int | 否 | 30 | **每页数量**。 |
|
||||
| doc_ids | array<string> | 否 | - | **限定文档 ID**。仅在指定文档中检索。 |
|
||||
| similarity_threshold | float | 否 | 0.0 | **相似度阈值**。 |
|
||||
| top_k | int | 否 | 1024 | **Top-K 数量**。 |
|
||||
| highlight | boolean | 否 | false | **高亮匹配**。是否在返回内容中标记匹配关键词。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"kb_id": ["dataset_uuid_1"],
|
||||
"question": "refund policy",
|
||||
"top_k": 5,
|
||||
"highlight": true
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"total": 12, // 命中总是
|
||||
"chunks": [
|
||||
{
|
||||
"content_with_weight": "Refunds are processed within <em>7 days</em>...", // 支持高亮
|
||||
"doc_name": "policy.pdf",
|
||||
"doc_id": "doc_uuid_101",
|
||||
"similarity": 0.92,
|
||||
"img_id": ""
|
||||
},
|
||||
{
|
||||
"content_with_weight": "Product return guidelines...",
|
||||
"doc_name": "guidelines.docx",
|
||||
"doc_id": "doc_uuid_102",
|
||||
"similarity": 0.88
|
||||
}
|
||||
],
|
||||
"labels": [] // 如果启用了查询标签功能
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 通用会话问答 - `ask_about`
|
||||
**接口描述**: **内部/测试用**的通用会话问答接口。与 `ask_embedded` 不同,此接口通常用于 RAGFlow 控制台内部的“调试”或“预览”功能,鉴权依赖用户的登录 Token (User Token),且必须显式指定 `dataset_ids`。它不绑定特定的 Chat/Agent/SearchBot 配置。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/sessions/ask`
|
||||
**鉴权方式**: Header `Authorization: Bearer <USER_TOKEN>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| question | string | 是 | **用户问题**。 |
|
||||
| dataset_ids | array<string> | 是 | **知识库 ID 列表**。必须是当前用户有权访问的知识库。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"question": "Summary of report",
|
||||
"dataset_ids": ["dataset_uuid_internal_1"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Stream Response)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
```text
|
||||
data:{"code": 0, "message": "", "data": {"answer": "Here is the summary:", "reference": {}}}
|
||||
|
||||
data:{"code": 0, "message": "", "data": {"answer": " The report indicates...", "reference": {}}}
|
||||
|
||||
data:{"code": 0, "message": "", "data": true} // 结束
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 通用相关问题 - `related_questions`
|
||||
**接口描述**: **内部/测试用**的通用相关问题推荐接口。根据用户的问题和行业背景,利用 LLM 生成推荐问题。通常用于内部测试台。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/sessions/related_questions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <USER_TOKEN>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| question | string | 是 | - | **原始问题/关键词**。 |
|
||||
| industry | string | 否 | "" | **行业背景** (e.g., "Finance", "Healthcare")。帮助 LLM 生成更专业的推荐。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"question": "Data privacy",
|
||||
"industry": "IT"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
"GDPR compliance checklist",
|
||||
"Data encryption standards",
|
||||
"User consent management"
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -1,98 +0,0 @@
|
||||
# RAGFlow External API Reference (Grouped by File)
|
||||
|
||||
## File: `api/apps/sdk/agents.py`
|
||||
| Function Name | URL Pattern | Notes |
|
||||
|---|---|---|
|
||||
| `list_agents` | `/api/v1/agents` | List Agents |
|
||||
| `create_agent` | `/api/v1/agents` | Create Agent |
|
||||
| `update_agent` | `/api/v1/agents/<agent_id>` | Update Agent |
|
||||
| `delete_agent` | `/api/v1/agents/<agent_id>` | Delete Agent |
|
||||
| `webhook` | `/api/v1/webhook_test/<agent_id>` | Webhook Test |
|
||||
| `webhook_trace` | `/api/v1/webhook_trace/<agent_id>` | Webhook Trace |
|
||||
|
||||
## File: `api/apps/sdk/chat.py`
|
||||
| Function Name | URL Pattern | Notes |
|
||||
|---|---|---|
|
||||
| `create` | `/api/v1/chats` | Create Chat |
|
||||
| `delete_chats` | `/api/v1/chats` | Delete Chat |
|
||||
| `list_chat` | `/api/v1/chats` | List Chats |
|
||||
| `update` | `/api/v1/chats/<chat_id>` | Update Chat |
|
||||
|
||||
## File: `api/apps/sdk/dataset.py`
|
||||
| Function Name | URL Pattern | Notes |
|
||||
|---|---|---|
|
||||
| `create` | `/api/v1/datasets` | Create Dataset |
|
||||
| `delete` | `/api/v1/datasets` | Delete Dataset |
|
||||
| `list_datasets` | `/api/v1/datasets` | List Datasets |
|
||||
| `update` | `/api/v1/datasets/<dataset_id>` | Update Dataset |
|
||||
| `knowledge_graph` | `/api/v1/datasets/<dataset_id>/knowledge_graph` | Knowledge Graph |
|
||||
| `delete_knowledge_graph` | `/api/v1/datasets/<dataset_id>/knowledge_graph` | Delete Knowledge Graph |
|
||||
| `run_graphrag` | `/api/v1/datasets/<dataset_id>/run_graphrag` | Run GraphRAG |
|
||||
| `run_raptor` | `/api/v1/datasets/<dataset_id>/run_raptor` | Run Raptor |
|
||||
| `trace_graphrag` | `/api/v1/datasets/<dataset_id>/trace_graphrag` | Trace GraphRAG |
|
||||
| `trace_raptor` | `/api/v1/datasets/<dataset_id>/trace_raptor` | Trace Raptor |
|
||||
|
||||
## File: `api/apps/sdk/dify_retrieval.py`
|
||||
| Function Name | URL Pattern | Notes |
|
||||
|---|---|---|
|
||||
| `retrieval` | `/api/v1/dify/retrieval` | Dify Retrieval |
|
||||
|
||||
## File: `api/apps/sdk/doc.py`
|
||||
| Function Name | URL Pattern | Notes |
|
||||
|---|---|---|
|
||||
| `parse` | `/api/v1/datasets/<dataset_id>/chunks` | Parse Document Chunks |
|
||||
| `stop_parsing` | `/api/v1/datasets/<dataset_id>/chunks` | Stop Parsing |
|
||||
| `upload` | `/api/v1/datasets/<dataset_id>/documents` | Upload Document |
|
||||
| `list_docs` | `/api/v1/datasets/<dataset_id>/documents` | List Documents |
|
||||
| `delete` | `/api/v1/datasets/<dataset_id>/documents` | Delete Document |
|
||||
| `update_doc` | `/api/v1/datasets/<dataset_id>/documents/<document_id>` | Update Document |
|
||||
| `download` | `/api/v1/datasets/<dataset_id>/documents/<document_id>` | Download Document |
|
||||
| `list_chunks` | `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks` | List Chunks |
|
||||
| `add_chunk` | `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks` | Add Chunk |
|
||||
| `update_chunk` | `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks/<chunk_id>` | Update Chunk |
|
||||
| `rm_chunk` | `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks` | Remove Chunk |
|
||||
| `metadata_summary` | `/api/v1/datasets/<dataset_id>/metadata/summary` | Metadata Summary |
|
||||
| `metadata_batch_update` | `/api/v1/datasets/<dataset_id>/metadata/update` | Batch Update Metadata |
|
||||
| `retrieval_test` | `/api/v1/retrieval` | Retrieval Test |
|
||||
|
||||
## File: `api/apps/sdk/files.py`
|
||||
| Function Name | URL Pattern | Notes |
|
||||
|---|---|---|
|
||||
| `get_all_parent_folders` | `/api/v1/file/all_parent_folder` | Get All Parent Folders |
|
||||
| `convert` | `/api/v1/file/convert` | File Convert |
|
||||
| `create` | `/api/v1/file/create` | File Create |
|
||||
| `download_attachment` | `/api/v1/file/download/<attachment_id>` | Download Attachment |
|
||||
| `get` | `/api/v1/file/get/<file_id>` | Get File |
|
||||
| `list_files` | `/api/v1/file/list` | List Files |
|
||||
| `move` | `/api/v1/file/mv` | Move File |
|
||||
| `get_parent_folder` | `/api/v1/file/parent_folder` | Get Parent Folder |
|
||||
| `rename` | `/api/v1/file/rename` | Rename File |
|
||||
| `rm` | `/api/v1/file/rm` | Remove File |
|
||||
| `get_root_folder` | `/api/v1/file/root_folder` | Get Root Folder |
|
||||
| `upload` | `/api/v1/file/upload` | Upload File |
|
||||
|
||||
## File: `api/apps/sdk/session.py`
|
||||
| Function Name | URL Pattern | Notes |
|
||||
|---|---|---|
|
||||
| `agent_bot_completions` | `/api/v1/agentbots/<agent_id>/completions` | Agent Bot completion |
|
||||
| `begin_inputs` | `/api/v1/agentbots/<agent_id>/inputs` | Get Agent Bot inputs |
|
||||
| `agent_completions` | `/api/v1/agents/<agent_id>/completions` | Agent completion |
|
||||
| `create_agent_session` | `/api/v1/agents/<agent_id>/sessions` | Create Agent Session |
|
||||
| `list_agent_session` | `/api/v1/agents/<agent_id>/sessions` | List Agent Sessions |
|
||||
| `delete_agent_session` | `/api/v1/agents/<agent_id>/sessions` | Delete Agent Session |
|
||||
| `agents_completion_openai_compatibility` | `/api/v1/agents_openai/<agent_id>/chat/completions` | OpenAI compatible Agent completion |
|
||||
| `chatbot_completions` | `/api/v1/chatbots/<dialog_id>/completions` | Chatbot completion |
|
||||
| `chatbots_inputs` | `/api/v1/chatbots/<dialog_id>/info` | Chatbot info |
|
||||
| `chat_completion` | `/api/v1/chats/<chat_id>/completions` | Chat completion |
|
||||
| `create` | `/api/v1/chats/<chat_id>/sessions` | Create Chat Session |
|
||||
| `list_session` | `/api/v1/chats/<chat_id>/sessions` | List Chat Sessions |
|
||||
| `delete` | `/api/v1/chats/<chat_id>/sessions` | Delete Chat Session |
|
||||
| `update` | `/api/v1/chats/<chat_id>/sessions/<session_id>` | Update Chat Session |
|
||||
| `chat_completion_openai_like` | `/api/v1/chats_openai/<chat_id>/chat/completions` | OpenAI compatible Chat completion |
|
||||
| `ask_about_embedded` | `/api/v1/searchbots/ask` | Searchbot Ask |
|
||||
| `detail_share_embedded` | `/api/v1/searchbots/detail` | Searchbot Detail |
|
||||
| `mindmap` | `/api/v1/searchbots/mindmap` | Searchbot Mindmap |
|
||||
| `related_questions_embedded` | `/api/v1/searchbots/related_questions` | Searchbot Related Questions |
|
||||
| `retrieval_test_embedded` | `/api/v1/searchbots/retrieval_test` | Searchbot Retrieval Test |
|
||||
| `ask_about` | `/api/v1/sessions/ask` | Session Ask |
|
||||
| `related_questions` | `/api/v1/sessions/related_questions` | Session Related Questions |
|
||||
@@ -1,45 +0,0 @@
|
||||
# RAGFlow API 接口文档索引 (Unofficial Detailed Guide)
|
||||
|
||||
本文档汇集了 RAGFlow 核心模块的 API 详解。所有文档均遵循 **Zero Omissions (无省略)** 原则,全字段展开并包含中文注释。
|
||||
|
||||
## 📚 1. 知识库与文档管理 (Knowledge & Documents)
|
||||
核心的数据管理模块,负责上传文件、解析文档与建立索引。
|
||||
|
||||
- **[知识库管理 (Dataset)](./RAGFlow_Dataset接口详解.md)**
|
||||
- 涵盖知识库的创建、列表查询、更新、删除等接口。
|
||||
- **[文档处理 (Document)](./RAGFlow_Document接口详解.md)**
|
||||
- 涵盖文档的上传 (Upload)、解析配置更新 (Update)、解析状态查询 (Run Status)。
|
||||
- **切片管理**: 解析后的 Chunk 列表查询、增删改查。
|
||||
- **检索测试**: 直接对知识库进行召回测试 (Retrieval Test)。
|
||||
- **[文件管理 (File)](./RAGFlow_File接口详解.md)**
|
||||
- 类似网盘的文件操作体系。
|
||||
- **CRUD**: 上传、下载、列表。
|
||||
- **目录**: 文件夹创建、面包屑导航 (`get_all_parent_folders`)。
|
||||
- **操作**: 移动、重命名、删除、导入知识库 (`convert`).
|
||||
|
||||
## 💬 2. 聊天助手 (Chat Assistant)
|
||||
RAGFlow 原生的对话助手体系,基于 Assistant (Dialog) 模型。
|
||||
|
||||
- **[会话管理 (Chat Session)](./RAGFlow_Chat_Session接口详解.md)**
|
||||
- 管理 `/chats/` 下的会话生命周期。
|
||||
- 创建会话、获取历史记录、重命名、批量删除。
|
||||
- **[对话交互 (Chat Completion)](./RAGFlow_Chat_Completion接口详解.md)**
|
||||
- **Core Chat**: 原生流式对话 (`/chats/<id>/completions`), 支持引用 (`quote`)。
|
||||
- **OpenAI Compatible**: 完美兼容 OpenAI `/v1/chat/completions` 协议。
|
||||
- **Embedded Bot**: 面向 C 端嵌入窗口的对话接口 (`/chatbots/`).
|
||||
|
||||
## 🤖 3. Agent 与 机器人 (Agent & Bots)
|
||||
基于 Graph (DAG) 编排的复杂应用与各类机器人扩展。
|
||||
|
||||
- **[Agent 与 Dify 兼容 (Agent & Dify)](./RAGFlow_Agent_Dify接口详解.md)**
|
||||
- **Agent Session**: Agent 的会话管理与流式对话 (`agent_completions`)。
|
||||
- **Dify Adapter**: 兼容 Dify 协议的检索接口 (`retrieval`).
|
||||
- **[SearchBot 与 AgentBot](./RAGFlow_SearchBot_AgentBot接口详解.md)**
|
||||
- **SearchBot**: 纯搜索机器人,支持思维导图 (`mindmap`)、相关问题 (`related_questions`).
|
||||
- **AgentBot**: 嵌入式 Agent,支持前置表单 (`begin_inputs`).
|
||||
- **Agent OpenAI**: Agent 的 OpenAI 兼容接口。
|
||||
|
||||
## 🛠️ 4. 其他 (Extras)
|
||||
- **[通用与补充接口 (Session Extras)](./RAGFlow_Session_Extra接口详解.md)**
|
||||
- **引用详情**: 获取 SearchBot 引用来源 (`detail_share_embedded`).
|
||||
- **通用问答**: 内部调试用的直接问答 (`ask_about`).
|
||||
@@ -7,6 +7,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
/**
|
||||
@@ -129,6 +130,7 @@ public class DatasetDTO {
|
||||
@JsonProperty("parser_config")
|
||||
private ParserConfig parserConfig;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@Schema(description = "PageRank 权重 (0-100)", example = "50")
|
||||
private Integer pagerank;
|
||||
}
|
||||
|
||||
+10
-1
@@ -176,12 +176,21 @@ public abstract class KnowledgeBaseAdapter {
|
||||
|
||||
/**
|
||||
* 获取数据集的文档数量
|
||||
*
|
||||
*
|
||||
* @param datasetId 数据集ID
|
||||
* @return 文档数量
|
||||
*/
|
||||
public abstract Integer getDocumentCount(String datasetId);
|
||||
|
||||
/**
|
||||
* 获取数据集完整信息(名称、简介、文档数量等)
|
||||
* 用于检测 RAGFlow 端是否已删除、同步名称/简介变更
|
||||
*
|
||||
* @param datasetId 数据集ID
|
||||
* @return 数据集详情,若 RAGFlow 端不存在则返回 null
|
||||
*/
|
||||
public abstract DatasetDTO.InfoVO getDatasetInfo(String datasetId);
|
||||
|
||||
/**
|
||||
* 发送流式请求 (SSE)
|
||||
*
|
||||
|
||||
+19
-12
@@ -486,7 +486,20 @@ public class RAGFlowAdapter extends KnowledgeBaseAdapter {
|
||||
@Override
|
||||
public Integer getDocumentCount(String datasetId) {
|
||||
try {
|
||||
// [Fix] 使用列表过滤接口获取详情 (GET /datasets?id={id})
|
||||
DatasetDTO.InfoVO info = getDatasetInfo(datasetId);
|
||||
if (info != null && info.getDocumentCount() != null) {
|
||||
return info.getDocumentCount().intValue();
|
||||
}
|
||||
return 0;
|
||||
} catch (Exception e) {
|
||||
log.warn("获取文档数量失败: {}", e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatasetDTO.InfoVO getDatasetInfo(String datasetId) {
|
||||
try {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", datasetId);
|
||||
params.put("page", 1);
|
||||
@@ -498,20 +511,14 @@ public class RAGFlowAdapter extends KnowledgeBaseAdapter {
|
||||
if (dataObj instanceof List) {
|
||||
List<?> list = (List<?>) dataObj;
|
||||
if (!list.isEmpty()) {
|
||||
Object firstItem = list.get(0);
|
||||
if (firstItem instanceof Map) {
|
||||
Object countObj = ((Map<?, ?>) firstItem).get("document_count");
|
||||
if (countObj instanceof Number) {
|
||||
return ((Number) countObj).intValue();
|
||||
}
|
||||
}
|
||||
return objectMapper.convertValue(list.get(0), DatasetDTO.InfoVO.class);
|
||||
}
|
||||
}
|
||||
// 降级:未找到或结构不匹配
|
||||
return 0;
|
||||
// RAGFlow 端不存在该数据集
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.warn("获取文档数量失败: {}", e.getMessage());
|
||||
return 0;
|
||||
log.warn("获取数据集信息失败: datasetId={}, error={}", datasetId, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -96,7 +96,7 @@ public interface KnowledgeFilesService {
|
||||
/**
|
||||
* 保存文档影子记录
|
||||
*/
|
||||
void saveDocumentShadow(String datasetId, KnowledgeFilesDTO result, String originalName, String chunkMethod,
|
||||
boolean saveDocumentShadow(String datasetId, KnowledgeFilesDTO result, String originalName, String chunkMethod,
|
||||
Map<String, Object> parserConfig);
|
||||
|
||||
/**
|
||||
@@ -120,4 +120,13 @@ public interface KnowledgeFilesService {
|
||||
* 同步所有处于 RUNNING 状态的文档 (供定时任务调用)
|
||||
*/
|
||||
void syncRunningDocuments();
|
||||
|
||||
/**
|
||||
* 从RAGFlow全量同步文档到本地影子表
|
||||
* 拉取远端所有文档,与本地影子表对比,插入缺失的记录
|
||||
*
|
||||
* @param datasetId 数据集ID
|
||||
* @return 新同步的文档数量
|
||||
*/
|
||||
int syncDocumentsFromRAG(String datasetId);
|
||||
}
|
||||
+90
-7
@@ -19,6 +19,8 @@ import xiaozhi.common.service.impl.BaseServiceImpl;
|
||||
import xiaozhi.common.utils.ConvertUtils;
|
||||
import xiaozhi.common.utils.JsonUtils;
|
||||
import xiaozhi.modules.knowledge.dao.KnowledgeBaseDao;
|
||||
import xiaozhi.modules.knowledge.dao.DocumentDao;
|
||||
import xiaozhi.modules.knowledge.entity.DocumentEntity;
|
||||
import xiaozhi.modules.knowledge.dto.KnowledgeBaseDTO;
|
||||
import xiaozhi.modules.knowledge.dto.dataset.DatasetDTO;
|
||||
import xiaozhi.modules.knowledge.entity.KnowledgeBaseEntity;
|
||||
@@ -46,6 +48,7 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
|
||||
implements KnowledgeBaseService {
|
||||
|
||||
private final KnowledgeBaseDao knowledgeBaseDao;
|
||||
private final DocumentDao documentDao;
|
||||
private final ModelConfigService modelConfigService;
|
||||
private final ModelConfigDao modelConfigDao;
|
||||
private final RedisUtils redisUtils;
|
||||
@@ -67,27 +70,107 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
|
||||
|
||||
// Enrich with Document Count from RAG (Optional / Lazy)
|
||||
if (pageData != null && pageData.getList() != null) {
|
||||
for (KnowledgeBaseDTO dto : pageData.getList()) {
|
||||
pageData.getList().removeIf(dto -> {
|
||||
enrichDocumentCount(dto);
|
||||
}
|
||||
// syncDatasetFromRAG 检测到 RAGFlow 端已删除时,会将本地记录清理
|
||||
// 此时 datasetId 被置空作为标记,需要在列表中移除该条目
|
||||
return dto.getDatasetId() == null;
|
||||
});
|
||||
}
|
||||
return pageData;
|
||||
}
|
||||
|
||||
private void enrichDocumentCount(KnowledgeBaseDTO dto) {
|
||||
syncDatasetFromRAG(dto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 RAGFlow 同步数据集信息:检测删除、同步名称/简介、获取文档数量
|
||||
* 每次列表刷新时实时查询 RAGFlow,确保立即感知远端变更
|
||||
*/
|
||||
private void syncDatasetFromRAG(KnowledgeBaseDTO dto) {
|
||||
try {
|
||||
if (StringUtils.isNotBlank(dto.getDatasetId()) && StringUtils.isNotBlank(dto.getRagModelId())) {
|
||||
KnowledgeBaseAdapter adapter = getAdapterByModelId(dto.getRagModelId());
|
||||
if (adapter != null) {
|
||||
dto.setDocumentCount(adapter.getDocumentCount(dto.getDatasetId()));
|
||||
if (StringUtils.isBlank(dto.getDatasetId()) || StringUtils.isBlank(dto.getRagModelId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
KnowledgeBaseAdapter adapter = getAdapterByModelId(dto.getRagModelId());
|
||||
if (adapter == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
DatasetDTO.InfoVO datasetInfo = adapter.getDatasetInfo(dto.getDatasetId());
|
||||
|
||||
if (datasetInfo == null) {
|
||||
// RAGFlow 端已删除 → 本地级联清理
|
||||
log.info("数据集 {} 在 RAGFlow 端不存在,执行本地清理", dto.getDatasetId());
|
||||
cleanupLocalDataset(dto.getDatasetId(), dto.getId());
|
||||
// 标记为已删除,让上层从列表中移除
|
||||
dto.setDatasetId(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// 同步名称(去掉 username_ 前缀)
|
||||
String ragflowName = datasetInfo.getName();
|
||||
if (StringUtils.isNotBlank(ragflowName)) {
|
||||
String localName = ragflowName.contains("_") ? ragflowName.substring(ragflowName.indexOf('_') + 1) : ragflowName;
|
||||
if (!localName.equals(dto.getName())) {
|
||||
log.info("同步知识库名称: {} -> {}", dto.getName(), localName);
|
||||
KnowledgeBaseEntity entity = knowledgeBaseDao.selectById(dto.getId());
|
||||
if (entity != null) {
|
||||
entity.setName(localName);
|
||||
knowledgeBaseDao.updateById(entity);
|
||||
dto.setName(localName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 同步简介
|
||||
String ragflowDesc = datasetInfo.getDescription();
|
||||
String localDesc = dto.getDescription();
|
||||
boolean descChanged = (ragflowDesc == null && localDesc != null) || (ragflowDesc != null && !ragflowDesc.equals(localDesc));
|
||||
if (descChanged) {
|
||||
log.info("同步知识库简介: datasetId={}", dto.getDatasetId());
|
||||
KnowledgeBaseEntity entity = knowledgeBaseDao.selectById(dto.getId());
|
||||
if (entity != null) {
|
||||
entity.setDescription(ragflowDesc);
|
||||
knowledgeBaseDao.updateById(entity);
|
||||
dto.setDescription(ragflowDesc);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置文档数量(保留原有功能)
|
||||
if (datasetInfo.getDocumentCount() != null) {
|
||||
dto.setDocumentCount(datasetInfo.getDocumentCount().intValue());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.warn("无法获取知识库 {} 的文档计数: {}", dto.getName(), e.getMessage());
|
||||
log.warn("同步数据集信息失败 {}: {}", dto.getName(), e.getMessage());
|
||||
dto.setDocumentCount(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地级联清理:RAGFlow 端已删除时,清理本地所有关联数据
|
||||
* 不调用 RAGFlow 删除 API
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void cleanupLocalDataset(String datasetId, String entityId) {
|
||||
try {
|
||||
// 1. 删除文档影子记录
|
||||
documentDao.delete(new QueryWrapper<DocumentEntity>().eq("dataset_id", datasetId));
|
||||
// 2. 删除插件映射
|
||||
knowledgeBaseDao.deletePluginMappingByKnowledgeBaseId(entityId);
|
||||
// 3. 删除知识库记录
|
||||
knowledgeBaseDao.deleteById(entityId);
|
||||
// 4. 清理缓存
|
||||
redisUtils.delete(RedisKeys.getKnowledgeBaseCacheKey(entityId));
|
||||
log.info("本地级联清理完成: datasetId={}, entityId={}", datasetId, entityId);
|
||||
} catch (Exception e) {
|
||||
log.error("本地级联清理失败: datasetId={}, entityId={}", datasetId, entityId, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public KnowledgeBaseDTO getById(String id) {
|
||||
KnowledgeBaseEntity entity = knowledgeBaseDao.selectById(id);
|
||||
|
||||
+192
-8
@@ -4,6 +4,8 @@ import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
@@ -76,6 +78,13 @@ public class KnowledgeFilesServiceImpl extends BaseServiceImpl<DocumentDao, Docu
|
||||
throw new RenException(ErrorCode.RAG_DATASET_ID_AND_MODEL_ID_NOT_NULL);
|
||||
}
|
||||
|
||||
// 全量对账同步: 从RAGFlow拉取远端文档,实时同步确保立即感知远端变更
|
||||
try {
|
||||
self.syncDocumentsFromRAG(datasetId);
|
||||
} catch (Exception e) {
|
||||
log.warn("从RAGFlow全量同步文档失败(不影响本地查询): datasetId={}, error={}", datasetId, e.getMessage());
|
||||
}
|
||||
|
||||
// 1. 获取本地影子表数据 (MyBatis-Plus 分页)
|
||||
Page<DocumentEntity> pageParams = new Page<>(page, limit);
|
||||
QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
|
||||
@@ -408,10 +417,13 @@ public class KnowledgeFilesServiceImpl extends BaseServiceImpl<DocumentDao, Docu
|
||||
}
|
||||
|
||||
/**
|
||||
* 原子化保存影子记录,确保本地数据绝对一致
|
||||
* 原子化保存影子记录(Upsert 语义)
|
||||
* 若 document_id 已存在则更新,不存在则插入,避免 UNIQUE 约束冲突
|
||||
*
|
||||
* @return true=新插入, false=更新已有记录
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveDocumentShadow(String datasetId, KnowledgeFilesDTO result, String originalName, String chunkMethod,
|
||||
public boolean saveDocumentShadow(String datasetId, KnowledgeFilesDTO result, String originalName, String chunkMethod,
|
||||
Map<String, Object> parserConfig) {
|
||||
DocumentEntity entity = new DocumentEntity();
|
||||
entity.setDatasetId(datasetId);
|
||||
@@ -453,12 +465,23 @@ public class KnowledgeFilesServiceImpl extends BaseServiceImpl<DocumentDao, Docu
|
||||
entity.setCreatedAt(result.getCreatedAt() != null ? result.getCreatedAt() : new Date());
|
||||
entity.setUpdatedAt(result.getUpdatedAt() != null ? result.getUpdatedAt() : new Date());
|
||||
|
||||
// 插入影子表 (若失败将抛出异常,触发调用方报错,确保 Local-First 列表一致性)
|
||||
documentDao.insert(entity);
|
||||
// Upsert: 检查 document_id 是否已存在,存在则更新,不存在则插入
|
||||
DocumentEntity existing = documentDao.selectOne(
|
||||
new QueryWrapper<DocumentEntity>().eq("document_id", entity.getDocumentId()));
|
||||
|
||||
// Issue 4: 同步递增数据集文档总数统计,保持父子表一致
|
||||
knowledgeBaseService.updateStatistics(datasetId, 1, 0L, 0L);
|
||||
log.info("已同步递增数据集统计: datasetId={}", datasetId);
|
||||
if (existing != null) {
|
||||
entity.setId(existing.getId());
|
||||
entity.setCreatedAt(existing.getCreatedAt()); // 保留原始创建时间
|
||||
documentDao.updateById(entity);
|
||||
log.info("影子记录已更新: documentId={}", entity.getDocumentId());
|
||||
return false;
|
||||
} else {
|
||||
documentDao.insert(entity);
|
||||
// 新增记录时递增数据集文档总数统计
|
||||
knowledgeBaseService.updateStatistics(datasetId, 1, 0L, 0L);
|
||||
log.info("影子记录已插入: documentId={}, datasetId={}", entity.getDocumentId(), datasetId);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -738,6 +761,167 @@ public class KnowledgeFilesServiceImpl extends BaseServiceImpl<DocumentDao, Docu
|
||||
this.deleteDocuments(datasetId, req);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int syncDocumentsFromRAG(String datasetId) {
|
||||
log.info("=== 开始从RAGFlow全量同步文档到本地影子表: datasetId={} ===", datasetId);
|
||||
|
||||
// 1. 获取适配器
|
||||
Map<String, Object> ragConfig = knowledgeBaseService.getRAGConfigByDatasetId(datasetId);
|
||||
KnowledgeBaseAdapter adapter = KnowledgeBaseAdapterFactory.getAdapter(extractAdapterType(ragConfig), ragConfig);
|
||||
|
||||
// 2. 分页拉取远端所有文档
|
||||
List<KnowledgeFilesDTO> allRemoteDocs = new ArrayList<>();
|
||||
int pageNum = 1;
|
||||
int pageSize = 100;
|
||||
long totalRemote = Long.MAX_VALUE;
|
||||
|
||||
while ((long) (pageNum - 1) * pageSize < totalRemote) {
|
||||
DocumentDTO.ListReq req = DocumentDTO.ListReq.builder()
|
||||
.page(pageNum)
|
||||
.pageSize(pageSize)
|
||||
.build();
|
||||
PageData<KnowledgeFilesDTO> remotePage = adapter.getDocumentList(datasetId, req);
|
||||
if (remotePage == null || remotePage.getList() == null || remotePage.getList().isEmpty()) {
|
||||
break;
|
||||
}
|
||||
allRemoteDocs.addAll(remotePage.getList());
|
||||
totalRemote = remotePage.getTotal();
|
||||
pageNum++;
|
||||
}
|
||||
|
||||
// 3. 获取本地已有文档
|
||||
List<DocumentEntity> localDocs = documentDao.selectList(
|
||||
new QueryWrapper<DocumentEntity>().eq("dataset_id", datasetId));
|
||||
Set<String> localDocIds = localDocs.stream()
|
||||
.map(DocumentEntity::getDocumentId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 4. 远端文档ID集合
|
||||
Set<String> remoteDocIds = allRemoteDocs.stream()
|
||||
.map(KnowledgeFilesDTO::getDocumentId)
|
||||
.filter(id -> id != null)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 5. 补充: 插入远端存在但本地缺失的文档
|
||||
List<KnowledgeFilesDTO> newDocs = allRemoteDocs.stream()
|
||||
.filter(doc -> doc.getDocumentId() != null && !localDocIds.contains(doc.getDocumentId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
int syncCount = 0;
|
||||
if (!newDocs.isEmpty()) {
|
||||
for (KnowledgeFilesDTO doc : newDocs) {
|
||||
try {
|
||||
self.saveDocumentShadow(datasetId, doc, doc.getName(), doc.getChunkMethod(), doc.getParserConfig());
|
||||
// 同步远端已有的 token/chunk 统计
|
||||
Long tokenCount = doc.getTokenCount() != null ? doc.getTokenCount() : 0L;
|
||||
long chunkCount = doc.getChunkCount() != null ? doc.getChunkCount().longValue() : 0L;
|
||||
if (tokenCount > 0 || chunkCount > 0) {
|
||||
knowledgeBaseService.updateStatistics(datasetId, 0, chunkCount, tokenCount);
|
||||
}
|
||||
syncCount++;
|
||||
} catch (Exception e) {
|
||||
log.warn("同步单个文档影子记录失败: docId={}, error={}", doc.getDocumentId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
log.info("从RAGFlow新增同步 {} 个文档影子记录, datasetId={}", syncCount, datasetId);
|
||||
}
|
||||
|
||||
// 6. 清理: 删除远端已不存在但本地仍保留的影子记录
|
||||
List<DocumentEntity> deletedDocs = localDocs.stream()
|
||||
.filter(entity -> !remoteDocIds.contains(entity.getDocumentId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!deletedDocs.isEmpty()) {
|
||||
List<String> deletedDocIds = new ArrayList<>();
|
||||
long totalChunkDelta = 0;
|
||||
long totalTokenDelta = 0;
|
||||
|
||||
for (DocumentEntity entity : deletedDocs) {
|
||||
deletedDocIds.add(entity.getDocumentId());
|
||||
totalChunkDelta += entity.getChunkCount() != null ? entity.getChunkCount() : 0L;
|
||||
totalTokenDelta += entity.getTokenCount() != null ? entity.getTokenCount() : 0L;
|
||||
}
|
||||
try {
|
||||
self.deleteDocumentShadows(deletedDocIds, datasetId, totalChunkDelta, totalTokenDelta);
|
||||
log.info("清理远端已删除的影子记录: {} 个, datasetId={}", deletedDocs.size(), datasetId);
|
||||
} catch (Exception e) {
|
||||
log.warn("清理远端已删除的影子记录失败: datasetId={}, error={}", datasetId, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 7. 全量更新: 远端和本地都存在的文档,以远端为准同步所有字段
|
||||
// 处理 RAGFlow 复用 documentId 重传、远端编辑后元数据变化等场景
|
||||
Map<String, KnowledgeFilesDTO> remoteDocMap = allRemoteDocs.stream()
|
||||
.filter(doc -> doc.getDocumentId() != null)
|
||||
.collect(Collectors.toMap(KnowledgeFilesDTO::getDocumentId, doc -> doc, (a, b) -> b));
|
||||
|
||||
Map<String, DocumentEntity> localDocMap = localDocs.stream()
|
||||
.collect(Collectors.toMap(DocumentEntity::getDocumentId, e -> e, (a, b) -> b));
|
||||
|
||||
int updateCount = 0;
|
||||
for (Map.Entry<String, KnowledgeFilesDTO> entry : remoteDocMap.entrySet()) {
|
||||
String docId = entry.getKey();
|
||||
DocumentEntity local = localDocMap.get(docId);
|
||||
if (local == null) {
|
||||
continue; // 不在本地,由步骤5处理
|
||||
}
|
||||
KnowledgeFilesDTO remote = entry.getValue();
|
||||
|
||||
// 全量字段更新(以远端为准),确保本地与 RAGFlow 完全一致
|
||||
UpdateWrapper<DocumentEntity> updateWrapper = new UpdateWrapper<DocumentEntity>()
|
||||
.set("run", remote.getRun())
|
||||
.set("status", remote.getStatus() != null ? remote.getStatus() : local.getStatus())
|
||||
.set("progress", remote.getProgress())
|
||||
.set("chunk_count", remote.getChunkCount())
|
||||
.set("token_count", remote.getTokenCount())
|
||||
.set("size", remote.getFileSize())
|
||||
.set("error", remote.getError())
|
||||
.set("process_duration", remote.getProcessDuration())
|
||||
.set("updated_at", new Date())
|
||||
.set("last_sync_at", new Date())
|
||||
.eq("document_id", docId)
|
||||
.eq("dataset_id", datasetId);
|
||||
|
||||
if (remote.getName() != null) {
|
||||
updateWrapper.set("name", remote.getName());
|
||||
}
|
||||
if (remote.getThumbnail() != null) {
|
||||
updateWrapper.set("thumbnail", remote.getThumbnail());
|
||||
}
|
||||
if (remote.getMetaFields() != null) {
|
||||
try {
|
||||
updateWrapper.set("meta_fields", objectMapper.writeValueAsString(remote.getMetaFields()));
|
||||
} catch (Exception e) {
|
||||
log.warn("同步更新元数据序列化失败: docId={}, error={}", docId, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
documentDao.update(null, updateWrapper);
|
||||
|
||||
// 同步统计差异(chunk/token 计数变化时修正父表)
|
||||
Long remoteTokenCount = remote.getTokenCount() != null ? remote.getTokenCount() : 0L;
|
||||
Long localTokenCount = local.getTokenCount() != null ? local.getTokenCount() : 0L;
|
||||
long remoteChunkCount = remote.getChunkCount() != null ? remote.getChunkCount().longValue() : 0L;
|
||||
long localChunkCount = local.getChunkCount() != null ? local.getChunkCount().longValue() : 0L;
|
||||
long tokenDelta = remoteTokenCount - localTokenCount;
|
||||
long chunkDelta = remoteChunkCount - localChunkCount;
|
||||
if (tokenDelta != 0 || chunkDelta != 0) {
|
||||
knowledgeBaseService.updateStatistics(datasetId, 0, chunkDelta, tokenDelta);
|
||||
log.info("影子更新: 修正知识库统计, docId={}, chunkDelta={}, tokenDelta={}", docId, chunkDelta, tokenDelta);
|
||||
}
|
||||
|
||||
updateCount++;
|
||||
}
|
||||
|
||||
if (syncCount == 0 && deletedDocs.isEmpty() && updateCount == 0) {
|
||||
log.info("本地影子表已与RAGFlow完全同步, datasetId={}", datasetId);
|
||||
} else {
|
||||
log.info("同步完成: 新增={}, 清理={}, 更新={}, datasetId={}", syncCount, deletedDocs.size(), updateCount, datasetId);
|
||||
}
|
||||
|
||||
return syncCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncRunningDocuments() {
|
||||
// 1. 查询所有 RUNNING 状态的文档
|
||||
@@ -755,7 +939,7 @@ public class KnowledgeFilesServiceImpl extends BaseServiceImpl<DocumentDao, Docu
|
||||
|
||||
// 2. 按 DatasetID 分组,复用 Adapter
|
||||
Map<String, List<DocumentEntity>> groupedDocs = runningDocs.stream()
|
||||
.collect(java.util.stream.Collectors.groupingBy(DocumentEntity::getDatasetId));
|
||||
.collect(Collectors.groupingBy(DocumentEntity::getDatasetId));
|
||||
|
||||
groupedDocs.forEach((datasetId, docs) -> {
|
||||
KnowledgeBaseAdapter adapter = null;
|
||||
|
||||
@@ -67,4 +67,13 @@ public interface LLMService {
|
||||
* @return 是否可用
|
||||
*/
|
||||
boolean isAvailable(String modelId);
|
||||
|
||||
/**
|
||||
* 生成会话标题
|
||||
*
|
||||
* @param conversation 对话内容
|
||||
* @param modelId 模型ID
|
||||
* @return 标题(约15字)
|
||||
*/
|
||||
String generateTitle(String conversation, String modelId);
|
||||
}
|
||||
+122
-2
@@ -1,6 +1,7 @@
|
||||
package xiaozhi.modules.llm.service.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -30,13 +31,38 @@ import xiaozhi.modules.model.service.ModelConfigService;
|
||||
@Service
|
||||
public class OpenAIStyleLLMServiceImpl implements LLMService {
|
||||
|
||||
// 需要禁用思考模式的平台域名及其对应参数
|
||||
private static final Map<String, Map<String, Object>> THINKING_DISABLED_DOMAINS = new LinkedHashMap<>();
|
||||
static {
|
||||
THINKING_DISABLED_DOMAINS.put("aliyuncs.com", Map.of("enable_thinking", false));
|
||||
Map<String, Object> thinkingDisabled = Map.of("thinking", Map.of("type", "disabled"));
|
||||
THINKING_DISABLED_DOMAINS.put("bigmodel.cn", thinkingDisabled);
|
||||
THINKING_DISABLED_DOMAINS.put("moonshot.cn", thinkingDisabled);
|
||||
THINKING_DISABLED_DOMAINS.put("volces.com", thinkingDisabled);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private ModelConfigService modelConfigService;
|
||||
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
/**
|
||||
* 根据域名自动禁用思考模式
|
||||
*/
|
||||
private void applyThinkingDisabled(String baseUrl, Map<String, Object> requestBody) {
|
||||
for (Map.Entry<String, Map<String, Object>> entry : THINKING_DISABLED_DOMAINS.entrySet()) {
|
||||
if (baseUrl.contains(entry.getKey())) {
|
||||
requestBody.putAll(entry.getValue());
|
||||
log.info("为域名 {} 禁用思考模式,参数: {}", baseUrl, entry.getValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String DEFAULT_SUMMARY_PROMPT = "你是一个经验丰富的记忆总结者,擅长将对话内容进行总结摘要,遵循以下规则:\n1、总结用户的重要信息,以便在未来的对话中提供更个性化的服务\n2、不要重复总结,不要遗忘之前记忆,除非原来的记忆超过了1800字,否则不要遗忘、不要压缩用户的历史记忆\n3、用户操控的设备音量、播放音乐、天气、退出、不想对话等和用户本身无关的内容,这些信息不需要加入到总结中\n4、聊天内容中的今天的日期时间、今天的天气情况与用户事件无关的数据,这些信息如果当成记忆存储会影响后续对话,这些信息不需要加入到总结中\n5、不要把设备操控的成果结果和失败结果加入到总结中,也不要把用户的一些废话加入到总结中\n6、不要为了总结而总结,如果用户的聊天没有意义,请返回原来的历史记录也是可以的\n7、只需要返回总结摘要,严格控制在1800字内\n8、不要包含代码、xml,不需要解释、注释和说明,保存记忆时仅从对话提取信息,不要混入示例内容\n9、如果提供了历史记忆,请将新对话内容与历史记忆进行智能合并,保留有价值的历史信息,同时添加新的重要信息\n\n历史记忆:\n{history_memory}\n\n新对话内容:\n{conversation}";
|
||||
|
||||
private static final String DEFAULT_TITLE_PROMPT = "请根据以下对话内容,生成一个简洁的会话标题(约15字以内),只返回标题,不要包含任何解释或标点符号:\n{conversation}";
|
||||
|
||||
@Override
|
||||
public String generateSummary(String conversation) {
|
||||
return generateSummary(conversation, null, null);
|
||||
@@ -100,6 +126,9 @@ public class OpenAIStyleLLMServiceImpl implements LLMService {
|
||||
requestBody.put("temperature", temperature != null ? temperature : 0.7);
|
||||
requestBody.put("max_tokens", maxTokens != null ? maxTokens : 2000);
|
||||
|
||||
// 禁用思考模式
|
||||
applyThinkingDisabled(baseUrl, requestBody);
|
||||
|
||||
// 发送HTTP请求
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
@@ -154,10 +183,8 @@ public class OpenAIStyleLLMServiceImpl implements LLMService {
|
||||
// 从智控台获取LLM模型配置
|
||||
ModelConfigEntity llmConfig;
|
||||
if (modelId != null && !modelId.trim().isEmpty()) {
|
||||
// 通过具体模型ID获取配置
|
||||
llmConfig = modelConfigService.getModelByIdFromCache(modelId);
|
||||
} else {
|
||||
// 保持向后兼容,使用默认配置
|
||||
llmConfig = getDefaultLLMConfig();
|
||||
}
|
||||
|
||||
@@ -195,6 +222,9 @@ public class OpenAIStyleLLMServiceImpl implements LLMService {
|
||||
requestBody.put("temperature", 0.2);
|
||||
requestBody.put("max_tokens", 2000);
|
||||
|
||||
// 禁用思考模式
|
||||
applyThinkingDisabled(baseUrl, requestBody);
|
||||
|
||||
// 发送HTTP请求
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
@@ -302,4 +332,94 @@ public class OpenAIStyleLLMServiceImpl implements LLMService {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateTitle(String conversation, String modelId) {
|
||||
if (!isAvailable()) {
|
||||
log.warn("LLM服务不可用,无法生成标题");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
ModelConfigEntity llmConfig;
|
||||
if (modelId != null && !modelId.trim().isEmpty()) {
|
||||
llmConfig = modelConfigService.getModelByIdFromCache(modelId);
|
||||
} else {
|
||||
llmConfig = getDefaultLLMConfig();
|
||||
}
|
||||
|
||||
if (llmConfig == null || llmConfig.getConfigJson() == null) {
|
||||
log.error("未找到可用的LLM模型配置,modelId: {}", modelId);
|
||||
return null;
|
||||
}
|
||||
|
||||
JSONObject configJson = llmConfig.getConfigJson();
|
||||
String baseUrl = configJson.getStr("base_url");
|
||||
String model = configJson.getStr("model_name");
|
||||
String apiKey = configJson.getStr("api_key");
|
||||
|
||||
if (StringUtils.isBlank(baseUrl) || StringUtils.isBlank(apiKey)) {
|
||||
log.error("LLM配置不完整,baseUrl或apiKey为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
String prompt = DEFAULT_TITLE_PROMPT.replace("{conversation}", conversation);
|
||||
|
||||
Map<String, Object> requestBody = new HashMap<>();
|
||||
requestBody.put("model", model != null ? model : "gpt-3.5-turbo");
|
||||
|
||||
Map<String, Object>[] messages = new Map[1];
|
||||
Map<String, Object> message = new HashMap<>();
|
||||
message.put("role", "user");
|
||||
message.put("content", prompt);
|
||||
messages[0] = message;
|
||||
|
||||
requestBody.put("messages", messages);
|
||||
requestBody.put("temperature", 0.3);
|
||||
requestBody.put("max_tokens", 50);
|
||||
|
||||
// 禁用思考模式
|
||||
applyThinkingDisabled(baseUrl, requestBody);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.set("Authorization", "Bearer " + apiKey);
|
||||
|
||||
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
|
||||
|
||||
String apiUrl = baseUrl;
|
||||
if (!apiUrl.endsWith("/chat/completions")) {
|
||||
if (!apiUrl.endsWith("/")) {
|
||||
apiUrl += "/";
|
||||
}
|
||||
apiUrl += "chat/completions";
|
||||
}
|
||||
|
||||
ResponseEntity<String> response = restTemplate.exchange(
|
||||
apiUrl, HttpMethod.POST, entity, String.class);
|
||||
|
||||
if (response.getStatusCode().is2xxSuccessful()) {
|
||||
JSONObject responseJson = JSONUtil.parseObj(response.getBody());
|
||||
JSONArray choices = responseJson.getJSONArray("choices");
|
||||
if (choices != null && choices.size() > 0) {
|
||||
JSONObject choice = choices.getJSONObject(0);
|
||||
JSONObject messageObj = choice.getJSONObject("message");
|
||||
String title = messageObj.getStr("content");
|
||||
if (StringUtils.isNotBlank(title)) {
|
||||
title = title.trim().replaceAll("[,。!?、:;''\"\"【】()]", "");
|
||||
if (title.length() > 15) {
|
||||
title = title.substring(0, 15);
|
||||
}
|
||||
return title;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.error("LLM API调用失败,状态码:{},响应:{}", response.getStatusCode(), response.getBody());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("调用LLM服务生成标题时发生异常,modelId: {}", modelId, e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+16
-1
@@ -57,7 +57,8 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
|
||||
.eq("model_type", modelType)
|
||||
.eq("is_enabled", 1)
|
||||
.like(StringUtils.isNotBlank(modelName), "model_name", modelName)
|
||||
.select("id", "model_name"));
|
||||
.select("id", "model_name")
|
||||
.orderByAsc("sort"));
|
||||
return ConvertUtils.sourceToTarget(entities, ModelBasicInfoDTO.class);
|
||||
}
|
||||
|
||||
@@ -370,6 +371,13 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
|
||||
}
|
||||
}
|
||||
|
||||
// 删除在新JSON中不存在的非敏感字段
|
||||
for (String oldKey : originalJson.keySet().toArray(new String[0])) {
|
||||
if (!modelConfigBodyDTO.getConfigJson().containsKey(oldKey) && !SensitiveDataUtils.isSensitiveField(oldKey)) {
|
||||
updatedJson.remove(oldKey);
|
||||
}
|
||||
}
|
||||
|
||||
modelConfigEntity.setConfigJson(updatedJson);
|
||||
}
|
||||
|
||||
@@ -402,6 +410,13 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除在新JSON中不存在的非敏感子字段
|
||||
for (String oldChildKey : originalChild.keySet().toArray(new String[0])) {
|
||||
if (!updated.containsKey(oldChildKey) && !SensitiveDataUtils.isSensitiveField(oldChildKey)) {
|
||||
originalChild.remove(oldChildKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-1
@@ -95,6 +95,7 @@ public class ModelProviderServiceImpl extends BaseServiceImpl<ModelProviderDao,
|
||||
|
||||
QueryWrapper<ModelProviderEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("model_type", StringUtils.isBlank(modelType) ? "" : modelType);
|
||||
queryWrapper.orderByAsc("sort");
|
||||
List<ModelProviderEntity> providerEntities = modelProviderDao.selectList(queryWrapper);
|
||||
return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class);
|
||||
}
|
||||
@@ -147,7 +148,8 @@ public class ModelProviderServiceImpl extends BaseServiceImpl<ModelProviderDao,
|
||||
UserDetail user = SecurityUser.getUser();
|
||||
modelProviderDTO.setUpdater(user.getId());
|
||||
modelProviderDTO.setUpdateDate(new Date());
|
||||
if (modelProviderDao.updateById(ConvertUtils.sourceToTarget(modelProviderDTO, ModelProviderEntity.class)) == 0) {
|
||||
if (modelProviderDao
|
||||
.updateById(ConvertUtils.sourceToTarget(modelProviderDTO, ModelProviderEntity.class)) == 0) {
|
||||
throw new RenException(ErrorCode.UPDATE_DATA_FAILED);
|
||||
}
|
||||
return ConvertUtils.sourceToTarget(modelProviderDTO, ModelProviderDTO.class);
|
||||
|
||||
@@ -90,6 +90,7 @@ public class ShiroConfig {
|
||||
filterMap.put("/agent/chat-history/report", "server");
|
||||
filterMap.put("/agent/chat-history/download/**", "anon");
|
||||
filterMap.put("/agent/chat-summary/**", "server");
|
||||
filterMap.put("/agent/chat-title/**", "server");
|
||||
filterMap.put("/agent/play/**", "anon");
|
||||
filterMap.put("/voiceClone/play/**", "anon");
|
||||
filterMap.put("/**", "oauth2");
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
-- 新增仅上报聊天记录记忆模型供应器
|
||||
|
||||
delete from `ai_model_provider` where `id` = 'SYSTEM_Memory_mem_report_only';
|
||||
delete from `ai_model_config` where `id` = 'Memory_mem_report_only';
|
||||
|
||||
INSERT INTO `ai_model_provider` VALUES ('SYSTEM_Memory_mem_report_only', 'Memory', 'mem_report_only', '仅上报聊天记录', '[]', 4, 1, NOW(), 1, NOW());
|
||||
INSERT INTO `ai_model_config` VALUES ('Memory_mem_report_only', 'Memory', 'mem_report_only', '仅上报聊天记录', 0, 1, '{"type": "mem_report_only"}', NULL, '仅上报聊天记录,不总结记忆', 3, NULL, NULL, NULL, NULL);
|
||||
@@ -0,0 +1,2 @@
|
||||
-- 修改聊天内容字段类型
|
||||
ALTER TABLE ai_agent_chat_history MODIFY COLUMN content TEXT COMMENT '聊天内容';
|
||||
@@ -0,0 +1,7 @@
|
||||
-- 修改记忆模型名称
|
||||
|
||||
UPDATE `ai_model_config` SET `model_name` = '本地短期记忆(总结记忆)' WHERE `id` = 'Memory_mem_local_short';
|
||||
UPDATE `ai_model_provider` SET `name` = '本地短期记忆(总结记忆)' WHERE `id` = 'SYSTEM_Memory_mem_local_short';
|
||||
|
||||
UPDATE `ai_model_config` SET `model_name` = '仅上报聊天记录(不总结记忆)' WHERE `id` = 'Memory_mem_report_only';
|
||||
UPDATE `ai_model_provider` SET `name` = '仅上报聊天记录(不总结记忆)' WHERE `id` = 'SYSTEM_Memory_mem_report_only';
|
||||
@@ -0,0 +1 @@
|
||||
INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (312, 'tool_call_timeout', '30', 'number', 1, '工具调用超时时间(秒)');
|
||||
@@ -0,0 +1,16 @@
|
||||
-- 智能体表添加小模型ID字段
|
||||
SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ai_agent' AND COLUMN_NAME = 'slm_model_id');
|
||||
SET @sql = IF(@col_exists = 0, 'ALTER TABLE `ai_agent` ADD COLUMN `slm_model_id` VARCHAR(255) NULL COMMENT ''小模型ID'' AFTER `llm_model_id`', 'SELECT ''Column slm_model_id already exists'' AS msg');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 创建聊天标题表
|
||||
DROP TABLE IF EXISTS `ai_agent_chat_title`;
|
||||
CREATE TABLE `ai_agent_chat_title` (
|
||||
`id` VARCHAR(32) NOT NULL COMMENT '主键ID',
|
||||
`session_id` VARCHAR(255) NOT NULL COMMENT '会话ID',
|
||||
`title` VARCHAR(255) DEFAULT NULL COMMENT '聊天标题',
|
||||
`created_at` DATETIME DEFAULT NULL COMMENT '创建时间',
|
||||
`updated_at` DATETIME DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_session_id` (`session_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='智能体聊天标题表';
|
||||
@@ -0,0 +1,17 @@
|
||||
-- 更新模型名称:qwen2.5-vl-3b-instruct 改为 qwen3.5-flash
|
||||
UPDATE `ai_model_config`
|
||||
SET `config_json` = JSON_SET(`config_json`, '$.model_name', 'qwen3.5-flash')
|
||||
WHERE `id` = 'VLLM_QwenVLVLLM'
|
||||
AND JSON_EXTRACT(`config_json`, '$.model_name') = 'qwen2.5-vl-3b-instruct';
|
||||
|
||||
-- 更新模型名称:qwen-turbo 改为 qwen-flash
|
||||
UPDATE `ai_model_config`
|
||||
SET `config_json` = JSON_SET(`config_json`, '$.model_name', 'qwen-flash')
|
||||
WHERE `id` = 'LLM_AliLLM'
|
||||
AND JSON_EXTRACT(`config_json`, '$.model_name') = 'qwen-turbo';
|
||||
|
||||
-- 更新备注:qwen-turbo 改为 qwen-flash
|
||||
UPDATE `ai_model_config`
|
||||
SET `remark` = REPLACE(`remark`, 'qwen-turbo', 'qwen-flash')
|
||||
WHERE `id` = 'LLM_AliLLM'
|
||||
AND `remark` LIKE '%qwen-turbo%';
|
||||
@@ -0,0 +1,102 @@
|
||||
-- 新增豆包语音合成模型2.0供应器(使用seed-tts-2.0资源ID)
|
||||
-- 与火山双流式TTS配置相同,但resource_id固定为seed-tts-2.0
|
||||
|
||||
-- 插入豆包语音合成模型2.0供应器
|
||||
delete from `ai_model_provider` where id = 'SYSTEM_TTS_HSDSTTS_V2';
|
||||
INSERT INTO `ai_model_provider` (`id`, `model_type`, `provider_code`, `name`, `fields`, `sort`, `creator`, `create_date`, `updater`, `update_date`) VALUES
|
||||
('SYSTEM_TTS_HSDSTTS_V2', 'TTS', 'huoshan_double_stream', '豆包语音合成模型2.0', '[
|
||||
{"key": "ws_url", "type": "string", "label": "WebSocket地址"},
|
||||
{"key": "appid", "type": "string", "label": "应用ID"},
|
||||
{"key": "access_token", "type": "string", "label": "访问令牌"},
|
||||
{"key": "resource_id", "type": "string", "label": "资源ID"},
|
||||
{"key": "speaker", "type": "string", "label": "默认音色"},
|
||||
{"key": "enable_ws_reuse", "type": "boolean", "label": "是否开启链接复用", "default": true},
|
||||
{"key": "audio_params", "type": "dict", "label": "音频输出配置"},
|
||||
{"key": "additions", "type": "dict", "label": "高级文本处理配置"},
|
||||
{"key": "mix_speaker", "type": "dict", "label": "混音控制配置"}
|
||||
]', 14, 1, NOW(), 1, NOW());
|
||||
|
||||
-- 插入豆包语音合成模型2.0配置
|
||||
delete from `ai_model_config` where id = 'TTS_HSDSTTS_V2';
|
||||
INSERT INTO `ai_model_config` VALUES ('TTS_HSDSTTS_V2', 'TTS', 'HuoshanDoubleStreamTTSV2', '豆包语音合成模型2.0', 0, 1, '{
|
||||
"type": "huoshan_double_stream",
|
||||
"ws_url": "wss://openspeech.bytedance.com/api/v3/tts/bidirection",
|
||||
"appid": "",
|
||||
"access_token": "",
|
||||
"resource_id": "seed-tts-2.0",
|
||||
"speaker": "zh_female_xiaohe_uranus_bigtts",
|
||||
"enable_ws_reuse": true,
|
||||
"audio_params": {
|
||||
"speech_rate": 0,
|
||||
"loudness_rate": 0
|
||||
},
|
||||
"additions": {
|
||||
"aigc_metadata": {},
|
||||
"cache_config": {},
|
||||
"post_process": {
|
||||
"pitch": 0
|
||||
}
|
||||
},
|
||||
"mix_speaker": {}
|
||||
}', NULL, NULL, 17, NULL, NULL, NULL, NULL);
|
||||
|
||||
-- 豆包语音合成模型2.0配置说明文档
|
||||
UPDATE `ai_model_config` SET
|
||||
`doc_link` = 'https://www.volcengine.com/docs/6561/1329505',
|
||||
`remark` = '豆包语音合成模型2.0配置说明(基于火山引擎seed-tts-2.0):
|
||||
1. 访问 https://www.volcengine.com/ 注册并开通火山引擎账号
|
||||
2. 访问 https://console.volcengine.com/speech/service/10035 开通语音合成大模型,购买音色
|
||||
3. 在页面底部获取appid和access_token
|
||||
4. 资源ID固定为:seed-tts-2.0(豆包语音合成模型2.0)
|
||||
5. 链接复用:开启WebSocket连接复用,默认true减少链接损耗(注意:复用后设备处于聆听状态时空闲链接会占并发数)
|
||||
|
||||
详细参数文档:https://www.volcengine.com/docs/6561/1329505
|
||||
【audio_params】音频输出配置 - 用户可自定义添加火山引擎支持的任何音频参数
|
||||
- speech_rate: 语速(-50~100),默认0
|
||||
- loudness_rate: 音量(-50~100),默认0
|
||||
示例:{"speech_rate": 10, "loudness_rate": 5}
|
||||
|
||||
【additions】高级文本处理配置 - 用户可自定义添加火山引擎支持的任何高级参数
|
||||
- post_process.pitch: 音高(-12~12),默认0
|
||||
- aigc_metadata: AIGC元数据配置
|
||||
- cache_config: 缓存配置
|
||||
示例:{"post_process": {"pitch": 2}, "aigc_metadata": {}, "cache_config": {}}
|
||||
|
||||
注意:
|
||||
- 豆包语音合成模型2.0使用seed-tts-2.0资源ID,与火山双流式TTS(volc.service_type.10029)不同
|
||||
- 相关音色列表:https://www.volcengine.com/docs/6561/1257544
|
||||
- 用户可根据火山引擎API文档自行添加更多参数
|
||||
' WHERE `id` = 'TTS_HSDSTTS_V2';
|
||||
|
||||
-- 添加豆包语音合成模型2.0音色(与火山双流式TTS音色相同)
|
||||
delete from `ai_tts_voice` where tts_model_id = 'TTS_HSDSTTS_V2';
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0001', 'TTS_HSDSTTS_V2', 'Vivi', 'zh_female_vv_uranus_bigtts', '普通话、日语、印尼语、墨西哥西班牙语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_vv_uranus_bigtts.wav', NULL, NULL, NULL, 1, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0002', 'TTS_HSDSTTS_V2', '小何', 'zh_female_xiaohe_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_xiaohe_uranus_bigtts.mp3', NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0003', 'TTS_HSDSTTS_V2', '云舟', 'zh_male_m191_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_m191_uranus_bigtts.mp3', NULL, NULL, NULL, 3, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0004', 'TTS_HSDSTTS_V2', '小天', 'zh_male_taocheng_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_taocheng_uranus_bigtts.mp3', NULL, NULL, NULL, 4, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0005', 'TTS_HSDSTTS_V2', '刘飞', 'zh_male_liufei_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_liufei_uranus_bigtts.mp3', NULL, NULL, NULL, 5, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0006', 'TTS_HSDSTTS_V2', '魅力苏菲', 'zh_female_sophie_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_sophie_uranus_bigtts.mp3', NULL, NULL, NULL, 6, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0007', 'TTS_HSDSTTS_V2', '清新女声', 'zh_female_qingxinnvsheng_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_qingxinnvsheng_uranus_bigtts.mp3', NULL, NULL, NULL, 7, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0008', 'TTS_HSDSTTS_V2', '知性灿灿', 'zh_female_cancan_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_cancan_uranus_bigtts.mp3', NULL, NULL, NULL, 8, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0009', 'TTS_HSDSTTS_V2', '撒娇学妹', 'zh_female_sajiaoxuemei_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_sajiaoxuemei_uranus_bigtts.mp3', NULL, NULL, NULL, 9, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0010', 'TTS_HSDSTTS_V2', '甜美小源', 'zh_female_tianmeixiaoyuan_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_tianmeixiaoyuan_uranus_bigtts.mp3', NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0011', 'TTS_HSDSTTS_V2', '甜美桃子', 'zh_female_tianmeitaozi_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_tianmeitaozi_uranus_bigtts.mp3', NULL, NULL, NULL, 11, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0012', 'TTS_HSDSTTS_V2', '爽快思思', 'zh_female_shuangkuaisisi_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_shuangkuaisisi_uranus_bigtts.mp3', NULL, NULL, NULL, 12, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0013', 'TTS_HSDSTTS_V2', '佩奇猪', 'zh_female_peiqi_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_peiqi_uranus_bigtts.mp3', NULL, NULL, NULL, 13, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0014', 'TTS_HSDSTTS_V2', '邻家女孩', 'zh_female_linjianvhai_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_linjianvhai_uranus_bigtts.mp3', NULL, NULL, NULL, 14, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0015', 'TTS_HSDSTTS_V2', '少年梓辛/Brayan', 'zh_male_shaonianzixin_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_shaonianzixin_uranus_bigtts.mp3', NULL, NULL, NULL, 15, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0016', 'TTS_HSDSTTS_V2', '猴哥', 'zh_male_sunwukong_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_sunwukong_uranus_bigtts.mp3', NULL, NULL, NULL, 16, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0017', 'TTS_HSDSTTS_V2', '魅力女友', 'zh_female_meilinvyou_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_meilinvyou_uranus_bigtts.mp3', NULL, NULL, NULL, 17, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0018', 'TTS_HSDSTTS_V2', 'Tim', 'en_male_tim_uranus_bigtts', '英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/en_male_tim_uranus_bigtts.mp3', NULL, NULL, NULL, 18, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0019', 'TTS_HSDSTTS_V2', 'Dacey', 'en_female_dacey_uranus_bigtts', '英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/en_female_dacey_uranus_bigtts.mp3', NULL, NULL, NULL, 19, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0020', 'TTS_HSDSTTS_V2', 'Stokie', 'en_female_stokie_uranus_bigtts', '英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/en_female_stokie_uranus_bigtts.mp3', NULL, NULL, NULL, 20, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0021', 'TTS_HSDSTTS_V2', '温暖阿虎/Alvin', 'zh_male_wennuanahu_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_wennuanahu_uranus_bigtts.mp3', NULL, NULL, NULL, 21, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0022', 'TTS_HSDSTTS_V2', '奶气萌娃', 'zh_male_naiqimengwa_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_naiqimengwa_uranus_bigtts.mp3', NULL, NULL, NULL, 22, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0023', 'TTS_HSDSTTS_V2', '婆婆', 'zh_female_popo_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_popo_uranus_bigtts.mp3', NULL, NULL, NULL, 23, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0024', 'TTS_HSDSTTS_V2', '开朗姐姐', 'zh_female_kailangjiejie_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_kailangjiejie_uranus_bigtts.mp3', NULL, NULL, NULL, 24, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0025', 'TTS_HSDSTTS_V2', '轻盈朵朵', 'saturn_zh_female_qingyingduoduo_cs_tob', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/ICL_zh_female_qingyingduoduo_cs_tob.mp3', NULL, NULL, NULL, 25, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0026', 'TTS_HSDSTTS_V2', '温婉珊珊', 'saturn_zh_female_wenwanshanshan_cs_tob', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/ICL_zh_female_wenwanshanshan_cs_tob.mp3', NULL, NULL, NULL, 26, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0027', 'TTS_HSDSTTS_V2', '霸气青叔', 'zh_male_baqiqingshu_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_baqiqingshu_uranus_bigtts.mp3', NULL, NULL, NULL, 27, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0028', 'TTS_HSDSTTS_V2', '悬疑解说', 'zh_male_xuanyijieshuo_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_xuanyijieshuo_uranus_bigtts.mp3', NULL, NULL, NULL, 28, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0029', 'TTS_HSDSTTS_V2', '古风少御', 'zh_female_gufengshaoyu_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_gufengshaoyu_uranus_bigtts.mp3', NULL, NULL, NULL, 29, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0030', 'TTS_HSDSTTS_V2', '唐僧', 'zh_male_tangseng_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_tangseng_uranus_bigtts.mp3', NULL, NULL, NULL, 30, NULL, NULL, NULL, NULL);
|
||||
@@ -0,0 +1,38 @@
|
||||
-- 智能体替换词文件表
|
||||
CREATE TABLE IF NOT EXISTS `ai_agent_correct_word_file` (
|
||||
`id` VARCHAR(32) NOT NULL,
|
||||
`file_name` VARCHAR(256) NOT NULL COMMENT '原始文件名',
|
||||
`word_count` INT NOT NULL DEFAULT 0 COMMENT '替换词数量',
|
||||
`content` TEXT COMMENT '文件原始内容',
|
||||
`creator` BIGINT DEFAULT NULL,
|
||||
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`updater` BIGINT DEFAULT NULL,
|
||||
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `idx_creator` (`creator`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='替换词文件';
|
||||
|
||||
-- 替换词词条表
|
||||
CREATE TABLE IF NOT EXISTS `ai_agent_correct_word_item` (
|
||||
`id` VARCHAR(32) NOT NULL,
|
||||
`file_id` VARCHAR(32) NOT NULL COMMENT '所属文件ID',
|
||||
`source_word` VARCHAR(128) NOT NULL COMMENT '原词',
|
||||
`target_word` VARCHAR(128) NOT NULL COMMENT '替换词',
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `idx_file_id` (`file_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='替换词词条';
|
||||
|
||||
-- 智能体替换词文件关联表
|
||||
CREATE TABLE IF NOT EXISTS `ai_agent_correct_word_mapping` (
|
||||
`id` VARCHAR(32) NOT NULL,
|
||||
`agent_id` VARCHAR(32) NOT NULL,
|
||||
`file_id` VARCHAR(32) NOT NULL,
|
||||
`creator` BIGINT DEFAULT NULL,
|
||||
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`updater` BIGINT DEFAULT NULL,
|
||||
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `uk_agent_file` (`agent_id`, `file_id`),
|
||||
INDEX `idx_agent_id` (`agent_id`),
|
||||
INDEX `idx_file_id` (`file_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='智能体替换词文件关联';
|
||||
@@ -0,0 +1,45 @@
|
||||
-- 修复豆包语音合成模型2.0 provider_code 重复问题,添加 ASR 2.0 支持
|
||||
|
||||
-- ==================== 豆包语音合成模型2.0 ====================
|
||||
-- 删除 TTS 2.0 供应器(不再需要单独的供应器)
|
||||
delete from `ai_model_provider` where id = 'SYSTEM_TTS_HSDSTTS_V2';
|
||||
|
||||
-- ==================== 豆包语音识别(流式) ====================
|
||||
-- 修正原有豆包语音识别(流式)供应器,移除cluster字段,添加resource_id字段
|
||||
UPDATE `ai_model_provider` SET `fields` = '[{"key":"appid","type":"string","label":"应用ID"},{"key":"access_token","type":"string","label":"访问令牌"},{"key":"boosting_table_name","type":"string","label":"热词文件名称"},{"key":"correct_table_name","type":"string","label":"替换词文件名称"},{"key":"output_dir","type":"string","label":"输出目录"},{"key":"end_window_size","type":"number","label":"静音判定时长(ms)"},{"key":"enable_multilingual","type":"boolean","label":"是否开启多语种识别模式"},{"key":"language","type":"string","label":"指定语言编码"},{"key":"resource_id","type":"string","label":"资源ID"}]' WHERE `id` = 'SYSTEM_ASR_DoubaoStreamASR';
|
||||
|
||||
-- 修正原有豆包语音识别(流式)配置,移除cluster字段,添加resource_id默认值
|
||||
UPDATE `ai_model_config` SET `config_json` = JSON_REMOVE(JSON_SET(`config_json`, '$.resource_id', 'volc.bigasr.sauc.duration'), '$.cluster') WHERE `id` = 'ASR_DoubaoStreamASR';
|
||||
|
||||
-- ==================== 豆包语音识别模型2.0 ====================
|
||||
|
||||
-- 插入豆包语音识别模型2.0配置
|
||||
delete from `ai_model_config` where id = 'ASR_DoubaoStreamASRV2';
|
||||
INSERT INTO `ai_model_config` VALUES ('ASR_DoubaoStreamASRV2', 'ASR', 'DoubaoStreamASRV2', '豆包语音识别模型2.0', 0, 1, '{
|
||||
"type": "doubao_stream",
|
||||
"appid": "",
|
||||
"access_token": "",
|
||||
"resource_id": "volc.seedasr.sauc.duration",
|
||||
"end_window_size": 200,
|
||||
"enable_multilingual": false,
|
||||
"language": "zh-CN",
|
||||
"output_dir": "tmp/"
|
||||
}', NULL, NULL, 6, NULL, NULL, NULL, NULL);
|
||||
|
||||
-- 豆包语音识别模型2.0配置说明文档
|
||||
UPDATE `ai_model_config` SET
|
||||
`doc_link` = 'https://www.volcengine.com/docs/6561/109979',
|
||||
`remark` = '豆包语音识别模型2.0配置说明(基于火山引擎seed-asr):
|
||||
1. 访问 https://www.volcengine.com/ 注册并开通火山引擎账号
|
||||
2. 访问 https://console.volcengine.com/speech/service/10038 开通豆包流式语音识别模型2.0
|
||||
3. 在页面底部获取appid和access_token
|
||||
4. 资源ID有两种:小时版(volc.seedasr.sauc.duration)和并发版(volc.seedasr.sauc.concurrent)
|
||||
- 小时版:固定为:volc.seedasr.sauc.duration(豆包语音识别模型2.0)
|
||||
- 并发版:固定为:volc.seedasr.sauc.concurrent(豆包语音识别模型2.0)
|
||||
|
||||
详细参数文档:https://www.volcengine.com/docs/6561/109979
|
||||
|
||||
注意:
|
||||
- 豆包语音识别模型2.0使用volc.seedasr.sauc.duration资源ID,与豆包语音识别(流式)(volc.bigasr.sauc.duration)不同
|
||||
- 语音识别模型2.0价格更为便宜,建议在高并发场景下使用并发版资源ID
|
||||
' WHERE `id` = 'ASR_DoubaoStreamASRV2';
|
||||
@@ -0,0 +1,57 @@
|
||||
-- 修改模型名称
|
||||
UPDATE `ai_model_config` SET `model_name` = '豆包语音识别2.0(流式)' WHERE `id` = 'ASR_DoubaoStreamASRV2';
|
||||
|
||||
UPDATE `ai_model_config` SET `model_name` = '豆包语音合成2.0(流式)' WHERE `id` = 'TTS_HSDSTTS_V2';
|
||||
|
||||
-- 调整模型音色
|
||||
delete from `ai_tts_voice` where tts_model_id = 'TTS_HSDSTTS_V2';
|
||||
|
||||
-- 通用场景 and 视频配音
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0001', 'TTS_HSDSTTS_V2', '湾湾小何', 'zh_female_xiaohe_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_xiaohe_uranus_bigtts.mp3', NULL, NULL, NULL, 1, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0002', 'TTS_HSDSTTS_V2', 'Vivi', 'zh_female_vv_uranus_bigtts', '普通话、日语、印尼语、墨西哥西班牙语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_vv_uranus_bigtts.wav', NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0003', 'TTS_HSDSTTS_V2', '可爱女生', 'saturn_zh_female_keainvsheng_tob', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/saturn_zh_female_keainvsheng_tob.wav', NULL, NULL, NULL, 3, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0004', 'TTS_HSDSTTS_V2', '调皮公主', 'saturn_zh_female_tiaopigongzhu_tob', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/saturn_zh_female_tiaopigongzhu_tob.wav', NULL, NULL, NULL, 4, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0005', 'TTS_HSDSTTS_V2', '阳光青年', 'zh_male_yangguangqingnian_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_yangguangqingnian_uranus_bigtts.mp3', NULL, NULL, NULL, 5, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0006', 'TTS_HSDSTTS_V2', '爽朗少年', 'saturn_zh_male_shuanglangshaonian_tob', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/saturn_zh_male_shuanglangshaonian_tob.wav', NULL, NULL, NULL, 6, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0007', 'TTS_HSDSTTS_V2', '爽朗少年', 'saturn_zh_male_tiancaitongzhuo_tob', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/saturn_zh_male_tiancaitongzhuo_tob.wav', NULL, NULL, NULL, 7, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0008', 'TTS_HSDSTTS_V2', '大壹', 'zh_male_dayi_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_dayi_saturn_bigtts.wav', NULL, NULL, NULL, 8, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0009', 'TTS_HSDSTTS_V2', '黑猫侦探社咪仔', 'zh_female_mizai_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_mizai_saturn_bigtts.wav', NULL, NULL, NULL, 9, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0010', 'TTS_HSDSTTS_V2', '鸡汤女', 'zh_female_jitangnv_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_jitangnv_saturn_bigtts.wav', NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0011', 'TTS_HSDSTTS_V2', '魅力女友', 'zh_female_meilinvyou_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_meilinvyou_saturn_bigtts.wav', NULL, NULL, NULL, 11, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0012', 'TTS_HSDSTTS_V2', '流畅女声', 'zh_female_liuchangnv_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/%E6%B5%81%E7%95%85%E5%A5%B3%E5%A3%B0.wav', NULL, NULL, NULL, 12, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0013', 'TTS_HSDSTTS_V2', '儒雅逸辰', 'zh_male_ruyayichen_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_ruyayichen_saturn_bigtts.wav', NULL, NULL, NULL, 13, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0014', 'TTS_HSDSTTS_V2', '云舟', 'zh_male_m191_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_m191_uranus_bigtts.mp3', NULL, NULL, NULL, 14, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0015', 'TTS_HSDSTTS_V2', '小天', 'zh_male_taocheng_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_taocheng_uranus_bigtts.mp3', NULL, NULL, NULL, 15, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0016', 'TTS_HSDSTTS_V2', '刘飞', 'zh_male_liufei_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_liufei_uranus_bigtts.mp3', NULL, NULL, NULL, 16, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0017', 'TTS_HSDSTTS_V2', '魅力苏菲', 'zh_female_sophie_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_sophie_uranus_bigtts.mp3', NULL, NULL, NULL, 17, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0018', 'TTS_HSDSTTS_V2', '清新女声', 'zh_female_qingxinnvsheng_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_qingxinnvsheng_uranus_bigtts.mp3', NULL, NULL, NULL, 18, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0019', 'TTS_HSDSTTS_V2', '知性灿灿', 'zh_female_cancan_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_cancan_uranus_bigtts.mp3', NULL, NULL, NULL, 19, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0020', 'TTS_HSDSTTS_V2', '撒娇学妹', 'zh_female_sajiaoxuemei_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_sajiaoxuemei_uranus_bigtts.mp3', NULL, NULL, NULL, 20, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0021', 'TTS_HSDSTTS_V2', '甜美小源', 'zh_female_tianmeixiaoyuan_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_tianmeixiaoyuan_uranus_bigtts.mp3', NULL, NULL, NULL, 21, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0022', 'TTS_HSDSTTS_V2', '甜美桃子', 'zh_female_tianmeitaozi_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_tianmeitaozi_uranus_bigtts.mp3', NULL, NULL, NULL, 22, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0023', 'TTS_HSDSTTS_V2', '邻家女孩', 'zh_female_linjianvhai_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_linjianvhai_uranus_bigtts.mp3', NULL, NULL, NULL, 23, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0024', 'TTS_HSDSTTS_V2', '爽快思思', 'zh_female_shuangkuaisisi_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_shuangkuaisisi_uranus_bigtts.mp3', NULL, NULL, NULL, 24, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0025', 'TTS_HSDSTTS_V2', '少年梓辛/Brayan', 'zh_male_shaonianzixin_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_shaonianzixin_uranus_bigtts.mp3', NULL, NULL, NULL, 25, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0026', 'TTS_HSDSTTS_V2', '温暖阿虎/Alvin', 'zh_male_wennuanahu_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_wennuanahu_uranus_bigtts.mp3', NULL, NULL, NULL, 26, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0027', 'TTS_HSDSTTS_V2', '奶气萌娃', 'zh_male_naiqimengwa_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_naiqimengwa_uranus_bigtts.mp3', NULL, NULL, NULL, 27, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0028', 'TTS_HSDSTTS_V2', '婆婆', 'zh_female_popo_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_popo_uranus_bigtts.mp3', NULL, NULL, NULL, 28, NULL, NULL, NULL, NULL);
|
||||
|
||||
-- 客服场景
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0029', 'TTS_HSDSTTS_V2', '轻盈朵朵', 'saturn_zh_female_qingyingduoduo_cs_tob', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/ICL_zh_female_qingyingduoduo_cs_tob.mp3', NULL, NULL, NULL, 29, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0030', 'TTS_HSDSTTS_V2', '温婉珊珊', 'saturn_zh_female_wenwanshanshan_cs_tob', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/ICL_zh_female_wenwanshanshan_cs_tob.mp3', NULL, NULL, NULL, 30, NULL, NULL, NULL, NULL);
|
||||
|
||||
-- 多语种
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0031', 'TTS_HSDSTTS_V2', 'Tim', 'en_male_tim_uranus_bigtts', '英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/en_male_tim_uranus_bigtts.mp3', NULL, NULL, NULL, 31, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0032', 'TTS_HSDSTTS_V2', 'Dacey', 'en_female_dacey_uranus_bigtts', '英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/en_female_dacey_uranus_bigtts.mp3', NULL, NULL, NULL, 32, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0033', 'TTS_HSDSTTS_V2', 'Stokie', 'en_female_stokie_uranus_bigtts', '英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/en_female_stokie_uranus_bigtts.mp3', NULL, NULL, NULL, 33, NULL, NULL, NULL, NULL);
|
||||
|
||||
-- 有声阅读
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0034', 'TTS_HSDSTTS_V2', '古风少御', 'zh_female_gufengshaoyu_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_gufengshaoyu_uranus_bigtts.mp3', NULL, NULL, NULL, 34, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0035', 'TTS_HSDSTTS_V2', '霸气青叔', 'zh_male_baqiqingshu_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_baqiqingshu_uranus_bigtts.mp3', NULL, NULL, NULL, 35, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0036', 'TTS_HSDSTTS_V2', '悬疑解说', 'zh_male_xuanyijieshuo_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_xuanyijieshuo_uranus_bigtts.mp3', NULL, NULL, NULL, 36, NULL, NULL, NULL, NULL);
|
||||
|
||||
-- 角色扮演
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0037', 'TTS_HSDSTTS_V2', '佩奇猪', 'zh_female_peiqi_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_female_peiqi_uranus_bigtts.mp3', NULL, NULL, NULL, 37, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0038', 'TTS_HSDSTTS_V2', '猴哥', 'zh_male_sunwukong_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_sunwukong_uranus_bigtts.mp3', NULL, NULL, NULL, 38, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0039', 'TTS_HSDSTTS_V2', '猪八戒', 'zh_male_zhubajie_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_zhubajie_uranus_bigtts.mp3', NULL, NULL, NULL, 39, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `ai_tts_voice` VALUES ('TTS_HSDSTTS_V2_0040', 'TTS_HSDSTTS_V2', '唐僧', 'zh_male_tangseng_uranus_bigtts', '普通话、英语', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/zh_male_tangseng_uranus_bigtts.mp3', NULL, NULL, NULL, 40, NULL, NULL, NULL, NULL);
|
||||
@@ -0,0 +1,5 @@
|
||||
-- 删除provider_code为ttson的供应器
|
||||
DELETE FROM `ai_model_provider` WHERE `provider_code` = 'ttson';
|
||||
|
||||
-- 删除model_code为ACGNTTS的配置
|
||||
DELETE FROM `ai_model_config` WHERE `model_code` = 'ACGNTTS';
|
||||
@@ -0,0 +1,6 @@
|
||||
-- 删除model_code为GizwitsTTS的配置
|
||||
DELETE FROM `ai_model_config` WHERE `model_code` = 'GizwitsTTS';
|
||||
|
||||
-- 删除关联的TTS音色记录
|
||||
DELETE FROM `ai_tts_voice` WHERE `tts_model_id` = 'TTS_GizwitsTTS';
|
||||
DELETE FROM `ai_tts_voice` WHERE `tts_model_id` = 'TTS_ACGNTTS';
|
||||
@@ -0,0 +1,8 @@
|
||||
-- 删除provider_code为linkerai的供应商配置
|
||||
DELETE FROM `ai_model_provider` WHERE `provider_code` = 'linkerai';
|
||||
|
||||
-- 删除model_code为LinkeraiTTS的模型配置
|
||||
DELETE FROM `ai_model_config` WHERE `model_code` = 'LinkeraiTTS';
|
||||
|
||||
-- 删除LinkeraiTTS关联的TTS音色记录
|
||||
DELETE FROM `ai_tts_voice` WHERE `tts_model_id` = 'TTS_LinkeraiTTS';
|
||||
@@ -571,3 +571,94 @@ databaseChangeLog:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202603111131.sql
|
||||
- changeSet:
|
||||
id: 202603231037
|
||||
author: rainv123
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202603231037.sql
|
||||
- changeSet:
|
||||
id: 202603311200
|
||||
author: cgd
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202603311200.sql
|
||||
- changeSet:
|
||||
id: 202604010930
|
||||
author: rainv123
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202604010930.sql
|
||||
- changeSet:
|
||||
id: 202604011035
|
||||
author: RanChen
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202604011035.sql
|
||||
- changeSet:
|
||||
id: 202604011545
|
||||
author: rainv123
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202604011545.sql
|
||||
- changeSet:
|
||||
id: 202604161357
|
||||
author: hrz
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202604161357.sql
|
||||
- changeSet:
|
||||
id: 202604201719
|
||||
author: RanChen
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202604201719.sql
|
||||
- changeSet:
|
||||
id: 202604211515
|
||||
author: rainv123
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202604211515.sql
|
||||
- changeSet:
|
||||
id: 202604211700
|
||||
author: RanChen
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202604211700.sql
|
||||
- changeSet:
|
||||
id: 202604300930
|
||||
author: RanChen
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202604300930.sql
|
||||
- changeSet:
|
||||
id: 202605071037
|
||||
author: fyb
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202605071037.sql
|
||||
- changeSet:
|
||||
id: 202605071120
|
||||
author: fyb
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202605071120.sql
|
||||
- changeSet:
|
||||
id: 202605081008
|
||||
author: fyb
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202605081008.sql
|
||||
|
||||
@@ -206,4 +206,8 @@
|
||||
10197=\u6807\u7B7E\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
|
||||
10198=\u6807\u7B7E\u4E0D\u5B58\u5728
|
||||
10199=\u89E3\u6790\u4E2D\u6587\u4EF6\u6682\u4E0D\u652F\u6301\u6B64\u64CD\u4F5C
|
||||
|
||||
10200=\u6CA1\u6709\u6743\u9650\u67E5\u770B\u8BE5\u667A\u80FD\u4F53\u7684MCP\u63A5\u5165\u70B9\u5730\u5740
|
||||
10201=\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u8FDB\u5165\u53C2\u6570\u7BA1\u7406\u914D\u7F6Emcp\u63A5\u5165\u70B9\u5730\u5740
|
||||
10202=\u6CA1\u6709\u6743\u9650\u67E5\u770B\u8BE5\u667A\u80FD\u4F53\u7684MCP\u5DE5\u5177\u5217\u8868
|
||||
10203=\u6587\u4EF6\u540D\u79F0\u5DF2\u5B58\u5728
|
||||
10204=\u6587\u4EF6\u5927\u5C0F\u8D85\u8FC71MB\u9650\u5236
|
||||
@@ -206,4 +206,8 @@
|
||||
10197=Tag-Name darf nicht leer sein
|
||||
10198=Tag nicht gefunden
|
||||
10199=Dateianalyse l\u00E4uft, dieser Vorgang wird nicht unterst\u00FCtzt
|
||||
|
||||
10200=Keine Berechtigung, die MCP-Endpunktadresse dieses Agenten anzuzeigen
|
||||
10201=Bitte kontaktieren Sie den Administrator, um die MCP-Endpunktadresse in der Parameterverwaltung zu konfigurieren
|
||||
10202=Keine Berechtigung, die MCP-Tool-Liste dieses Agenten anzuzeigen
|
||||
10203=Dateiname existiert bereits
|
||||
10204=Dateigr\u00f6\u00dfe \u00fcberschreitet 1MB Limit
|
||||
@@ -206,4 +206,9 @@
|
||||
10197=Tag name cannot be empty
|
||||
10198=Tag not found
|
||||
10199=Parsing in progress, this operation is not supported
|
||||
10200=No permission to view the MCP endpoint address of this agent
|
||||
10201=Please contact the administrator to configure the MCP endpoint address in parameter management
|
||||
10202=No permission to view the MCP tool list of this agent
|
||||
10203=File name already exists
|
||||
10204=File size exceeds 1MB limit
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
10015=Exclua primeiro os usu\u00E1rios do departamento
|
||||
10016=Falha na implanta\u00E7\u00E3o, sem fluxo
|
||||
10017=Diagrama incorreto, verifique
|
||||
10018=Falha na exporta\u00E7\u00E3o, ID do modelo � {0}
|
||||
10018=Falha na exporta\u00E7\u00E3o, ID do modelo � {0}
|
||||
|
||||
10019=Por favor, fa\u00E7a upload do arquivo
|
||||
10020=Token n\u00E3o pode ser vazio
|
||||
@@ -57,7 +57,7 @@
|
||||
10046=Erro ao salvar impress\u00E3o vocal, entre em contato com o administrador
|
||||
10047=Limite di\u00E1rio de envio atingido
|
||||
10048=Erro na inser\u00E7\u00E3o da senha antiga
|
||||
10049=LLM configurado n\u00E3o � openai ou Collama
|
||||
10049=LLM configurado n\u00E3o � openai ou Collama
|
||||
10050=Falha na gera\u00E7\u00E3o do token
|
||||
10051=Recurso n\u00E3o existe
|
||||
10052=Agente padr\u00E3o n\u00E3o encontrado
|
||||
@@ -72,12 +72,12 @@
|
||||
10061=C\u00F3digo de ativa\u00E7\u00E3o n\u00E3o pode ser vazio
|
||||
10062=C\u00F3digo de ativa\u00E7\u00E3o incorreto
|
||||
10063=Dispositivo j\u00E1 ativado
|
||||
10064=Este modelo � o modelo padr\u00E3o, configure primeiro outro modelo como padr\u00E3o
|
||||
10064=Este modelo � o modelo padr\u00E3o, configure primeiro outro modelo como padr\u00E3o
|
||||
10065=Falha ao adicionar dados
|
||||
10066=Falha ao modificar dados
|
||||
10067=C\u00F3digo de verifica\u00E7\u00E3o gr\u00E1fico incorreto
|
||||
10068=Registro por telefone n\u00E3o habilitado, fun\u00E7\u00E3o de c\u00F3digo de verifica\u00E7\u00E3o por SMS indispon\u00EDvel
|
||||
10069=Nome de usu\u00E1rio n\u00E3o � n\u00FAmero de telefone, por favor insira novamente
|
||||
10069=Nome de usu\u00E1rio n\u00E3o � n\u00FAmero de telefone, por favor insira novamente
|
||||
10070=Este n\u00FAmero de telefone j\u00E1 est\u00E1 registrado
|
||||
10071=N\u00FAmero de telefone inserido n\u00E3o est\u00E1 registrado
|
||||
10072=Registro de usu\u00E1rio comum n\u00E3o permitido atualmente
|
||||
@@ -90,7 +90,7 @@
|
||||
10079=Par\u00E2metros de sele\u00E7\u00E3o incompat\u00EDveis entre LLM e reconhecimento de inten\u00E7\u00E3o Intent
|
||||
10080=A pessoa ({0}) correspondente a esta impress\u00E3o vocal j\u00E1 est\u00E1 registrada, escolha outra voz para registrar
|
||||
10081=Erro ao excluir impress\u00E3o vocal
|
||||
10082=Esta modifica\u00E7\u00E3o n\u00E3o � permitida, esta voz j\u00E1 est\u00E1 registrada como impress\u00E3o vocal ({0})
|
||||
10082=Esta modifica\u00E7\u00E3o n\u00E3o � permitida, esta voz j\u00E1 est\u00E1 registrada como impress\u00E3o vocal ({0})
|
||||
10083=Erro ao modificar impress\u00E3o vocal, entre em contato com o administrador
|
||||
10084=Erro no endere\u00E7o da interface de impress\u00E3o vocal, acesse o gerenciamento de par\u00E2metros para modificar o endere\u00E7o
|
||||
10085=Dados de \u00E1udio n\u00E3o pertencem a este agente
|
||||
@@ -205,4 +205,9 @@
|
||||
10196=Nome da etiqueta j\u00E1 existe
|
||||
10197=Nome da etiqueta n\u00E3o pode ser vazio
|
||||
10198=Etiqueta n\u00E3o existe
|
||||
10199=Esta opera\u00E7\u00E3o n\u00E3o � suportada na an\u00E1lise de arquivos chineses
|
||||
10199=Esta opera\u00E7\u00E3o n\u00E3o � suportada na an\u00E1lise de arquivos chineses
|
||||
10200=Sem permiss\u00e3o para visualizar o endere\u00e7o do endpoint MCP deste agente
|
||||
10201=Por favor, contate o administrador para configurar o endere\u00e7o do endpoint MCP no gerenciamento de par\u00e2metros
|
||||
10202=Sem permiss\u00e3o para visualizar a lista de ferramentas MCP deste agente
|
||||
10203=Nome do arquivo j\u00E1 existe
|
||||
10204=O tamanho do arquivo excede o limite de 1MB
|
||||
@@ -206,4 +206,8 @@
|
||||
10197=T\u00EAn th\u1EB9\uFFFD kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng
|
||||
10198=Kh\u00F4ng t\u00ECm th\u1EA5y th\u1EB9\uFFFD
|
||||
10199=T\u1EC7p \u0111ang \u0111\u01B0\u1EE3c ph\u00E2n t\u00EDch, thao t\u00E1c n\u00E0y kh\u00F4ng \u0111\u01B0\u1EE3c h\u1ED7 tr\u1EE3
|
||||
|
||||
10200=Kh\u00f4ng c\u00f3 quy\u1ec1n xem \u0111\u1ecba ch\u1ec9 \u0111i\u1ec3m cu\u1ed1i MCP c\u1ee7a \u0111\u1ea1i l\u00fd n\u00e0y
|
||||
10201=Vui l\u00f2ng li\u00ean h\u1ec7 qu\u1ea3n tr\u1ecb vi\u00ean \u0111\u1ec3 c\u1ea5u h\u00ecnh \u0111\u1ecba ch\u1ec9 \u0111i\u1ec3m cu\u1ed1i MCP trong qu\u1ea3n l\u00fd tham s\u1ed1
|
||||
10202=Kh\u00f4ng c\u00f3 quy\u1ec1n xem danh s\u00e1ch c\u00f4ng c\u1ee5 MCP c\u1ee7a \u0111\u1ea1i l\u00fd n\u00e0y
|
||||
10203=T\u00EAn t\u1EC7p \u0111\u00E3 t\u1ED3n t\u1EA1i
|
||||
10204=K\u00EDch th\u01b0\u1edbc t\u1ec7p v\u01b0\u1ee3t qu\u00e1 1MB
|
||||
@@ -206,3 +206,8 @@
|
||||
10197=\u6807\u7B7E\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
|
||||
10198=\u6807\u7B7E\u4E0D\u5B58\u5728
|
||||
10199=\u89E3\u6790\u4E2D\u6587\u4EF6\u6682\u4E0D\u652F\u6301\u6B64\u64CD\u4F5C
|
||||
10200=\u6CA1\u6709\u6743\u9650\u67E5\u770B\u8BE5\u667A\u80FD\u4F53\u7684MCP\u63A5\u5165\u70B9\u5730\u5740
|
||||
10201=\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u8FDB\u5165\u53C2\u6570\u7BA1\u7406\u914D\u7F6Emcp\u63A5\u5165\u70B9\u5730\u5740
|
||||
10202=\u6CA1\u6709\u6743\u9650\u67E5\u770B\u8BE5\u667A\u80FD\u4F53\u7684MCP\u5DE5\u5177\u5217\u8868
|
||||
10203=\u6587\u4EF6\u540D\u79F0\u5DF2\u5B58\u5728
|
||||
10204=\u6587\u4EF6\u5927\u5C0F\u8D85\u8FC71MB\u9650\u5236
|
||||
@@ -206,4 +206,8 @@
|
||||
10197=\u6A19\u7C64\u540D\u7A31\u4E0D\u80FD\u4E3A\u7A7A
|
||||
10198=\u6A19\u7C64\u4E0D\u5B58\u5728
|
||||
10199=\u89E3\u6790\u4E2D\u6587\u4EF6\u66AB\u4E0D\u652F\u6301\u6B64\u64CD\u4F5C
|
||||
|
||||
10200=\u6C92\u6709\u6B0A\u9650\u67E5\u770B\u8A72\u667A\u80FD\u9AD4\u7684MCP\u63A5\u5165\u9EDE\u5730\u5740
|
||||
10201=\u8ACB\u806F\u7E6B\u7BA1\u7406\u54E1\u9032\u5165\u53C3\u6578\u7BA1\u7406\u914D\u7F6Emcp\u63A5\u5165\u9EDE\u5730\u5740
|
||||
10202=\u6C92\u6709\u6B0A\u9650\u67E5\u770B\u8A72\u667A\u80FD\u9AD4\u7684MCP\u5DE5\u5177\u5217\u8868
|
||||
10203=\u6A94\u6848\u540D\u7A31\u5DF2\u5B58\u5728
|
||||
10204=\u6A94\u6848\u5927\u5C0F\u8D85\u904E1MB\u9650\u5236
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="xiaozhi.modules.agent.dao.AgentCorrectWordMappingDao">
|
||||
|
||||
<delete id="deleteByAgentId">
|
||||
DELETE FROM ai_agent_correct_word_mapping WHERE agent_id = #{agentId}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteByFileId">
|
||||
DELETE FROM ai_agent_correct_word_mapping WHERE file_id = #{fileId}
|
||||
</delete>
|
||||
|
||||
<insert id="batchInsertMapping" parameterType="java.util.List">
|
||||
INSERT INTO ai_agent_correct_word_mapping (id, agent_id, file_id, creator, created_at, updater, updated_at)
|
||||
VALUES
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.id}, #{item.agentId}, #{item.fileId}, #{item.creator}, #{item.createdAt}, #{item.updater}, #{item.updatedAt})
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<select id="selectByAgentId" resultType="xiaozhi.modules.agent.entity.AgentCorrectWordMappingEntity">
|
||||
SELECT id, agent_id, file_id, creator, created_at, updater, updated_at
|
||||
FROM ai_agent_correct_word_mapping
|
||||
WHERE agent_id = #{agentId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -14,6 +14,8 @@
|
||||
<result column="asrModelId" property="asrModelId"/>
|
||||
<result column="vadModelId" property="vadModelId"/>
|
||||
<result column="llmModelId" property="llmModelId"/>
|
||||
<result column="slmModelId" property="slmModelId"/>
|
||||
<result column="vllmModelId" property="vllmModelId"/>
|
||||
<result column="ttsModelId" property="ttsModelId"/>
|
||||
<result column="ttsVoiceId" property="ttsVoiceId"/>
|
||||
<result column="ttsLanguage" property="ttsLanguage"/>
|
||||
@@ -46,6 +48,7 @@
|
||||
a.asr_model_id AS asrModelId,
|
||||
a.vad_model_id AS vadModelId,
|
||||
a.llm_model_id AS llmModelId,
|
||||
a.slm_model_id AS slmModelId,
|
||||
a.vllm_model_id AS vllmModelId,
|
||||
a.tts_model_id AS ttsModelId,
|
||||
a.tts_voice_id AS ttsVoiceId,
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="xiaozhi.modules.correctword.dao.CorrectWordItemDao">
|
||||
|
||||
<insert id="batchInsert" parameterType="java.util.List">
|
||||
INSERT INTO ai_agent_correct_word_item (id, file_id, source_word, target_word)
|
||||
VALUES
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.id}, #{item.fileId}, #{item.sourceWord}, #{item.targetWord})
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
</mapper>
|
||||
@@ -131,6 +131,7 @@ export function getMcpAddress(agentId: string) {
|
||||
meta: {
|
||||
ignoreAuth: false,
|
||||
toast: false,
|
||||
isExposeError: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ export interface AgentDetail {
|
||||
asrModelId: string
|
||||
vadModelId: string
|
||||
llmModelId: string
|
||||
slmModelId: string
|
||||
vllmModelId: string
|
||||
ttsModelId: string
|
||||
ttsVoiceId: string
|
||||
|
||||
@@ -34,6 +34,9 @@ export function getChatHistory(agentId: string, sessionId: string) {
|
||||
ignoreAuth: false,
|
||||
toast: false,
|
||||
},
|
||||
cacheFor: {
|
||||
expire: -1,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ export interface ChatSession {
|
||||
sessionId: string
|
||||
createdAt: string
|
||||
chatCount: number
|
||||
title: string
|
||||
}
|
||||
|
||||
// 聊天会话列表响应
|
||||
@@ -14,7 +15,7 @@ export interface ChatSessionsResponse {
|
||||
// 聊天消息
|
||||
export interface ChatMessage {
|
||||
createdAt: string
|
||||
chatType: 1 | 2 // 1是用户,2是AI
|
||||
chatType: 1 | 2 | 3 // 1是用户,2是AI,3是参数说明
|
||||
content: string
|
||||
audioId: string | null
|
||||
macAddress: string
|
||||
|
||||
@@ -60,3 +60,13 @@ export function updateVoicePrint(data: VoicePrint) {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 获取音频下载ID
|
||||
export function getAudioDownloadId(audioId: string) {
|
||||
return http.Post<string>(`/agent/audio/${audioId}`, {}, {
|
||||
meta: {
|
||||
ignoreAuth: false,
|
||||
toast: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { uniappRequestAdapter } from '@alova/adapter-uniapp'
|
||||
import type { IResponse } from './types'
|
||||
import type { Language } from '@/store/lang'
|
||||
import AdapterUniapp from '@alova/adapter-uniapp'
|
||||
import { createAlova } from 'alova'
|
||||
import { createServerTokenAuthentication } from 'alova/client'
|
||||
@@ -8,6 +9,16 @@ import { getEnvBaseUrl } from '@/utils'
|
||||
import { toast } from '@/utils/toast'
|
||||
import { ContentTypeEnum, ResultEnum, ShowMessage } from './enum'
|
||||
|
||||
// 语言映射, 用于设置 Accept-language 头
|
||||
const langMap: Record<Language, string> = {
|
||||
zh_CN: 'zh-CN',
|
||||
en: 'en-US',
|
||||
zh_TW: 'zh-TW',
|
||||
de: 'de',
|
||||
vi: 'vi',
|
||||
pt_BR: 'pt-BR',
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建请求实例
|
||||
*/
|
||||
@@ -51,6 +62,7 @@ const alovaInstance = createAlova({
|
||||
// 检查混合内容错误(HTTPS页面请求HTTP接口)
|
||||
const currentProtocol = typeof window !== 'undefined' && window.location.protocol
|
||||
const requestProtocol = method.baseURL?.split(':')[0]
|
||||
const currentLang = langMap[uni.getStorageSync('app_language') as Language || 'zh_CN']
|
||||
if (currentProtocol === 'https:' && requestProtocol === 'http') {
|
||||
const errorMessage = '无法配置http协议地址,请检查接口地址'
|
||||
throw new Error(errorMessage)
|
||||
@@ -60,6 +72,7 @@ const alovaInstance = createAlova({
|
||||
method.config.headers = {
|
||||
'Content-Type': ContentTypeEnum.JSON,
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
'Accept-language': currentLang,
|
||||
...method.config.headers,
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ export default {
|
||||
'login.navigationTitle': 'Anmelden',
|
||||
'login.fetchConfigError': 'Konfiguration konnte nicht abgerufen werden:',
|
||||
'login.selectLanguage': 'Sprache auswählen',
|
||||
'login.selectLanguageTip': 'Vi',
|
||||
'login.selectLanguageTip': 'De',
|
||||
'login.welcomeBack': 'Willkommen zurück',
|
||||
'login.pleaseLogin': 'Bitte melden Sie sich an',
|
||||
'login.enterUsername': 'Bitte Benutzernamen eingeben',
|
||||
@@ -69,7 +69,7 @@ export default {
|
||||
'home.createFirstAgent': 'Klicken Sie auf die + Schaltfläche unten rechts, um Ihren ersten Agenten zu erstellen',
|
||||
'home.dialogTitle': 'Agent erstellen',
|
||||
'home.inputPlaceholder': 'z.B. Kundenservice-Assistent, Sprachassistent, Wissens-F&A',
|
||||
'home.createError': 'Bitte Agenten-Namen eingeben',
|
||||
'home.createError': 'Der Name muss zwischen 1 und 64 Zeichen lang sein.',
|
||||
'home.createNow': 'Jetzt erstellen',
|
||||
'home.justNow': 'Gerade eben',
|
||||
'home.minutesAgo': 'Minuten her',
|
||||
@@ -85,7 +85,7 @@ export default {
|
||||
'agent.chatHistory': 'Chat-Verlauf',
|
||||
'agent.voiceprintManagement': 'Stimmabdruckverwaltung',
|
||||
'agent.editTitle': 'Agent bearbeiten',
|
||||
'agent.toolsTitle': 'Funktionen bearbeiten',
|
||||
'agent.toolsTitle': 'Bearbeiten',
|
||||
'agent.voiceActivityDetection': 'Sprachaktivitätserkennung',
|
||||
'agent.speechRecognition': 'Spracherkennung',
|
||||
'agent.largeLanguageModel': 'Großes Sprachmodell',
|
||||
@@ -108,7 +108,8 @@ export default {
|
||||
'agent.modelConfig': 'Modellkonfiguration',
|
||||
'agent.vad': 'Sprachaktivitätserkennung',
|
||||
'agent.asr': 'Spracherkennung',
|
||||
'agent.llm': 'Großes Sprachmodell',
|
||||
'agent.llm': 'Hauptsprachenmodell',
|
||||
'agent.slm': 'Kleine Parametermodelle',
|
||||
'agent.vllm': 'Vision-Sprachmodell',
|
||||
'agent.intent': 'Absichtserkennung',
|
||||
'agent.memory': 'Speicher',
|
||||
@@ -116,7 +117,7 @@ export default {
|
||||
'agent.tts': 'Text-zu-Sprache',
|
||||
'agent.voiceprint': 'Agenten-Stimme',
|
||||
'agent.plugins': 'Plugins',
|
||||
'agent.editFunctions': 'Funktionen bearbeiten',
|
||||
'agent.editFunctions': 'Bearbeiten',
|
||||
'agent.historyMemory': 'Verlaufsspeicher',
|
||||
'agent.memoryContent': 'Speicherinhalt',
|
||||
'agent.saving': 'Wird gespeichert...',
|
||||
@@ -371,7 +372,7 @@ export default {
|
||||
'agent.tools.mcpAccessPoint': 'MCP-Zugangspunkt',
|
||||
'agent.tools.copy': 'Kopieren',
|
||||
'agent.tools.noTools': 'Keine Werkzeuge verfügbar',
|
||||
'agent.tools.parameterConfig': 'Parameterkonfiguration',
|
||||
'agent.tools.parameterConfig': 'Konfig',
|
||||
'agent.tools.noParamsNeeded': 'Keine Parameter benötigt',
|
||||
'agent.tools.pleaseInput': 'Bitte eingeben',
|
||||
'agent.tools.inputOneItemPerLine': 'Ein Element pro Zeile eingeben',
|
||||
@@ -471,6 +472,7 @@ export default {
|
||||
'deviceConfig.reCheck': 'Erneut prüfen',
|
||||
'deviceConfig.connectedXiaozhiHotspot': 'Mit xiaozhi Hotspot verbunden',
|
||||
'deviceConfig.wifiNetwork': 'WiFi-Netzwerk',
|
||||
'deviceConfig.wifiPassword': 'WiFi-Passwort',
|
||||
'deviceConfig.scanning': 'Wird gescannt',
|
||||
'deviceConfig.cancel': 'Abbrechen',
|
||||
'deviceConfig.clickRefreshScan': 'Bitte Scan aktualisieren klicken',
|
||||
@@ -484,6 +486,7 @@ export default {
|
||||
'deviceConfig.wifiConfigFailed': 'WiFi-Konfiguration fehlgeschlagen',
|
||||
'deviceConfig.pleaseCheckNetworkConnection': 'Bitte Netzwerkverbindung prüfen',
|
||||
'deviceConfig.startWifiConfigButton': 'Konfiguration starten',
|
||||
'deviceConfig.configuring': 'Wird konfiguriert...',
|
||||
'deviceConfig.wifiConfigInstructions': 'WiFi-Konfigurationsanleitung',
|
||||
'deviceConfig.phoneConnectXiaozhiHotspot': 'Telefon mit xiaozhi Hotspot verbinden',
|
||||
'deviceConfig.selectTargetWifiNetwork': 'Ziel-WiFi-Netzwerk auswählen',
|
||||
@@ -492,4 +495,9 @@ export default {
|
||||
'deviceConfig.afterConfigSuccessDeviceWillRestart': 'Nach erfolgreicher Konfiguration startet Gerät automatisch neu',
|
||||
'deviceConfig.audioPlaybackError': 'Audio-Wiedergabe-Fehler',
|
||||
'deviceConfig.playbackFailed': 'Wiedergabe fehlgeschlagen',
|
||||
|
||||
// Voiceprint page
|
||||
'voiceprint.audioNotExist': 'Audio existiert nicht',
|
||||
'voiceprint.getAudioFailed': 'Audio konnte nicht abgerufen werden',
|
||||
'voiceprint.audioPlayFailed': 'Audio-Wiedergabe fehlgeschlagen',
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export default {
|
||||
'login.navigationTitle': 'Login',
|
||||
'login.fetchConfigError': 'Failed to fetch configuration:',
|
||||
'login.selectLanguage': 'Select Language',
|
||||
'login.selectLanguageTip': '中文',
|
||||
'login.selectLanguageTip': 'En',
|
||||
'login.welcomeBack': 'Welcome Back',
|
||||
'login.pleaseLogin': 'Please log in to your account',
|
||||
'login.enterUsername': 'Please enter username',
|
||||
@@ -69,7 +69,7 @@ export default {
|
||||
'home.createFirstAgent': 'Click the + button in the lower right corner to create your first agent',
|
||||
'home.dialogTitle': 'Create Agent',
|
||||
'home.inputPlaceholder': 'e.g. Customer Service Assistant, Voice Assistant, Knowledge Q&A',
|
||||
'home.createError': 'Please input agent name',
|
||||
'home.createError': 'The name length must be between 1 and 64 characters',
|
||||
'home.createNow': 'Create Now',
|
||||
'home.justNow': 'Just now',
|
||||
'home.minutesAgo': 'minutes ago',
|
||||
@@ -108,7 +108,8 @@ export default {
|
||||
'agent.modelConfig': 'Model Configuration',
|
||||
'agent.vad': 'Voice Activity Detection',
|
||||
'agent.asr': 'Speech Recognition',
|
||||
'agent.llm': 'Large Language Model',
|
||||
'agent.llm': 'Main language model',
|
||||
'agent.slm': 'Small parameter model',
|
||||
'agent.vllm': 'Vision Language Model',
|
||||
'agent.intent': 'Intent Recognition',
|
||||
'agent.memory': 'Memory',
|
||||
@@ -371,7 +372,7 @@ export default {
|
||||
'agent.tools.mcpAccessPoint': 'MCP Access Point',
|
||||
'agent.tools.copy': 'Copy',
|
||||
'agent.tools.noTools': 'No tools available',
|
||||
'agent.tools.parameterConfig': 'Parameter Configuration',
|
||||
'agent.tools.parameterConfig': 'Param Config',
|
||||
'agent.tools.noParamsNeeded': 'No parameters needed',
|
||||
'agent.tools.pleaseInput': 'Please input',
|
||||
'agent.tools.inputOneItemPerLine': 'Input one item per line',
|
||||
@@ -471,6 +472,7 @@ export default {
|
||||
'deviceConfig.reCheck': 'Re-check',
|
||||
'deviceConfig.connectedXiaozhiHotspot': 'Connected to xiaozhi hotspot',
|
||||
'deviceConfig.wifiNetwork': 'WiFi Network',
|
||||
'deviceConfig.wifiPassword': 'WiFi Password',
|
||||
'deviceConfig.scanning': 'Scanning',
|
||||
'deviceConfig.cancel': 'Cancel',
|
||||
'deviceConfig.clickRefreshScan': 'Please click Refresh Scan',
|
||||
@@ -484,6 +486,7 @@ export default {
|
||||
'deviceConfig.wifiConfigFailed': 'WiFi configuration failed',
|
||||
'deviceConfig.pleaseCheckNetworkConnection': 'Please check network connection',
|
||||
'deviceConfig.startWifiConfigButton': 'Start Configuration',
|
||||
'deviceConfig.configuring': 'Configuring...',
|
||||
'deviceConfig.wifiConfigInstructions': 'WiFi Configuration Instructions',
|
||||
'deviceConfig.phoneConnectXiaozhiHotspot': 'Phone connect to xiaozhi hotspot',
|
||||
'deviceConfig.selectTargetWifiNetwork': 'Select target WiFi network',
|
||||
@@ -492,4 +495,9 @@ export default {
|
||||
'deviceConfig.afterConfigSuccessDeviceWillRestart': 'After successful configuration, device will automatically restart',
|
||||
'deviceConfig.audioPlaybackError': 'Audio playback error',
|
||||
'deviceConfig.playbackFailed': 'Playback failed',
|
||||
|
||||
// Voiceprint page
|
||||
'voiceprint.audioNotExist': 'Audio does not exist',
|
||||
'voiceprint.getAudioFailed': 'Failed to get audio',
|
||||
'voiceprint.audioPlayFailed': 'Audio playback failed',
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user