diff --git a/README.md b/README.md index 30bbe022490..2acab933241 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ https://github.com/labring/FastGPT/assets/15308462/7d3a38df-eb0e-4388-9250-2409b `4` OpenAPI 接口 - [x] completions 接口 (chat 模式对齐 GPT 接口) - [x] 知识库 CRUD - - [ ] 对话 CRUD + - [x] 对话 CRUD `5` 运营能力 - [x] 免登录分享窗口 diff --git a/docSite/content/zh-cn/docs/development/configuration.md b/docSite/content/zh-cn/docs/development/configuration.md index 82ace2bfb2f..65924f7e505 100644 --- a/docSite/content/zh-cn/docs/development/configuration.md +++ b/docSite/content/zh-cn/docs/development/configuration.md @@ -227,6 +227,27 @@ weight: 708 } ``` +### ReRank 接入(硅基流动) + +有免费的 `bge-reranker-v2-m3` 模型可以使用。 + +1. 注册硅基流动账号: https://siliconflow.cn/ +2. 进入控制台,获取 API key: https://cloud.siliconflow.cn/account/ak +3. 修改 FastGPT 配置文件 + +```json +{ + "reRankModels": [ + { + "model": "BAAI/bge-reranker-v2-m3", // 这里的model需要对应 siliconflow 的模型名 + "name": "BAAI/bge-reranker-v2-m3", + "requestUrl": "https://api.siliconflow.cn/v1/rerank", + "requestAuth": "siliconflow 上申请的 key" + } + ] +} +``` + ### ReRank 接入(Cohere) 这个重排模型对中文不是很好,不如 bge 的好用。 @@ -239,7 +260,7 @@ weight: 708 "reRankModels": [ { "model": "rerank-multilingual-v2.0", // 这里的model需要对应 cohere 的模型名 - "name": "检索重排", // 随意 + "name": "rerank-multilingual-v2.0", "requestUrl": "https://api.cohere.ai/v1/rerank", "requestAuth": "Coherer上申请的key" } diff --git a/docSite/content/zh-cn/docs/development/openapi/chat.md b/docSite/content/zh-cn/docs/development/openapi/chat.md index 85fbb31ee60..db931fe0847 100644 --- a/docSite/content/zh-cn/docs/development/openapi/chat.md +++ b/docSite/content/zh-cn/docs/development/openapi/chat.md @@ -7,13 +7,15 @@ toc: true weight: 852 --- +# 发起对话 + {{% alert icon="🤖 " context="success" %}} * 该接口的 API Key 需使用`应用特定的 key`,否则会报错。 * 有些包调用时,`BaseUrl`需要添加`v1`路径,有些不需要,如果出现404情况,可补充`v1`重试。 {{% /alert %}} -## 发起对话(简易应用和工作流) +## 请求简易应用和工作流 对话接口兼容`GPT`的接口!如果你的项目使用的是标准的`GPT`官方接口,可以直接通过修改`BaseUrl`和 `Authorization`来访问 FastGpt 应用,不过需要注意下面几个规则: @@ -24,12 +26,12 @@ weight: 852 ### 请求 -{{< tabs tabTotal="2" >}} -{{< tab tabName="请求示例" >}} +{{< tabs tabTotal="3" >}} +{{< tab tabName="基础请求示例" >}} {{< markdownify >}} ```bash -curl --location --request POST 'https://api.fastgpt.in/api/v1/chat/completions' \ +curl --location --request POST 'http://localhost:3000/api/v1/chat/completions' \ --header 'Authorization: Bearer fastgpt-xxxxxx' \ --header 'Content-Type: application/json' \ --data-raw '{ @@ -42,8 +44,49 @@ curl --location --request POST 'https://api.fastgpt.in/api/v1/chat/completions' }, "messages": [ { + "role": "user", "content": "导演是谁", - "role": "user" + } + ] +}' +``` + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="图片/文件请求示例" >}} +{{< markdownify >}} + +* 仅`messages`有部分区别,其他参数一致。 +* 目前不支持上次文件,需上传到自己的对象存储中,获取对应的文件链接。 + +```bash +curl --location --request POST 'http://localhost:3000/api/v1/chat/completions' \ +--header 'Authorization: Bearer fastgpt-xxxxxx' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "chatId": "abcd", + "stream": false, + "messages": [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "导演是谁" + }, + { + "type": "image_url", + "image_url": { + "url": "图片链接" + } + }, + { + "type": "file_url", + "name": "文件名", + "url": "文档链接,支持 txt md html word pdf ppt csv excel" + } + ] } ] }' @@ -269,7 +312,6 @@ event取值: {{< /tabs >}} - ## 请求插件 插件的接口与对话接口一致,仅请求参数略有区别,有以下规定: @@ -455,8 +497,728 @@ event取值: {{< /tab >}} {{< /tabs >}} -## 使用案例 -- [接入 NextWeb/ChatGPT web 等应用](/docs/course/openapi) -- [接入 onwechat](/docs/use-cases/onwechat) -- [接入 飞书](/docs/course/feishu) \ No newline at end of file + +# 对话 CRUD + +{{% alert icon="🤖 " context="success" %}} +* 以下接口可使用任意`API Key`调用。 +* 4.8.12 以上版本才能使用 +{{% /alert %}} + +**重要字段** + +* chatId - 指一个应用下,某一个对话窗口的 ID +* dataId - 指一个对话窗口下,某一个对话记录的 ID + +## 历史记录 + +### 获取某个应用历史记录 + +{{< tabs tabTotal="3" >}} +{{< tab tabName="请求示例" >}} +{{< markdownify >}} + +```bash +curl --location --request POST 'http://localhost:3000/api/core/chat/getHistories' \ +--header 'Authorization: Bearer {{apikey}}' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "appId": "appId", + "offset": 0, + "pageSize": 20 +}' +``` + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="参数说明" >}} +{{< markdownify >}} + +{{% alert icon=" " context="success" %}} +- appId - 应用 Id +- offset - 偏移量,即从第几条数据开始取 +- pageSize - 记录数量 +{{% /alert %}} + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="响应示例" >}} +{{< markdownify >}} + +```json +{ + "code": 200, + "statusText": "", + "message": "", + "data": { + "list": [ + { + "chatId": "usdAP1GbzSGu", + "updateTime": "2024-10-13T03:29:05.779Z", + "appId": "66e29b870b24ce35330c0f08", + "customTitle": "", + "title": "你好", + "top": false + }, + { + "chatId": "lC0uTAsyNBlZ", + "updateTime": "2024-10-13T03:22:19.950Z", + "appId": "66e29b870b24ce35330c0f08", + "customTitle": "", + "title": "测试", + "top": false + } + ], + "total": 2 + } +} +``` + +{{< /markdownify >}} +{{< /tab >}} +{{< /tabs >}} + +### 修改某个对话的标题 + +{{< tabs tabTotal="3" >}} +{{< tab tabName="请求示例" >}} +{{< markdownify >}} + +```bash +curl --location --request POST 'http://localhost:3000/api/core/chat/updateHistory' \ +--header 'Authorization: Bearer {{apikey}}' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "appId": "appId", + "chatId": "chatId", + "customTitle": "自定义标题" +}' +``` + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="参数说明" >}} +{{< markdownify >}} + +{{% alert icon=" " context="success" %}} +- appId - 应用 Id +- chatId - 历史记录 Id +- customTitle - 自定义对话名 +{{% /alert %}} + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="响应示例" >}} +{{< markdownify >}} + +```json +{ + "code": 200, + "statusText": "", + "message": "", + "data": null +} +``` + +{{< /markdownify >}} +{{< /tab >}} +{{< /tabs >}} + +### 置顶 / 取消置顶 +{{< tabs tabTotal="3" >}} +{{< tab tabName="请求示例" >}} +{{< markdownify >}} + +```bash +curl --location --request POST 'http://localhost:3000/api/core/chat/updateHistory' \ +--header 'Authorization: Bearer {{apikey}}' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "appId": "appId", + "chatId": "chatId", + "top": true +}' +``` + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="参数说明" >}} +{{< markdownify >}} + +{{% alert icon=" " context="success" %}} +- appId - 应用Id +- chatId - 历史记录 Id +- top - 是否置顶,ture 置顶,false 取消置顶 +{{% /alert %}} + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="响应示例" >}} +{{< markdownify >}} + +```json +{ + "code": 200, + "statusText": "", + "message": "", + "data": null +} +``` + +{{< /markdownify >}} +{{< /tab >}} +{{< /tabs >}} + +### 删除某个历史记录 + +{{< tabs tabTotal="3" >}} +{{< tab tabName="请求示例" >}} +{{< markdownify >}} + +```bash +curl --location --request DELETE 'http://localhost:3000/api/core/chat/delHistory?chatId={{chatId}}&appId={{appId}}' \ +--header 'Authorization: Bearer {{apikey}}' +``` + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="参数说明" >}} +{{< markdownify >}} + +{{% alert icon=" " context="success" %}} +- appId - 应用 Id +- chatId - 历史记录 Id +{{% /alert %}} + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="响应示例" >}} +{{< markdownify >}} + +```json +{ + "code": 200, + "statusText": "", + "message": "", + "data": null +} +``` + +{{< /markdownify >}} +{{< /tab >}} +{{< /tabs >}} + +### 清空所有历史记录 + +{{< tabs tabTotal="3" >}} +{{< tab tabName="请求示例" >}} +{{< markdownify >}} + +```bash +curl --location --request DELETE 'http://localhost:3000/api/core/chat/clearHistories?appId={{appId}}' \ +--header 'Authorization: Bearer {{apikey}}' +``` + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="参数说明" >}} +{{< markdownify >}} + +{{% alert icon=" " context="success" %}} +- appId - 应用 Id +{{% /alert %}} + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="响应示例" >}} +{{< markdownify >}} + +```json +{ + "code": 200, + "statusText": "", + "message": "", + "data": null +} +``` + +{{< /markdownify >}} +{{< /tab >}} +{{< /tabs >}} + +## 对话记录 + +指的是某个 chatId 下的对话记录操作。 + +### 获取单个对话初始化信息 + +{{< tabs tabTotal="3" >}} +{{< tab tabName="请求示例" >}} +{{< markdownify >}} + +```bash +curl --location --request GET 'http://localhost:3000/api/core/chat/init?appId={{appId}}&chatId={{chatId}}' \ +--header 'Authorization: Bearer {{apikey}}' +``` +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="参数说明" >}} +{{< markdownify >}} + +{{% alert icon=" " context="success" %}} +- appId - 应用 Id +- chatId - 历史记录 Id +{{% /alert %}} + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="响应示例" >}} +{{< markdownify >}} +```json +{ + "code": 200, + "statusText": "", + "message": "", + "data": { + "chatId": "sPVOuEohjo3w", + "appId": "66e29b870b24ce35330c0f08", + "variables": { + + }, + "app": { + "chatConfig": { + "questionGuide": true, + "ttsConfig": { + "type": "web" + }, + "whisperConfig": { + "open": false, + "autoSend": false, + "autoTTSResponse": false + }, + "chatInputGuide": { + "open": false, + "textList": [ + + ], + "customUrl": "" + }, + "instruction": "", + "variables": [ + + ], + "fileSelectConfig": { + "canSelectFile": true, + "canSelectImg": true, + "maxFiles": 10 + }, + "_id": "66f1139aaab9ddaf1b5c596d", + "welcomeText": "" + }, + "chatModels": [ + "GPT-4o-mini" + ], + "name": "测试", + "avatar": "/imgs/app/avatar/workflow.svg", + "intro": "", + "type": "advanced", + "pluginInputs": [ + + ] + } + } +} +``` + +{{< /markdownify >}} +{{< /tab >}} +{{< /tabs >}} + +### 获取对话记录列表 + +{{< tabs tabTotal="3" >}} +{{< tab tabName="请求示例" >}} +{{< markdownify >}} + +```bash +curl --location --request POST 'http://localhost:3000/api/core/chat/getPaginationRecords' \ +--header 'Authorization: Bearer {{apikey}}' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "appId": "appId", + "chatId": "chatId", + "offset": 0, + "pageSize": 10, + "loadCustomFeedbacks": true +}' +``` + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="参数说明" >}} +{{< markdownify >}} + +{{% alert icon=" " context="success" %}} +- appId - 应用 Id +- chatId - 历史记录 Id +- offset - 偏移量 +- pageSize - 记录数量 +- loadCustomFeedbacks - 是否读取自定义反馈(可选) +{{% /alert %}} + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="响应示例" >}} +{{< markdownify >}} + +```json +{ + "code": 200, + "statusText": "", + "message": "", + "data": { + "list": [ + { + "_id": "670b84e6796057dda04b0fd2", + "dataId": "jzqdV4Ap1u004rhd2WW8yGLn", + "obj": "Human", + "value": [ + { + "type": "text", + "text": { + "content": "你好" + } + } + ], + "customFeedbacks": [ + + ] + }, + { + "_id": "670b84e6796057dda04b0fd3", + "dataId": "x9KQWcK9MApGdDQH7z7bocw1", + "obj": "AI", + "value": [ + { + "type": "text", + "text": { + "content": "你好!有什么我可以帮助你的吗?" + } + } + ], + "customFeedbacks": [ + + ], + "llmModuleAccount": 1, + "totalQuoteList": [ + + ], + "totalRunningTime": 2.42, + "historyPreviewLength": 2 + } + ], + "total": 2 + } +} +``` + +{{< /markdownify >}} +{{< /tab >}} +{{< /tabs >}} + +### 获取单个对话记录运行详情 + +{{< tabs tabTotal="3" >}} +{{< tab tabName="请求示例" >}} +{{< markdownify >}} + +```bash +curl --location --request GET 'http://localhost:3000/api/core/chat/getResData?appId={{appId}}&chatId={{chatId}}&dataId={{dataId}}' \ +--header 'Authorization: Bearer {{apikey}}' +``` + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="参数说明" >}} +{{< markdownify >}} + +{{% alert icon=" " context="success" %}} +- appId - 应用 Id +- chatId - 对话 Id +- dataId - 对话记录 Id +{{% /alert %}} + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="响应示例" >}} +{{< markdownify >}} + +```json +{ + "code": 200, + "statusText": "", + "message": "", + "data": [ + { + "id": "mVlxkz8NfyfU", + "nodeId": "448745", + "moduleName": "common:core.module.template.work_start", + "moduleType": "workflowStart", + "runningTime": 0 + }, + { + "id": "b3FndAdHSobY", + "nodeId": "z04w8JXSYjl3", + "moduleName": "AI 对话", + "moduleType": "chatNode", + "runningTime": 1.22, + "totalPoints": 0.02475, + "model": "GPT-4o-mini", + "tokens": 75, + "query": "测试", + "maxToken": 2000, + "historyPreview": [ + { + "obj": "Human", + "value": "你好" + }, + { + "obj": "AI", + "value": "你好!有什么我可以帮助你的吗?" + }, + { + "obj": "Human", + "value": "测试" + }, + { + "obj": "AI", + "value": "测试成功!请问你有什么具体的问题或者需要讨论的话题吗?" + } + ], + "contextTotalLen": 4 + } + ] +} +``` + +{{< /markdownify >}} +{{< /tab >}} +{{< /tabs >}} + + +### 删除对话记录 + +{{< tabs tabTotal="3" >}} +{{< tab tabName="请求示例" >}} +{{< markdownify >}} + +```bash +curl --location --request DELETE 'http://localhost:3000/api/core/chat/item/delete?contentId={{contentId}}&chatId={{chatId}}&appId={{appId}}' \ +--header 'Authorization: Bearer {{apikey}}' +``` + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="参数说明" >}} +{{< markdownify >}} + +{{% alert icon=" " context="success" %}} +- appId - 应用 Id +- chatId - 历史记录 Id +- contentId - 对话记录 Id +{{% /alert %}} + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="响应示例" >}} +{{< markdownify >}} + +```json +{ + "code": 200, + "statusText": "", + "message": "", + "data": null +} +``` + +{{< /markdownify >}} +{{< /tab >}} +{{< /tabs >}} + +### 点赞 / 取消点赞 + +{{< tabs tabTotal="3" >}} +{{< tab tabName="请求示例" >}} +{{< markdownify >}} + +```bash +curl --location --request POST 'http://localhost:3000/api/core/chat/feedback/updateUserFeedback' \ +--header 'Authorization: Bearer {{apikey}}' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "appId": "appId", + "chatId": "chatId", + "dataId": "dataId", + "userGoodFeedback": "yes" +}' +``` + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="参数说明" >}} +{{< markdownify >}} + +{{% alert icon=" " context="success" %}} +- appId - 应用 Id +- chatId - 历史记录 Id +- dataId - 对话记录 Id +- userGoodFeedback - 用户点赞时的信息(可选),取消点赞时不填此参数即可 +{{% /alert %}} + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="响应示例" >}} +{{< markdownify >}} + +```json +{ + "code": 200, + "statusText": "", + "message": "", + "data": null +} +``` + +{{< /markdownify >}} +{{< /tab >}} +{{< /tabs >}} + +### 点踩 / 取消点踩 + +{{< tabs tabTotal="3" >}} +{{< tab tabName="请求示例" >}} +{{< markdownify >}} + +```bash +curl --location --request POST 'http://localhost:3000/api/core/chat/feedback/updateUserFeedback' \ +--header 'Authorization: Bearer {{apikey}}' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "appId": "appId", + "chatId": "chatId", + "dataId": "dataId", + "userBadFeedback": "yes" +}' +``` + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="参数说明" >}} +{{< markdownify >}} + +{{% alert icon=" " context="success" %}} +- appId - 应用 Id +- chatId - 历史记录 Id +- dataId - 对话记录 Id +- userBadFeedback - 用户点踩时的信息(可选),取消点踩时不填此参数即可 +{{% /alert %}} + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="响应示例" >}} +{{< markdownify >}} + +```json +{ + "code": 200, + "statusText": "", + "message": "", + "data": null +} +``` +{{< /markdownify >}} +{{< /tab >}} +{{< /tabs >}} + +## 猜你想问 + +{{< tabs tabTotal="3" >}} +{{< tab tabName="请求示例" >}} +{{< markdownify >}} + +```bash +curl --location --request POST 'http://localhost:3000/api/core/ai/agent/createQuestionGuide' \ +--header 'Authorization: Bearer {{apikey}}' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "messages":[ + { + "role": "user", + "content": "你好" + }, + { + "role": "assistant", + "content": "你好!有什么我可以帮助你的吗?" + } + ] +}' +``` + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="参数说明" >}} +{{< markdownify >}} + +{{% alert icon=" " context="success" %}} +- messages - 对话消息,提供给 AI 的消息记录 +{{% /alert %}} + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="响应示例" >}} +{{< markdownify >}} + +```json +{ + "code": 200, + "statusText": "", + "message": "", + "data": [ + "你对AI有什么看法?", + "想了解AI的应用吗?", + "你希望AI能做什么?" + ] +} +``` +{{< /markdownify >}} +{{< /tab >}} +{{< /tabs >}} + + + diff --git a/docSite/content/zh-cn/docs/development/openapi/dataset.md b/docSite/content/zh-cn/docs/development/openapi/dataset.md index 8f059053b0a..a6a69c1fd11 100644 --- a/docSite/content/zh-cn/docs/development/openapi/dataset.md +++ b/docSite/content/zh-cn/docs/development/openapi/dataset.md @@ -22,7 +22,7 @@ weight: 853 **新例子** ```bash -curl --location --request POST 'https://api.fastgpt.in/api/support/wallet/usage/createTrainingUsage' \ +curl --location --request POST 'http://localhost:3000/api/support/wallet/usage/createTrainingUsage' \ --header 'Authorization: Bearer {{apikey}}' \ --header 'Content-Type: application/json' \ --data-raw '{ @@ -34,7 +34,7 @@ curl --location --request POST 'https://api.fastgpt.in/api/support/wallet/usage/ **x例子** ```bash -curl --location --request POST 'https://api.fastgpt.in/api/support/wallet/bill/createTrainingBill' \ +curl --location --request POST 'http://localhost:3000/api/support/wallet/bill/createTrainingBill' \ --header 'Authorization: Bearer {{apikey}}' \ --header 'Content-Type: application/json' \ --data-raw '{ diff --git a/packages/global/core/chat/api.d.ts b/packages/global/core/chat/api.d.ts index ee3d1ef34c7..4646d908370 100644 --- a/packages/global/core/chat/api.d.ts +++ b/packages/global/core/chat/api.d.ts @@ -1,7 +1,7 @@ export type UpdateChatFeedbackProps = { appId: string; chatId: string; - chatItemId: string; + dataId: string; shareId?: string; teamId?: string; teamToken?: string; diff --git a/packages/global/core/chat/type.d.ts b/packages/global/core/chat/type.d.ts index 0cdcc1db201..da55c5365e6 100644 --- a/packages/global/core/chat/type.d.ts +++ b/packages/global/core/chat/type.d.ts @@ -100,7 +100,7 @@ export type ChatItemSchema = (UserChatItemType | SystemChatItemType | AIChatItem }; export type AdminFbkType = { - dataId: string; + feedbackDataId: string; datasetId: string; collectionId: string; q: string; diff --git a/packages/service/core/chat/controller.ts b/packages/service/core/chat/controller.ts index 458c7eb0053..1c5bbaadc13 100644 --- a/packages/service/core/chat/controller.ts +++ b/packages/service/core/chat/controller.ts @@ -55,22 +55,22 @@ export const adaptStringValue = (value: any): ChatItemValueItemType[] => { export const addCustomFeedbacks = async ({ appId, chatId, - chatItemId, + dataId, feedbacks }: { appId: string; chatId?: string; - chatItemId?: string; + dataId?: string; feedbacks: string[]; }) => { - if (!chatId || !chatItemId) return; + if (!chatId || !dataId) return; try { await MongoChatItem.findOneAndUpdate( { appId, chatId, - dataId: chatItemId + dataId }, { $push: { customFeedbacks: { $each: feedbacks } } diff --git a/packages/service/core/workflow/dispatch/tools/customFeedback.ts b/packages/service/core/workflow/dispatch/tools/customFeedback.ts index a4a46833a57..feb3ff19ccd 100644 --- a/packages/service/core/workflow/dispatch/tools/customFeedback.ts +++ b/packages/service/core/workflow/dispatch/tools/customFeedback.ts @@ -17,7 +17,7 @@ export const dispatchCustomFeedback = (props: Record): Response => const { runningAppInfo: { id: appId }, chatId, - responseChatItemId: chatItemId, + responseChatItemId: dataId, stream, workflowStreamResponse, params: { system_textareaInput: feedbackText = '' } @@ -27,13 +27,13 @@ export const dispatchCustomFeedback = (props: Record): Response => addCustomFeedbacks({ appId, chatId, - chatItemId, + dataId, feedbacks: [feedbackText] }); }, 60000); if (stream) { - if (!chatId || !chatItemId) { + if (!chatId || !dataId) { workflowStreamResponse?.({ event: SseResponseEventEnum.fastAnswer, data: textAdaptGptResponse({ diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/FeedbackModal.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/FeedbackModal.tsx index f159c9b3ebb..f62ffd40371 100644 --- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/FeedbackModal.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/FeedbackModal.tsx @@ -8,7 +8,7 @@ import { updateChatUserFeedback } from '@/web/core/chat/api'; const FeedbackModal = ({ appId, chatId, - chatItemId, + dataId, teamId, teamToken, shareId, @@ -18,7 +18,7 @@ const FeedbackModal = ({ }: { appId: string; chatId: string; - chatItemId: string; + dataId: string; shareId?: string; teamId?: string; teamToken?: string; @@ -35,7 +35,7 @@ const FeedbackModal = ({ return updateChatUserFeedback({ appId, chatId, - chatItemId, + dataId, shareId, teamId, teamToken, diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/SelectMarkCollection.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/SelectMarkCollection.tsx index 00d679d6a23..be059f96595 100644 --- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/SelectMarkCollection.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/SelectMarkCollection.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React from 'react'; import { ModalBody, useTheme, ModalFooter, Button, Box, Card, Flex, Grid } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; import Avatar from '@fastgpt/web/components/common/Avatar'; @@ -13,7 +13,7 @@ import EmptyTip from '@fastgpt/web/components/common/EmptyTip'; const InputDataModal = dynamic(() => import('@/pages/dataset/detail/components/InputDataModal')); export type AdminMarkType = { - dataId?: string; + feedbackDataId?: string; datasetId?: string; collectionId?: string; q: string; @@ -137,7 +137,7 @@ const SelectMarkCollection = ({ }); }} collectionId={adminMarkData.collectionId} - dataId={adminMarkData.dataId} + dataId={adminMarkData.feedbackDataId} defaultValue={{ q: adminMarkData.q, a: adminMarkData.a @@ -153,7 +153,7 @@ const SelectMarkCollection = ({ } onSuccess({ - dataId: data.dataId, + feedbackDataId: data.dataId, datasetId: adminMarkData.datasetId, collectionId: adminMarkData.collectionId, q: data.q, diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx index e00bac7b52c..eadc1a2a8fe 100644 --- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx @@ -142,10 +142,10 @@ const ChatBox = ( const [feedbackId, setFeedbackId] = useState(); const [readFeedbackData, setReadFeedbackData] = useState<{ - chatItemId: string; + dataId: string; content: string; }>(); - const [adminMarkData, setAdminMarkData] = useState(); + const [adminMarkData, setAdminMarkData] = useState(); const [questionGuides, setQuestionGuide] = useState([]); const { @@ -660,16 +660,16 @@ const ChatBox = ( if (chat.adminFeedback) { setAdminMarkData({ - chatItemId: chat.dataId, + dataId: chat.dataId, datasetId: chat.adminFeedback.datasetId, collectionId: chat.adminFeedback.collectionId, - dataId: chat.adminFeedback.dataId, + feedbackDataId: chat.adminFeedback.feedbackDataId, q: chat.adminFeedback.q || q || '', a: chat.adminFeedback.a }); } else { setAdminMarkData({ - chatItemId: chat.dataId, + dataId: chat.dataId, q, a: formatChatValue2InputType(chat.value).text }); @@ -703,7 +703,7 @@ const ChatBox = ( chatId, teamId, teamToken, - chatItemId: chat.dataId, + dataId: chat.dataId, shareId, outLinkUid, userGoodFeedback: isGoodFeedback ? undefined : 'yes' @@ -725,7 +725,7 @@ const ChatBox = ( teamId, teamToken, chatId, - chatItemId: chat.dataId, + dataId: chat.dataId, userGoodFeedback: undefined }); }; @@ -750,7 +750,7 @@ const ChatBox = ( updateChatUserFeedback({ appId, chatId, - chatItemId: chat.dataId, + dataId: chat.dataId, shareId, teamId, teamToken, @@ -767,7 +767,7 @@ const ChatBox = ( return () => { if (!chat.dataId) return; setReadFeedbackData({ - chatItemId: chat.dataId || '', + dataId: chat.dataId || '', content: chat.userBadFeedback || '' }); }; @@ -778,7 +778,7 @@ const ChatBox = ( closeCustomFeedback({ appId, chatId, - chatItemId: chat.dataId, + dataId: chat.dataId, index: i }); // update dom @@ -945,7 +945,7 @@ const ChatBox = ( text={t('common:core.app.feedback.Custom feedback')} /> {item.customFeedbacks.map((text, i) => ( - + @@ -1035,7 +1035,7 @@ const ChatBox = ( teamId={teamId} teamToken={teamToken} chatId={chatId} - chatItemId={feedbackId} + dataId={feedbackId} shareId={shareId} outLinkUid={outLinkUid} onClose={() => setFeedbackId(undefined)} @@ -1057,7 +1057,7 @@ const ChatBox = ( onCloseFeedback={() => { setChatHistories((state) => state.map((chatItem) => - chatItem.dataId === readFeedbackData.chatItemId + chatItem.dataId === readFeedbackData.dataId ? { ...chatItem, userBadFeedback: undefined } : chatItem ) @@ -1067,7 +1067,7 @@ const ChatBox = ( updateChatUserFeedback({ appId, chatId, - chatItemId: readFeedbackData.chatItemId + dataId: readFeedbackData.dataId }); } catch (error) {} setReadFeedbackData(undefined); @@ -1078,21 +1078,21 @@ const ChatBox = ( {!!adminMarkData && ( setAdminMarkData({ ...e, chatItemId: adminMarkData.chatItemId })} + setAdminMarkData={(e) => setAdminMarkData({ ...e, dataId: adminMarkData.dataId })} onClose={() => setAdminMarkData(undefined)} onSuccess={(adminFeedback) => { - if (!appId || !chatId || !adminMarkData.chatItemId) return; + if (!appId || !chatId || !adminMarkData.dataId) return; updateChatAdminFeedback({ appId, chatId, - chatItemId: adminMarkData.chatItemId, + dataId: adminMarkData.dataId, ...adminFeedback }); // update dom setChatHistories((state) => state.map((chatItem) => - chatItem.dataId === adminMarkData.chatItemId + chatItem.dataId === adminMarkData.dataId ? { ...chatItem, adminFeedback @@ -1105,12 +1105,12 @@ const ChatBox = ( updateChatUserFeedback({ appId, chatId, - chatItemId: readFeedbackData.chatItemId, + dataId: readFeedbackData.dataId, userBadFeedback: undefined }); setChatHistories((state) => state.map((chatItem) => - chatItem.dataId === readFeedbackData.chatItemId + chatItem.dataId === readFeedbackData.dataId ? { ...chatItem, userBadFeedback: undefined } : chatItem ) diff --git a/projects/app/src/global/core/chat/api.d.ts b/projects/app/src/global/core/chat/api.d.ts index c3ba36701e2..9f016e9c5ef 100644 --- a/projects/app/src/global/core/chat/api.d.ts +++ b/projects/app/src/global/core/chat/api.d.ts @@ -84,12 +84,12 @@ export type DeleteChatItemProps = OutLinkChatAuthProps & { export type AdminUpdateFeedbackParams = AdminFbkType & { appId: string; chatId: string; - chatItemId: string; + dataId: string; }; export type CloseCustomFeedbackParams = { appId: string; chatId: string; - chatItemId: string; + dataId: string; index: number; }; diff --git a/projects/app/src/pages/api/core/ai/agent/createQuestionGuide.ts b/projects/app/src/pages/api/core/ai/agent/createQuestionGuide.ts index d34de5abdbd..6c86d3f5f76 100644 --- a/projects/app/src/pages/api/core/ai/agent/createQuestionGuide.ts +++ b/projects/app/src/pages/api/core/ai/agent/createQuestionGuide.ts @@ -13,7 +13,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< const { tmbId, teamId } = await authChatCert({ req, - authToken: true + authToken: true, + authApiKey: true }); const qgModel = global.llmModels[0]; diff --git a/projects/app/src/pages/api/core/chat/clearHistories.ts b/projects/app/src/pages/api/core/chat/clearHistories.ts index acbc455f450..c366f885f53 100644 --- a/projects/app/src/pages/api/core/chat/clearHistories.ts +++ b/projects/app/src/pages/api/core/chat/clearHistories.ts @@ -36,7 +36,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { }; } if (appId) { - const { tmbId } = await authCert({ req, authToken: true }); + const { tmbId } = await authCert({ req, authToken: true, authApiKey: true }); return { tmbId, diff --git a/projects/app/src/pages/api/core/chat/delHistory.ts b/projects/app/src/pages/api/core/chat/delHistory.ts index b68a21ba0c2..aba8c7a0be5 100644 --- a/projects/app/src/pages/api/core/chat/delHistory.ts +++ b/projects/app/src/pages/api/core/chat/delHistory.ts @@ -17,6 +17,7 @@ async function handler(req: ApiRequestProps<{}, DelHistoryProps>, res: NextApiRe await authChatCrud({ req, authToken: true, + authApiKey: true, ...req.query, per: WritePermissionVal }); diff --git a/projects/app/src/pages/api/core/chat/feedback/adminUpdate.ts b/projects/app/src/pages/api/core/chat/feedback/adminUpdate.ts index 336d0260655..abd7f204f88 100644 --- a/projects/app/src/pages/api/core/chat/feedback/adminUpdate.ts +++ b/projects/app/src/pages/api/core/chat/feedback/adminUpdate.ts @@ -10,10 +10,10 @@ import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { await connectToDatabase(); - const { appId, chatId, chatItemId, datasetId, dataId, q, a } = + const { appId, chatId, dataId, datasetId, feedbackDataId, q, a } = req.body as AdminUpdateFeedbackParams; - if (!chatItemId || !datasetId || !dataId || !q) { + if (!dataId || !datasetId || !feedbackDataId || !q) { throw new Error('missing parameter'); } @@ -29,12 +29,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) { appId, chatId, - dataId: chatItemId + dataId }, { adminFeedback: { datasetId, - dataId, + dataId: feedbackDataId, q, a } diff --git a/projects/app/src/pages/api/core/chat/feedback/closeCustom.ts b/projects/app/src/pages/api/core/chat/feedback/closeCustom.ts index 57c7f90b049..0cc9ff568f7 100644 --- a/projects/app/src/pages/api/core/chat/feedback/closeCustom.ts +++ b/projects/app/src/pages/api/core/chat/feedback/closeCustom.ts @@ -6,14 +6,15 @@ import type { CloseCustomFeedbackParams } from '@/global/core/chat/api.d'; import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema'; import { authChatCrud } from '@/service/support/permission/auth/chat'; import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant'; +import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun'; /* remove custom feedback */ export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { await connectToDatabase(); - const { appId, chatId, chatItemId, index } = req.body as CloseCustomFeedbackParams; + const { appId, chatId, dataId, index } = req.body as CloseCustomFeedbackParams; - if (!chatItemId || !appId || !chatId || !chatItemId) { + if (!dataId || !appId || !chatId) { throw new Error('missing parameter'); } @@ -26,10 +27,22 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }); await authCert({ req, authToken: true }); - await MongoChatItem.findOneAndUpdate( - { appId, chatId, dataId: chatItemId }, - { $unset: { [`customFeedbacks.${index}`]: 1 } } - ); + await mongoSessionRun(async (session) => { + await MongoChatItem.findOneAndUpdate( + { appId, chatId, dataId }, + { $unset: { [`customFeedbacks.${index}`]: 1 } }, + { + session + } + ); + await MongoChatItem.findOneAndUpdate( + { appId, chatId, dataId }, + { $pull: { customFeedbacks: null } }, + { + session + } + ); + }); jsonRes(res); } catch (err) { diff --git a/projects/app/src/pages/api/core/chat/feedback/updateUserFeedback.ts b/projects/app/src/pages/api/core/chat/feedback/updateUserFeedback.ts index e0733b0ca6b..e75a53f39a8 100644 --- a/projects/app/src/pages/api/core/chat/feedback/updateUserFeedback.ts +++ b/projects/app/src/pages/api/core/chat/feedback/updateUserFeedback.ts @@ -11,7 +11,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const { appId, chatId, - chatItemId, + dataId, shareId, teamId, teamToken, @@ -36,15 +36,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) per: ReadPermissionVal }); - if (!chatItemId) { - throw new Error('chatItemId is required'); + if (!dataId) { + throw new Error('dataId is required'); } await MongoChatItem.findOneAndUpdate( { appId, chatId, - dataId: chatItemId + dataId }, { $unset: { diff --git a/projects/app/src/pages/api/core/chat/getHistories.ts b/projects/app/src/pages/api/core/chat/getHistories.ts index cd406e10a6f..b0ea459254a 100644 --- a/projects/app/src/pages/api/core/chat/getHistories.ts +++ b/projects/app/src/pages/api/core/chat/getHistories.ts @@ -43,7 +43,7 @@ async function handler( }; } if (appId) { - const { tmbId } = await authCert({ req, authToken: true }); + const { tmbId } = await authCert({ req, authToken: true, authApiKey: true }); return { tmbId, appId, diff --git a/projects/app/src/pages/api/core/chat/getPaginationRecords.ts b/projects/app/src/pages/api/core/chat/getPaginationRecords.ts index 82d1ed1c708..975c08f3d67 100644 --- a/projects/app/src/pages/api/core/chat/getPaginationRecords.ts +++ b/projects/app/src/pages/api/core/chat/getPaginationRecords.ts @@ -26,7 +26,14 @@ async function handler( req: ApiRequestProps, res: ApiResponseType ): Promise { - const { chatId, appId, offset, pageSize = 10, loadCustomFeedbacks, type } = req.body; + const { + appId, + chatId, + offset, + pageSize = 10, + loadCustomFeedbacks, + type = GetChatTypeEnum.normal + } = req.body; if (!appId || !chatId) { return { @@ -40,6 +47,7 @@ async function handler( authChatCrud({ req, authToken: true, + authApiKey: true, ...req.body, per: ReadPermissionVal }) diff --git a/projects/app/src/pages/api/core/chat/getResData.ts b/projects/app/src/pages/api/core/chat/getResData.ts index 02fddcb233f..c306f707c78 100644 --- a/projects/app/src/pages/api/core/chat/getResData.ts +++ b/projects/app/src/pages/api/core/chat/getResData.ts @@ -37,6 +37,7 @@ async function handler( await authChatCrud({ req, authToken: true, + authApiKey: true, ...req.query, per: ReadPermissionVal }); @@ -44,6 +45,7 @@ async function handler( await authApp({ req, authToken: true, + authApiKey: true, appId, per: ManagePermissionVal }); diff --git a/projects/app/src/pages/api/core/chat/init.ts b/projects/app/src/pages/api/core/chat/init.ts index 19efff18867..75c8e0b13b0 100644 --- a/projects/app/src/pages/api/core/chat/init.ts +++ b/projects/app/src/pages/api/core/chat/init.ts @@ -29,6 +29,7 @@ async function handler( authApp({ req, authToken: true, + authApiKey: true, appId, per: ReadPermissionVal }), diff --git a/projects/app/src/pages/api/core/chat/item/delete.ts b/projects/app/src/pages/api/core/chat/item/delete.ts index b8a6f7840e0..11c721f7872 100644 --- a/projects/app/src/pages/api/core/chat/item/delete.ts +++ b/projects/app/src/pages/api/core/chat/item/delete.ts @@ -1,6 +1,5 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; +import type { NextApiResponse } from 'next'; import { jsonRes } from '@fastgpt/service/common/response'; -import { connectToDatabase } from '@/service/mongo'; import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema'; import { authChatCrud } from '@/service/support/permission/auth/chat'; import type { DeleteChatItemProps } from '@/global/core/chat/api.d'; @@ -9,7 +8,7 @@ import { ApiRequestProps } from '@fastgpt/service/type/next'; import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'; async function handler(req: ApiRequestProps<{}, DeleteChatItemProps>, res: NextApiResponse) { - const { appId, chatId, contentId, shareId, outLinkUid } = req.query; + const { appId, chatId, contentId } = req.query; if (!contentId || !chatId) { return jsonRes(res); @@ -18,6 +17,7 @@ async function handler(req: ApiRequestProps<{}, DeleteChatItemProps>, res: NextA await authChatCrud({ req, authToken: true, + authApiKey: true, ...req.query, per: WritePermissionVal }); diff --git a/projects/app/src/pages/api/core/chat/item/getSpeech.ts b/projects/app/src/pages/api/core/chat/item/getSpeech.ts index 012e9b5fc3d..41d34184a41 100644 --- a/projects/app/src/pages/api/core/chat/item/getSpeech.ts +++ b/projects/app/src/pages/api/core/chat/item/getSpeech.ts @@ -24,7 +24,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) throw new Error('model or voice not found'); } - const { teamId, tmbId, authType } = await authChatCert({ req, authToken: true }); + const { teamId, tmbId, authType } = await authChatCert({ + req, + authToken: true, + authApiKey: true + }); const ttsModel = getAudioSpeechModel(ttsConfig.model); const voiceData = ttsModel.voices?.find((item) => item.value === ttsConfig.voice); diff --git a/projects/app/src/pages/api/core/chat/updateHistory.ts b/projects/app/src/pages/api/core/chat/updateHistory.ts index a5e23fb0b02..1eabb54c0ea 100644 --- a/projects/app/src/pages/api/core/chat/updateHistory.ts +++ b/projects/app/src/pages/api/core/chat/updateHistory.ts @@ -1,4 +1,4 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; +import type { NextApiResponse } from 'next'; import { jsonRes } from '@fastgpt/service/common/response'; import { UpdateHistoryProps } from '@/global/core/chat/api.d'; import { MongoChat } from '@fastgpt/service/core/chat/chatSchema'; @@ -13,6 +13,7 @@ async function handler(req: ApiRequestProps, res: NextApiRes await authChatCrud({ req, authToken: true, + authApiKey: true, ...req.body, per: WritePermissionVal }); diff --git a/projects/app/src/pages/api/plugins/customFeedback/index.ts b/projects/app/src/pages/api/plugins/customFeedback/index.ts index 7f67bff1b06..c8b8b8732db 100644 --- a/projects/app/src/pages/api/plugins/customFeedback/index.ts +++ b/projects/app/src/pages/api/plugins/customFeedback/index.ts @@ -18,7 +18,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< const { appId, chatId, - responseChatItemId: chatItemId, + responseChatItemId: dataId, defaultFeedback, customFeedback } = req.body as Props; @@ -38,12 +38,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< addCustomFeedbacks({ appId, chatId, - chatItemId, + dataId, feedbacks: [feedback] }); }, 60000); - if (!chatId || !chatItemId) { + if (!chatId || !dataId) { return res.json({ response: `\\n\\n**自动反馈调试**: ${feedback}\\n\\n` }); diff --git a/projects/app/src/pages/api/plugins/customFeedback/v2/index.ts b/projects/app/src/pages/api/plugins/customFeedback/v2/index.ts index 8351bce5410..e22d1e789ae 100644 --- a/projects/app/src/pages/api/plugins/customFeedback/v2/index.ts +++ b/projects/app/src/pages/api/plugins/customFeedback/v2/index.ts @@ -20,7 +20,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< customFeedback, appId, chatId, - responseChatItemId: chatItemId, + responseChatItemId: dataId, customInputs } = req.body as Props; @@ -37,12 +37,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< addCustomFeedbacks({ appId, chatId, - chatItemId, + dataId, feedbacks: [feedbackText] }); }, 60000); - if (!chatId || !chatItemId) { + if (!chatId || !dataId) { return res.json({ [NodeOutputKeyEnum.answerText]: `\\n\\n**自动反馈调试**: "${feedbackText}"\\n\\n`, text: feedbackText diff --git a/projects/app/src/web/core/dataset/store/markdata.ts b/projects/app/src/web/core/dataset/store/markdata.ts index 76fb9403f6b..772faeffaea 100644 --- a/projects/app/src/web/core/dataset/store/markdata.ts +++ b/projects/app/src/web/core/dataset/store/markdata.ts @@ -1,9 +1,9 @@ import { create } from 'zustand'; -import { devtools, persist } from 'zustand/middleware'; +import { devtools } from 'zustand/middleware'; import { immer } from 'zustand/middleware/immer'; export type MarkDataStore = { - chatItemId: string; + dataId: string; datasetId?: string; collectionId?: string; q: string;