mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-08-10 16:59:01 +08:00
feat: create a chat assistant and extract SimilaritySlider (#67)
* feat: extract SimilaritySlider * feat: create a chat assistant
This commit is contained in:
parent
a8294f2168
commit
8c4ec9955e
5
web/src/assets/svg/chat-app-cube.svg
Normal file
5
web/src/assets/svg/chat-app-cube.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="15" height="14" viewBox="0 0 15 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M6.1875 12.1045L7.04673 12.5819C7.21217 12.6738 7.29489 12.7197 7.38249 12.7377C7.46002 12.7537 7.53998 12.7537 7.61751 12.7377C7.70511 12.7197 7.78783 12.6738 7.95327 12.5819L8.8125 12.1045M3.5625 10.6462L2.73007 10.1837C2.55535 10.0866 2.46798 10.0381 2.40437 9.96907C2.34809 9.908 2.3055 9.83562 2.27945 9.75677C2.25 9.66764 2.25 9.5677 2.25 9.36782V8.45867M2.25 5.542V4.63284C2.25 4.43297 2.25 4.33303 2.27945 4.2439C2.3055 4.16505 2.34809 4.09267 2.40437 4.0316C2.46798 3.96257 2.55535 3.91403 2.73007 3.81696L3.5625 3.3545M6.1875 1.89617L7.04673 1.41882C7.21217 1.32691 7.29489 1.28095 7.38249 1.26294C7.46002 1.24699 7.53998 1.24699 7.61751 1.26294C7.70511 1.28095 7.78783 1.32691 7.95327 1.41882L8.8125 1.89617M11.4375 3.3545L12.2699 3.81696C12.4447 3.91403 12.532 3.96257 12.5956 4.0316C12.6519 4.09266 12.6945 4.16505 12.7206 4.2439C12.75 4.33303 12.75 4.43297 12.75 4.63284V5.542M12.75 8.45867V9.36782C12.75 9.5677 12.75 9.66764 12.7206 9.75677C12.6945 9.83562 12.6519 9.908 12.5956 9.96907C12.532 10.0381 12.4447 10.0866 12.2699 10.1837L11.4375 10.6462M6.1875 6.27117L7.5 7.00033M7.5 7.00033L8.8125 6.27117M7.5 7.00033V8.45867M2.25 4.08367L3.5625 4.81283M11.4375 4.81283L12.75 4.08367M7.5 11.3753V12.8337"
|
||||
stroke="#A5A3A9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
29
web/src/components/similarity-slider/index.tsx
Normal file
29
web/src/components/similarity-slider/index.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import { Form, Slider } from 'antd';
|
||||
|
||||
type FieldType = {
|
||||
similarity_threshold?: number;
|
||||
vector_similarity_weight?: number;
|
||||
};
|
||||
|
||||
const SimilaritySlider = () => {
|
||||
return (
|
||||
<>
|
||||
<Form.Item<FieldType>
|
||||
label="Similarity threshold"
|
||||
name={'similarity_threshold'}
|
||||
initialValue={0}
|
||||
>
|
||||
<Slider max={1} step={0.01} />
|
||||
</Form.Item>
|
||||
<Form.Item<FieldType>
|
||||
label="Vector similarity weight"
|
||||
name={'vector_similarity_weight'}
|
||||
initialValue={0}
|
||||
>
|
||||
<Slider max={1} step={0.01} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SimilaritySlider;
|
@ -11,3 +11,40 @@ export enum RunningStatus {
|
||||
DONE = '3', // need to refresh
|
||||
FAIL = '4', // need to refresh
|
||||
}
|
||||
|
||||
export enum ModelVariableType {
|
||||
Improvise = 'Improvise',
|
||||
Precise = 'Precise',
|
||||
Balance = 'Balance',
|
||||
}
|
||||
|
||||
export const settledModelVariableMap = {
|
||||
[ModelVariableType.Improvise]: {
|
||||
temperature: 0.9,
|
||||
top_p: 0.9,
|
||||
frequency_penalty: 0.2,
|
||||
presence_penalty: 0.4,
|
||||
max_tokens: 512,
|
||||
},
|
||||
[ModelVariableType.Precise]: {
|
||||
temperature: 0.1,
|
||||
top_p: 0.3,
|
||||
frequency_penalty: 0.7,
|
||||
presence_penalty: 0.4,
|
||||
max_tokens: 215,
|
||||
},
|
||||
[ModelVariableType.Balance]: {
|
||||
temperature: 0.5,
|
||||
top_p: 0.5,
|
||||
frequency_penalty: 0.7,
|
||||
presence_penalty: 0.4,
|
||||
max_tokens: 215,
|
||||
},
|
||||
};
|
||||
|
||||
export enum LlmModelType {
|
||||
Embedding = 'embedding',
|
||||
Chat = 'chat',
|
||||
Image2text = 'image2text',
|
||||
Speech2text = 'speech2text',
|
||||
}
|
||||
|
@ -124,3 +124,22 @@ export const useFetchKnowledgeBaseConfiguration = () => {
|
||||
fetchKnowledgeBaseConfiguration();
|
||||
}, [fetchKnowledgeBaseConfiguration]);
|
||||
};
|
||||
|
||||
export const useFetchKnowledgeList = (): IKnowledge[] => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const knowledgeModel = useSelector((state: any) => state.knowledgeModel);
|
||||
const { data = [] } = knowledgeModel;
|
||||
|
||||
const fetchList = useCallback(() => {
|
||||
dispatch({
|
||||
type: 'knowledgeModel/getList',
|
||||
});
|
||||
}, [dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchList();
|
||||
}, [fetchList]);
|
||||
|
||||
return data;
|
||||
};
|
||||
|
39
web/src/hooks/llmHooks.ts
Normal file
39
web/src/hooks/llmHooks.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { LlmModelType } from '@/constants/knowledge';
|
||||
import { IThirdOAIModelCollection } from '@/interfaces/database/llm';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useDispatch, useSelector } from 'umi';
|
||||
|
||||
export const useFetchLlmList = (modelType: LlmModelType) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const fetchLlmList = useCallback(() => {
|
||||
dispatch({
|
||||
type: 'settingModel/llm_list',
|
||||
payload: { model_type: modelType },
|
||||
});
|
||||
}, [dispatch, modelType]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchLlmList();
|
||||
}, [fetchLlmList]);
|
||||
};
|
||||
|
||||
export const useSelectLlmOptions = () => {
|
||||
const llmInfo: IThirdOAIModelCollection = useSelector(
|
||||
(state: any) => state.settingModel.llmInfo,
|
||||
);
|
||||
|
||||
const embeddingModelOptions = useMemo(() => {
|
||||
return Object.entries(llmInfo).map(([key, value]) => {
|
||||
return {
|
||||
label: key,
|
||||
options: value.map((x) => ({
|
||||
label: x.llm_name,
|
||||
value: x.llm_name,
|
||||
})),
|
||||
};
|
||||
});
|
||||
}, [llmInfo]);
|
||||
|
||||
return embeddingModelOptions;
|
||||
};
|
47
web/src/interfaces/database/chat.ts
Normal file
47
web/src/interfaces/database/chat.ts
Normal file
@ -0,0 +1,47 @@
|
||||
export interface PromptConfig {
|
||||
empty_response: string;
|
||||
parameters: Parameter[];
|
||||
prologue: string;
|
||||
system: string;
|
||||
}
|
||||
|
||||
export interface Parameter {
|
||||
key: string;
|
||||
optional: boolean;
|
||||
}
|
||||
|
||||
export interface LlmSetting {
|
||||
Creative: Variable;
|
||||
Custom: Variable;
|
||||
Evenly: Variable;
|
||||
Precise: Variable;
|
||||
}
|
||||
|
||||
export interface Variable {
|
||||
frequency_penalty: number;
|
||||
max_tokens: number;
|
||||
presence_penalty: number;
|
||||
temperature: number;
|
||||
top_p: number;
|
||||
}
|
||||
|
||||
export interface IDialog {
|
||||
create_date: string;
|
||||
create_time: number;
|
||||
description: string;
|
||||
icon: string;
|
||||
id: string;
|
||||
kb_ids: string[];
|
||||
kb_names: string[];
|
||||
language: string;
|
||||
llm_id: string;
|
||||
llm_setting: LlmSetting;
|
||||
llm_setting_type: string;
|
||||
name: string;
|
||||
prompt_config: PromptConfig;
|
||||
prompt_type: string;
|
||||
status: string;
|
||||
tenant_id: string;
|
||||
update_date: string;
|
||||
update_time: number;
|
||||
}
|
@ -53,7 +53,7 @@ const RenameModal = () => {
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldValue('name', initialName);
|
||||
}, [initialName, documentId]);
|
||||
}, [initialName, documentId, form]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
|
@ -17,13 +17,14 @@ import {
|
||||
UploadFile,
|
||||
} from 'antd';
|
||||
import pick from 'lodash/pick';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'umi';
|
||||
|
||||
import { useFetchLlmList, useSelectLlmOptions } from '@/hooks/llmHooks';
|
||||
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
|
||||
import { IKnowledge } from '@/interfaces/database/knowledge';
|
||||
import { IThirdOAIModelCollection } from '@/interfaces/database/llm';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { LlmModelType } from '../../constant';
|
||||
import styles from './index.less';
|
||||
|
||||
const { Title } = Typography;
|
||||
@ -35,9 +36,6 @@ const Configuration = () => {
|
||||
const knowledgeBaseId = useKnowledgeBaseId();
|
||||
const loading = useOneNamespaceEffectsLoading('kSModel', ['updateKb']);
|
||||
|
||||
const llmInfo: IThirdOAIModelCollection = useSelector(
|
||||
(state: any) => state.settingModel.llmInfo,
|
||||
);
|
||||
const knowledgeDetails: IKnowledge = useSelector(
|
||||
(state: any) => state.kSModel.knowledgeDetails,
|
||||
);
|
||||
@ -51,17 +49,7 @@ const Configuration = () => {
|
||||
|
||||
const parserList = useSelectParserList();
|
||||
|
||||
const embeddingModelOptions = useMemo(() => {
|
||||
return Object.entries(llmInfo).map(([key, value]) => {
|
||||
return {
|
||||
label: key,
|
||||
options: value.map((x) => ({
|
||||
label: x.llm_name,
|
||||
value: x.llm_name,
|
||||
})),
|
||||
};
|
||||
});
|
||||
}, [llmInfo]);
|
||||
const embeddingModelOptions = useSelectLlmOptions();
|
||||
|
||||
const onFinish = async (values: any) => {
|
||||
console.info(values);
|
||||
@ -86,13 +74,6 @@ const Configuration = () => {
|
||||
console.log('Failed:', errorInfo);
|
||||
};
|
||||
|
||||
const fetchLlmList = useCallback(() => {
|
||||
dispatch({
|
||||
type: 'settingModel/llm_list',
|
||||
payload: { model_type: 'embedding' },
|
||||
});
|
||||
}, [dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
const avatar = knowledgeDetails.avatar;
|
||||
let fileList: UploadFile[] = [];
|
||||
@ -115,9 +96,7 @@ const Configuration = () => {
|
||||
useFetchParserList();
|
||||
useFetchKnowledgeBaseConfiguration();
|
||||
|
||||
useEffect(() => {
|
||||
fetchLlmList();
|
||||
}, [fetchLlmList]);
|
||||
useFetchLlmList(LlmModelType.Embedding);
|
||||
|
||||
return (
|
||||
<div className={styles.configurationWrapper}>
|
||||
|
@ -16,14 +16,10 @@ const KnowledgeTesting = () => {
|
||||
const handleTesting = async () => {
|
||||
const values = await form.validateFields();
|
||||
console.info(values);
|
||||
const similarity_threshold = values.similarity_threshold / 100;
|
||||
const vector_similarity_weight = values.vector_similarity_weight / 100;
|
||||
dispatch({
|
||||
type: 'testingModel/testDocumentChunk',
|
||||
payload: {
|
||||
...values,
|
||||
similarity_threshold,
|
||||
vector_similarity_weight,
|
||||
kb_id: knowledgeBaseId,
|
||||
},
|
||||
});
|
||||
|
@ -1,3 +1,5 @@
|
||||
import SimilaritySlider from '@/components/similarity-slider';
|
||||
import { DeleteOutlined, HistoryOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
@ -6,22 +8,15 @@ import {
|
||||
Form,
|
||||
Input,
|
||||
Slider,
|
||||
SliderSingleProps,
|
||||
Space,
|
||||
Tag,
|
||||
} from 'antd';
|
||||
|
||||
import { DeleteOutlined, HistoryOutlined } from '@ant-design/icons';
|
||||
import { FormInstance } from 'antd/lib';
|
||||
|
||||
import styles from './index.less';
|
||||
|
||||
const list = [1, 2, 3];
|
||||
|
||||
const marks: SliderSingleProps['marks'] = {
|
||||
0: '0',
|
||||
100: '1',
|
||||
};
|
||||
|
||||
type FieldType = {
|
||||
similarity_threshold?: number;
|
||||
vector_similarity_weight?: number;
|
||||
@ -29,12 +24,6 @@ type FieldType = {
|
||||
question: string;
|
||||
};
|
||||
|
||||
const formatter = (value: number | undefined) => {
|
||||
return typeof value === 'number' ? value / 100 : 0;
|
||||
};
|
||||
|
||||
const tooltip = { formatter };
|
||||
|
||||
interface IProps {
|
||||
form: FormInstance;
|
||||
handleTesting: () => Promise<any>;
|
||||
@ -59,23 +48,12 @@ const TestingControl = ({ form, handleTesting }: IProps) => {
|
||||
layout="vertical"
|
||||
form={form}
|
||||
initialValues={{
|
||||
similarity_threshold: 20,
|
||||
vector_similarity_weight: 30,
|
||||
similarity_threshold: 0.2,
|
||||
vector_similarity_weight: 0.3,
|
||||
top_k: 1024,
|
||||
}}
|
||||
>
|
||||
<Form.Item<FieldType>
|
||||
label="Similarity threshold"
|
||||
name={'similarity_threshold'}
|
||||
>
|
||||
<Slider marks={marks} defaultValue={0} tooltip={tooltip} />
|
||||
</Form.Item>
|
||||
<Form.Item<FieldType>
|
||||
label="Vector similarity weight"
|
||||
name={'vector_similarity_weight'}
|
||||
>
|
||||
<Slider marks={marks} defaultValue={0} tooltip={tooltip} />
|
||||
</Form.Item>
|
||||
<SimilaritySlider></SimilaritySlider>
|
||||
<Form.Item<FieldType> label="Top k" name={'top_k'}>
|
||||
<Slider marks={{ 0: 0, 2048: 2048 }} defaultValue={0} max={2048} />
|
||||
</Form.Item>
|
||||
|
@ -1,11 +1,20 @@
|
||||
import { Form, Input } from 'antd';
|
||||
import { Form, Input, Select } from 'antd';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { ISegmentedContentProps } from './interface';
|
||||
|
||||
import { useFetchKnowledgeList } from '@/hooks/knowledgeHook';
|
||||
import styles from './index.less';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
const AssistantSetting = ({ show }: ISegmentedContentProps) => {
|
||||
const knowledgeList = useFetchKnowledgeList();
|
||||
const knowledgeOptions = knowledgeList.map((x) => ({
|
||||
label: x.name,
|
||||
value: x.id,
|
||||
}));
|
||||
|
||||
return (
|
||||
<section
|
||||
className={classNames({
|
||||
@ -19,15 +28,43 @@ const AssistantSetting = ({ show }: ISegmentedContentProps) => {
|
||||
>
|
||||
<Input placeholder="e.g. Resume Jarvis" />
|
||||
</Form.Item>
|
||||
<Form.Item name={'avatar'} label="Assistant avatar">
|
||||
<Form.Item name={'icon'} label="Assistant avatar">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name={'keywords'} label="Keywords">
|
||||
<Input.TextArea autoSize={{ minRows: 3 }} />
|
||||
<Form.Item name={'language'} label="Language" initialValue={'Chinese'}>
|
||||
<Select
|
||||
options={[
|
||||
{ value: 'Chinese', label: 'Chinese' },
|
||||
{ value: 'English', label: 'English' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item name={'opener'} label="Set an opener">
|
||||
<Form.Item
|
||||
name={['prompt_config', 'empty_response']}
|
||||
label="Empty response"
|
||||
>
|
||||
<Input placeholder="" />
|
||||
</Form.Item>
|
||||
<Form.Item name={['prompt_config', 'prologue']} label="Set an opener">
|
||||
<Input.TextArea autoSize={{ minRows: 5 }} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Select one context"
|
||||
name="kb_ids"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: 'Please select!',
|
||||
type: 'array',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select
|
||||
mode="multiple"
|
||||
options={knowledgeOptions}
|
||||
placeholder="Please select"
|
||||
></Select>
|
||||
</Form.Item>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
7
web/src/pages/chat/chat-configuration-modal/constants.ts
Normal file
7
web/src/pages/chat/chat-configuration-modal/constants.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export const variableEnabledFieldMap = {
|
||||
temperatureEnabled: 'temperature',
|
||||
topPEnabled: 'top_p',
|
||||
presencePenaltyEnabled: 'presence_penalty',
|
||||
frequencyPenaltyEnabled: 'frequency_penalty',
|
||||
maxTokensEnabled: 'max_tokens',
|
||||
};
|
@ -41,3 +41,10 @@
|
||||
width: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sliderInputNumber {
|
||||
width: 80px;
|
||||
}
|
||||
.variableSlider {
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -2,17 +2,20 @@ import { ReactComponent as ChatConfigurationAtom } from '@/assets/svg/chat-confi
|
||||
import { IModalManagerChildrenProps } from '@/components/modal-manager';
|
||||
import { Divider, Flex, Form, Modal, Segmented } from 'antd';
|
||||
import { SegmentedValue } from 'antd/es/segmented';
|
||||
import { useState } from 'react';
|
||||
import omit from 'lodash/omit';
|
||||
import { useRef, useState } from 'react';
|
||||
import AssistantSetting from './assistant-setting';
|
||||
import ModelSetting from './model-setting';
|
||||
import PromptEngine from './prompt-engine';
|
||||
|
||||
import { useSetDialog } from '../hooks';
|
||||
import { variableEnabledFieldMap } from './constants';
|
||||
import styles from './index.less';
|
||||
|
||||
enum ConfigurationSegmented {
|
||||
AssistantSetting = 'Assistant Setting',
|
||||
ModelSetting = 'Model Setting',
|
||||
PromptEngine = 'Prompt Engine',
|
||||
ModelSetting = 'Model Setting',
|
||||
}
|
||||
|
||||
const segmentedMap = {
|
||||
@ -45,10 +48,24 @@ const ChatConfigurationModal = ({
|
||||
const [value, setValue] = useState<ConfigurationSegmented>(
|
||||
ConfigurationSegmented.AssistantSetting,
|
||||
);
|
||||
const promptEngineRef = useRef(null);
|
||||
|
||||
const setDialog = useSetDialog();
|
||||
|
||||
const handleOk = async () => {
|
||||
const x = await form.validateFields();
|
||||
console.info(x);
|
||||
const values = await form.validateFields();
|
||||
const nextValues: any = omit(values, Object.keys(variableEnabledFieldMap));
|
||||
const finalValues = {
|
||||
...nextValues,
|
||||
prompt_config: {
|
||||
...nextValues.prompt_config,
|
||||
parameters: promptEngineRef.current,
|
||||
},
|
||||
};
|
||||
console.info(promptEngineRef.current);
|
||||
console.info(nextValues);
|
||||
console.info(finalValues);
|
||||
setDialog(finalValues);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -97,7 +114,14 @@ const ChatConfigurationModal = ({
|
||||
colon={false}
|
||||
>
|
||||
{Object.entries(segmentedMap).map(([key, Element]) => (
|
||||
<Element key={key} show={key === value}></Element>
|
||||
<Element
|
||||
key={key}
|
||||
show={key === value}
|
||||
form={form}
|
||||
{...(key === ConfigurationSegmented.PromptEngine
|
||||
? { ref: promptEngineRef }
|
||||
: {})}
|
||||
></Element>
|
||||
))}
|
||||
</Form>
|
||||
</Modal>
|
||||
|
@ -1,3 +1,14 @@
|
||||
import { FormInstance } from 'antd';
|
||||
|
||||
export interface ISegmentedContentProps {
|
||||
show: boolean;
|
||||
form: FormInstance;
|
||||
}
|
||||
|
||||
export interface IVariable {
|
||||
temperature: number;
|
||||
top_p: number;
|
||||
frequency_penalty: number;
|
||||
presence_penalty: number;
|
||||
max_tokens: number;
|
||||
}
|
||||
|
@ -1,12 +1,48 @@
|
||||
import { Divider, Flex, Form, InputNumber, Select, Slider } from 'antd';
|
||||
import {
|
||||
LlmModelType,
|
||||
ModelVariableType,
|
||||
settledModelVariableMap,
|
||||
} from '@/constants/knowledge';
|
||||
import { Divider, Flex, Form, InputNumber, Select, Slider, Switch } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { useEffect } from 'react';
|
||||
import { ISegmentedContentProps } from './interface';
|
||||
|
||||
import { useFetchLlmList, useSelectLlmOptions } from '@/hooks/llmHooks';
|
||||
import { variableEnabledFieldMap } from './constants';
|
||||
import styles from './index.less';
|
||||
|
||||
const { Option } = Select;
|
||||
const ModelSetting = ({ show, form }: ISegmentedContentProps) => {
|
||||
const parameterOptions = Object.values(ModelVariableType).map((x) => ({
|
||||
label: x,
|
||||
value: x,
|
||||
}));
|
||||
|
||||
const parameters: ModelVariableType = Form.useWatch('parameters', form);
|
||||
|
||||
const modelOptions = useSelectLlmOptions();
|
||||
|
||||
const handleParametersChange = (value: ModelVariableType) => {
|
||||
console.info(value);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const variable = settledModelVariableMap[parameters];
|
||||
form.setFieldsValue({ llm_setting: variable });
|
||||
}, [parameters, form]);
|
||||
|
||||
useEffect(() => {
|
||||
const values = Object.keys(variableEnabledFieldMap).reduce<
|
||||
Record<string, boolean>
|
||||
>((pre, field) => {
|
||||
pre[field] = true;
|
||||
return pre;
|
||||
}, {});
|
||||
form.setFieldsValue(values);
|
||||
}, [form]);
|
||||
|
||||
useFetchLlmList(LlmModelType.Chat);
|
||||
|
||||
const ModelSetting = ({ show }: ISegmentedContentProps) => {
|
||||
return (
|
||||
<section
|
||||
className={classNames({
|
||||
@ -15,135 +51,170 @@ const ModelSetting = ({ show }: ISegmentedContentProps) => {
|
||||
>
|
||||
<Form.Item
|
||||
label="Model"
|
||||
name="model"
|
||||
// rules={[{ required: true, message: 'Please input!' }]}
|
||||
name="llm_id"
|
||||
rules={[{ required: true, message: 'Please select!' }]}
|
||||
>
|
||||
<Select />
|
||||
<Select options={modelOptions} />
|
||||
</Form.Item>
|
||||
<Divider></Divider>
|
||||
<Form.Item
|
||||
label="Parameters"
|
||||
name="parameters"
|
||||
initialValue={ModelVariableType.Precise}
|
||||
// rules={[{ required: true, message: 'Please input!' }]}
|
||||
>
|
||||
<Select />
|
||||
<Select<ModelVariableType>
|
||||
options={parameterOptions}
|
||||
onChange={handleParametersChange}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="Temperature">
|
||||
<Flex gap={20}>
|
||||
<Form.Item label="Temperature" tooltip={'xx'}>
|
||||
<Flex gap={20} align="center">
|
||||
<Form.Item
|
||||
name={'temperatureEnabled'}
|
||||
valuePropName="checked"
|
||||
noStyle
|
||||
>
|
||||
<Switch size="small" />
|
||||
</Form.Item>
|
||||
<Flex flex={1}>
|
||||
<Form.Item
|
||||
name={['address', 'province']}
|
||||
name={['llm_setting', 'temperature']}
|
||||
noStyle
|
||||
rules={[{ required: true, message: 'Province is required' }]}
|
||||
>
|
||||
<Slider style={{ display: 'inline-block', width: '100%' }} />
|
||||
<Slider className={styles.variableSlider} max={1} step={0.01} />
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
<Form.Item
|
||||
name={['address', 'street']}
|
||||
name={['llm_setting', 'temperature']}
|
||||
noStyle
|
||||
rules={[{ required: true, message: 'Street is required' }]}
|
||||
>
|
||||
<InputNumber
|
||||
style={{
|
||||
width: 50,
|
||||
}}
|
||||
className={styles.sliderInputNumber}
|
||||
max={1}
|
||||
min={0}
|
||||
step={0.01}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
</Form.Item>
|
||||
<Form.Item label="Top P">
|
||||
<Flex gap={20}>
|
||||
<Form.Item label="Top P" tooltip={'xx'}>
|
||||
<Flex gap={20} align="center">
|
||||
<Form.Item name={'topPEnabled'} valuePropName="checked" noStyle>
|
||||
<Switch size="small" />
|
||||
</Form.Item>
|
||||
<Flex flex={1}>
|
||||
<Form.Item
|
||||
name={['address', 'province']}
|
||||
name={['llm_setting', 'top_p']}
|
||||
noStyle
|
||||
rules={[{ required: true, message: 'Province is required' }]}
|
||||
>
|
||||
<Slider style={{ display: 'inline-block', width: '100%' }} />
|
||||
<Slider className={styles.variableSlider} max={1} step={0.01} />
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
<Form.Item
|
||||
name={['address', 'street']}
|
||||
name={['llm_setting', 'top_p']}
|
||||
noStyle
|
||||
rules={[{ required: true, message: 'Street is required' }]}
|
||||
>
|
||||
<InputNumber
|
||||
style={{
|
||||
width: 50,
|
||||
}}
|
||||
className={styles.sliderInputNumber}
|
||||
max={1}
|
||||
min={0}
|
||||
step={0.01}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
</Form.Item>
|
||||
<Form.Item label="Presence Penalty">
|
||||
<Flex gap={20}>
|
||||
<Form.Item label="Presence Penalty" tooltip={'xx'}>
|
||||
<Flex gap={20} align="center">
|
||||
<Form.Item
|
||||
name={'presencePenaltyEnabled'}
|
||||
valuePropName="checked"
|
||||
noStyle
|
||||
>
|
||||
<Switch size="small" />
|
||||
</Form.Item>
|
||||
<Flex flex={1}>
|
||||
<Form.Item
|
||||
name={['address', 'province']}
|
||||
name={['llm_setting', 'presence_penalty']}
|
||||
noStyle
|
||||
rules={[{ required: true, message: 'Province is required' }]}
|
||||
>
|
||||
<Slider style={{ display: 'inline-block', width: '100%' }} />
|
||||
<Slider className={styles.variableSlider} max={1} step={0.01} />
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
<Form.Item
|
||||
name={['address', 'street']}
|
||||
name={['llm_setting', 'presence_penalty']}
|
||||
noStyle
|
||||
rules={[{ required: true, message: 'Street is required' }]}
|
||||
>
|
||||
<InputNumber
|
||||
style={{
|
||||
width: 50,
|
||||
}}
|
||||
className={styles.sliderInputNumber}
|
||||
max={1}
|
||||
min={0}
|
||||
step={0.01}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
</Form.Item>
|
||||
<Form.Item label="Frequency Penalty">
|
||||
<Flex gap={20}>
|
||||
<Form.Item label="Frequency Penalty" tooltip={'xx'}>
|
||||
<Flex gap={20} align="center">
|
||||
<Form.Item
|
||||
name={'frequencyPenaltyEnabled'}
|
||||
valuePropName="checked"
|
||||
noStyle
|
||||
>
|
||||
<Switch size="small" />
|
||||
</Form.Item>
|
||||
<Flex flex={1}>
|
||||
<Form.Item
|
||||
name={['address', 'province']}
|
||||
name={['llm_setting', 'frequency_penalty']}
|
||||
noStyle
|
||||
rules={[{ required: true, message: 'Province is required' }]}
|
||||
>
|
||||
<Slider style={{ display: 'inline-block', width: '100%' }} />
|
||||
<Slider className={styles.variableSlider} max={1} step={0.01} />
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
<Form.Item
|
||||
name={['address', 'street']}
|
||||
name={['llm_setting', 'frequency_penalty']}
|
||||
noStyle
|
||||
rules={[{ required: true, message: 'Street is required' }]}
|
||||
>
|
||||
<InputNumber
|
||||
style={{
|
||||
width: 50,
|
||||
}}
|
||||
className={styles.sliderInputNumber}
|
||||
max={1}
|
||||
min={0}
|
||||
step={0.01}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
</Form.Item>
|
||||
<Form.Item label="Max Tokens">
|
||||
<Flex gap={20}>
|
||||
<Form.Item label="Max Tokens" tooltip={'xx'}>
|
||||
<Flex gap={20} align="center">
|
||||
<Form.Item name={'maxTokensEnabled'} valuePropName="checked" noStyle>
|
||||
<Switch size="small" />
|
||||
</Form.Item>
|
||||
<Flex flex={1}>
|
||||
<Form.Item
|
||||
name={['address', 'province']}
|
||||
name={['llm_setting', 'max_tokens']}
|
||||
noStyle
|
||||
rules={[{ required: true, message: 'Province is required' }]}
|
||||
>
|
||||
<Slider style={{ display: 'inline-block', width: '100%' }} />
|
||||
<Slider className={styles.variableSlider} max={2048} />
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
<Form.Item
|
||||
name={['address', 'street']}
|
||||
name={['llm_setting', 'max_tokens']}
|
||||
noStyle
|
||||
rules={[{ required: true, message: 'Street is required' }]}
|
||||
>
|
||||
<InputNumber
|
||||
style={{
|
||||
width: 50,
|
||||
}}
|
||||
className={styles.sliderInputNumber}
|
||||
max={2048}
|
||||
min={0}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
|
@ -1,3 +1,4 @@
|
||||
import SimilaritySlider from '@/components/similarity-slider';
|
||||
import { DeleteOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
Button,
|
||||
@ -6,13 +7,19 @@ import {
|
||||
Form,
|
||||
Input,
|
||||
Row,
|
||||
Select,
|
||||
Slider,
|
||||
Switch,
|
||||
Table,
|
||||
TableProps,
|
||||
} from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
ForwardedRef,
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { EditableCell, EditableRow } from './editable-cell';
|
||||
import { ISegmentedContentProps } from './interface';
|
||||
@ -21,12 +28,20 @@ import styles from './index.less';
|
||||
|
||||
interface DataType {
|
||||
key: string;
|
||||
variable: string;
|
||||
optional: boolean;
|
||||
}
|
||||
|
||||
const { Option } = Select;
|
||||
type FieldType = {
|
||||
similarity_threshold?: number;
|
||||
vector_similarity_weight?: number;
|
||||
top_n?: number;
|
||||
};
|
||||
|
||||
const PromptEngine = ({ show }: ISegmentedContentProps) => {
|
||||
const PromptEngine = (
|
||||
{ show, form }: ISegmentedContentProps,
|
||||
ref: ForwardedRef<Array<Omit<DataType, 'variable'>>>,
|
||||
) => {
|
||||
const [dataSource, setDataSource] = useState<DataType[]>([]);
|
||||
|
||||
const components = {
|
||||
@ -52,6 +67,44 @@ const PromptEngine = ({ show }: ISegmentedContentProps) => {
|
||||
setDataSource(newData);
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
setDataSource((state) => [
|
||||
...state,
|
||||
{
|
||||
key: uuid(),
|
||||
variable: '',
|
||||
optional: true,
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
const handleOptionalChange = (row: DataType) => (checked: boolean) => {
|
||||
const newData = [...dataSource];
|
||||
const index = newData.findIndex((item) => row.key === item.key);
|
||||
const item = newData[index];
|
||||
newData.splice(index, 1, {
|
||||
...item,
|
||||
optional: checked,
|
||||
});
|
||||
setDataSource(newData);
|
||||
};
|
||||
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
() => {
|
||||
return dataSource
|
||||
.filter((x) => x.variable.trim() !== '')
|
||||
.map((x) => ({ key: x.variable, optional: x.optional }));
|
||||
},
|
||||
[dataSource],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldValue(['prompt_config', 'parameters'], dataSource);
|
||||
const x = form.getFieldValue(['prompt_config', 'parameters']);
|
||||
console.info(x);
|
||||
}, [dataSource, form]);
|
||||
|
||||
const columns: TableProps<DataType>['columns'] = [
|
||||
{
|
||||
title: 'key',
|
||||
@ -71,8 +124,14 @@ const PromptEngine = ({ show }: ISegmentedContentProps) => {
|
||||
key: 'optional',
|
||||
width: 40,
|
||||
align: 'center',
|
||||
render() {
|
||||
return <Switch size="small" />;
|
||||
render(text, record) {
|
||||
return (
|
||||
<Switch
|
||||
size="small"
|
||||
checked={text}
|
||||
onChange={handleOptionalChange(record)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -87,17 +146,6 @@ const PromptEngine = ({ show }: ISegmentedContentProps) => {
|
||||
},
|
||||
];
|
||||
|
||||
const handleAdd = () => {
|
||||
setDataSource((state) => [
|
||||
...state,
|
||||
{
|
||||
key: uuid(),
|
||||
variable: '',
|
||||
optional: true,
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
return (
|
||||
<section
|
||||
className={classNames({
|
||||
@ -106,12 +154,20 @@ const PromptEngine = ({ show }: ISegmentedContentProps) => {
|
||||
>
|
||||
<Form.Item
|
||||
label="Orchestrate"
|
||||
name="orchestrate"
|
||||
rules={[{ required: true, message: 'Please input!' }]}
|
||||
name={['prompt_config', 'system']}
|
||||
initialValue={`你是一个智能助手,请总结知识库的内容来回答问题,请列举知识库中的数据详细回答。当所有知识库内容都与问题无关时,你的回答必须包括“知识库中未找到您要的答案!”这句话。回答需要考虑聊天历史。
|
||||
以下是知识库:
|
||||
{knowledge}
|
||||
以上是知识库。`}
|
||||
>
|
||||
<Input.TextArea autoSize={{ maxRows: 5, minRows: 5 }} />
|
||||
</Form.Item>
|
||||
<Divider></Divider>
|
||||
<SimilaritySlider></SimilaritySlider>
|
||||
<Form.Item<FieldType> label="Top n" name={'top_n'} initialValue={0}>
|
||||
<Slider max={30} />
|
||||
</Form.Item>
|
||||
<section className={classNames(styles.variableContainer)}>
|
||||
<Row align={'middle'} justify="end">
|
||||
<Col span={6} className={styles.variableAlign}>
|
||||
@ -139,25 +195,8 @@ const PromptEngine = ({ show }: ISegmentedContentProps) => {
|
||||
</Row>
|
||||
)}
|
||||
</section>
|
||||
<Form.Item
|
||||
label="Select one context"
|
||||
name="context"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: 'Please select your favourite colors!',
|
||||
type: 'array',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select mode="multiple" placeholder="Please select favourite colors">
|
||||
<Option value="red">Red</Option>
|
||||
<Option value="green">Green</Option>
|
||||
<Option value="blue">Blue</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default PromptEngine;
|
||||
export default forwardRef(PromptEngine);
|
||||
|
29
web/src/pages/chat/hooks.ts
Normal file
29
web/src/pages/chat/hooks.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { IDialog } from '@/interfaces/database/chat';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'umi';
|
||||
|
||||
export const useFetchDialogList = () => {
|
||||
const dispatch = useDispatch();
|
||||
const dialogList: IDialog[] = useSelector(
|
||||
(state: any) => state.chatModel.dialogList,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch({ type: 'chatModel/listDialog' });
|
||||
}, [dispatch]);
|
||||
|
||||
return dialogList;
|
||||
};
|
||||
|
||||
export const useSetDialog = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const setDialog = useCallback(
|
||||
(payload: IDialog) => {
|
||||
dispatch({ type: 'chatModel/setDialog', payload });
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
return setDialog;
|
||||
};
|
@ -4,6 +4,17 @@
|
||||
.chatAppWrapper {
|
||||
width: 288px;
|
||||
padding: 26px;
|
||||
|
||||
.chatAppCard {
|
||||
:global(.ant-card-body) {
|
||||
padding: 10px;
|
||||
}
|
||||
.cubeIcon {
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.chatTitleWrapper {
|
||||
width: 220px;
|
||||
|
@ -1,14 +1,73 @@
|
||||
import { FormOutlined } from '@ant-design/icons';
|
||||
import { Button, Card, Divider, Flex, Space, Tag } from 'antd';
|
||||
import { useSelector } from 'umi';
|
||||
import { DeleteOutlined, EditOutlined, FormOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Divider,
|
||||
Dropdown,
|
||||
Flex,
|
||||
MenuProps,
|
||||
Space,
|
||||
Tag,
|
||||
} from 'antd';
|
||||
import ChatContainer from './chat-container';
|
||||
|
||||
import { ReactComponent as ChatAppCube } from '@/assets/svg/chat-app-cube.svg';
|
||||
import ModalManager from '@/components/modal-manager';
|
||||
import classNames from 'classnames';
|
||||
import ChatConfigurationModal from './chat-configuration-modal';
|
||||
import { useFetchDialogList } from './hooks';
|
||||
|
||||
import { useState } from 'react';
|
||||
import styles from './index.less';
|
||||
|
||||
const Chat = () => {
|
||||
const { name } = useSelector((state: any) => state.chatModel);
|
||||
const dialogList = useFetchDialogList();
|
||||
const [activated, setActivated] = useState<string>('');
|
||||
|
||||
const handleAppCardEnter = (id: string) => () => {
|
||||
setActivated(id);
|
||||
};
|
||||
|
||||
const handleAppCardLeave = () => {
|
||||
setActivated('');
|
||||
};
|
||||
|
||||
const items: MenuProps['items'] = [
|
||||
{
|
||||
key: '1',
|
||||
label: (
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="https://www.antgroup.com"
|
||||
>
|
||||
1st menu item
|
||||
</a>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const appItems: MenuProps['items'] = [
|
||||
{
|
||||
key: '1',
|
||||
label: (
|
||||
<Space>
|
||||
<EditOutlined />
|
||||
Edit
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{ type: 'divider' },
|
||||
{
|
||||
key: '2',
|
||||
label: (
|
||||
<Space>
|
||||
<DeleteOutlined />
|
||||
Delete chat
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Flex className={styles.chatWrapper}>
|
||||
@ -32,9 +91,33 @@ const Chat = () => {
|
||||
</ModalManager>
|
||||
|
||||
<Divider></Divider>
|
||||
<Card>
|
||||
<p>Card content</p>
|
||||
</Card>
|
||||
<Space direction={'vertical'} size={'middle'}>
|
||||
{dialogList.map((x) => (
|
||||
<Card
|
||||
key={x.id}
|
||||
className={classNames(styles.chatAppCard)}
|
||||
onMouseEnter={handleAppCardEnter(x.id)}
|
||||
onMouseLeave={handleAppCardLeave}
|
||||
>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Space>
|
||||
{x.icon}
|
||||
<section>
|
||||
<b>{x.name}</b>
|
||||
<div>{x.description}</div>
|
||||
</section>
|
||||
</Space>
|
||||
{activated === x.id && (
|
||||
<section>
|
||||
<Dropdown menu={{ items: appItems }}>
|
||||
<ChatAppCube className={styles.cubeIcon}></ChatAppCube>
|
||||
</Dropdown>
|
||||
</section>
|
||||
)}
|
||||
</Flex>
|
||||
</Card>
|
||||
))}
|
||||
</Space>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Divider type={'vertical'} className={styles.divider}></Divider>
|
||||
@ -49,7 +132,9 @@ const Chat = () => {
|
||||
<b>Chat</b>
|
||||
<Tag>25</Tag>
|
||||
</Space>
|
||||
<FormOutlined />
|
||||
<Dropdown menu={{ items }}>
|
||||
<FormOutlined />
|
||||
</Dropdown>
|
||||
</Flex>
|
||||
<Divider></Divider>
|
||||
<section className={styles.chatTitleContent}>today</section>
|
||||
|
@ -1,13 +1,18 @@
|
||||
import { IDialog } from '@/interfaces/database/chat';
|
||||
import chatService from '@/services/chatService';
|
||||
import { message } from 'antd';
|
||||
import { DvaModel } from 'umi';
|
||||
|
||||
export interface ChatModelState {
|
||||
name: string;
|
||||
dialogList: IDialog[];
|
||||
}
|
||||
|
||||
const model: DvaModel<ChatModelState> = {
|
||||
namespace: 'chatModel',
|
||||
state: {
|
||||
name: 'kate',
|
||||
dialogList: [],
|
||||
},
|
||||
reducers: {
|
||||
save(state, action) {
|
||||
@ -16,16 +21,41 @@ const model: DvaModel<ChatModelState> = {
|
||||
...action.payload,
|
||||
};
|
||||
},
|
||||
},
|
||||
subscriptions: {
|
||||
setup({ dispatch, history }) {
|
||||
return history.listen((query) => {
|
||||
console.log(query);
|
||||
});
|
||||
setDialogList(state, { payload }) {
|
||||
return {
|
||||
...state,
|
||||
dialogList: payload,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
effects: {
|
||||
*query({ payload }, { call, put }) {},
|
||||
*getDialog({ payload }, { call, put }) {
|
||||
const { data } = yield call(chatService.getDialog, payload);
|
||||
},
|
||||
*setDialog({ payload }, { call, put }) {
|
||||
const { data } = yield call(chatService.setDialog, payload);
|
||||
if (data.retcode === 0) {
|
||||
yield put({ type: 'listDialog' });
|
||||
message.success('Created successfully !');
|
||||
}
|
||||
},
|
||||
*listDialog({ payload }, { call, put }) {
|
||||
const { data } = yield call(chatService.listDialog, payload);
|
||||
yield put({ type: 'setDialogList', payload: data.data });
|
||||
},
|
||||
*listConversation({ payload }, { call, put }) {
|
||||
const { data } = yield call(chatService.listConversation, payload);
|
||||
},
|
||||
*getConversation({ payload }, { call, put }) {
|
||||
const { data } = yield call(chatService.getConversation, payload);
|
||||
},
|
||||
*setConversation({ payload }, { call, put }) {
|
||||
const { data } = yield call(chatService.setConversation, payload);
|
||||
},
|
||||
*completeConversation({ payload }, { call, put }) {
|
||||
const { data } = yield call(chatService.completeConversation, payload);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -2,33 +2,14 @@ import { ReactComponent as FilterIcon } from '@/assets/filter.svg';
|
||||
import ModalManager from '@/components/modal-manager';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { Button, Flex, Space } from 'antd';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useDispatch, useNavigate, useSelector } from 'umi';
|
||||
import KnowledgeCard from './knowledge-card';
|
||||
import KnowledgeCreatingModal from './knowledge-creating-modal';
|
||||
|
||||
import { useFetchKnowledgeList } from '@/hooks/knowledgeHook';
|
||||
import styles from './index.less';
|
||||
|
||||
const Knowledge = () => {
|
||||
const dispatch = useDispatch();
|
||||
const knowledgeModel = useSelector((state: any) => state.knowledgeModel);
|
||||
const navigate = useNavigate();
|
||||
const { data = [] } = knowledgeModel;
|
||||
|
||||
const fetchList = useCallback(() => {
|
||||
dispatch({
|
||||
type: 'knowledgeModel/getList',
|
||||
payload: {},
|
||||
});
|
||||
}, []);
|
||||
|
||||
// const handleAddKnowledge = () => {
|
||||
// navigate(`/knowledge/${KnowledgeRouteKey.Configuration}`);
|
||||
// };
|
||||
|
||||
useEffect(() => {
|
||||
fetchList();
|
||||
}, [fetchList]);
|
||||
const data = useFetchKnowledgeList();
|
||||
|
||||
return (
|
||||
<div className={styles.knowledge}>
|
||||
|
@ -37,7 +37,7 @@ const SettingList = () => {
|
||||
type: 'settingModel/my_llm',
|
||||
payload: {},
|
||||
});
|
||||
}, []);
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
48
web/src/services/chatService.ts
Normal file
48
web/src/services/chatService.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import api from '@/utils/api';
|
||||
import registerServer from '@/utils/registerServer';
|
||||
import request from '@/utils/request';
|
||||
|
||||
const {
|
||||
getDialog,
|
||||
setDialog,
|
||||
listDialog,
|
||||
getConversation,
|
||||
setConversation,
|
||||
completeConversation,
|
||||
listConversation,
|
||||
} = api;
|
||||
|
||||
const methods = {
|
||||
getDialog: {
|
||||
url: getDialog,
|
||||
method: 'get',
|
||||
},
|
||||
setDialog: {
|
||||
url: setDialog,
|
||||
method: 'post',
|
||||
},
|
||||
listDialog: {
|
||||
url: listDialog,
|
||||
method: 'get',
|
||||
},
|
||||
listConversation: {
|
||||
url: listConversation,
|
||||
method: 'get',
|
||||
},
|
||||
getConversation: {
|
||||
url: getConversation,
|
||||
method: 'get',
|
||||
},
|
||||
setConversation: {
|
||||
url: setConversation,
|
||||
method: 'post',
|
||||
},
|
||||
completeConversation: {
|
||||
url: completeConversation,
|
||||
method: 'post',
|
||||
},
|
||||
} as const;
|
||||
|
||||
const chatService = registerServer<keyof typeof methods>(methods, request);
|
||||
|
||||
export default chatService;
|
@ -42,4 +42,14 @@ export default {
|
||||
document_create: `${api_host}/document/create`,
|
||||
document_run: `${api_host}/document/run`,
|
||||
document_change_parser: `${api_host}/document/change_parser`,
|
||||
|
||||
setDialog: `${api_host}/dialog/set`,
|
||||
getDialog: `${api_host}/dialog/get`,
|
||||
listDialog: `${api_host}/dialog/list`,
|
||||
|
||||
setConversation: `${api_host}/conversation/set`,
|
||||
getConversation: `${api_host}/conversation/get`,
|
||||
listConversation: `${api_host}/conversation/list`,
|
||||
removeConversation: `${api_host}/conversation/rm`,
|
||||
completeConversation: `${api_host}/conversation/completion`,
|
||||
};
|
||||
|
@ -5,22 +5,23 @@
|
||||
*/
|
||||
// import numeral from 'numeral';
|
||||
|
||||
import JSEncrypt from 'jsencrypt';
|
||||
import { Base64 } from 'js-base64';
|
||||
import JSEncrypt from 'jsencrypt';
|
||||
|
||||
export const getWidth = () => {
|
||||
return { width: window.innerWidth };
|
||||
};
|
||||
export const rsaPsw = (password: string) => {
|
||||
const pub = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArq9XTUSeYr2+N1h3Afl/z8Dse/2yD0ZGrKwx+EEEcdsBLca9Ynmx3nIB5obmLlSfmskLpBo0UACBmB5rEjBp2Q2f3AG3Hjd4B+gNCG6BDaawuDlgANIhGnaTLrIqWrrcm4EMzJOnAOI1fgzJRsOOUEfaS318Eq9OVO3apEyCCt0lOQK6PuksduOjVxtltDav+guVAA068NrPYmRNabVKRNLJpL8w4D44sfth5RvZ3q9t+6RTArpEtc5sh5ChzvqPOzKGMXW83C95TxmXqpbK6olN4RevSfVjEAgCydH6HN6OhtOQEcnrU97r9H0iZOWwbw3pVrZiUkuRD1R56Wzs2wIDAQAB-----END PUBLIC KEY-----"
|
||||
const encryptor = new JSEncrypt()
|
||||
const pub =
|
||||
'-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArq9XTUSeYr2+N1h3Afl/z8Dse/2yD0ZGrKwx+EEEcdsBLca9Ynmx3nIB5obmLlSfmskLpBo0UACBmB5rEjBp2Q2f3AG3Hjd4B+gNCG6BDaawuDlgANIhGnaTLrIqWrrcm4EMzJOnAOI1fgzJRsOOUEfaS318Eq9OVO3apEyCCt0lOQK6PuksduOjVxtltDav+guVAA068NrPYmRNabVKRNLJpL8w4D44sfth5RvZ3q9t+6RTArpEtc5sh5ChzvqPOzKGMXW83C95TxmXqpbK6olN4RevSfVjEAgCydH6HN6OhtOQEcnrU97r9H0iZOWwbw3pVrZiUkuRD1R56Wzs2wIDAQAB-----END PUBLIC KEY-----';
|
||||
const encryptor = new JSEncrypt();
|
||||
|
||||
encryptor.setPublicKey(pub)
|
||||
encryptor.setPublicKey(pub);
|
||||
|
||||
return encryptor.encrypt(Base64.encode(password))
|
||||
}
|
||||
return encryptor.encrypt(Base64.encode(password));
|
||||
};
|
||||
|
||||
export default {
|
||||
getWidth,
|
||||
rsaPsw
|
||||
rsaPsw,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user