From 5ca9763443ee2663196582e4702b20840145a447 Mon Sep 17 00:00:00 2001 From: wangdan-fit2cloud Date: Fri, 18 Sep 2026 14:13:14 +0800 Subject: [PATCH] feat: conversation api --- ui/AGENTS.md | 3 +- ui/src/api/API_README.md | 42 ++++- ui/src/api/admin/core/request.ts | 24 ++- ui/src/api/admin/file.ts | 19 +++ ui/src/api/admin/workspace/conversation.ts | 73 +++++++++ ui/src/api/chat/README.md | 15 +- ui/src/api/chat/conversation.ts | 42 +++++ ui/src/api/chat/core/request.ts | 41 ++++- ui/src/api/chat/file.ts | 19 +++ ui/src/api/enums/file.ts | 11 ++ ui/src/api/enums/index.ts | 1 + ui/src/api/types/file.ts | 3 + ui/src/api/types/index.ts | 1 + ui/src/conversation-panel/api/index.ts | 154 ------------------ .../conversation-panel/chat-panel/index.vue | 3 +- ui/src/conversation-panel/common/enums.ts | 5 + ui/src/conversation-panel/common/get-api.ts | 9 + ui/src/conversation-panel/common/types.ts | 4 +- .../common/use-chat-store/chat/index.ts | 45 ++--- .../common/use-chat-store/debug/index.ts | 47 +++--- .../common/use-chat-store/index.ts | 3 +- .../shared/use-stream-manager.ts | 50 ++---- ui/src/conversation-panel/index.vue | 3 +- ui/src/conversation-panel/sidebar/index.vue | 3 +- 24 files changed, 366 insertions(+), 254 deletions(-) create mode 100644 ui/src/api/admin/file.ts create mode 100644 ui/src/api/admin/workspace/conversation.ts create mode 100644 ui/src/api/chat/conversation.ts create mode 100644 ui/src/api/chat/file.ts create mode 100644 ui/src/api/enums/file.ts create mode 100644 ui/src/api/types/file.ts delete mode 100644 ui/src/conversation-panel/api/index.ts create mode 100644 ui/src/conversation-panel/common/enums.ts create mode 100644 ui/src/conversation-panel/common/get-api.ts diff --git a/ui/AGENTS.md b/ui/AGENTS.md index 9795b43096d..d4134d5dcc9 100644 --- a/ui/AGENTS.md +++ b/ui/AGENTS.md @@ -65,6 +65,7 @@ ui/ │ │ ├── global/ # Frequently used components auto-registered by Vite │ │ │ └── mk-icon/ # Unified SVG Symbol and Element Plus icon component │ │ └── / # Less-frequent shared components imported explicitly +│ ├── conversation-panel/ # Conversation UI, local state, streaming, and API mode selection │ ├── constants/ # Cross-feature constants grouped by domain │ │ └── CONSTANT_README.md # Shared constant placement and naming rules │ ├── layout/ # Shared application shells, headers, sidebars, types, and helpers @@ -117,7 +118,7 @@ ui/ ``` Internationalization is not yet integrated; `src/locales/` has not been created. Chat currently has a -placeholder route page and a reserved independent API directory. Add files to the matching feature +placeholder route page and an independent API client with conversation endpoints. Add files to the matching feature directory instead of creating parallel top-level structures. Structural responsibilities: diff --git a/ui/src/api/API_README.md b/ui/src/api/API_README.md index b1f206d446c..eee95b3c9ad 100644 --- a/ui/src/api/API_README.md +++ b/ui/src/api/API_README.md @@ -1,12 +1,13 @@ # API 目录说明 -`src/api` 负责前端与服务端之间的通信,按照应用入口隔离 Admin 与 Chat 请求体系。当前只实现 -Admin API;Chat 目录作为独立体系预留。 +`src/api` 负责前端与服务端之间的通信,按照应用入口隔离 Admin 与 Chat 请求体系。 +Admin 与 Chat 分别维护请求客户端和业务接口。 ```text src/api/ ├── constants.ts # Admin 与 Chat 的 API base 路径常量 ├── admin/ +│ ├── file.ts # 通用文件上传、进度与取消 │ ├── auth/ # Admin 登录认证与当前用户接口 │ │ └── types.ts # 认证 API 与认证 Store 共用类型 │ ├── core/ # Admin 请求基础能力 @@ -18,6 +19,7 @@ src/api/ │ │ ├── shared-resources/ # System 共享资源接口 │ │ └── .ts # 其他 System 单资源接口 │ ├── workspace/ # 工作空间业务接口 +│ │ ├── conversation.ts # 调试对话、历史会话与语音接口 │ │ ├── application/ # 智能体接口 │ │ ├── knowledge/ # 知识库接口 │ │ ├── model/ # 模型接口 @@ -25,8 +27,12 @@ src/api/ │ │ ├── tool/ # 工具、工具工作流及工具商店接口 │ │ └── .ts # 工作空间公共资源接口 │ └── provider.ts # Workspace 与 System 共用的模型供应商接口 -├── chat/ # Chat 独立请求体系,当前预留 -│ └── README.md # Chat API 边界与后续实现说明 +├── chat/ # Chat 独立请求体系 +│ ├── core/request.ts # JSON 与流式请求 +│ ├── core/types.ts # Chat 请求协议类型 +│ ├── file.ts # Chat 文件上传、进度与取消 +│ ├── conversation.ts # 正式对话、历史会话与语音接口 +│ └── README.md # Chat API 边界说明 ├── enums/ # 后端固定枚举值 │ ├── index.ts # API 枚举值的唯一导入入口 │ └── .ts # 按明确业务域拆分的枚举值 @@ -342,3 +348,31 @@ API 对象和工作空间上下文,作为该抽屉的范围选择例外;用 `getRanking` 与 `exportRanking` 通过 `HomeRankingKind` 选择后端排行路径,名称及起止日期 筛选保持一致;分页使用 `ParamsPage` 与 `ResponsePage`。导出沿用 `getExportFile`。 工作空间总量接口返回数值,不与 System 首页的对象响应混用。 + +### 对话面板接口 + +`admin/workspace/conversation.ts` 集中维护调试对话的打开、发送、取消、续传、历史会话、 +记录分页、删除、修改和语音识别接口,保留可选 `applicationId` 对历史资源范围的选择。 +其中 `postSpeechToText(applicationId, data)` 请求指定智能体的 +`/workspace//application//speech_to_text`,loading 由调用方管理。 +`chat/conversation.ts` 维护正式对话对应的接口。两者使用各自 `core/request.ts` 的请求方法; +`postStream` 返回原始 `Response`,由 `conversation-panel/stream.ts` 解析。 + +面板内部的 `conversation-panel/common/get-api.ts` 通过 `ChatType` 选择完整 API 对象, +仅负责模式判断,不声明 URL 或发送请求;固定模式的 Store 直接导入对应业务 API。 +面板模式值统一维护在 `conversation-panel/common/enums.ts` 的 `CHAT_TYPE`, +`common/types.ts` 中的 `ChatType` 从该对象派生。 + +### 通用文件上传 + +`admin/file.ts` 与 `chat/file.ts` 分别提供 `postUploadFile(file, sourceId, sourceType, onProgress?)`, +通过各自请求客户端向 `/oss/file` 提交 FormData 的 `file`、`source_id` 和 `source_type`。 +返回值统一为 `{ request, abort }`,`request` 解包得到文件地址,`abort()` 中断客户端请求。 +普通上传直接等待 `request`,需要进度时传入 `(percent, event)`;只有能获取上传总量时才回调 +0–100 的百分比,100 表示请求体已上传,不代表服务端处理成功,完成状态以 `request` 为准。 +取消时 Promise 仍拒绝,由调用方处理状态,请求层不弹出通用错误提示;loading 由调用方在 +`finally` 中恢复。 + +资源类型使用 `@/api/enums` 的 `FILE_SOURCE_TYPE` 与 `@/api/types` 的 `FileSourceType`, +包括知识库、智能体、工具、文档、对话及三种临时文件有效期。对话 Store 使用 +`FILE_SOURCE_TYPE.CHAT` 调用对应 File API,对话 API 不再维护上传接口。 diff --git a/ui/src/api/admin/core/request.ts b/ui/src/api/admin/core/request.ts index e04e77d3a76..96c8ff6b44a 100644 --- a/ui/src/api/admin/core/request.ts +++ b/ui/src/api/admin/core/request.ts @@ -1,6 +1,6 @@ /** 提供 Admin API 的 Axios 实例与常用 HTTP 请求封装。 */ -import axios, { AxiosHeaders, type AxiosRequestConfig, type AxiosResponse, type InternalAxiosRequestConfig } from 'axios' +import axios, { AxiosHeaders, type AxiosRequestConfig, type AxiosResponse, type AxiosProgressEvent, type InternalAxiosRequestConfig } from 'axios' import router from '@/router/admin' import { useStore } from '@/stores' import type { ApiResponse } from './types' @@ -109,6 +109,10 @@ request.interceptors.response.use( return response }, async (error: unknown) => { + if (axios.isCancel(error)) { + return Promise.reject(error) + } + if (!axios.isAxiosError>(error)) { return Promise.reject(error) } @@ -214,4 +218,22 @@ export function del(url: string, params?: Dict(request.delete>(url, { params, data, timeout })) } +/** 上传文件,支持进度回调与取消,响应统一解包。 */ +export function postUpload(url: string, data: FormData, onProgress?: (percent: number, event: AxiosProgressEvent) => void) { + const controller = new AbortController() + const uploadRequest = promise( + request.post>(url, data, { + signal: controller.signal, + onUploadProgress: onProgress + ? (event) => { + if (event.total && event.total > 0) { + onProgress(Math.min(100, Math.max(0, Math.round((event.loaded / event.total) * 100))), event) + } + } + : undefined, + }), + ) + return { request: uploadRequest, abort: () => controller.abort() } +} + export default request diff --git a/ui/src/api/admin/file.ts b/ui/src/api/admin/file.ts new file mode 100644 index 00000000000..060a999559a --- /dev/null +++ b/ui/src/api/admin/file.ts @@ -0,0 +1,19 @@ +import type { AxiosProgressEvent } from 'axios' +import { postUpload } from './core/request' +import type { FileSourceType } from '@/api/types' + +/** 上传资源文件,支持可选的进度回调与取消操作。 */ +const postUploadFile = ( + file: File, + sourceId: string, + sourceType: FileSourceType, + onProgress?: (percent: number, event: AxiosProgressEvent) => void, +) => { + const formData = new FormData() + formData.append('file', file) + formData.append('source_id', sourceId) + formData.append('source_type', sourceType) + return postUpload('/oss/file', formData, onProgress) +} + +export default { postUploadFile } diff --git a/ui/src/api/admin/workspace/conversation.ts b/ui/src/api/admin/workspace/conversation.ts new file mode 100644 index 00000000000..9372c462e8b --- /dev/null +++ b/ui/src/api/admin/workspace/conversation.ts @@ -0,0 +1,73 @@ +import { get, post, put, del, postStream } from '../core/request' +import { getWorkspaceId } from '@/utils/resource-context' +import { ADMIN_API_BASE_PATH as adminApiBase } from '@/api/constants' + +/** 打开对话。 */ +const getConversationOpen = (applicationId: string) => get(`/workspace/${getWorkspaceId()}/application/${applicationId}/open`) + +/** 发送对话消息并返回原始流式响应。 */ +const postConversationMessage = (chatId: string, data: unknown, applicationId?: string) => + postStream(adminApiBase, `/workspace/${getWorkspaceId()}/application/${applicationId}/chat/${chatId}/chat_message`, data) + +/** 取消对话消息生成。 */ +const postCancelConversationMessage = (chatId: string, applicationId?: string) => + post(`/workspace/${getWorkspaceId()}/application/${applicationId}/chat/${chatId}/cancel_chat_message`, {}) + +/** 恢复对话消息流。 */ +const postResumeConversationMessage = (chatId: string, chatRecordId: string, applicationId?: string) => + postStream( + adminApiBase, + `/workspace/${getWorkspaceId()}/application/${applicationId}/chat/${chatId}/chat_record/${chatRecordId}/resume_chat_message`, + ) + +/** 获取历史会话分页。 */ +const getConversationPage = (page: number, size: number, applicationId?: string) => { + const wsId = getWorkspaceId() + if (applicationId) { + return get(`/workspace/${wsId}/application/${applicationId}/historical_conversation/${page}/${size}`) + } + return get(`/workspace/${wsId}/historical_conversation/${page}/${size}`) +} + +/** 获取会话记录分页。 */ +const getConversationRecordPage = (chatId: string, page: number, size: number, applicationId?: string) => { + const wsId = getWorkspaceId() + if (applicationId) { + return get(`/workspace/${wsId}/application/${applicationId}/historical_conversation_record/${chatId}/${page}/${size}`) + } + return get(`/workspace/${wsId}/historical_conversation_record/${chatId}/${page}/${size}`) +} + +/** 删除会话。 */ +const deleteConversation = (chatId: string, applicationId?: string) => { + const wsId = getWorkspaceId() + if (applicationId) { + return del(`/workspace/${wsId}/application/${applicationId}/historical_conversation/${chatId}`) + } + return del(`/workspace/${wsId}/historical_conversation/${chatId}`) +} + +/** 修改会话信息。 */ +const putConversation = (chatId: string, data: unknown, applicationId?: string) => { + const wsId = getWorkspaceId() + if (applicationId) { + return put(`/workspace/${wsId}/application/${applicationId}/historical_conversation/${chatId}`, data) + } + return put(`/workspace/${wsId}/historical_conversation/${chatId}`, data) +} + +/** 使用指定智能体将语音转换为文字。 */ +const postSpeechToText = (applicationId: string, data: unknown) => + post(`/workspace/${getWorkspaceId()}/application/${applicationId}/speech_to_text`, data) + +export default { + getConversationOpen, + postConversationMessage, + postCancelConversationMessage, + postResumeConversationMessage, + getConversationPage, + getConversationRecordPage, + deleteConversation, + putConversation, + postSpeechToText, +} diff --git a/ui/src/api/chat/README.md b/ui/src/api/chat/README.md index 77d0c102941..bd6a1e5a759 100644 --- a/ui/src/api/chat/README.md +++ b/ui/src/api/chat/README.md @@ -1,4 +1,15 @@ # Chat API -该目录预留给 Chat 应用的独立请求体系。Chat API 不复用 Admin 请求客户端;开始开发时, -在本目录内单独规划请求基础能力和业务接口。 +`core/request.ts` 提供独立的 Axios 客户端、JSON 响应解包和 `postStream` 流式请求, +不复用 Admin 请求客户端。当前 JSON 与流式请求均通过 `useStore()` 获取已有 token 和语言。 +流式请求返回原始 `Response`,由对话面板解析,不在请求层维护消息或 loading。 + +`conversation.ts` 维护正式对话的打开、发送、取消、续传、历史分页、记录分页、删除、修改、 +语音识别接口,默认导出完整 API 对象。调试对话接口位于 +`admin/workspace/conversation.ts`,面板模式选择位于 `conversation-panel/common/get-api.ts`。 + +接口命名、类型和请求约定统一遵循 `../API_README.md`。 + +`file.ts` 提供通用 `postUploadFile`,通过本应用的 `core/request.ts` 中 `postUpload` 支持 +可选进度回调及取消,统一返回 `{ request, abort }`。`request` 解包得到文件地址; +取消仍拒绝 Promise,但不弹出通用错误提示。loading 由调用方管理。 diff --git a/ui/src/api/chat/conversation.ts b/ui/src/api/chat/conversation.ts new file mode 100644 index 00000000000..c02f4dd5668 --- /dev/null +++ b/ui/src/api/chat/conversation.ts @@ -0,0 +1,42 @@ +import { get, post, put, del, postStream } from './core/request' +import { CHAT_API_BASE_PATH as chatApiBase } from '@/api/constants' + +/** 打开对话。 */ +const getConversationOpen = () => get('/open') + +/** 发送对话消息并返回原始流式响应。 */ +const postConversationMessage = (chatId: string, data: unknown) => postStream(chatApiBase, `/chat_message/${chatId}`, data) + +/** 取消对话消息生成。 */ +const postCancelConversationMessage = (chatId: string) => post(`/chat_message/${chatId}/cancel`, {}) + +/** 恢复对话消息流。 */ +const postResumeConversationMessage = (chatId: string, chatRecordId: string) => + postStream(chatApiBase, `/chat_message/${chatId}/resume/${chatRecordId}`) + +/** 获取历史会话分页。 */ +const getConversationPage = (page: number, size: number) => get(`/historical_conversation/${page}/${size}`) + +/** 获取会话记录分页。 */ +const getConversationRecordPage = (chatId: string, page: number, size: number) => get(`/historical_conversation_record/${chatId}/${page}/${size}`) + +/** 删除会话。 */ +const deleteConversation = (chatId: string) => del(`/historical_conversation/${chatId}`) + +/** 修改会话信息。 */ +const putConversation = (chatId: string, data: unknown) => put(`/historical_conversation/${chatId}`, data) + +/** 将语音转换为文字。 */ +const postSpeechToText = (data: unknown) => post('/speech_to_text', data) + +export default { + getConversationOpen, + postConversationMessage, + postCancelConversationMessage, + postResumeConversationMessage, + getConversationPage, + getConversationRecordPage, + deleteConversation, + putConversation, + postSpeechToText, +} diff --git a/ui/src/api/chat/core/request.ts b/ui/src/api/chat/core/request.ts index ff96cb9a62c..d49446e1cb6 100644 --- a/ui/src/api/chat/core/request.ts +++ b/ui/src/api/chat/core/request.ts @@ -1,6 +1,6 @@ /** 提供 Chat API 的 Axios 实例与常用 HTTP 请求封装。 */ -import axios, { AxiosHeaders, type AxiosResponse, type InternalAxiosRequestConfig } from 'axios' +import axios, { AxiosHeaders, type AxiosResponse, type AxiosProgressEvent, type InternalAxiosRequestConfig } from 'axios' import { useStore } from '@/stores' import type { ApiResponse } from './types' import type { Dict } from '@/api/types' @@ -55,6 +55,10 @@ request.interceptors.response.use( return response }, async (error: unknown) => { + if (axios.isCancel(error)) { + return Promise.reject(error) + } + if (!axios.isAxiosError>(error)) { return Promise.reject(error) } @@ -93,4 +97,39 @@ export function del(url: string, params?: Dict(request.delete>(url, { params, data, timeout })) } +/** 发送流式 POST 请求,返回原始 `Response` 供 SSE 读取。 */ +export function postStream(base: string, path: string, data?: unknown) { + const { auth, user } = useStore() + const headers: Record = { 'Content-Type': 'application/json' } + if (auth.token) { + headers['Authorization'] = `Bearer ${auth.token}` + } + if (user.language) { + headers['Accept-Language'] = user.language + } + return fetch(`${base}${path.startsWith('/') ? path : `/${path}`}`, { + method: 'POST', + headers, + body: data === undefined ? undefined : JSON.stringify(data), + }) +} + +/** 上传文件,支持进度回调与取消,响应统一解包。 */ +export function postUpload(url: string, data: FormData, onProgress?: (percent: number, event: AxiosProgressEvent) => void) { + const controller = new AbortController() + const uploadRequest = promise( + request.post>(url, data, { + signal: controller.signal, + onUploadProgress: onProgress + ? (event) => { + if (event.total && event.total > 0) { + onProgress(Math.min(100, Math.max(0, Math.round((event.loaded / event.total) * 100))), event) + } + } + : undefined, + }), + ) + return { request: uploadRequest, abort: () => controller.abort() } +} + export default request diff --git a/ui/src/api/chat/file.ts b/ui/src/api/chat/file.ts new file mode 100644 index 00000000000..060a999559a --- /dev/null +++ b/ui/src/api/chat/file.ts @@ -0,0 +1,19 @@ +import type { AxiosProgressEvent } from 'axios' +import { postUpload } from './core/request' +import type { FileSourceType } from '@/api/types' + +/** 上传资源文件,支持可选的进度回调与取消操作。 */ +const postUploadFile = ( + file: File, + sourceId: string, + sourceType: FileSourceType, + onProgress?: (percent: number, event: AxiosProgressEvent) => void, +) => { + const formData = new FormData() + formData.append('file', file) + formData.append('source_id', sourceId) + formData.append('source_type', sourceType) + return postUpload('/oss/file', formData, onProgress) +} + +export default { postUploadFile } diff --git a/ui/src/api/enums/file.ts b/ui/src/api/enums/file.ts new file mode 100644 index 00000000000..b21fd5764e1 --- /dev/null +++ b/ui/src/api/enums/file.ts @@ -0,0 +1,11 @@ +/** 文件上传的资源归属及临时文件有效期。 */ +export const FILE_SOURCE_TYPE = { + KNOWLEDGE: 'KNOWLEDGE', + APPLICATION: 'APPLICATION', + TOOL: 'TOOL', + DOCUMENT: 'DOCUMENT', + CHAT: 'CHAT', + TEMPORARY_30_MINUTE: 'TEMPORARY_30_MINUTE', + TEMPORARY_120_MINUTE: 'TEMPORARY_120_MINUTE', + TEMPORARY_1_DAY: 'TEMPORARY_1_DAY', +} as const diff --git a/ui/src/api/enums/index.ts b/ui/src/api/enums/index.ts index 7a8c1556992..b8481f79fb3 100644 --- a/ui/src/api/enums/index.ts +++ b/ui/src/api/enums/index.ts @@ -8,3 +8,4 @@ export * from './resource-authorization' export * from './tool' export * from './knowledge' export * from './trigger' +export * from './file' diff --git a/ui/src/api/types/file.ts b/ui/src/api/types/file.ts new file mode 100644 index 00000000000..5642593da34 --- /dev/null +++ b/ui/src/api/types/file.ts @@ -0,0 +1,3 @@ +import type { FILE_SOURCE_TYPE } from '@/api/enums' + +export type FileSourceType = (typeof FILE_SOURCE_TYPE)[keyof typeof FILE_SOURCE_TYPE] diff --git a/ui/src/api/types/index.ts b/ui/src/api/types/index.ts index 4fe18a1fc35..c4730c357fc 100644 --- a/ui/src/api/types/index.ts +++ b/ui/src/api/types/index.ts @@ -22,3 +22,4 @@ export type * from './workflow-version' export type * from './workflow-template' export type * from './homepage' +export type * from './file' diff --git a/ui/src/conversation-panel/api/index.ts b/ui/src/conversation-panel/api/index.ts deleted file mode 100644 index 7560c8a7d6c..00000000000 --- a/ui/src/conversation-panel/api/index.ts +++ /dev/null @@ -1,154 +0,0 @@ -/** - * 会话组件的请求封装。 - * - * 普通请求统一走各自应用的 core 请求客户端(admin:`@/api/admin/core/request`, - * chat:`@/api/chat/core/request`),返回已解包的业务数据。 - * 唯一的例外是流式对话:core 客户端基于 axios,无法读取 SSE 流,因此这里就地用 fetch - * 封装 `postStream`,返回原始 `Response` 交给 `ConversationStream` 解析。 - */ - -import { - get as adminGet, - post as adminPost, - put as adminPut, - del as adminDel, -} from '@/api/admin/core/request' -import { - get as chatGet, - post as chatPost, - put as chatPut, - del as chatDel, -} from '@/api/chat/core/request' -import { useStore } from '@/stores' -import { getWorkspaceId } from '@/utils/resource-context' -import { ADMIN_API_BASE_PATH as adminApiBase, CHAT_API_BASE_PATH as chatApiBase } from '@/api/constants' - -/** 发送流式 POST 请求,返回原始 `Response` 供 SSE 读取。 */ -function postStream(base: string, path: string, data?: unknown) { - const { auth, user } = useStore() - const headers: Record = { 'Content-Type': 'application/json' } - if (auth.token) { - headers['Authorization'] = `Bearer ${auth.token}` - } - if (user.language) { - headers['Accept-Language'] = user.language - } - return fetch(`${base}${path.startsWith('/') ? path : `/${path}`}`, { - method: 'POST', - headers, - body: data === undefined ? undefined : JSON.stringify(data), - }) -} - -export const debugApi = { - open: (applicationId: string) => - adminGet(`/workspace/${getWorkspaceId()}/application/${applicationId}/open`), - - chat: (chatId: string, data: any, applicationId?: string) => - postStream( - adminApiBase, - `/workspace/${getWorkspaceId()}/application/${applicationId}/chat/${chatId}/chat_message`, - data, - ), - - cancelChat: (chatId: string, applicationId?: string) => - adminPost( - `/workspace/${getWorkspaceId()}/application/${applicationId}/chat/${chatId}/cancel_chat_message`, - {}, - ), - - resumeStream: (chatId: string, chatRecordId: string, applicationId?: string) => - postStream( - adminApiBase, - `/workspace/${getWorkspaceId()}/application/${applicationId}/chat/${chatId}/chat_record/${chatRecordId}/resume_chat_message`, - ), - - history: (page: number, size: number, applicationId?: string) => { - const wsId = getWorkspaceId() - if (applicationId) { - return adminGet( - `/workspace/${wsId}/application/${applicationId}/historical_conversation/${page}/${size}`, - ) - } - return adminGet(`/workspace/${wsId}/historical_conversation/${page}/${size}`) - }, - - records: (chatId: string, page: number, size: number, applicationId?: string) => { - const wsId = getWorkspaceId() - if (applicationId) { - return adminGet( - `/workspace/${wsId}/application/${applicationId}/historical_conversation_record/${chatId}/${page}/${size}`, - ) - } - return adminGet(`/workspace/${wsId}/historical_conversation_record/${chatId}/${page}/${size}`) - }, - - deleteChat: (chatId: string, applicationId?: string) => { - const wsId = getWorkspaceId() - if (applicationId) { - return adminDel( - `/workspace/${wsId}/application/${applicationId}/historical_conversation/${chatId}`, - ) - } - return adminDel(`/workspace/${wsId}/historical_conversation/${chatId}`) - }, - - modifyChat: (chatId: string, data: any, applicationId?: string) => { - const wsId = getWorkspaceId() - if (applicationId) { - return adminPut( - `/workspace/${wsId}/application/${applicationId}/historical_conversation/${chatId}`, - data, - ) - } - return adminPut(`/workspace/${wsId}/historical_conversation/${chatId}`, data) - }, - - uploadFile: (file: File, chatId: string) => { - const fd = new FormData() - fd.append('file', file) - fd.append('source_id', chatId) - fd.append('source_type', 'CHAT') - return adminPost('/oss/file', fd) - }, - - speechToText: (data: any) => adminPost('/speech_to_text', data), -} - -export const chatApi = { - open: () => chatGet('/open'), - - chat: (chatId: string, data: any) => postStream(chatApiBase, `/chat_message/${chatId}`, data), - - cancelChat: (chatId: string) => chatPost(`/chat_message/${chatId}/cancel`, {}), - - resumeStream: (chatId: string, chatRecordId: string) => - postStream(chatApiBase, `/chat_message/${chatId}/resume/${chatRecordId}`), - - history: (page: number, size: number) => - chatGet(`/historical_conversation/${page}/${size}`), - - records: (chatId: string, page: number, size: number) => - chatGet(`/historical_conversation_record/${chatId}/${page}/${size}`), - - deleteChat: (chatId: string) => chatDel(`/historical_conversation/${chatId}`), - - modifyChat: (chatId: string, data: any) => - chatPut(`/historical_conversation/${chatId}`, data), - - uploadFile: (file: File, chatId: string) => { - const fd = new FormData() - fd.append('file', file) - fd.append('source_id', chatId) - fd.append('source_type', 'CHAT') - return chatPost('/oss/file', fd) - }, - - speechToText: (data: any) => chatPost('/speech_to_text', data), -} - -export type ChatType = 'CHAT' | 'DEBUG' - -export function getApi(type: ChatType) { - return type === 'DEBUG' ? debugApi : chatApi -} diff --git a/ui/src/conversation-panel/chat-panel/index.vue b/ui/src/conversation-panel/chat-panel/index.vue index 22d54dd57ee..9192e8c686c 100644 --- a/ui/src/conversation-panel/chat-panel/index.vue +++ b/ui/src/conversation-panel/chat-panel/index.vue @@ -236,6 +236,7 @@