Pārlūkot izejas kodu

Feat: Added meta data to the chat configuration page #8531 (#9417)

### 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
balibabu pirms 2 mēnešiem
vecāks
revīzija
3d18284dd6
Revīzijas autora e-pasta adrese nav piesaistīta nevienam kontam

+ 7
- 0
web/src/interfaces/database/chat.ts Parādīt failu

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 {

+ 9
- 2
web/src/locales/en.ts Parādīt failu

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',

+ 10
- 0
web/src/locales/zh.ts Parādīt failu

tavilyApiKeyHelp: '如何获取?', tavilyApiKeyHelp: '如何获取?',
crossLanguage: '跨语言搜索', crossLanguage: '跨语言搜索',
crossLanguageTip: `选择一种或多种语言进行跨语言搜索。如果未选择任何语言,系统将使用原始查询进行搜索。`, crossLanguageTip: `选择一种或多种语言进行跨语言搜索。如果未选择任何语言,系统将使用原始查询进行搜索。`,
metadata: '元数据',
metadataTip:
'元数据过滤是使用元数据属性(例如标签、类别或访问权限)来优化和控制系统内相关信息检索的过程。',
conditions: '条件',
addCondition: '增加条件',
meta: {
disabled: '禁用',
automatic: '自动',
manual: '手动',
},
}, },
setting: { setting: {
profile: '概要', profile: '概要',

+ 1
- 1
web/src/pages/agent/form/switch-form/index.tsx Parādīt failu

return icon; return icon;
}; };


function useBuildSwitchOperatorOptions() {
export function useBuildSwitchOperatorOptions() {
const { t } = useTranslation(); const { t } = useTranslation();


const switchOperatorOptions = useMemo(() => { const switchOperatorOptions = useMemo(() => {

+ 10
- 15
web/src/pages/chat/chat-configuration-modal/assistant-setting.tsx Parādīt failu



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>

+ 10
- 6
web/src/pages/chat/chat-configuration-modal/metadata-filter-conditions.tsx Parādīt failu

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>

+ 84
- 91
web/src/pages/next-chats/chat/app-settings/chat-basic-settings.tsx Parādīt failu

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>
); );
} }

+ 20
- 24
web/src/pages/next-chats/chat/app-settings/chat-model-settings.tsx Parādīt failu

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>
); );
} }

+ 27
- 31
web/src/pages/next-chats/chat/app-settings/chat-prompt-engine.tsx Parādīt failu

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>
); );
} }

+ 0
- 23
web/src/pages/next-chats/chat/app-settings/chat-settings-sheet.tsx Parādīt failu

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>
);
}

+ 15
- 0
web/src/pages/next-chats/chat/app-settings/chat-settings.tsx Parādīt failu

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>

+ 0
- 9
web/src/pages/next-chats/chat/app-settings/subhead.tsx Parādīt failu

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>
);
}

+ 2
- 0
web/src/pages/next-chats/chat/app-settings/use-chat-setting-schema.tsx Parādīt failu

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;

+ 10
- 2
web/src/pages/next-chats/chat/sessions.tsx Parādīt failu

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

Notiek ielāde…
Atcelt
Saglabāt