### What problem does this PR solve? Feat: Added meta data to the chat configuration page #8531 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.20.2
| prologue: string; | prologue: string; | ||||
| system: string; | system: string; | ||||
| tts?: boolean; | tts?: boolean; | ||||
| quote: boolean; | |||||
| keyword: boolean; | |||||
| refine_multiturn: boolean; | |||||
| use_kg: boolean; | |||||
| } | } | ||||
| export interface Parameter { | export interface Parameter { | ||||
| presence_penalty?: number; | presence_penalty?: number; | ||||
| temperature?: number; | temperature?: number; | ||||
| top_p?: number; | top_p?: number; | ||||
| llm_id?: string; | |||||
| } | } | ||||
| export interface IDialog { | export interface IDialog { | ||||
| update_time: number; | update_time: number; | ||||
| vector_similarity_weight: number; | vector_similarity_weight: number; | ||||
| similarity_threshold: number; | similarity_threshold: number; | ||||
| top_k: number; | |||||
| top_n: number; | |||||
| } | } | ||||
| export interface IConversation { | export interface IConversation { |
| crossLanguage: 'Cross-language search', | crossLanguage: 'Cross-language search', | ||||
| crossLanguageTip: `Select one or more languages for cross‑language search. If no language is selected, the system searches with the original query.`, | crossLanguageTip: `Select one or more languages for cross‑language search. If no language is selected, the system searches with the original query.`, | ||||
| createChat: 'Create chat', | createChat: 'Create chat', | ||||
| metadata: 'Metadata', | |||||
| metadataTip: 'Metadata', | |||||
| metadata: 'Meta Data', | |||||
| metadataTip: | |||||
| 'Metadata filtering is the process of using metadata attributes (such as tags, categories, or access permissions) to refine and control the retrieval of relevant information within a system.', | |||||
| conditions: 'Conditions', | conditions: 'Conditions', | ||||
| addCondition: 'Add Condition', | |||||
| meta: { | |||||
| disabled: 'Disabled', | |||||
| automatic: 'Automatic', | |||||
| manual: 'Manual', | |||||
| }, | |||||
| }, | }, | ||||
| setting: { | setting: { | ||||
| profile: 'Profile', | profile: 'Profile', |
| tavilyApiKeyHelp: '如何获取?', | tavilyApiKeyHelp: '如何获取?', | ||||
| crossLanguage: '跨语言搜索', | crossLanguage: '跨语言搜索', | ||||
| crossLanguageTip: `选择一种或多种语言进行跨语言搜索。如果未选择任何语言,系统将使用原始查询进行搜索。`, | crossLanguageTip: `选择一种或多种语言进行跨语言搜索。如果未选择任何语言,系统将使用原始查询进行搜索。`, | ||||
| metadata: '元数据', | |||||
| metadataTip: | |||||
| '元数据过滤是使用元数据属性(例如标签、类别或访问权限)来优化和控制系统内相关信息检索的过程。', | |||||
| conditions: '条件', | |||||
| addCondition: '增加条件', | |||||
| meta: { | |||||
| disabled: '禁用', | |||||
| automatic: '自动', | |||||
| manual: '手动', | |||||
| }, | |||||
| }, | }, | ||||
| setting: { | setting: { | ||||
| profile: '概要', | profile: '概要', |
| return icon; | return icon; | ||||
| }; | }; | ||||
| function useBuildSwitchOperatorOptions() { | |||||
| export function useBuildSwitchOperatorOptions() { | |||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const switchOperatorOptions = useMemo(() => { | const switchOperatorOptions = useMemo(() => { |
| const emptyResponseField = ['prompt_config', 'empty_response']; | const emptyResponseField = ['prompt_config', 'empty_response']; | ||||
| const MetadataOptions = Object.values(DatasetMetadata).map((x) => { | |||||
| let value: DatasetMetadata | boolean = x; | |||||
| if (x === DatasetMetadata.Disabled) { | |||||
| value = false; | |||||
| } else if (x === DatasetMetadata.Automatic) { | |||||
| value = true; | |||||
| } | |||||
| return { | |||||
| value, | |||||
| label: x, | |||||
| }; | |||||
| }); | |||||
| const AssistantSetting = ({ | const AssistantSetting = ({ | ||||
| show, | show, | ||||
| form, | form, | ||||
| const { t } = useTranslate('chat'); | const { t } = useTranslate('chat'); | ||||
| const { data } = useFetchTenantInfo(true); | const { data } = useFetchTenantInfo(true); | ||||
| const metadata = Form.useWatch(['meta_data_filter', 'auto'], form); | |||||
| const MetadataOptions = Object.values(DatasetMetadata).map((x) => { | |||||
| return { | |||||
| value: x, | |||||
| label: t(`meta.${x}`), | |||||
| }; | |||||
| }); | |||||
| const metadata = Form.useWatch(['meta_data_filter', 'method'], form); | |||||
| const kbIds = Form.useWatch(['kb_ids'], form); | const kbIds = Form.useWatch(['kb_ids'], form); | ||||
| const hasKnowledge = Array.isArray(kbIds) && kbIds.length > 0; | const hasKnowledge = Array.isArray(kbIds) && kbIds.length > 0; | ||||
| {hasKnowledge && ( | {hasKnowledge && ( | ||||
| <Form.Item | <Form.Item | ||||
| label={t('metadata')} | label={t('metadata')} | ||||
| name={['meta_data_filter', 'auto']} | |||||
| name={['meta_data_filter', 'method']} | |||||
| tooltip={t('metadataTip')} | tooltip={t('metadataTip')} | ||||
| initialValue={DatasetMetadata.Disabled} | |||||
| > | > | ||||
| <Select options={MetadataOptions} /> | <Select options={MetadataOptions} /> | ||||
| </Form.Item> | </Form.Item> |
| import { useFetchKnowledgeMetadata } from '@/hooks/use-knowledge-request'; | import { useFetchKnowledgeMetadata } from '@/hooks/use-knowledge-request'; | ||||
| import { SwitchOperatorOptions } from '@/pages/agent/constant'; | import { SwitchOperatorOptions } from '@/pages/agent/constant'; | ||||
| import { useBuildSwitchOperatorOptions } from '@/pages/agent/form/switch-form'; | |||||
| import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; | import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; | ||||
| import { | import { | ||||
| Button, | Button, | ||||
| Space, | Space, | ||||
| } from 'antd'; | } from 'antd'; | ||||
| import { useCallback } from 'react'; | import { useCallback } from 'react'; | ||||
| import { useTranslation } from 'react-i18next'; | |||||
| export function MetadataFilterConditions({ kbIds }: { kbIds: string[] }) { | export function MetadataFilterConditions({ kbIds }: { kbIds: string[] }) { | ||||
| const metadata = useFetchKnowledgeMetadata(kbIds); | const metadata = useFetchKnowledgeMetadata(kbIds); | ||||
| const { t } = useTranslation(); | |||||
| const switchOperatorOptions = useBuildSwitchOperatorOptions(); | |||||
| const renderItems = useCallback( | const renderItems = useCallback( | ||||
| (add: FormListOperation['add']) => { | (add: FormListOperation['add']) => { | ||||
| <Form.Item | <Form.Item | ||||
| {...restField} | {...restField} | ||||
| name={[name, 'key']} | name={[name, 'key']} | ||||
| rules={[{ required: true, message: 'Missing first name' }]} | |||||
| rules={[{ required: true, message: t('common.pleaseInput') }]} | |||||
| > | > | ||||
| <Input placeholder="First Name" /> | |||||
| <Input placeholder={t('common.pleaseInput')} /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item {...restField} name={[name, 'op']} className="w-20"> | <Form.Item {...restField} name={[name, 'op']} className="w-20"> | ||||
| <Select | <Select | ||||
| options={SwitchOperatorOptions} | |||||
| options={switchOperatorOptions} | |||||
| popupMatchSelectWidth={false} | popupMatchSelectWidth={false} | ||||
| /> | /> | ||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | <Form.Item | ||||
| {...restField} | {...restField} | ||||
| name={[name, 'value']} | name={[name, 'value']} | ||||
| rules={[{ required: true, message: 'Missing last name' }]} | |||||
| rules={[{ required: true, message: t('common.pleaseInput') }]} | |||||
| > | > | ||||
| <Input placeholder="Last Name" /> | |||||
| <Input placeholder={t('common.pleaseInput')} /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <MinusCircleOutlined onClick={() => remove(name)} /> | <MinusCircleOutlined onClick={() => remove(name)} /> | ||||
| </Space> | </Space> | ||||
| <Form.Item> | <Form.Item> | ||||
| <Dropdown trigger={['click']} menu={{ items: renderItems(add) }}> | <Dropdown trigger={['click']} menu={{ items: renderItems(add) }}> | ||||
| <Button type="dashed" block icon={<PlusOutlined />}> | <Button type="dashed" block icon={<PlusOutlined />}> | ||||
| Add Condition | |||||
| {t('chat.addCondition')} | |||||
| </Button> | </Button> | ||||
| </Dropdown> | </Dropdown> | ||||
| </Form.Item> | </Form.Item> |
| FormMessage, | FormMessage, | ||||
| } from '@/components/ui/form'; | } from '@/components/ui/form'; | ||||
| import { Input } from '@/components/ui/input'; | import { Input } from '@/components/ui/input'; | ||||
| import { Textarea } from '@/components/ui/textarea'; | |||||
| import { useTranslate } from '@/hooks/common-hooks'; | import { useTranslate } from '@/hooks/common-hooks'; | ||||
| import { useFormContext } from 'react-hook-form'; | import { useFormContext } from 'react-hook-form'; | ||||
| import { Subhead } from './subhead'; | |||||
| export default function ChatBasicSetting() { | export default function ChatBasicSetting() { | ||||
| const { t } = useTranslate('chat'); | const { t } = useTranslate('chat'); | ||||
| const form = useFormContext(); | const form = useFormContext(); | ||||
| return ( | return ( | ||||
| <section> | |||||
| <Subhead>Basic settings</Subhead> | |||||
| <div className="space-y-8"> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'icon'} | |||||
| render={({ field }) => ( | |||||
| <div className="space-y-6"> | |||||
| <FormItem className="w-full"> | |||||
| <FormLabel>{t('assistantAvatar')}</FormLabel> | |||||
| <FormControl> | |||||
| <FileUploader | |||||
| value={field.value} | |||||
| onValueChange={field.onChange} | |||||
| maxFileCount={1} | |||||
| maxSize={4 * 1024 * 1024} | |||||
| // progresses={progresses} | |||||
| // pass the onUpload function here for direct upload | |||||
| // onUpload={uploadFiles} | |||||
| // disabled={isUploading} | |||||
| /> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| </div> | |||||
| )} | |||||
| /> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name="name" | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('assistantName')}</FormLabel> | |||||
| <div className="space-y-8"> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'icon'} | |||||
| render={({ field }) => ( | |||||
| <div className="space-y-6"> | |||||
| <FormItem className="w-full"> | |||||
| <FormLabel>{t('assistantAvatar')}</FormLabel> | |||||
| <FormControl> | <FormControl> | ||||
| <Input {...field}></Input> | |||||
| <FileUploader | |||||
| value={field.value} | |||||
| onValueChange={field.onChange} | |||||
| maxFileCount={1} | |||||
| maxSize={4 * 1024 * 1024} | |||||
| /> | |||||
| </FormControl> | </FormControl> | ||||
| <FormMessage /> | <FormMessage /> | ||||
| </FormItem> | </FormItem> | ||||
| )} | |||||
| /> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name="description" | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('description')}</FormLabel> | |||||
| <FormControl> | |||||
| <Input {...field}></Input> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'prompt_config.empty_response'} | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('emptyResponse')}</FormLabel> | |||||
| <FormControl> | |||||
| <Input {...field}></Input> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'prompt_config.prologue'} | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('setAnOpener')}</FormLabel> | |||||
| <FormControl> | |||||
| <Input {...field}></Input> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <SwitchFormField | |||||
| name={'prompt_config.quote'} | |||||
| label={t('quote')} | |||||
| ></SwitchFormField> | |||||
| <SwitchFormField | |||||
| name={'prompt_config.keyword'} | |||||
| label={t('keyword')} | |||||
| ></SwitchFormField> | |||||
| <SwitchFormField | |||||
| name={'prompt_config.tts'} | |||||
| label={t('tts')} | |||||
| ></SwitchFormField> | |||||
| <KnowledgeBaseFormField></KnowledgeBaseFormField> | |||||
| </div> | |||||
| </section> | |||||
| </div> | |||||
| )} | |||||
| /> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name="name" | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('assistantName')}</FormLabel> | |||||
| <FormControl> | |||||
| <Input {...field}></Input> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name="description" | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('description')}</FormLabel> | |||||
| <FormControl> | |||||
| <Textarea {...field}></Textarea> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'prompt_config.empty_response'} | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('emptyResponse')}</FormLabel> | |||||
| <FormControl> | |||||
| <Textarea {...field}></Textarea> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'prompt_config.prologue'} | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('setAnOpener')}</FormLabel> | |||||
| <FormControl> | |||||
| <Textarea {...field}></Textarea> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <SwitchFormField | |||||
| name={'prompt_config.quote'} | |||||
| label={t('quote')} | |||||
| ></SwitchFormField> | |||||
| <SwitchFormField | |||||
| name={'prompt_config.keyword'} | |||||
| label={t('keyword')} | |||||
| ></SwitchFormField> | |||||
| <SwitchFormField | |||||
| name={'prompt_config.tts'} | |||||
| label={t('tts')} | |||||
| ></SwitchFormField> | |||||
| <KnowledgeBaseFormField></KnowledgeBaseFormField> | |||||
| </div> | |||||
| ); | ); | ||||
| } | } |
| import { Textarea } from '@/components/ui/textarea'; | import { Textarea } from '@/components/ui/textarea'; | ||||
| import { useTranslate } from '@/hooks/common-hooks'; | import { useTranslate } from '@/hooks/common-hooks'; | ||||
| import { useFormContext } from 'react-hook-form'; | import { useFormContext } from 'react-hook-form'; | ||||
| import { Subhead } from './subhead'; | |||||
| export function ChatModelSettings() { | export function ChatModelSettings() { | ||||
| const { t } = useTranslate('chat'); | const { t } = useTranslate('chat'); | ||||
| const form = useFormContext(); | const form = useFormContext(); | ||||
| return ( | return ( | ||||
| <section> | |||||
| <Subhead>Model Setting</Subhead> | |||||
| <div className="space-y-8"> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name="prompt_config.system" | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('system')}</FormLabel> | |||||
| <FormControl> | |||||
| <Textarea | |||||
| placeholder="Tell us a little bit about yourself" | |||||
| className="resize-none" | |||||
| {...field} | |||||
| /> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <LlmSettingFieldItems></LlmSettingFieldItems> | |||||
| </div> | |||||
| </section> | |||||
| <div className="space-y-8"> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name="prompt_config.system" | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('system')}</FormLabel> | |||||
| <FormControl> | |||||
| <Textarea | |||||
| placeholder="Tell us a little bit about yourself" | |||||
| className="resize-none" | |||||
| {...field} | |||||
| /> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <LlmSettingFieldItems prefix="llm_setting"></LlmSettingFieldItems> | |||||
| </div> | |||||
| ); | ); | ||||
| } | } |
| import { UseKnowledgeGraphFormField } from '@/components/use-knowledge-graph-item'; | import { UseKnowledgeGraphFormField } from '@/components/use-knowledge-graph-item'; | ||||
| import { useTranslate } from '@/hooks/common-hooks'; | import { useTranslate } from '@/hooks/common-hooks'; | ||||
| import { useFormContext } from 'react-hook-form'; | import { useFormContext } from 'react-hook-form'; | ||||
| import { Subhead } from './subhead'; | |||||
| export function ChatPromptEngine() { | export function ChatPromptEngine() { | ||||
| const { t } = useTranslate('chat'); | const { t } = useTranslate('chat'); | ||||
| const form = useFormContext(); | const form = useFormContext(); | ||||
| return ( | return ( | ||||
| <section> | |||||
| <Subhead>Prompt engine</Subhead> | |||||
| <div className="space-y-8"> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name="prompt_config.system" | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('system')}</FormLabel> | |||||
| <FormControl> | |||||
| <Textarea | |||||
| placeholder="Tell us a little bit about yourself" | |||||
| className="resize-none" | |||||
| {...field} | |||||
| /> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <SimilaritySliderFormField></SimilaritySliderFormField> | |||||
| <TopNFormField></TopNFormField> | |||||
| <SwitchFormField | |||||
| name={'prompt_config.refine_multiturn'} | |||||
| label={t('multiTurn')} | |||||
| ></SwitchFormField> | |||||
| <UseKnowledgeGraphFormField name="prompt_config.use_kg"></UseKnowledgeGraphFormField> | |||||
| <RerankFormFields></RerankFormFields> | |||||
| </div> | |||||
| </section> | |||||
| <div className="space-y-8"> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name="prompt_config.system" | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('system')}</FormLabel> | |||||
| <FormControl> | |||||
| <Textarea | |||||
| placeholder="Tell us a little bit about yourself" | |||||
| className="resize-none" | |||||
| {...field} | |||||
| /> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <SimilaritySliderFormField></SimilaritySliderFormField> | |||||
| <TopNFormField></TopNFormField> | |||||
| <SwitchFormField | |||||
| name={'prompt_config.refine_multiturn'} | |||||
| label={t('multiTurn')} | |||||
| ></SwitchFormField> | |||||
| <UseKnowledgeGraphFormField name="prompt_config.use_kg"></UseKnowledgeGraphFormField> | |||||
| <RerankFormFields></RerankFormFields> | |||||
| </div> | |||||
| ); | ); | ||||
| } | } |
| import { | |||||
| Sheet, | |||||
| SheetContent, | |||||
| SheetHeader, | |||||
| SheetTitle, | |||||
| SheetTrigger, | |||||
| } from '@/components/ui/sheet'; | |||||
| import { PropsWithChildren } from 'react'; | |||||
| import { ChatSettings } from './chat-settings'; | |||||
| export function ChatSettingSheet({ children }: PropsWithChildren) { | |||||
| return ( | |||||
| <Sheet> | |||||
| <SheetTrigger asChild>{children}</SheetTrigger> | |||||
| <SheetContent> | |||||
| <SheetHeader> | |||||
| <SheetTitle>Chat Settings</SheetTitle> | |||||
| </SheetHeader> | |||||
| <ChatSettings></ChatSettings> | |||||
| </SheetContent> | |||||
| </Sheet> | |||||
| ); | |||||
| } |
| import { Button } from '@/components/ui/button'; | import { Button } from '@/components/ui/button'; | ||||
| import { Separator } from '@/components/ui/separator'; | |||||
| import { useFetchDialog } from '@/hooks/use-chat-request'; | |||||
| import { transformBase64ToFile } from '@/utils/file-util'; | |||||
| import { zodResolver } from '@hookform/resolvers/zod'; | import { zodResolver } from '@hookform/resolvers/zod'; | ||||
| import { PanelRightClose } from 'lucide-react'; | import { PanelRightClose } from 'lucide-react'; | ||||
| import { useEffect } from 'react'; | |||||
| import { FormProvider, useForm } from 'react-hook-form'; | import { FormProvider, useForm } from 'react-hook-form'; | ||||
| import { z } from 'zod'; | import { z } from 'zod'; | ||||
| import ChatBasicSetting from './chat-basic-settings'; | import ChatBasicSetting from './chat-basic-settings'; | ||||
| type ChatSettingsProps = { switchSettingVisible(): void }; | type ChatSettingsProps = { switchSettingVisible(): void }; | ||||
| export function ChatSettings({ switchSettingVisible }: ChatSettingsProps) { | export function ChatSettings({ switchSettingVisible }: ChatSettingsProps) { | ||||
| const formSchema = useChatSettingSchema(); | const formSchema = useChatSettingSchema(); | ||||
| const { data } = useFetchDialog(); | |||||
| const form = useForm<z.infer<typeof formSchema>>({ | const form = useForm<z.infer<typeof formSchema>>({ | ||||
| resolver: zodResolver(formSchema), | resolver: zodResolver(formSchema), | ||||
| console.log(values); | console.log(values); | ||||
| } | } | ||||
| useEffect(() => { | |||||
| const nextData = { | |||||
| ...data, | |||||
| icon: data.icon ? [transformBase64ToFile(data.icon)] : [], | |||||
| }; | |||||
| form.reset(nextData as z.infer<typeof formSchema>); | |||||
| }, [data, form]); | |||||
| return ( | return ( | ||||
| <section className="p-5 w-[400px] max-w-[20%]"> | <section className="p-5 w-[400px] max-w-[20%]"> | ||||
| <div className="flex justify-between items-center text-base"> | <div className="flex justify-between items-center text-base"> | ||||
| className="space-y-6 overflow-auto max-h-[87vh] pr-4" | className="space-y-6 overflow-auto max-h-[87vh] pr-4" | ||||
| > | > | ||||
| <ChatBasicSetting></ChatBasicSetting> | <ChatBasicSetting></ChatBasicSetting> | ||||
| <Separator /> | |||||
| <ChatPromptEngine></ChatPromptEngine> | <ChatPromptEngine></ChatPromptEngine> | ||||
| <Separator /> | |||||
| <ChatModelSettings></ChatModelSettings> | <ChatModelSettings></ChatModelSettings> | ||||
| </form> | </form> | ||||
| </FormProvider> | </FormProvider> |
| import { PropsWithChildren } from 'react'; | |||||
| export function Subhead({ children }: PropsWithChildren) { | |||||
| return ( | |||||
| <div className="text-xl font-bold mb-4 text-colors-text-neutral-strong"> | |||||
| {children} | |||||
| </div> | |||||
| ); | |||||
| } |
| import { LlmSettingSchema } from '@/components/llm-setting-items/next'; | |||||
| import { useTranslate } from '@/hooks/common-hooks'; | import { useTranslate } from '@/hooks/common-hooks'; | ||||
| import { z } from 'zod'; | import { z } from 'zod'; | ||||
| top_n: z.number(), | top_n: z.number(), | ||||
| vector_similarity_weight: z.number(), | vector_similarity_weight: z.number(), | ||||
| top_k: z.number(), | top_k: z.number(), | ||||
| llm_setting: z.object(LlmSettingSchema), | |||||
| }); | }); | ||||
| return formSchema; | return formSchema; |
| import { RAGFlowAvatar } from '@/components/ragflow-avatar'; | import { RAGFlowAvatar } from '@/components/ragflow-avatar'; | ||||
| import { Button } from '@/components/ui/button'; | import { Button } from '@/components/ui/button'; | ||||
| import { Card, CardContent } from '@/components/ui/card'; | import { Card, CardContent } from '@/components/ui/card'; | ||||
| import { SearchInput } from '@/components/ui/input'; | |||||
| import { useSetModalState } from '@/hooks/common-hooks'; | import { useSetModalState } from '@/hooks/common-hooks'; | ||||
| import { | import { | ||||
| useFetchDialog, | useFetchDialog, | ||||
| } from '@/hooks/use-chat-request'; | } from '@/hooks/use-chat-request'; | ||||
| import { cn } from '@/lib/utils'; | import { cn } from '@/lib/utils'; | ||||
| import { PanelLeftClose, PanelRightClose, Plus } from 'lucide-react'; | import { PanelLeftClose, PanelRightClose, Plus } from 'lucide-react'; | ||||
| import { useCallback } from 'react'; | |||||
| import { useCallback, useState } from 'react'; | |||||
| import { useHandleClickConversationCard } from '../hooks/use-click-card'; | import { useHandleClickConversationCard } from '../hooks/use-click-card'; | ||||
| import { useSelectDerivedConversationList } from '../hooks/use-select-conversation-list'; | import { useSelectDerivedConversationList } from '../hooks/use-select-conversation-list'; | ||||
| useSelectDerivedConversationList(); | useSelectDerivedConversationList(); | ||||
| const { data } = useFetchDialog(); | const { data } = useFetchDialog(); | ||||
| const { visible, switchVisible } = useSetModalState(true); | const { visible, switchVisible } = useSetModalState(true); | ||||
| const [searchStr, setSearchStr] = useState(''); | |||||
| const handleCardClick = useCallback( | const handleCardClick = useCallback( | ||||
| (conversationId: string, isNew: boolean) => () => { | (conversationId: string, isNew: boolean) => () => { | ||||
| /> | /> | ||||
| </section> | </section> | ||||
| <div className="flex justify-between items-center mb-4 pt-10"> | <div className="flex justify-between items-center mb-4 pt-10"> | ||||
| <span className="text-xl font-bold">Conversations</span> | |||||
| <span className="text-base font-bold">Conversations</span> | |||||
| <Button variant={'ghost'} onClick={addTemporaryConversation}> | <Button variant={'ghost'} onClick={addTemporaryConversation}> | ||||
| <Plus></Plus> | <Plus></Plus> | ||||
| </Button> | </Button> | ||||
| </div> | </div> | ||||
| <div className="pb-4"> | |||||
| <SearchInput | |||||
| onChange={(e) => setSearchStr(e.target.value)} | |||||
| value={searchStr} | |||||
| ></SearchInput> | |||||
| </div> | |||||
| <div className="space-y-4 flex-1 overflow-auto"> | <div className="space-y-4 flex-1 overflow-auto"> | ||||
| {conversationList.map((x) => ( | {conversationList.map((x) => ( | ||||
| <Card | <Card |