From bfac393ab1c6d0e488430bc41eff8afdeefa5ced Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Mon, 16 Dec 2024 13:49:31 +0800 Subject: [PATCH] Add question guide config (#3403) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat:Prompt task (#3337) * feat:猜你想问自定义功能 * 修改用户输入框部分,去除冗余代码 * 删除不必要的属性 * 删除多余内容 * 修正了格式问题,并实现获取调试和app最新参数 * 修正了几行代码 * feat:Prompt task (#3337) * feat:猜你想问自定义功能 * 修改用户输入框部分,去除冗余代码 * 删除不必要的属性 * 删除多余内容 * 修正了格式问题,并实现获取调试和app最新参数 * 修正了几行代码 * perf: question gudide code * fix: i18n * hunyuan logo * fix: cq templates * perf: create question guide code * udpate svg --------- Co-authored-by: Jiangween <145003935+Jiangween@users.noreply.github.com> --- .../zh-cn/docs/development/configuration.md | 2 +- .../zh-cn/docs/development/openapi/chat.md | 79 +++++++ .../zh-cn/docs/development/upgrading/4816.md | 13 +- packages/global/core/ai/prompt/agent.ts | 10 + packages/global/core/app/constants.ts | 10 +- packages/global/core/app/type.d.ts | 10 +- packages/global/core/workflow/utils.ts | 15 +- .../plugins/src/Doc2X/PDF2text/template.json | 4 +- packages/plugins/src/bing/template.json | 4 +- .../src/databaseConnection/template.json | 4 +- .../src/drawing/baseChart/template.json | 4 +- packages/plugins/src/google/template.json | 4 +- packages/plugins/src/wiki/template.json | 4 +- .../core/ai/functions/createQuestionGuide.ts | 32 +-- packages/service/core/app/schema.ts | 2 +- .../common/Icon/icons/core/chat/QGFill.svg | 11 +- .../Textarea/CustomPromptEditor/index.tsx | 158 ++++++++++++++ packages/web/i18n/en/app.json | 4 + packages/web/i18n/en/common.json | 9 +- packages/web/i18n/zh-CN/app.json | 4 + packages/web/i18n/zh-CN/common.json | 9 +- packages/web/i18n/zh-Hant/app.json | 4 + packages/web/i18n/zh-Hant/common.json | 9 +- .../appMarketTemplates/CQ/template.json | 118 +++-------- .../appMarketTemplates/Chinese/template.json | 6 +- .../TranslateRobot/template.json | 6 +- .../animalLife/template.json | 6 +- .../chatGuide/template.json | 68 +----- .../divination/template.json | 6 +- .../githubIssue/template.json | 6 +- .../appMarketTemplates/google/template.json | 6 +- .../longTranslate/template.json | 6 +- .../simpleDatasetChat/template.json | 51 +---- .../srt-translate/template.json | 6 +- .../appMarketTemplates/stock/template.json | 6 +- .../app/public/imgs/app/nextQuestion-icon.svg | 20 +- projects/app/public/imgs/app/nextQuestion.svg | 112 +++++----- projects/app/public/imgs/model/hunyuan.svg | 13 ++ projects/app/public/imgs/model/minimax.svg | 11 +- .../app/src/components/core/app/QGConfig.tsx | 194 ++++++++++++++++++ .../app/src/components/core/app/QGSwitch.tsx | 22 -- projects/app/src/components/core/app/Tip.tsx | 2 +- .../chat/ChatContainer/ChatBox/Provider.tsx | 26 ++- .../core/chat/ChatContainer/ChatBox/index.tsx | 5 +- .../core/ai/agent/v2/createQuestionGuide.ts | 27 ++- .../detail/components/SimpleApp/EditForm.tsx | 8 +- .../components/SimpleApp/useSnapshots.tsx | 4 +- .../Flow/nodes/NodeSystemConfig.tsx | 18 +- .../app/src/pages/price/components/Points.tsx | 2 +- projects/app/src/web/core/app/templates.ts | 12 +- 50 files changed, 775 insertions(+), 397 deletions(-) create mode 100644 packages/web/components/common/Textarea/CustomPromptEditor/index.tsx create mode 100644 projects/app/public/imgs/model/hunyuan.svg create mode 100644 projects/app/src/components/core/app/QGConfig.tsx delete mode 100644 projects/app/src/components/core/app/QGSwitch.tsx diff --git a/docSite/content/zh-cn/docs/development/configuration.md b/docSite/content/zh-cn/docs/development/configuration.md index 06e4e2b79..eb5b6b653 100644 --- a/docSite/content/zh-cn/docs/development/configuration.md +++ b/docSite/content/zh-cn/docs/development/configuration.md @@ -201,7 +201,7 @@ weight: 708 - /imgs/model/qwen.svg - 通义千问 - /imgs/model/sparkDesk.svg - 讯飞星火 - /imgs/model/yi.svg - 零一万物 -- +- /imgs/model/hunyuan.svg - 腾讯混元 ## 特殊模型 diff --git a/docSite/content/zh-cn/docs/development/openapi/chat.md b/docSite/content/zh-cn/docs/development/openapi/chat.md index 3af0542cd..b5f1c276d 100644 --- a/docSite/content/zh-cn/docs/development/openapi/chat.md +++ b/docSite/content/zh-cn/docs/development/openapi/chat.md @@ -1313,6 +1313,83 @@ curl --location --request POST 'http://localhost:3000/api/core/chat/feedback/upd ## 猜你想问 +**4.8.16 后新版接口** + +新版猜你想问,必须包含 appId 和 chatId 的参数才可以进行使用。会自动根据 chatId 去拉取最近 6 轮对话记录作为上下文来引导回答。 + +{{< tabs tabTotal="3" >}} +{{< tab tabName="请求示例" >}} +{{< markdownify >}} + +```bash +curl --location --request POST 'http://localhost:3000/api/core/ai/agent/v2/createQuestionGuide' \ +--header 'Authorization: Bearer {{apikey}}' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "appId": "appId", + "chatId": "chatId", + "questionGuide": { + "open": true, + "model": "GPT-4o-mini", + "customPrompt": "你是一个智能助手,请根据用户的问题生成猜你想问。" + } +}' +``` + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="参数说明" >}} +{{< markdownify >}} + +{{% alert icon=" " context="success" %}} + +| 参数名 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | +| appId | string | ✅ | 应用 Id | +| chatId | string | ✅ | 对话 Id | +| questionGuide | object | | 自定义配置,不传的话,则会根据 appId,取最新发布版本的配置 | + +```ts +type CreateQuestionGuideParams = OutLinkChatAuthProps & { + appId: string; + chatId: string; + questionGuide?: { + open: boolean; + model?: string; + customPrompt?: string; + }; +}; +``` + +{{% /alert %}} + +{{< /markdownify >}} +{{< /tab >}} + +{{< tab tabName="响应示例" >}} +{{< markdownify >}} + +```json +{ + "code": 200, + "statusText": "", + "message": "", + "data": [ + "你对AI有什么看法?", + "想了解AI的应用吗?", + "你希望AI能做什么?" + ] +} +``` +{{< /markdownify >}} +{{< /tab >}} +{{< /tabs >}} + +--- + +**4.8.16 前旧版接口:** + {{< tabs tabTotal="3" >}} {{< tab tabName="请求示例" >}} {{< markdownify >}} @@ -1369,3 +1446,5 @@ curl --location --request POST 'http://localhost:3000/api/core/ai/agent/createQu + + diff --git a/docSite/content/zh-cn/docs/development/upgrading/4816.md b/docSite/content/zh-cn/docs/development/upgrading/4816.md index 1ad3e672e..12260fb5e 100644 --- a/docSite/content/zh-cn/docs/development/upgrading/4816.md +++ b/docSite/content/zh-cn/docs/development/upgrading/4816.md @@ -12,9 +12,10 @@ weight: 808 1. 2. 新增 - 商业版支持 API 知识库和链接集合定时同步。 -3. 优化 - 工作流/简易模式变量初始化代码,去除监听初始化,避免因渲染顺序不一致导致的失败。 -4. 修复 - 无法自动切换默认语言。增加分享链接,强制执行一次切换默认语言。 -5. 修复 - 数组选择器自动兼容 4.8.13 以前的数据。 -6. 修复 - 站点同步知识库,链接同步时未使用选择器。 -7. 修复 - 简易模式转工作流,没有把系统配置项转化。 -8. 修复 - 插件独立运行,变量初始值未赋上。 \ No newline at end of file +3. 新增 - 猜你想问支持选择模型和自定义提示词。 +4. 优化 - 工作流/简易模式变量初始化代码,去除监听初始化,避免因渲染顺序不一致导致的失败。 +5. 修复 - 无法自动切换默认语言。增加分享链接,强制执行一次切换默认语言。 +6. 修复 - 数组选择器自动兼容 4.8.13 以前的数据。 +7. 修复 - 站点同步知识库,链接同步时未使用选择器。 +8. 修复 - 简易模式转工作流,没有把系统配置项转化。 +9. 修复 - 插件独立运行,变量初始值未赋上。 \ No newline at end of file diff --git a/packages/global/core/ai/prompt/agent.ts b/packages/global/core/ai/prompt/agent.ts index ca93dc83d..ea3362ed8 100644 --- a/packages/global/core/ai/prompt/agent.ts +++ b/packages/global/core/ai/prompt/agent.ts @@ -65,3 +65,13 @@ export const Prompt_CQJson = `请帮我执行一个“问题分类”任务, 问题:"{{question}}" 类型ID= `; + +export const PROMPT_QUESTION_GUIDE = `You are an AI assistant tasked with predicting the user's next question based on the conversation history. Your goal is to generate 3 potential questions that will guide the user to continue the conversation. When generating these questions, adhere to the following rules: + +1. Use the same language as the user's last question in the conversation history. +2. Keep each question under 20 characters in length. + +Analyze the conversation history provided to you and use it as context to generate relevant and engaging follow-up questions. Your predictions should be logical extensions of the current topic or related areas that the user might be interested in exploring further. + +Remember to maintain consistency in tone and style with the existing conversation while providing diverse options for the user to choose from. Your goal is to keep the conversation flowing naturally and help the user delve deeper into the subject matter or explore related topics.`; +export const PROMPT_QUESTION_GUIDE_FOOTER = `Please strictly follow the format rules: \nReturn questions in JSON format: ['Question 1', 'Question 2', 'Question 3']. Your output: `; diff --git a/packages/global/core/app/constants.ts b/packages/global/core/app/constants.ts index 62d1f5874..ba9485036 100644 --- a/packages/global/core/app/constants.ts +++ b/packages/global/core/app/constants.ts @@ -1,8 +1,10 @@ +import { PROMPT_QUESTION_GUIDE } from '../ai/prompt/agent'; import { AppTTSConfigType, AppFileSelectConfigType, AppWhisperConfigType, - AppAutoExecuteConfigType + AppAutoExecuteConfigType, + AppQGConfigType } from './type'; export enum AppTypeEnum { @@ -28,6 +30,12 @@ export const defaultWhisperConfig: AppWhisperConfigType = { autoTTSResponse: false }; +export const defaultQGConfig: AppQGConfigType = { + open: false, + model: 'gpt-4o-mini', + customPrompt: PROMPT_QUESTION_GUIDE +}; + export const defaultChatInputGuideConfig = { open: false, textList: [], diff --git a/packages/global/core/app/type.d.ts b/packages/global/core/app/type.d.ts index b735a1e30..c10ab9ddc 100644 --- a/packages/global/core/app/type.d.ts +++ b/packages/global/core/app/type.d.ts @@ -97,7 +97,7 @@ export type AppChatConfigType = { welcomeText?: string; variables?: VariableItemType[]; autoExecute?: AppAutoExecuteConfigType; - questionGuide?: boolean; + questionGuide?: AppQGConfigType; ttsConfig?: AppTTSConfigType; whisperConfig?: AppWhisperConfigType; scheduledTriggerConfig?: AppScheduledTriggerConfigType; @@ -148,6 +148,14 @@ export type AppWhisperConfigType = { autoSend: boolean; autoTTSResponse: boolean; }; + +// question guide +export type AppQGConfigType = { + open: boolean; + model?: string; + customPrompt?: string; +}; + // question guide text export type ChatInputGuideConfigType = { open: boolean; diff --git a/packages/global/core/workflow/utils.ts b/packages/global/core/workflow/utils.ts index 3e082c235..06307c403 100644 --- a/packages/global/core/workflow/utils.ts +++ b/packages/global/core/workflow/utils.ts @@ -26,12 +26,14 @@ import type { AppScheduledTriggerConfigType, ChatInputGuideConfigType, AppChatConfigType, - AppAutoExecuteConfigType + AppAutoExecuteConfigType, + AppQGConfigType } from '../app/type'; import { EditorVariablePickerType } from '../../../web/components/common/Textarea/PromptEditor/type'; import { defaultAutoExecuteConfig, defaultChatInputGuideConfig, + defaultQGConfig, defaultTTSConfig, defaultWhisperConfig } from '../app/constants'; @@ -76,9 +78,14 @@ export const splitGuideModule = (guideModules?: StoreNodeItemType) => { const variables: VariableItemType[] = guideModules?.inputs.find((item) => item.key === NodeInputKeyEnum.variables)?.value ?? []; - const questionGuide: boolean = - !!guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.questionGuide)?.value ?? - false; + // Adapt old version + const questionGuideVal = guideModules?.inputs?.find( + (item) => item.key === NodeInputKeyEnum.questionGuide + )?.value; + const questionGuide: AppQGConfigType = + typeof questionGuideVal === 'boolean' + ? { ...defaultQGConfig, open: questionGuideVal } + : questionGuideVal ?? defaultQGConfig; const ttsConfig: AppTTSConfigType = guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.tts)?.value ?? diff --git a/packages/plugins/src/Doc2X/PDF2text/template.json b/packages/plugins/src/Doc2X/PDF2text/template.json index 9a84c51a6..8d2368967 100644 --- a/packages/plugins/src/Doc2X/PDF2text/template.json +++ b/packages/plugins/src/Doc2X/PDF2text/template.json @@ -439,7 +439,9 @@ } ], "chatConfig": { - "questionGuide": false, + "questionGuide": { + "open": false + }, "ttsConfig": { "type": "web" }, diff --git a/packages/plugins/src/bing/template.json b/packages/plugins/src/bing/template.json index 65780248c..0cb410b49 100644 --- a/packages/plugins/src/bing/template.json +++ b/packages/plugins/src/bing/template.json @@ -489,7 +489,9 @@ "chatConfig": { "welcomeText": "", "variables": [], - "questionGuide": false, + "questionGuide": { + "open": false + }, "ttsConfig": { "type": "web" }, diff --git a/packages/plugins/src/databaseConnection/template.json b/packages/plugins/src/databaseConnection/template.json index 6aaa4cbf3..97caec65e 100644 --- a/packages/plugins/src/databaseConnection/template.json +++ b/packages/plugins/src/databaseConnection/template.json @@ -666,7 +666,9 @@ "chatConfig": { "welcomeText": "", "variables": [], - "questionGuide": false, + "questionGuide": { + "open": false + }, "ttsConfig": { "type": "web" }, diff --git a/packages/plugins/src/drawing/baseChart/template.json b/packages/plugins/src/drawing/baseChart/template.json index c249ced14..1fe584558 100644 --- a/packages/plugins/src/drawing/baseChart/template.json +++ b/packages/plugins/src/drawing/baseChart/template.json @@ -502,7 +502,9 @@ "chatConfig": { "welcomeText": "", "variables": [], - "questionGuide": false, + "questionGuide": { + "open": false + }, "ttsConfig": { "type": "web" }, diff --git a/packages/plugins/src/google/template.json b/packages/plugins/src/google/template.json index 9ceab6be2..7009049ae 100644 --- a/packages/plugins/src/google/template.json +++ b/packages/plugins/src/google/template.json @@ -538,7 +538,9 @@ "chatConfig": { "welcomeText": "", "variables": [], - "questionGuide": false, + "questionGuide": { + "open": false + }, "ttsConfig": { "type": "web" }, diff --git a/packages/plugins/src/wiki/template.json b/packages/plugins/src/wiki/template.json index c9a98e427..c52da3d9c 100644 --- a/packages/plugins/src/wiki/template.json +++ b/packages/plugins/src/wiki/template.json @@ -320,7 +320,9 @@ "chatConfig": { "welcomeText": "", "variables": [], - "questionGuide": false, + "questionGuide": { + "open": false + }, "ttsConfig": { "type": "web" }, diff --git a/packages/service/core/ai/functions/createQuestionGuide.ts b/packages/service/core/ai/functions/createQuestionGuide.ts index bb332180c..0124536be 100644 --- a/packages/service/core/ai/functions/createQuestionGuide.ts +++ b/packages/service/core/ai/functions/createQuestionGuide.ts @@ -3,29 +3,30 @@ import { createChatCompletion } from '../config'; import { countGptMessagesTokens } from '../../../common/string/tiktoken/index'; import { loadRequestMessages } from '../../chat/utils'; import { llmCompletionsBodyFormat } from '../utils'; - -export const Prompt_QuestionGuide = `You are an AI assistant tasked with predicting the user's next question based on the conversation history. Your goal is to generate 3 potential questions that will guide the user to continue the conversation. When generating these questions, adhere to the following rules: - -1. Use the same language as the user's last question in the conversation history. -2. Keep each question under 20 characters in length. -3. Return the questions in JSON format: ["question1", "question2", "question3"]. - -Analyze the conversation history provided to you and use it as context to generate relevant and engaging follow-up questions. Your predictions should be logical extensions of the current topic or related areas that the user might be interested in exploring further. - -Remember to maintain consistency in tone and style with the existing conversation while providing diverse options for the user to choose from. Your goal is to keep the conversation flowing naturally and help the user delve deeper into the subject matter or explore related topics.`; +import { + PROMPT_QUESTION_GUIDE, + PROMPT_QUESTION_GUIDE_FOOTER +} from '@fastgpt/global/core/ai/prompt/agent'; +import { addLog } from '../../../common/system/log'; +import json5 from 'json5'; export async function createQuestionGuide({ messages, - model + model, + customPrompt }: { messages: ChatCompletionMessageParam[]; model: string; -}) { + customPrompt?: string; +}): Promise<{ + result: string[]; + tokens: number; +}> { const concatMessages: ChatCompletionMessageParam[] = [ ...messages, { role: 'user', - content: Prompt_QuestionGuide + content: `${customPrompt || PROMPT_QUESTION_GUIDE}\n${PROMPT_QUESTION_GUIDE_FOOTER}` } ]; @@ -53,6 +54,7 @@ export async function createQuestionGuide({ const tokens = await countGptMessagesTokens(concatMessages); if (start === -1 || end === -1) { + addLog.warn('Create question guide error', { answer }); return { result: [], tokens: 0 @@ -66,10 +68,12 @@ export async function createQuestionGuide({ try { return { - result: JSON.parse(jsonStr), + result: json5.parse(jsonStr), tokens }; } catch (error) { + console.log(error); + return { result: [], tokens: 0 diff --git a/packages/service/core/app/schema.ts b/packages/service/core/app/schema.ts index 4e396d40e..ce042a500 100644 --- a/packages/service/core/app/schema.ts +++ b/packages/service/core/app/schema.ts @@ -11,7 +11,7 @@ export const AppCollectionName = 'apps'; export const chatConfigType = { welcomeText: String, variables: Array, - questionGuide: Boolean, + questionGuide: Object, ttsConfig: Object, whisperConfig: Object, scheduledTriggerConfig: Object, diff --git a/packages/web/components/common/Icon/icons/core/chat/QGFill.svg b/packages/web/components/common/Icon/icons/core/chat/QGFill.svg index 1974fb398..3257f19ab 100644 --- a/packages/web/components/common/Icon/icons/core/chat/QGFill.svg +++ b/packages/web/components/common/Icon/icons/core/chat/QGFill.svg @@ -1 +1,10 @@ - \ No newline at end of file + + + + + + + + + + diff --git a/packages/web/components/common/Textarea/CustomPromptEditor/index.tsx b/packages/web/components/common/Textarea/CustomPromptEditor/index.tsx new file mode 100644 index 000000000..776dcf4af --- /dev/null +++ b/packages/web/components/common/Textarea/CustomPromptEditor/index.tsx @@ -0,0 +1,158 @@ +import { + Box, + Button, + Flex, + Textarea, + ModalFooter, + HStack, + Icon, + ModalBody +} from '@chakra-ui/react'; +import MyIcon from '../../Icon/index'; + +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'next-i18next'; +import MyModal from '../../MyModal'; + +const CustomLightTip = () => { + const { t } = useTranslation(); + + return ( + + + + {t('common:core.app.QG.Custom prompt tip1')} + + {t('common:core.app.QG.Custom prompt tip2')} + + {t('common:core.app.QG.Custom prompt tip3')} + + + ); +}; + +const FixBox = ({ children }: { children: React.ReactNode }) => { + return ( + + + {children} + + + ); +}; + +const CustomPromptEditor = ({ + defaultValue = '', + defaultPrompt, + footerPrompt, + onChange, + onClose +}: { + defaultValue?: string; + defaultPrompt: string; + footerPrompt?: string; + onChange: (e: string) => void; + onClose: () => void; +}) => { + const ref = useRef(null); + const { t } = useTranslation(); + const [value, setValue] = useState(defaultValue || defaultPrompt); + + const adjustHeight = useCallback(() => { + const textarea = ref.current; + if (!textarea) return; + + textarea.style.height = '22px'; + textarea.style.height = `${textarea.scrollHeight}px`; + }, []); + + useEffect(() => { + adjustHeight(); + const timer = setTimeout(adjustHeight, 0); + return () => clearTimeout(timer); + }, [value, adjustHeight]); + + return ( + + + + + + + {t('common:core.ai.Prompt')} + + + + + + +