feat: AI 场景路由、ASR 服务及前后端全链路同步
- 新增 AI 场景路由控制器和管理接口 - 新增 ASR 语音识别服务及前后端集成 - 同步 AI Runtime 客户端到 Web/小程序/Life-Script - 完善 AI 配置测试修复和管理后台路由配置 - 新增数据库迁移脚本 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,878 @@
|
||||
# Dify 平台接口文档
|
||||
|
||||
> 内部接口文档:本文包含可用 API Key,请勿提交到公开仓库或外部分享。
|
||||
|
||||
## 1. 基本信息
|
||||
|
||||
| 项 | 值 |
|
||||
| --- | --- |
|
||||
| 服务器端地址 | `http://49.232.138.53/v1` |
|
||||
| 鉴权方式 | `Authorization: Bearer {API_KEY}` |
|
||||
| API Key | `app-MqQOx09gCu9zzlKMpeLqHQHv` |
|
||||
| 适用应用 | 短片小说生成、剧本生成 |
|
||||
|
||||
## 2. 通用鉴权
|
||||
|
||||
Service API 使用 API-Key 进行鉴权。所有 API 请求都应在 `Authorization` HTTP Header 中携带 API Key。
|
||||
|
||||
```http
|
||||
Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv
|
||||
```
|
||||
|
||||
建议只在后端服务中保存和调用 API Key,避免将 Key 暴露到小程序、Web 前端或其它客户端。
|
||||
|
||||
## 3. 接口总览
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `POST` | `/chat-messages` | 发送对话消息 |
|
||||
| `POST` | `/files/upload` | 上传文件 |
|
||||
| `GET` | `/files/:file_id/preview` | 文件预览 |
|
||||
| `POST` | `/chat-messages/:task_id/stop` | 停止响应 |
|
||||
| `POST` | `/messages/:message_id/feedbacks` | 消息反馈 |
|
||||
| `GET` | `/app/feedbacks` | 获取 App 的消息点赞和反馈 |
|
||||
| `GET` | `/messages/{message_id}/suggested` | 获取下一轮建议问题列表 |
|
||||
| `GET` | `/messages` | 获取会话历史消息 |
|
||||
| `GET` | `/conversations` | 获取会话列表 |
|
||||
| `DELETE` | `/conversations/:conversation_id` | 删除会话 |
|
||||
| `POST` | `/conversations/:conversation_id/name` | 会话重命名 |
|
||||
| `GET` | `/conversations/:conversation_id/variables` | 获取对话变量 |
|
||||
| `PUT` | `/conversations/:conversation_id/variables/:variable_id` | 更新对话变量 |
|
||||
| `POST` | `/audio-to-text` | 语音转文字 |
|
||||
| `POST` | `/text-to-audio` | 文字转语音 |
|
||||
| `GET` | `/info` | 获取应用基本信息 |
|
||||
| `GET` | `/parameters` | 获取应用参数 |
|
||||
| `GET` | `/meta` | 获取应用 Meta 信息 |
|
||||
| `GET` | `/site` | 获取应用 WebApp 设置 |
|
||||
| `GET` | `/apps/annotations` | 获取标注列表 |
|
||||
| `POST` | `/apps/annotations` | 创建标注 |
|
||||
| `PUT` | `/apps/annotations/{annotation_id}` | 更新标注 |
|
||||
| `DELETE` | `/apps/annotations/{annotation_id}` | 删除标注 |
|
||||
| `POST` | `/apps/annotation-reply/{action}` | 标注回复初始设置 |
|
||||
| `GET` | `/apps/annotation-reply/{action}/status/{job_id}` | 查询标注回复初始设置任务状态 |
|
||||
|
||||
## 4. 应用说明
|
||||
|
||||
### 4.1 短片小说生成
|
||||
|
||||
短片小说生成使用 Dify 对话型应用 API。接口路径、鉴权方式、请求参数和响应结构与本文后续章节一致。
|
||||
|
||||
### 4.2 剧本生成
|
||||
|
||||
剧本生成使用 Dify 工作流编排对话型应用 API。对话应用支持会话持久化,可将之前的聊天记录作为上下文继续回答,适用于聊天、客服 AI、脚本生成等场景。
|
||||
|
||||
## 5. 对话接口
|
||||
|
||||
### 5.1 发送对话消息
|
||||
|
||||
`POST /chat-messages`
|
||||
|
||||
创建会话消息。
|
||||
|
||||
#### 请求体参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `query` | `string` | 是 | 用户输入或提问内容。 |
|
||||
| `inputs` | `object` | 否 | App 定义的变量值,默认为 `{}`。如果变量是文件类型,请按 `files` 中的文件结构传入。 |
|
||||
| `response_mode` | `string` | 是 | 响应模式:`streaming` 为流式模式,`blocking` 为阻塞模式。推荐使用 `streaming`。 |
|
||||
| `user` | `string` | 是 | 终端用户标识。由开发者定义,需保证在应用内唯一。 |
|
||||
| `conversation_id` | `string` | 否 | 会话 ID。继续历史会话时传入之前响应中的 `conversation_id`。 |
|
||||
| `files` | `array<object>` | 否 | 文件列表。适用于模型支持 Vision/Video 能力时的图文、多模态理解。 |
|
||||
| `auto_generate_name` | `bool` | 否 | 是否自动生成会话标题,默认 `true`。 |
|
||||
| `workflow_id` | `string` | 否 | 工作流 ID。用于指定特定已发布版本,不传则使用默认已发布版本。 |
|
||||
| `trace_id` | `string` | 否 | 链路追踪 ID。也可通过 Header `X-Trace-Id` 或查询参数 `trace_id` 传递。优先级:Header > Query > Body。 |
|
||||
|
||||
#### `files` 参数结构
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `type` | `string` | 文件类型,支持 `document`、`image`、`audio`、`video`、`custom`。 |
|
||||
| `transfer_method` | `string` | 文件传递方式:`remote_url` 或 `local_file`。 |
|
||||
| `url` | `string` | 文件地址。仅当 `transfer_method` 为 `remote_url` 时使用。 |
|
||||
| `upload_file_id` | `string` | 上传文件 ID。仅当 `transfer_method` 为 `local_file` 时使用。 |
|
||||
|
||||
文件类型支持范围:
|
||||
|
||||
| 类型 | 支持格式 |
|
||||
| --- | --- |
|
||||
| `document` | `TXT`、`MD`、`MARKDOWN`、`MDX`、`PDF`、`HTML`、`XLSX`、`XLS`、`VTT`、`PROPERTIES`、`DOC`、`DOCX`、`CSV`、`EML`、`MSG`、`PPTX`、`PPT`、`XML`、`EPUB` |
|
||||
| `image` | `JPG`、`JPEG`、`PNG`、`GIF`、`WEBP`、`SVG` |
|
||||
| `audio` | `MP3`、`M4A`、`WAV`、`WEBM`、`MPGA` |
|
||||
| `video` | `MP4`、`MOV`、`MPEG`、`WEBM` |
|
||||
| `custom` | 其它文件类型 |
|
||||
|
||||
#### 响应说明
|
||||
|
||||
当 `response_mode` 为 `blocking` 时,返回 `ChatCompletionResponse`。当 `response_mode` 为 `streaming` 时,返回 `ChunkChatCompletionResponse` 流式序列。
|
||||
|
||||
##### ChatCompletionResponse
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `event` | `string` | 事件类型,固定为 `message`。 |
|
||||
| `task_id` | `string` | 任务 ID,可用于停止响应接口。 |
|
||||
| `id` | `string` | 唯一 ID。 |
|
||||
| `message_id` | `string` | 消息唯一 ID。 |
|
||||
| `conversation_id` | `string` | 会话 ID。 |
|
||||
| `mode` | `string` | App 模式,固定为 `chat`。 |
|
||||
| `answer` | `string` | 完整回复内容。 |
|
||||
| `metadata` | `object` | 元数据。 |
|
||||
| `usage` | `Usage` | 模型用量信息。 |
|
||||
| `retriever_resources` | `array<RetrieverResource>` | 引用和归属分段列表。 |
|
||||
| `created_at` | `int` | 消息创建时间戳,例如 `1705395332`。 |
|
||||
|
||||
##### ChunkChatCompletionResponse
|
||||
|
||||
流式响应的 `Content-Type` 为 `text/event-stream`。每个流式块以 `data:` 开头,块之间使用两个换行符分隔。
|
||||
|
||||
常见事件:
|
||||
|
||||
| 事件 | 说明 |
|
||||
| --- | --- |
|
||||
| `message` | LLM 文本块事件。 |
|
||||
| `message_file` | 文件事件,表示有新文件需要展示。 |
|
||||
| `message_end` | 消息结束事件,收到后表示流式返回结束。 |
|
||||
| `tts_message` | TTS 音频流事件。 |
|
||||
| `tts_message_end` | TTS 音频流结束事件。 |
|
||||
| `message_replace` | 消息内容替换事件,通常用于内容审查命中后的预设回复。 |
|
||||
| `workflow_started` | 工作流开始执行。 |
|
||||
| `node_started` | 工作流节点开始执行。 |
|
||||
| `node_finished` | 工作流节点执行结束。 |
|
||||
| `workflow_finished` | 工作流执行结束。 |
|
||||
| `error` | 流式输出过程中出现异常。 |
|
||||
| `ping` | 每 10 秒一次的连接保活事件。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl -X POST 'http://49.232.138.53/v1/chat-messages' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"inputs": {},
|
||||
"query": "What are the specs of the iPhone 13 Pro Max?",
|
||||
"response_mode": "streaming",
|
||||
"conversation_id": "",
|
||||
"user": "abc-123",
|
||||
"files": [
|
||||
{
|
||||
"type": "image",
|
||||
"transfer_method": "remote_url",
|
||||
"url": "https://cloud.dify.ai/logo/logo-site.png"
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
#### 阻塞模式响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"event": "message",
|
||||
"task_id": "c3800678-a077-43df-a102-53f23ed20b88",
|
||||
"id": "9da23599-e713-473b-982c-4328d4f5c78a",
|
||||
"message_id": "9da23599-e713-473b-982c-4328d4f5c78a",
|
||||
"conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2",
|
||||
"mode": "chat",
|
||||
"answer": "iPhone 13 Pro Max specs are listed here:...",
|
||||
"metadata": {
|
||||
"usage": {
|
||||
"prompt_tokens": 1033,
|
||||
"completion_tokens": 128,
|
||||
"total_tokens": 1161,
|
||||
"total_price": "0.0012890",
|
||||
"currency": "USD",
|
||||
"latency": 0.7682376249867957
|
||||
},
|
||||
"retriever_resources": []
|
||||
},
|
||||
"created_at": 1705407629
|
||||
}
|
||||
```
|
||||
|
||||
#### 流式模式响应示例
|
||||
|
||||
```text
|
||||
data: {"event":"message","message_id":"5ad4cb98-f0c7-4085-b384-88c403be6290","conversation_id":"45701982-8118-4bc5-8e9b-64562b4555f2","answer":"I","created_at":1679586595}
|
||||
|
||||
data: {"event":"message_end","conversation_id":"45701982-8118-4bc5-8e9b-64562b4555f2","metadata":{"usage":{"prompt_tokens":1033,"completion_tokens":135,"total_tokens":1168}}}
|
||||
```
|
||||
|
||||
#### 错误码
|
||||
|
||||
| HTTP 状态码 | 错误码 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `400` | `invalid_param` | 传入参数异常。 |
|
||||
| `400` | `app_unavailable` | App 配置不可用。 |
|
||||
| `400` | `provider_not_initialize` | 无可用模型凭据配置。 |
|
||||
| `400` | `provider_quota_exceeded` | 模型调用额度不足。 |
|
||||
| `400` | `model_currently_not_support` | 当前模型不可用。 |
|
||||
| `400` | `workflow_not_found` | 指定的工作流版本未找到。 |
|
||||
| `400` | `draft_workflow_error` | 无法使用草稿工作流版本。 |
|
||||
| `400` | `workflow_id_format_error` | 工作流 ID 格式错误,需要 UUID 格式。 |
|
||||
| `400` | `completion_request_error` | 文本生成失败。 |
|
||||
| `404` | - | 对话不存在。 |
|
||||
| `500` | - | 服务内部异常。 |
|
||||
|
||||
### 5.2 停止响应
|
||||
|
||||
`POST /chat-messages/:task_id/stop`
|
||||
|
||||
停止正在进行的流式响应。
|
||||
|
||||
#### 路径参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `task_id` | `string` | 任务 ID,由发送对话消息接口返回。 |
|
||||
|
||||
#### 请求体参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `user` | `string` | 是 | 终端用户标识,必须与发送消息时的 `user` 一致。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl -X POST 'http://49.232.138.53/v1/chat-messages/:task_id/stop' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"result": "success"
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 文件接口
|
||||
|
||||
### 6.1 上传文件
|
||||
|
||||
`POST /files/upload`
|
||||
|
||||
上传文件并在发送消息时使用,可实现图文多模态理解。上传文件仅供当前终端用户使用。
|
||||
|
||||
#### 请求体参数
|
||||
|
||||
该接口使用 `multipart/form-data` 请求。
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `file` | `file` | 是 | 要上传的文件。 |
|
||||
| `user` | `string` | 是 | 终端用户标识,需和发送消息接口的 `user` 保持一致。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl -X POST 'http://49.232.138.53/v1/files/upload' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv' \
|
||||
--form 'file=@localfile;type=image/png' \
|
||||
--form 'user=abc-123'
|
||||
```
|
||||
|
||||
#### 响应字段
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `id` | `string` | 文件 ID。 |
|
||||
| `name` | `string` | 文件名。 |
|
||||
| `size` | `int` | 文件大小,单位为字节。 |
|
||||
| `extension` | `string` | 文件扩展名。 |
|
||||
| `mime_type` | `string` | MIME 类型。 |
|
||||
| `created_by` | `string` | 上传用户。 |
|
||||
| `created_at` | `int` | 创建时间戳。 |
|
||||
|
||||
### 6.2 文件预览
|
||||
|
||||
`GET /files/:file_id/preview`
|
||||
|
||||
预览或下载已上传文件。
|
||||
|
||||
#### 路径参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `file_id` | `string` | 文件 ID。 |
|
||||
|
||||
#### 查询参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `as_attachment` | `bool` | 否 | 是否作为附件下载。传 `true` 时触发下载。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl -X GET 'http://49.232.138.53/v1/files/72fa9618-8f89-4a37-9b33-7e1178a24a67/preview' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv'
|
||||
```
|
||||
|
||||
#### 下载示例
|
||||
|
||||
```bash
|
||||
curl -X GET 'http://49.232.138.53/v1/files/72fa9618-8f89-4a37-9b33-7e1178a24a67/preview?as_attachment=true' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv'
|
||||
```
|
||||
|
||||
## 7. 消息与反馈接口
|
||||
|
||||
### 7.1 消息反馈
|
||||
|
||||
`POST /messages/:message_id/feedbacks`
|
||||
|
||||
提交消息点赞、点踩或文字反馈。
|
||||
|
||||
#### 路径参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `message_id` | `string` | 消息 ID。 |
|
||||
|
||||
#### 请求体参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `rating` | `string` | 否 | 反馈类型,例如 `like`、`dislike`。传 `null` 可取消反馈。 |
|
||||
| `user` | `string` | 是 | 终端用户标识。 |
|
||||
| `content` | `string` | 否 | 消息反馈的具体内容。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl -X POST 'http://49.232.138.53/v1/messages/:message_id/feedbacks' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"rating": "like",
|
||||
"user": "abc-123",
|
||||
"content": "message feedback information"
|
||||
}'
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"result": "success"
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 获取 App 的消息点赞和反馈
|
||||
|
||||
`GET /app/feedbacks`
|
||||
|
||||
获取应用终端用户的反馈和点赞记录。
|
||||
|
||||
#### 查询参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `page` | `string` | 否 | 分页页码,默认 `1`。 |
|
||||
| `limit` | `string` | 否 | 每页数量,默认 `20`。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl -X GET 'http://49.232.138.53/v1/app/feedbacks?page=1&limit=20' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv'
|
||||
```
|
||||
|
||||
### 7.3 获取下一轮建议问题列表
|
||||
|
||||
`GET /messages/{message_id}/suggested`
|
||||
|
||||
获取指定消息的下一轮建议问题列表。
|
||||
|
||||
#### 路径参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `message_id` | `string` | 消息 ID。 |
|
||||
|
||||
#### 查询参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `user` | `string` | 是 | 终端用户标识。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl --location --request GET 'http://49.232.138.53/v1/messages/{message_id}/suggested?user=abc-123' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv'
|
||||
```
|
||||
|
||||
### 7.4 获取会话历史消息
|
||||
|
||||
`GET /messages`
|
||||
|
||||
获取指定会话的历史消息。
|
||||
|
||||
#### 查询参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `user` | `string` | 是 | 终端用户标识。 |
|
||||
| `conversation_id` | `string` | 是 | 会话 ID。 |
|
||||
| `first_id` | `string` | 否 | 当前页第一条聊天记录 ID,用于分页。 |
|
||||
| `limit` | `int` | 否 | 一次请求返回多少条记录,默认 `20`。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl -X GET 'http://49.232.138.53/v1/messages?user=abc-123&conversation_id={conversation_id}' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv'
|
||||
```
|
||||
|
||||
## 8. 会话接口
|
||||
|
||||
### 8.1 获取会话列表
|
||||
|
||||
`GET /conversations`
|
||||
|
||||
获取当前用户的会话列表。
|
||||
|
||||
#### 查询参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `user` | `string` | 是 | 终端用户标识。 |
|
||||
| `last_id` | `string` | 否 | 当前页最后一条记录 ID,用于分页。 |
|
||||
| `limit` | `int` | 否 | 一次请求返回多少条记录,默认 `20`。 |
|
||||
| `sort_by` | `string` | 否 | 排序字段,例如 `created_at`、`updated_at`。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl -X GET 'http://49.232.138.53/v1/conversations?user=abc-123&last_id=&limit=20' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv'
|
||||
```
|
||||
|
||||
### 8.2 删除会话
|
||||
|
||||
`DELETE /conversations/:conversation_id`
|
||||
|
||||
删除指定会话。
|
||||
|
||||
#### 路径参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `conversation_id` | `string` | 会话 ID。 |
|
||||
|
||||
#### 请求体参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `user` | `string` | 是 | 终端用户标识。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl -X DELETE 'http://49.232.138.53/v1/conversations/{conversation_id}' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
|
||||
### 8.3 会话重命名
|
||||
|
||||
`POST /conversations/:conversation_id/name`
|
||||
|
||||
重命名指定会话。
|
||||
|
||||
#### 路径参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `conversation_id` | `string` | 会话 ID。 |
|
||||
|
||||
#### 请求体参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `name` | `string` | 否 | 新会话名称。 |
|
||||
| `auto_generate` | `bool` | 否 | 是否自动生成标题。 |
|
||||
| `user` | `string` | 是 | 终端用户标识。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl -X POST 'http://49.232.138.53/v1/conversations/{conversation_id}/name' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"name": "新的会话名称",
|
||||
"auto_generate": false,
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
|
||||
### 8.4 获取对话变量
|
||||
|
||||
`GET /conversations/:conversation_id/variables`
|
||||
|
||||
获取指定会话中的变量列表。
|
||||
|
||||
#### 路径参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `conversation_id` | `string` | 会话 ID。 |
|
||||
|
||||
#### 查询参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `user` | `string` | 是 | 终端用户标识。 |
|
||||
| `last_id` | `string` | 否 | 当前页最后一条记录 ID。 |
|
||||
| `limit` | `int` | 否 | 每页数量。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl -X GET 'http://49.232.138.53/v1/conversations/{conversation_id}/variables?user=abc-123' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv'
|
||||
```
|
||||
|
||||
### 8.5 更新对话变量
|
||||
|
||||
`PUT /conversations/:conversation_id/variables/:variable_id`
|
||||
|
||||
更新指定会话变量。
|
||||
|
||||
#### 路径参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `conversation_id` | `string` | 会话 ID。 |
|
||||
| `variable_id` | `string` | 变量 ID。 |
|
||||
|
||||
#### 请求体参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `value` | `string` | 是 | 变量值。 |
|
||||
| `user` | `string` | 是 | 终端用户标识。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl -X PUT 'http://49.232.138.53/v1/conversations/{conversation_id}/variables/{variable_id}' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"value": "Updated Value",
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
|
||||
## 9. 音频接口
|
||||
|
||||
### 9.1 语音转文字
|
||||
|
||||
`POST /audio-to-text`
|
||||
|
||||
将音频文件转写为文本。
|
||||
|
||||
#### 请求体参数
|
||||
|
||||
该接口使用 `multipart/form-data` 请求。
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `file` | `file` | 是 | 音频文件。 |
|
||||
| `user` | `string` | 是 | 终端用户标识。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl -X POST 'http://49.232.138.53/v1/audio-to-text' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv' \
|
||||
--form 'file=@localfile;type=audio/mpeg' \
|
||||
--form 'user=abc-123'
|
||||
```
|
||||
|
||||
### 9.2 文字转语音
|
||||
|
||||
`POST /text-to-audio`
|
||||
|
||||
将文本或消息内容转换为音频。
|
||||
|
||||
#### 请求体参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `message_id` | `string` | 否 | 消息 ID。传入后对指定消息内容进行语音合成。 |
|
||||
| `text` | `string` | 否 | 待转换文本。未传 `message_id` 时使用。 |
|
||||
| `user` | `string` | 是 | 终端用户标识。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl -o text-to-audio.mp3 -X POST 'http://49.232.138.53/v1/text-to-audio' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"text": "hello",
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
|
||||
## 10. 应用信息接口
|
||||
|
||||
### 10.1 获取应用基本信息
|
||||
|
||||
`GET /info`
|
||||
|
||||
获取应用基本信息。
|
||||
|
||||
```bash
|
||||
curl -X GET 'http://49.232.138.53/v1/info' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv'
|
||||
```
|
||||
|
||||
### 10.2 获取应用参数
|
||||
|
||||
`GET /parameters`
|
||||
|
||||
获取应用输入参数、用户输入表单、文件上传配置、系统参数等。
|
||||
|
||||
```bash
|
||||
curl -X GET 'http://49.232.138.53/v1/parameters' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv'
|
||||
```
|
||||
|
||||
### 10.3 获取应用 Meta 信息
|
||||
|
||||
`GET /meta`
|
||||
|
||||
获取应用 Meta 信息,例如工具图标等。
|
||||
|
||||
```bash
|
||||
curl -X GET 'http://49.232.138.53/v1/meta' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv'
|
||||
```
|
||||
|
||||
### 10.4 获取应用 WebApp 设置
|
||||
|
||||
`GET /site`
|
||||
|
||||
获取应用 WebApp 设置。
|
||||
|
||||
```bash
|
||||
curl -X GET 'http://49.232.138.53/v1/site' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv'
|
||||
```
|
||||
|
||||
## 11. 标注接口
|
||||
|
||||
### 11.1 获取标注列表
|
||||
|
||||
`GET /apps/annotations`
|
||||
|
||||
获取应用标注列表。
|
||||
|
||||
#### 查询参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `page` | `string` | 否 | 页码,默认 `1`。 |
|
||||
| `limit` | `string` | 否 | 每页数量,默认 `20`。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl --location --request GET 'http://49.232.138.53/v1/apps/annotations?page=1&limit=20' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv'
|
||||
```
|
||||
|
||||
### 11.2 创建标注
|
||||
|
||||
`POST /apps/annotations`
|
||||
|
||||
创建一条标注问答。
|
||||
|
||||
#### 请求体参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `question` | `string` | 是 | 问题。 |
|
||||
| `answer` | `string` | 是 | 答案。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl --location --request POST 'http://49.232.138.53/v1/apps/annotations' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"question": "What is Dify?",
|
||||
"answer": "Dify is an LLM application development platform."
|
||||
}'
|
||||
```
|
||||
|
||||
### 11.3 更新标注
|
||||
|
||||
`PUT /apps/annotations/{annotation_id}`
|
||||
|
||||
更新指定标注。
|
||||
|
||||
#### 路径参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `annotation_id` | `string` | 标注 ID。 |
|
||||
|
||||
#### 请求体参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `question` | `string` | 是 | 问题。 |
|
||||
| `answer` | `string` | 是 | 答案。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl --location --request PUT 'http://49.232.138.53/v1/apps/annotations/{annotation_id}' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"question": "What is Dify?",
|
||||
"answer": "Dify is an LLM application development platform."
|
||||
}'
|
||||
```
|
||||
|
||||
### 11.4 删除标注
|
||||
|
||||
`DELETE /apps/annotations/{annotation_id}`
|
||||
|
||||
删除指定标注。
|
||||
|
||||
#### 路径参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `annotation_id` | `string` | 标注 ID。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl --location --request DELETE 'http://49.232.138.53/v1/apps/annotations/{annotation_id}' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv'
|
||||
```
|
||||
|
||||
### 11.5 标注回复初始设置
|
||||
|
||||
`POST /apps/annotation-reply/{action}`
|
||||
|
||||
启用或禁用标注回复。该接口异步执行,返回 `job_id` 后可通过任务状态接口查询最终结果。
|
||||
|
||||
#### 路径参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `action` | `string` | 动作,只能是 `enable` 或 `disable`。 |
|
||||
|
||||
#### 请求体参数
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `score_threshold` | `number` | 是 | 相似度阈值。当相似度大于该阈值时,系统自动回复。 |
|
||||
| `embedding_provider_name` | `string` | 是 | 嵌入模型提供商。 |
|
||||
| `embedding_model_name` | `string` | 是 | 嵌入模型名称。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl --location --request POST 'http://49.232.138.53/v1/apps/annotation-reply/{action}' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"score_threshold": 0.9,
|
||||
"embedding_provider_name": "zhipu",
|
||||
"embedding_model_name": "embedding_3"
|
||||
}'
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"job_id": "b15c8f68-1cf4-4877-bf21-ed7cf2011802",
|
||||
"job_status": "waiting"
|
||||
}
|
||||
```
|
||||
|
||||
### 11.6 查询标注回复初始设置任务状态
|
||||
|
||||
`GET /apps/annotation-reply/{action}/status/{job_id}`
|
||||
|
||||
查询标注回复启用或禁用任务状态。
|
||||
|
||||
#### 路径参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `action` | `string` | 动作,只能是 `enable` 或 `disable`,并且必须和标注回复初始设置接口的动作一致。 |
|
||||
| `job_id` | `string` | 任务 ID,由标注回复初始设置接口返回。 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```bash
|
||||
curl --location --request GET 'http://49.232.138.53/v1/apps/annotation-reply/{action}/status/{job_id}' \
|
||||
--header 'Authorization: Bearer app-MqQOx09gCu9zzlKMpeLqHQHv'
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"job_id": "b15c8f68-1cf4-4877-bf21-ed7cf2011802",
|
||||
"job_status": "waiting",
|
||||
"error_msg": ""
|
||||
}
|
||||
```
|
||||
|
||||
## 12. 通用响应对象
|
||||
|
||||
### 12.1 Usage
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `prompt_tokens` | `int` | 提示词 token 数。 |
|
||||
| `prompt_unit_price` | `string` | 提示词单价。 |
|
||||
| `prompt_price_unit` | `string` | 提示词价格单位。 |
|
||||
| `prompt_price` | `string` | 提示词价格。 |
|
||||
| `completion_tokens` | `int` | 补全 token 数。 |
|
||||
| `completion_unit_price` | `string` | 补全单价。 |
|
||||
| `completion_price_unit` | `string` | 补全价格单位。 |
|
||||
| `completion_price` | `string` | 补全价格。 |
|
||||
| `total_tokens` | `int` | 总 token 数。 |
|
||||
| `total_price` | `string` | 总价格。 |
|
||||
| `currency` | `string` | 货币。 |
|
||||
| `latency` | `number` | 请求耗时。 |
|
||||
|
||||
### 12.2 RetrieverResource
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `position` | `int` | 引用位置。 |
|
||||
| `dataset_id` | `string` | 数据集 ID。 |
|
||||
| `dataset_name` | `string` | 数据集名称。 |
|
||||
| `document_id` | `string` | 文档 ID。 |
|
||||
| `document_name` | `string` | 文档名称。 |
|
||||
| `segment_id` | `string` | 分段 ID。 |
|
||||
| `score` | `number` | 相关性分数。 |
|
||||
| `content` | `string` | 分段内容。 |
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# Mini Program ASR Service Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Deploy a private Chinese ASR service on `101.200.208.45` and wire the mini program voice orb to transcribe speech into the wish input.
|
||||
|
||||
**Architecture:** A local FastAPI ASR service listens on `127.0.0.1:19120` and uses FunASR/SenseVoiceSmall when available. The Java backend exposes `/api/asr/transcribe` as the authenticated upload proxy, and the mini program records audio with `uni.getRecorderManager()` then uploads it through the existing request service.
|
||||
|
||||
**Tech Stack:** FunASR/SenseVoiceSmall, Python 3.11, FastAPI, Spring Boot multipart upload, uni-app recorder/upload APIs.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: ASR Service
|
||||
|
||||
**Files:**
|
||||
- Create: `backend-single/asr-service/app.py`
|
||||
- Create: `backend-single/asr-service/requirements.txt`
|
||||
- Create: `backend-single/asr-service/emotion-museum-asr.service`
|
||||
- Create: `backend-single/asr-service/README.md`
|
||||
|
||||
- [x] Add a FastAPI service with `/health` and `/transcribe`.
|
||||
- [x] Accept an uploaded audio file, save it under `/tmp/emotion-museum-asr`, run the ASR model, and return JSON with `success`, `text`, `language`, `durationMs`, `engine`, and `errorMessage`.
|
||||
- [x] Keep the service bound to `127.0.0.1:19120`.
|
||||
|
||||
### Task 2: Java Backend Proxy
|
||||
|
||||
**Files:**
|
||||
- Create: `backend-single/src/main/java/com/emotion/dto/response/asr/AsrTranscribeResponse.java`
|
||||
- Create: `backend-single/src/main/java/com/emotion/service/AsrService.java`
|
||||
- Create: `backend-single/src/main/java/com/emotion/service/impl/AsrServiceImpl.java`
|
||||
- Create: `backend-single/src/main/java/com/emotion/controller/AsrController.java`
|
||||
- Modify: `backend-single/src/main/resources/application.yml`
|
||||
- Modify: `backend-single/src/main/resources/application-prod.yml`
|
||||
|
||||
- [x] Add `emotion.asr` config for `enabled`, `engine-url`, `max-file-size`, and `allowed-types`.
|
||||
- [x] Validate upload presence, size, and suffix.
|
||||
- [x] Forward multipart audio to the local ASR service.
|
||||
- [x] Return a normal `Result<AsrTranscribeResponse>` to the mini program.
|
||||
|
||||
### Task 3: Mini Program Recording
|
||||
|
||||
**Files:**
|
||||
- Create: `mini-program/src/services/asr.js`
|
||||
- Modify: `mini-program/src/pages/main/ScriptView.vue`
|
||||
|
||||
- [x] Use `uni.getRecorderManager()` to start recording on press.
|
||||
- [x] Stop recording on release/cancel.
|
||||
- [x] Upload the recorded temp file to `/asr/transcribe`.
|
||||
- [x] Fill `wishText` with recognized text and keep the current visual theme.
|
||||
- [x] Track success/failure analytics.
|
||||
|
||||
### Task 4: Deploy And Verify
|
||||
|
||||
**Commands:**
|
||||
- `npm run build:mp-weixin`
|
||||
- `mvn -DskipTests package`
|
||||
- Deploy backend jar to `101.200.208.45`.
|
||||
- Install/start `emotion-museum-asr`.
|
||||
- Check `curl http://127.0.0.1:19120/health`.
|
||||
|
||||
**Acceptance:**
|
||||
- Pressing and releasing the mini program voice orb sends audio to backend ASR.
|
||||
- Recognized Chinese text appears in the wish input.
|
||||
- Server ASR and TTS services both remain active.
|
||||
@@ -0,0 +1,226 @@
|
||||
# AI 配置管理接口测试修复实施计划
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 删除废弃的旧 AI 配置页面,在新系统测试对话框中增加非流式测试功能
|
||||
|
||||
**Architecture:** 路由已正确指向新系统 `AiRoutingList.vue`,只需删除旧文件残留并增强测试对话框。后端接口 `testAiRuntime` 已存在,只需在 API 层和 UI 层连接。
|
||||
|
||||
**Tech Stack:** Vue 3, Element Plus, TypeScript
|
||||
|
||||
---
|
||||
|
||||
### 前置确认:检查生产数据库配置
|
||||
|
||||
- [ ] 在生产数据库上执行以下查询,确认 Dify provider 和 endpoint 状态
|
||||
|
||||
```sql
|
||||
-- 检查 Dify provider
|
||||
SELECT id, provider_code, provider_name, provider_type, base_url, is_enabled
|
||||
FROM t_ai_provider WHERE provider_code = 'dify_default';
|
||||
|
||||
-- 检查 Dify endpoints
|
||||
SELECT id, endpoint_code, endpoint_name, provider_id, api_path, support_stream, is_enabled
|
||||
FROM t_ai_endpoint_config WHERE endpoint_code LIKE 'dify.%';
|
||||
|
||||
-- 检查场景绑定
|
||||
SELECT id, scene_code, scene_name, endpoint_id, is_enabled, required_stream
|
||||
FROM t_ai_scene_binding WHERE is_enabled = 1;
|
||||
```
|
||||
|
||||
- [ ] 如果 Dify provider `is_enabled = 0`,执行:
|
||||
```sql
|
||||
UPDATE t_ai_provider SET is_enabled = 1 WHERE provider_code = 'dify_default';
|
||||
```
|
||||
|
||||
- [ ] 如果 Dify endpoints `is_enabled = 0`,执行:
|
||||
```sql
|
||||
UPDATE t_ai_endpoint_config SET is_enabled = 1 WHERE endpoint_code LIKE 'dify.%';
|
||||
```
|
||||
|
||||
### Task 1: 删除废弃的旧 AI 配置页面
|
||||
|
||||
**Files:**
|
||||
- Delete: `web-admin/src/views/aiconfig/AiConfigList.vue`
|
||||
|
||||
- [ ] 删除旧页面文件
|
||||
|
||||
```bash
|
||||
rm web-admin/src/views/aiconfig/AiConfigList.vue
|
||||
```
|
||||
|
||||
### Task 2: 在 API 层导出非流式测试函数
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/api/aiconfig.ts`
|
||||
|
||||
- [ ] 确认 `testAiRuntime` 已存在(已确认在第 263 行)
|
||||
|
||||
```typescript
|
||||
export function testAiRuntime(data: AiRuntimeRequest) {
|
||||
return request({ url: '/ai/runtime/test', method: 'post', data })
|
||||
}
|
||||
```
|
||||
|
||||
已存在,无需修改。但需要确认 `AiRoutingList.vue` 中是否 import 了这个函数。
|
||||
|
||||
检查 `web-admin/src/views/aiconfig/AiRoutingList.vue` 的 import 语句(当前第 269-281 行):
|
||||
- 当前 import 了 `streamAiRuntime`,**没有 import** `testAiRuntime`
|
||||
- 需要在 import 列表中添加 `testAiRuntime`
|
||||
|
||||
### Task 3: 在测试对话框中增加非流式测试按钮
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/views/aiconfig/AiRoutingList.vue`
|
||||
|
||||
- [ ] 在 import 中添加 `testAiRuntime`
|
||||
|
||||
修改第 269-281 行的 import 语句:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
deleteAiEndpoint,
|
||||
deleteAiProvider,
|
||||
deleteAiScene,
|
||||
listAiCallLogs,
|
||||
listAiEndpoints,
|
||||
listAiProviders,
|
||||
listAiScenes,
|
||||
saveAiEndpoint,
|
||||
saveAiProvider,
|
||||
saveAiScene,
|
||||
streamAiRuntime,
|
||||
testAiRuntime // ← 新增
|
||||
} from '@/api/aiconfig'
|
||||
```
|
||||
|
||||
- [ ] 在测试对话框 footer 中增加「非流式测试」按钮
|
||||
|
||||
找到第 257-261 行的 `<template #footer>`,修改为:
|
||||
|
||||
```vue
|
||||
<template #footer>
|
||||
<el-button @click="testDialog = false">关闭</el-button>
|
||||
<el-button :loading="testing" @click="submitNonStreamTest">非流式测试</el-button>
|
||||
<el-button type="primary" :loading="testing" @click="submitRuntimeTest">流式测试</el-button>
|
||||
</template>
|
||||
```
|
||||
|
||||
- [ ] 添加 `nonStreamResult` 响应式变量
|
||||
|
||||
在 `testResult` 声明后面(第 296 行)添加:
|
||||
|
||||
```typescript
|
||||
const nonStreamResult = ref<AiRuntimeTestResponse | null>(null)
|
||||
```
|
||||
|
||||
- [ ] 实现 `submitNonStreamTest` 函数
|
||||
|
||||
在 `submitRuntimeTest` 函数(第 451 行)之前添加:
|
||||
|
||||
```typescript
|
||||
async function submitNonStreamTest() {
|
||||
let inputs: Record<string, any>
|
||||
try {
|
||||
inputs = JSON.parse(testInputsJson.value || '{}')
|
||||
} catch (error) {
|
||||
ElMessage.error('入参 JSON 格式不正确')
|
||||
return
|
||||
}
|
||||
testing.value = true
|
||||
try {
|
||||
const res = await testAiRuntime({ sceneCode: testForm.sceneCode, inputs })
|
||||
nonStreamResult.value = res.data as AiRuntimeTestResponse
|
||||
if (nonStreamResult.value.status === 'success') {
|
||||
ElMessage.success('非流式测试成功')
|
||||
} else {
|
||||
ElMessage.error(`测试失败: ${nonStreamResult.value.errorMessage || nonStreamResult.value.errorCode}`)
|
||||
}
|
||||
await loadAll()
|
||||
} catch (error: any) {
|
||||
nonStreamResult.value = {
|
||||
sceneCode: testForm.sceneCode,
|
||||
status: 'failed',
|
||||
errorMessage: error?.message || '非流式测试失败'
|
||||
} as AiRuntimeTestResponse
|
||||
ElMessage.error(error?.message || '非流式测试失败')
|
||||
} finally {
|
||||
testing.value = false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] 在测试对话框中展示非流式测试结果
|
||||
|
||||
在 `submitRuntimeTest` 相关的 `<el-alert>` 和 `<pre>` 展示块(第 250-256 行)之前,添加非流式测试结果的展示:
|
||||
|
||||
```vue
|
||||
<el-alert
|
||||
v-if="nonStreamResult"
|
||||
:type="nonStreamResult.status === 'success' ? 'success' : 'error'"
|
||||
:title="nonStreamResult.status === 'success' ? '非流式测试成功' : '非流式测试失败'"
|
||||
show-icon
|
||||
:closable="false"
|
||||
style="margin-bottom: 12px;"
|
||||
/>
|
||||
<pre v-if="nonStreamResult" class="test-output">{{ nonStreamResult.output || nonStreamResult.errorMessage || '暂无输出' }}</pre>
|
||||
|
||||
<el-alert
|
||||
v-if="testResult"
|
||||
:type="testResult.status === 'success' ? 'success' : 'error'"
|
||||
:title="testResult.status === 'success' ? '流式测试成功' : '流式测试失败'"
|
||||
show-icon
|
||||
/>
|
||||
<pre v-if="testResult" class="test-output">{{ testResult.output || testResult.errorMessage || '暂无输出' }}</pre>
|
||||
```
|
||||
|
||||
- [ ] 在打开测试对话框时清空非流式结果
|
||||
|
||||
在 `openRuntimeTest` 函数(第 400-404 行)中添加:
|
||||
|
||||
```typescript
|
||||
function openRuntimeTest() {
|
||||
testForm.sceneCode = scenes.value.find(item => item.isEnabled === 1 && item.endpointId)?.sceneCode || scenes.value[0]?.sceneCode || ''
|
||||
testResult.value = null
|
||||
nonStreamResult.value = null // ← 新增
|
||||
testDialog.value = true
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] 在 TypeScript 类型定义中确保 `AiRuntimeTestResponse` 包含所有必要字段
|
||||
|
||||
检查 `web-admin/src/types/aiconfig.ts` 中的 `AiRuntimeTestResponse` 定义,确保包含:
|
||||
|
||||
```typescript
|
||||
export interface AiRuntimeTestResponse {
|
||||
sceneCode: string
|
||||
status: 'success' | 'failed'
|
||||
output?: string
|
||||
streamChunks?: number
|
||||
durationMs?: number
|
||||
errorCode?: string
|
||||
errorMessage?: string
|
||||
}
|
||||
```
|
||||
|
||||
### Task 4: 浏览器验证
|
||||
|
||||
- [ ] 启动 web-admin 开发服务器
|
||||
|
||||
```bash
|
||||
cd web-admin && npm run dev
|
||||
```
|
||||
|
||||
- [ ] 在浏览器中访问管理后台 `http://localhost:5174/emotion-museum-admin/`
|
||||
|
||||
- [ ] 导航到「AI 配置管理」页面,确认旧页面已删除、新页面正常显示
|
||||
|
||||
- [ ] 在「场景绑定」Tab 中点击「流式测试」按钮,确认测试对话框正常打开
|
||||
|
||||
- [ ] 确认测试对话框中有两个按钮:「非流式测试」和「流式测试」
|
||||
|
||||
- [ ] 选择一个场景(如 `script_generate`),输入入参 `{ "prompt": "请用一句中文回复测试成功。" }`,点击「非流式测试」,确认返回成功结果
|
||||
|
||||
- [ ] 点击「流式测试」,确认流式输出正常
|
||||
|
||||
- [ ] 确认浏览器 Console 中没有任何错误
|
||||
@@ -0,0 +1,58 @@
|
||||
# AI Routing Admin Runtime Fix Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Make the AI configuration center match the existing admin theme, use Chinese copy everywhere, show existing provider/workflow bindings from the database, and expose a single user-facing streaming runtime entry point driven by scene code plus JSON inputs.
|
||||
|
||||
**Architecture:** Keep the existing provider/endpoint/scene/log model. The admin page uses the current Element Plus dark glass theme and existing list-page conventions. Runtime calls accept `sceneCode` and `inputs` JSON, enrich inputs with the logged-in user context on the backend, resolve the scene binding from the database, then stream provider output back to the user.
|
||||
|
||||
**Tech Stack:** Spring Boot, MyBatis-Plus, FastJSON, Vue 3, Element Plus, uni-app chunked streaming.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Admin Page Theme And Chinese Copy
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/views/aiconfig/AiRoutingList.vue`
|
||||
|
||||
- [x] Replace English page title, tabs, table columns, dialogs, buttons, alerts, empty states, and confirm text with Chinese.
|
||||
- [x] Replace the standalone white panel styles with the project page-header, glass card, table card, and dark Element Plus table styles.
|
||||
- [x] Add summary cards for providers, endpoints, scenes, and logs so the page matches existing management pages.
|
||||
|
||||
### Task 2: User Runtime Request Shape
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend-single/src/main/java/com/emotion/dto/request/ai/AiRuntimeRequest.java`
|
||||
- Modify: `backend-single/src/main/java/com/emotion/controller/AiRoutingController.java`
|
||||
- Modify: `backend-single/src/main/java/com/emotion/service/impl/AiRuntimeServiceImpl.java`
|
||||
|
||||
- [x] Accept user calls as `sceneCode` plus `inputs` JSON.
|
||||
- [x] Keep user identity server-side by reading `UserContextHolder`.
|
||||
- [x] Enrich runtime inputs with safe user context keys before provider invocation.
|
||||
- [x] Keep SSE stream events as the only formal output path for user-facing AI calls.
|
||||
|
||||
### Task 3: Seed Existing Configurations Into Routing Tables
|
||||
|
||||
**Files:**
|
||||
- Modify: `sql/2026-05-22-ai-scene-routing.sql`
|
||||
|
||||
- [x] Insert a Coze provider from existing `t_ai_config` rows when missing.
|
||||
- [x] Insert endpoint rows from current enabled Coze workflow configurations.
|
||||
- [x] Bind existing scenes to known workflow configs where a safe mapping exists.
|
||||
- [x] Keep unknown scenes visible but disabled until explicitly bound in the admin page.
|
||||
|
||||
### Task 4: Verify End To End
|
||||
|
||||
**Commands:**
|
||||
- `mvn test`
|
||||
- `mvn -DskipTests clean package`
|
||||
- `npm run build`
|
||||
- `npm run build:mp-weixin`
|
||||
- Remote SQL migration execution.
|
||||
- Remote health checks for backend and ASR.
|
||||
|
||||
- [x] Backend tests pass.
|
||||
- [x] Backend package succeeds.
|
||||
- [x] Admin build succeeds.
|
||||
- [x] Mini program build succeeds.
|
||||
- [x] Remote routing tables contain provider, endpoints, and scene bindings.
|
||||
@@ -0,0 +1,66 @@
|
||||
# AI Runtime Client Sync Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Synchronize AI calls in web, web-admin, life-script, and mini-program so user-facing AI output uses the backend scene routing runtime and streams text progressively.
|
||||
|
||||
**Architecture:** The backend remains the single trust boundary for provider credentials, scene bindings, user context enrichment, and workflow selection. Browser and mini-program clients call `/ai/runtime/stream` with `sceneCode` and `inputs`, while existing WebSocket chat is bridged through `AiRuntimeService` so chat also follows the configured `chat` scene. Existing business save APIs remain responsible for persistence after a stream completes.
|
||||
|
||||
**Tech Stack:** Spring Boot, STOMP WebSocket, FastJSON, Vue 3, React/Vite, uni-app chunked request, Element Plus.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Backend Chat Bridge To Runtime
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend-single/src/main/java/com/emotion/service/impl/WebSocketServiceImpl.java`
|
||||
- Modify: `backend-single/src/main/java/com/emotion/dto/websocket/WebSocketMessage.java`
|
||||
|
||||
- [x] Route chat generation through `AiRuntimeService` with `sceneCode=chat`.
|
||||
- [x] Push `start`, `delta`, `done`, and `error` events over the existing user WebSocket topic.
|
||||
- [x] Save the final assistant message after `done` using the accumulated stream output.
|
||||
- [x] Preserve the existing user-message persistence and conversation ID behavior.
|
||||
|
||||
### Task 2: Shared Runtime Clients
|
||||
|
||||
**Files:**
|
||||
- Create: `web/src/services/aiRuntime.ts`
|
||||
- Create: `life-script/src/services/aiRuntime.js`
|
||||
- Modify: `mini-program/src/services/aiRuntime.js`
|
||||
- Modify: `web-admin/src/api/aiconfig.ts`
|
||||
- Modify: `web-admin/src/views/aiconfig/AiRoutingList.vue`
|
||||
|
||||
- [x] Add browser SSE client helpers that parse unified AI stream events.
|
||||
- [x] Keep mini-program chunk parsing but localize error messages and flush trailing frames.
|
||||
- [x] Add a web-admin stream test helper and make the test dialog render output progressively.
|
||||
|
||||
### Task 3: Client Scene Migration
|
||||
|
||||
**Files:**
|
||||
- Modify: `life-script/src/services/ai.js`
|
||||
- Modify: `life-script/src/views/ScriptView.jsx`
|
||||
- Modify: `life-script/src/views/TimelineView.jsx`
|
||||
- Modify: `life-script/src/views/PathView.jsx`
|
||||
- Modify: `mini-program/src/pages/main/ScriptView.vue`
|
||||
- Inspect: `web/src/stores/chat.ts`
|
||||
|
||||
- [x] Remove direct OpenRouter calls and hard-coded client API keys.
|
||||
- [x] Route `script_generate`, `life_healing`, and path generation through `streamAiScene`.
|
||||
- [x] Ensure pages append `delta` content instead of waiting for complete text.
|
||||
- [x] Keep final persistence through existing business save APIs after stream completion.
|
||||
|
||||
### Task 4: Verification
|
||||
|
||||
**Commands:**
|
||||
- `mvn test`
|
||||
- `mvn -DskipTests clean package`
|
||||
- `npm run build` in `web`
|
||||
- `npm run build` in `web-admin`
|
||||
- `npm run build` in `life-script`
|
||||
- `npm run build:mp-weixin` in `mini-program`
|
||||
|
||||
- [x] Backend tests pass.
|
||||
- [x] Backend package succeeds.
|
||||
- [x] All four frontend builds succeed.
|
||||
- [x] Source scan shows no client-side external AI provider key or direct Dify/Coze/OpenRouter call.
|
||||
- [x] Database scene bindings are enabled with streaming endpoints for `chat`, `script_generate`, `short_story_generate`, `diary_summary`, `emotion_summary`, `emotion_analysis`, and `life_healing`.
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
author: 华钟民
|
||||
created_at: 2026-05-23
|
||||
purpose: 修复 AI 配置管理接口测试功能,确保 Dify/Coze 等多提供商在 web-admin 后台能正常测试,全局确认前后端调用链路一致
|
||||
---
|
||||
|
||||
# AI 配置管理接口测试修复设计
|
||||
|
||||
## 1. 问题背景
|
||||
|
||||
在 web-admin 后台的"AI 配置管理"页面,流式测试 Dify 接口时报错:
|
||||
`"message":"user_id is required in input form"`。
|
||||
|
||||
根因是存在两套 AI 配置系统:
|
||||
- **旧系统**:`t_ai_config` 表 + `AiConfigList.vue`(已被路由废弃但文件残留)
|
||||
- **新系统**:`t_ai_provider` / `t_ai_endpoint_config` / `t_ai_scene_binding` 三表 + `AiRoutingList.vue`(路由当前指向的页面)
|
||||
|
||||
## 2. 当前状态确认
|
||||
|
||||
### 前端调用链路(全部走新系统)
|
||||
|
||||
| 项目 | 调用方式 | 目标接口 | 状态 |
|
||||
|------|---------|---------|------|
|
||||
| web | `streamAiScene()` → `fetch('/ai/runtime/stream')` | AiRuntimeService.invokeStream() | ✅ |
|
||||
| web-admin | `streamAiRuntime()` → `fetch('/ai/runtime/stream')` | AiRoutingController.runtimeStream() | ✅ |
|
||||
| life-script | `streamAiScene()` → `fetch('/ai/runtime/stream')` | AiRuntimeService.invokeStream() | ✅ |
|
||||
| mini-program | `streamAiScene()` → `uni.request('/ai/runtime/stream')` | AiRuntimeService.invokeStream() | ✅ |
|
||||
|
||||
### 后端服务调用链路(全部走新系统)
|
||||
|
||||
| 服务 | 调用方式 | 目标方法 | 状态 |
|
||||
|------|---------|---------|------|
|
||||
| AiChatServiceImpl | `aiRuntimeService.test()` | AiRuntimeServiceImpl.test() | ✅ |
|
||||
| WebSocketServiceImpl | `aiRuntimeService.invokeStream()` | AiRuntimeServiceImpl.invokeStream() | ✅ |
|
||||
| EpicScriptServiceImpl | `aiRuntimeService.test()` | AiRuntimeServiceImpl.test() | ✅ |
|
||||
| LifeEventServiceImpl | `aiRuntimeService.test()` | AiRuntimeServiceImpl.test() | ✅ |
|
||||
|
||||
### 数据库配置现状
|
||||
|
||||
`t_ai_provider` 已有 `dify_default`(`http://49.232.138.53/v1`,api_key=`app-MqQOx09gCu9zzlKMpeLqHQHv`),`t_ai_endpoint_config` 已迁移 Dify 对话接口。但场景绑定需注意:
|
||||
|
||||
- `chat` → Coze endpoint(旧系统遗留绑定)
|
||||
- `script_generate` → **Dify endpoint** ✅
|
||||
- `short_story_generate` → **Dify endpoint** ✅
|
||||
- `diary_summary` → Coze endpoint
|
||||
- `emotion_summary` → Coze endpoint
|
||||
- `emotion_analysis` → Coze endpoint
|
||||
- `life_healing` → Coze endpoint
|
||||
|
||||
**结论**:在 web-admin 测试 `script_generate` 和 `short_story_generate` 场景时,会走 Dify;其他场景走 Coze。这是预期行为。
|
||||
|
||||
## 3. 设计方案
|
||||
|
||||
### 3.1 删除旧系统残留
|
||||
|
||||
删除 `web-admin/src/views/aiconfig/AiConfigList.vue`。该文件路由已不再指向它,保留只会引起混淆。对应的后端 `/aiConfig/*` 接口保持不变(以防有遗留数据查询需求)。
|
||||
|
||||
### 3.2 新系统测试对话框增强
|
||||
|
||||
在 `AiRoutingList.vue` 的流式测试对话框(当前标题"流式调用测试")中增加「非流式测试」按钮,并将对话框标题改为「接口测试」:
|
||||
|
||||
- 流式测试走 `/ai/runtime/stream` → `streamAiRuntime()`(已有)
|
||||
- 非流式测试走 `/ai/runtime/test` → `testAiRuntime()`(已有接口,但当前未 import)
|
||||
- 两个按钮共享 `testing` 加载状态,避免并发冲突
|
||||
- 非流式和流式测试结果各自独立展示,互不干扰
|
||||
- 打开对话框时同时清空两个结果
|
||||
|
||||
### 3.3 路由清理
|
||||
|
||||
路由配置 `/aiconfig/list` 已正确指向 `AiRoutingList.vue`,无需改动。
|
||||
|
||||
### 3.4 数据库配置检查
|
||||
|
||||
实施前需确认生产数据库中 Dify provider 和 Dify endpoints 处于 `is_enabled = 1` 状态。SQL 迁移脚本 `2026-05-22-ai-scene-routing.sql` 中已设置了 `is_enabled = 1`,但可能在实际部署时未执行。
|
||||
|
||||
## 4. 风险
|
||||
|
||||
- 删除 `AiConfigList.vue` 后如果用户需要查询旧 `t_ai_config` 数据,仍有后端 `/aiConfig/*` 接口可用
|
||||
- 非流式测试新增不影响已有功能
|
||||
- Dify provider 和 endpoint 需确保 `is_enabled = 1`,否则测试会返回 `AI_ENDPOINT_DISABLED` 或 `AI_PROVIDER_DISABLED`
|
||||
Reference in New Issue
Block a user