### What problem does this PR solve? Feat: Chat without KB. #5216 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.17.0
| @@ -9,7 +9,15 @@ import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'; | |||
| import { FormControl, FormField, FormItem, FormLabel } from './ui/form'; | |||
| import { MultiSelect } from './ui/multi-select'; | |||
| const KnowledgeBaseItem = () => { | |||
| interface KnowledgeBaseItemProps { | |||
| required?: boolean; | |||
| onChange?(): void; | |||
| } | |||
| const KnowledgeBaseItem = ({ | |||
| required = true, | |||
| onChange, | |||
| }: KnowledgeBaseItemProps) => { | |||
| const { t } = useTranslate('chat'); | |||
| const { list: knowledgeList } = useFetchKnowledgeList(true); | |||
| @@ -35,7 +43,7 @@ const KnowledgeBaseItem = () => { | |||
| tooltip={t('knowledgeBasesTip')} | |||
| rules={[ | |||
| { | |||
| required: true, | |||
| required, | |||
| message: t('knowledgeBasesMessage'), | |||
| type: 'array', | |||
| }, | |||
| @@ -45,6 +53,7 @@ const KnowledgeBaseItem = () => { | |||
| mode="multiple" | |||
| options={knowledgeOptions} | |||
| placeholder={t('knowledgeBasesMessage')} | |||
| onChange={onChange} | |||
| ></Select> | |||
| </Form.Item> | |||
| ); | |||
| @@ -420,6 +420,7 @@ This procedure will improve precision of retrieval by adding more information to | |||
| language: 'Language', | |||
| emptyResponse: 'Empty response', | |||
| emptyResponseTip: `Set this as a response if no results are retrieved from the knowledge bases for your query, or leave this field blank to allow the LLM to improvise when nothing is found.`, | |||
| emptyResponseMessage: `Empty response will be triggered when nothing relevant is retrieved from knowledge bases. Erase 'Empty response' since none of knowledge base is selected.`, | |||
| setAnOpener: 'Opening greeting', | |||
| setAnOpenerInitial: `Hi! I'm your assistant, what can I do for you?`, | |||
| setAnOpenerTip: 'Set an opening greeting for users.', | |||
| @@ -402,6 +402,7 @@ export default { | |||
| language: '語言', | |||
| emptyResponse: '空回复', | |||
| emptyResponseTip: `如果在知識庫中沒有檢索到用戶的問題,它將使用它作為答案。如果您希望 LLM 在未檢索到任何內容時提出自己的意見,請將此留空。`, | |||
| emptyResponseMessage: `當知識庫中沒有檢索到任何相關內容時,將觸發空響應。由於未選擇任何知識庫,因此刪除“空響應”。`, | |||
| setAnOpener: '設置開場白', | |||
| setAnOpenerInitial: `你好!我是你的助理,有什麼可以幫到你的嗎?`, | |||
| setAnOpenerTip: '您想如何歡迎您的客戶?', | |||
| @@ -419,6 +419,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 | |||
| language: '语言', | |||
| emptyResponse: '空回复', | |||
| emptyResponseTip: `如果在知识库中没有检索到用户的问题,它将使用它作为答案。 如果您希望 LLM 在未检索到任何内容时提出自己的意见,请将此留空。`, | |||
| emptyResponseMessage: `当知识库中未检索到任何相关信息时,将触发空响应。由于未选择任何知识库,因此请清除“空响应”。`, | |||
| setAnOpener: '设置开场白', | |||
| setAnOpenerInitial: `你好! 我是你的助理,有什么可以帮到你的吗?`, | |||
| setAnOpenerTip: '您想如何欢迎您的客户?', | |||
| @@ -27,7 +27,7 @@ export default function AgentTemplates() { | |||
| back={navigateToAgentList} | |||
| title={t('flow.createGraph')} | |||
| ></PageHeader> | |||
| <div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-6 2xl:grid-cols-8 max-h-[84vh] overflow-auto px-8"> | |||
| <div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-6 2xl:grid-cols-8 max-h-[94vh] overflow-auto px-8"> | |||
| {list?.map((x) => { | |||
| return ( | |||
| <TemplateCard | |||
| @@ -1,18 +1,40 @@ | |||
| import KnowledgeBaseItem from '@/components/knowledge-base-item'; | |||
| import { useTranslate } from '@/hooks/common-hooks'; | |||
| import { useFetchTenantInfo } from '@/hooks/user-setting-hooks'; | |||
| import { PlusOutlined } from '@ant-design/icons'; | |||
| import { Form, Input, message, Select, Switch, Upload } from 'antd'; | |||
| import classNames from 'classnames'; | |||
| import { useCallback } from 'react'; | |||
| import { ISegmentedContentProps } from '../interface'; | |||
| import KnowledgeBaseItem from '@/components/knowledge-base-item'; | |||
| import { useTranslate } from '@/hooks/common-hooks'; | |||
| import { useFetchTenantInfo } from '@/hooks/user-setting-hooks'; | |||
| import { useCallback } from 'react'; | |||
| import styles from './index.less'; | |||
| const AssistantSetting = ({ show, form }: ISegmentedContentProps) => { | |||
| const emptyResponseField = ['prompt_config', 'empty_response']; | |||
| const AssistantSetting = ({ | |||
| show, | |||
| form, | |||
| setHasError, | |||
| }: ISegmentedContentProps) => { | |||
| const { t } = useTranslate('chat'); | |||
| const { data } = useFetchTenantInfo(true); | |||
| const handleChange = useCallback(() => { | |||
| const kbIds = form.getFieldValue('kb_ids'); | |||
| const emptyResponse = form.getFieldValue(emptyResponseField); | |||
| const required = | |||
| emptyResponse && ((Array.isArray(kbIds) && kbIds.length === 0) || !kbIds); | |||
| setHasError(required); | |||
| form.setFields([ | |||
| { | |||
| name: emptyResponseField, | |||
| errors: required ? [t('emptyResponseMessage')] : [], | |||
| }, | |||
| ]); | |||
| }, [form, setHasError, t]); | |||
| const normFile = (e: any) => { | |||
| if (Array.isArray(e)) { | |||
| return e; | |||
| @@ -31,7 +53,7 @@ const AssistantSetting = ({ show, form }: ISegmentedContentProps) => { | |||
| [data, form], | |||
| ); | |||
| const uploadButtion = ( | |||
| const uploadButton = ( | |||
| <button style={{ border: 0, background: 'none' }} type="button"> | |||
| <PlusOutlined /> | |||
| <div style={{ marginTop: 8 }}>{t('upload', { keyPrefix: 'common' })}</div> | |||
| @@ -66,7 +88,7 @@ const AssistantSetting = ({ show, form }: ISegmentedContentProps) => { | |||
| beforeUpload={() => false} | |||
| showUploadList={{ showPreviewIcon: false, showRemoveIcon: false }} | |||
| > | |||
| {show ? uploadButtion : null} | |||
| {show ? uploadButton : null} | |||
| </Upload> | |||
| </Form.Item> | |||
| <Form.Item | |||
| @@ -84,11 +106,11 @@ const AssistantSetting = ({ show, form }: ISegmentedContentProps) => { | |||
| /> | |||
| </Form.Item> | |||
| <Form.Item | |||
| name={['prompt_config', 'empty_response']} | |||
| name={emptyResponseField} | |||
| label={t('emptyResponse')} | |||
| tooltip={t('emptyResponseTip')} | |||
| > | |||
| <Input placeholder="" /> | |||
| <Input placeholder="" onChange={handleChange} /> | |||
| </Form.Item> | |||
| <Form.Item | |||
| name={['prompt_config', 'prologue']} | |||
| @@ -116,15 +138,6 @@ const AssistantSetting = ({ show, form }: ISegmentedContentProps) => { | |||
| > | |||
| <Switch /> | |||
| </Form.Item> | |||
| {/* <Form.Item | |||
| label={t('selfRag')} | |||
| valuePropName="checked" | |||
| name={['prompt_config', 'self_rag']} | |||
| tooltip={t('selfRagTip')} | |||
| initialValue={false} | |||
| > | |||
| <Switch /> | |||
| </Form.Item> */} | |||
| <Form.Item | |||
| label={t('tts')} | |||
| valuePropName="checked" | |||
| @@ -134,7 +147,10 @@ const AssistantSetting = ({ show, form }: ISegmentedContentProps) => { | |||
| > | |||
| <Switch onChange={handleTtsChange} /> | |||
| </Form.Item> | |||
| <KnowledgeBaseItem></KnowledgeBaseItem> | |||
| <KnowledgeBaseItem | |||
| required={false} | |||
| onChange={handleChange} | |||
| ></KnowledgeBaseItem> | |||
| </section> | |||
| ); | |||
| }; | |||
| @@ -64,6 +64,7 @@ const ChatConfigurationModal = ({ | |||
| clearDialog, | |||
| }: IProps) => { | |||
| const [form] = Form.useForm(); | |||
| const [hasError, setHasError] = useState(false); | |||
| const [value, setValue] = useState<ConfigurationSegmented>( | |||
| ConfigurationSegmented.AssistantSetting, | |||
| @@ -74,6 +75,9 @@ const ChatConfigurationModal = ({ | |||
| const handleOk = async () => { | |||
| const values = await form.validateFields(); | |||
| if (hasError) { | |||
| return; | |||
| } | |||
| const nextValues: any = removeUselessFieldsFromValues( | |||
| values, | |||
| 'llm_setting.', | |||
| @@ -173,6 +177,7 @@ const ChatConfigurationModal = ({ | |||
| key={key} | |||
| show={key === value} | |||
| form={form} | |||
| setHasError={setHasError} | |||
| {...(key === ConfigurationSegmented.ModelSetting | |||
| ? { initialLlmSetting: initialDialog.llm_setting, visible } | |||
| : {})} | |||
| @@ -4,6 +4,7 @@ import { FormInstance } from 'antd'; | |||
| export interface ISegmentedContentProps { | |||
| show: boolean; | |||
| form: FormInstance; | |||
| setHasError: (hasError: boolean) => void; | |||
| } | |||
| export interface IVariable { | |||