balibabu
commited on
Commit
·
8c4ec99
1
Parent(s):
a8294f2
feat: create a chat assistant and extract SimilaritySlider (#67)
Browse files* feat: extract SimilaritySlider
* feat: create a chat assistant
- web/src/assets/svg/chat-app-cube.svg +5 -0
- web/src/components/similarity-slider/index.tsx +29 -0
- web/src/constants/knowledge.ts +37 -0
- web/src/hooks/knowledgeHook.ts +19 -0
- web/src/hooks/llmHooks.ts +39 -0
- web/src/interfaces/database/chat.ts +47 -0
- web/src/pages/add-knowledge/components/knowledge-file/rename-modal/index.tsx +1 -1
- web/src/pages/add-knowledge/components/knowledge-setting/configuration.tsx +5 -26
- web/src/pages/add-knowledge/components/knowledge-testing/index.tsx +0 -4
- web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx +6 -28
- web/src/pages/chat/chat-configuration-modal/assistant-setting.tsx +42 -5
- web/src/pages/chat/chat-configuration-modal/constants.ts +7 -0
- web/src/pages/chat/chat-configuration-modal/index.less +7 -0
- web/src/pages/chat/chat-configuration-modal/index.tsx +29 -5
- web/src/pages/chat/chat-configuration-modal/interface.ts +11 -0
- web/src/pages/chat/chat-configuration-modal/model-setting.tsx +118 -47
- web/src/pages/chat/chat-configuration-modal/prompt-engine.tsx +75 -36
- web/src/pages/chat/hooks.ts +29 -0
- web/src/pages/chat/index.less +11 -0
- web/src/pages/chat/index.tsx +93 -8
- web/src/pages/chat/model.ts +37 -7
- web/src/pages/knowledge/index.tsx +2 -21
- web/src/pages/setting/List.tsx +1 -1
- web/src/services/chatService.ts +48 -0
- web/src/utils/api.ts +10 -0
- web/src/utils/index.ts +8 -7
web/src/assets/svg/chat-app-cube.svg
ADDED
|
web/src/components/similarity-slider/index.tsx
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Form, Slider } from 'antd';
|
2 |
+
|
3 |
+
type FieldType = {
|
4 |
+
similarity_threshold?: number;
|
5 |
+
vector_similarity_weight?: number;
|
6 |
+
};
|
7 |
+
|
8 |
+
const SimilaritySlider = () => {
|
9 |
+
return (
|
10 |
+
<>
|
11 |
+
<Form.Item<FieldType>
|
12 |
+
label="Similarity threshold"
|
13 |
+
name={'similarity_threshold'}
|
14 |
+
initialValue={0}
|
15 |
+
>
|
16 |
+
<Slider max={1} step={0.01} />
|
17 |
+
</Form.Item>
|
18 |
+
<Form.Item<FieldType>
|
19 |
+
label="Vector similarity weight"
|
20 |
+
name={'vector_similarity_weight'}
|
21 |
+
initialValue={0}
|
22 |
+
>
|
23 |
+
<Slider max={1} step={0.01} />
|
24 |
+
</Form.Item>
|
25 |
+
</>
|
26 |
+
);
|
27 |
+
};
|
28 |
+
|
29 |
+
export default SimilaritySlider;
|
web/src/constants/knowledge.ts
CHANGED
@@ -11,3 +11,40 @@ export enum RunningStatus {
|
|
11 |
DONE = '3', // need to refresh
|
12 |
FAIL = '4', // need to refresh
|
13 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
DONE = '3', // need to refresh
|
12 |
FAIL = '4', // need to refresh
|
13 |
}
|
14 |
+
|
15 |
+
export enum ModelVariableType {
|
16 |
+
Improvise = 'Improvise',
|
17 |
+
Precise = 'Precise',
|
18 |
+
Balance = 'Balance',
|
19 |
+
}
|
20 |
+
|
21 |
+
export const settledModelVariableMap = {
|
22 |
+
[ModelVariableType.Improvise]: {
|
23 |
+
temperature: 0.9,
|
24 |
+
top_p: 0.9,
|
25 |
+
frequency_penalty: 0.2,
|
26 |
+
presence_penalty: 0.4,
|
27 |
+
max_tokens: 512,
|
28 |
+
},
|
29 |
+
[ModelVariableType.Precise]: {
|
30 |
+
temperature: 0.1,
|
31 |
+
top_p: 0.3,
|
32 |
+
frequency_penalty: 0.7,
|
33 |
+
presence_penalty: 0.4,
|
34 |
+
max_tokens: 215,
|
35 |
+
},
|
36 |
+
[ModelVariableType.Balance]: {
|
37 |
+
temperature: 0.5,
|
38 |
+
top_p: 0.5,
|
39 |
+
frequency_penalty: 0.7,
|
40 |
+
presence_penalty: 0.4,
|
41 |
+
max_tokens: 215,
|
42 |
+
},
|
43 |
+
};
|
44 |
+
|
45 |
+
export enum LlmModelType {
|
46 |
+
Embedding = 'embedding',
|
47 |
+
Chat = 'chat',
|
48 |
+
Image2text = 'image2text',
|
49 |
+
Speech2text = 'speech2text',
|
50 |
+
}
|
web/src/hooks/knowledgeHook.ts
CHANGED
@@ -124,3 +124,22 @@ export const useFetchKnowledgeBaseConfiguration = () => {
|
|
124 |
fetchKnowledgeBaseConfiguration();
|
125 |
}, [fetchKnowledgeBaseConfiguration]);
|
126 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
fetchKnowledgeBaseConfiguration();
|
125 |
}, [fetchKnowledgeBaseConfiguration]);
|
126 |
};
|
127 |
+
|
128 |
+
export const useFetchKnowledgeList = (): IKnowledge[] => {
|
129 |
+
const dispatch = useDispatch();
|
130 |
+
|
131 |
+
const knowledgeModel = useSelector((state: any) => state.knowledgeModel);
|
132 |
+
const { data = [] } = knowledgeModel;
|
133 |
+
|
134 |
+
const fetchList = useCallback(() => {
|
135 |
+
dispatch({
|
136 |
+
type: 'knowledgeModel/getList',
|
137 |
+
});
|
138 |
+
}, [dispatch]);
|
139 |
+
|
140 |
+
useEffect(() => {
|
141 |
+
fetchList();
|
142 |
+
}, [fetchList]);
|
143 |
+
|
144 |
+
return data;
|
145 |
+
};
|
web/src/hooks/llmHooks.ts
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { LlmModelType } from '@/constants/knowledge';
|
2 |
+
import { IThirdOAIModelCollection } from '@/interfaces/database/llm';
|
3 |
+
import { useCallback, useEffect, useMemo } from 'react';
|
4 |
+
import { useDispatch, useSelector } from 'umi';
|
5 |
+
|
6 |
+
export const useFetchLlmList = (modelType: LlmModelType) => {
|
7 |
+
const dispatch = useDispatch();
|
8 |
+
|
9 |
+
const fetchLlmList = useCallback(() => {
|
10 |
+
dispatch({
|
11 |
+
type: 'settingModel/llm_list',
|
12 |
+
payload: { model_type: modelType },
|
13 |
+
});
|
14 |
+
}, [dispatch, modelType]);
|
15 |
+
|
16 |
+
useEffect(() => {
|
17 |
+
fetchLlmList();
|
18 |
+
}, [fetchLlmList]);
|
19 |
+
};
|
20 |
+
|
21 |
+
export const useSelectLlmOptions = () => {
|
22 |
+
const llmInfo: IThirdOAIModelCollection = useSelector(
|
23 |
+
(state: any) => state.settingModel.llmInfo,
|
24 |
+
);
|
25 |
+
|
26 |
+
const embeddingModelOptions = useMemo(() => {
|
27 |
+
return Object.entries(llmInfo).map(([key, value]) => {
|
28 |
+
return {
|
29 |
+
label: key,
|
30 |
+
options: value.map((x) => ({
|
31 |
+
label: x.llm_name,
|
32 |
+
value: x.llm_name,
|
33 |
+
})),
|
34 |
+
};
|
35 |
+
});
|
36 |
+
}, [llmInfo]);
|
37 |
+
|
38 |
+
return embeddingModelOptions;
|
39 |
+
};
|
web/src/interfaces/database/chat.ts
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export interface PromptConfig {
|
2 |
+
empty_response: string;
|
3 |
+
parameters: Parameter[];
|
4 |
+
prologue: string;
|
5 |
+
system: string;
|
6 |
+
}
|
7 |
+
|
8 |
+
export interface Parameter {
|
9 |
+
key: string;
|
10 |
+
optional: boolean;
|
11 |
+
}
|
12 |
+
|
13 |
+
export interface LlmSetting {
|
14 |
+
Creative: Variable;
|
15 |
+
Custom: Variable;
|
16 |
+
Evenly: Variable;
|
17 |
+
Precise: Variable;
|
18 |
+
}
|
19 |
+
|
20 |
+
export interface Variable {
|
21 |
+
frequency_penalty: number;
|
22 |
+
max_tokens: number;
|
23 |
+
presence_penalty: number;
|
24 |
+
temperature: number;
|
25 |
+
top_p: number;
|
26 |
+
}
|
27 |
+
|
28 |
+
export interface IDialog {
|
29 |
+
create_date: string;
|
30 |
+
create_time: number;
|
31 |
+
description: string;
|
32 |
+
icon: string;
|
33 |
+
id: string;
|
34 |
+
kb_ids: string[];
|
35 |
+
kb_names: string[];
|
36 |
+
language: string;
|
37 |
+
llm_id: string;
|
38 |
+
llm_setting: LlmSetting;
|
39 |
+
llm_setting_type: string;
|
40 |
+
name: string;
|
41 |
+
prompt_config: PromptConfig;
|
42 |
+
prompt_type: string;
|
43 |
+
status: string;
|
44 |
+
tenant_id: string;
|
45 |
+
update_date: string;
|
46 |
+
update_time: number;
|
47 |
+
}
|
web/src/pages/add-knowledge/components/knowledge-file/rename-modal/index.tsx
CHANGED
@@ -53,7 +53,7 @@ const RenameModal = () => {
|
|
53 |
|
54 |
useEffect(() => {
|
55 |
form.setFieldValue('name', initialName);
|
56 |
-
}, [initialName, documentId]);
|
57 |
|
58 |
return (
|
59 |
<Modal
|
|
|
53 |
|
54 |
useEffect(() => {
|
55 |
form.setFieldValue('name', initialName);
|
56 |
+
}, [initialName, documentId, form]);
|
57 |
|
58 |
return (
|
59 |
<Modal
|
web/src/pages/add-knowledge/components/knowledge-setting/configuration.tsx
CHANGED
@@ -17,13 +17,14 @@ import {
|
|
17 |
UploadFile,
|
18 |
} from 'antd';
|
19 |
import pick from 'lodash/pick';
|
20 |
-
import {
|
21 |
import { useDispatch, useSelector } from 'umi';
|
22 |
|
|
|
23 |
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
|
24 |
import { IKnowledge } from '@/interfaces/database/knowledge';
|
25 |
-
import { IThirdOAIModelCollection } from '@/interfaces/database/llm';
|
26 |
import { PlusOutlined } from '@ant-design/icons';
|
|
|
27 |
import styles from './index.less';
|
28 |
|
29 |
const { Title } = Typography;
|
@@ -35,9 +36,6 @@ const Configuration = () => {
|
|
35 |
const knowledgeBaseId = useKnowledgeBaseId();
|
36 |
const loading = useOneNamespaceEffectsLoading('kSModel', ['updateKb']);
|
37 |
|
38 |
-
const llmInfo: IThirdOAIModelCollection = useSelector(
|
39 |
-
(state: any) => state.settingModel.llmInfo,
|
40 |
-
);
|
41 |
const knowledgeDetails: IKnowledge = useSelector(
|
42 |
(state: any) => state.kSModel.knowledgeDetails,
|
43 |
);
|
@@ -51,17 +49,7 @@ const Configuration = () => {
|
|
51 |
|
52 |
const parserList = useSelectParserList();
|
53 |
|
54 |
-
const embeddingModelOptions =
|
55 |
-
return Object.entries(llmInfo).map(([key, value]) => {
|
56 |
-
return {
|
57 |
-
label: key,
|
58 |
-
options: value.map((x) => ({
|
59 |
-
label: x.llm_name,
|
60 |
-
value: x.llm_name,
|
61 |
-
})),
|
62 |
-
};
|
63 |
-
});
|
64 |
-
}, [llmInfo]);
|
65 |
|
66 |
const onFinish = async (values: any) => {
|
67 |
console.info(values);
|
@@ -86,13 +74,6 @@ const Configuration = () => {
|
|
86 |
console.log('Failed:', errorInfo);
|
87 |
};
|
88 |
|
89 |
-
const fetchLlmList = useCallback(() => {
|
90 |
-
dispatch({
|
91 |
-
type: 'settingModel/llm_list',
|
92 |
-
payload: { model_type: 'embedding' },
|
93 |
-
});
|
94 |
-
}, [dispatch]);
|
95 |
-
|
96 |
useEffect(() => {
|
97 |
const avatar = knowledgeDetails.avatar;
|
98 |
let fileList: UploadFile[] = [];
|
@@ -115,9 +96,7 @@ const Configuration = () => {
|
|
115 |
useFetchParserList();
|
116 |
useFetchKnowledgeBaseConfiguration();
|
117 |
|
118 |
-
|
119 |
-
fetchLlmList();
|
120 |
-
}, [fetchLlmList]);
|
121 |
|
122 |
return (
|
123 |
<div className={styles.configurationWrapper}>
|
|
|
17 |
UploadFile,
|
18 |
} from 'antd';
|
19 |
import pick from 'lodash/pick';
|
20 |
+
import { useEffect } from 'react';
|
21 |
import { useDispatch, useSelector } from 'umi';
|
22 |
|
23 |
+
import { useFetchLlmList, useSelectLlmOptions } from '@/hooks/llmHooks';
|
24 |
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
|
25 |
import { IKnowledge } from '@/interfaces/database/knowledge';
|
|
|
26 |
import { PlusOutlined } from '@ant-design/icons';
|
27 |
+
import { LlmModelType } from '../../constant';
|
28 |
import styles from './index.less';
|
29 |
|
30 |
const { Title } = Typography;
|
|
|
36 |
const knowledgeBaseId = useKnowledgeBaseId();
|
37 |
const loading = useOneNamespaceEffectsLoading('kSModel', ['updateKb']);
|
38 |
|
|
|
|
|
|
|
39 |
const knowledgeDetails: IKnowledge = useSelector(
|
40 |
(state: any) => state.kSModel.knowledgeDetails,
|
41 |
);
|
|
|
49 |
|
50 |
const parserList = useSelectParserList();
|
51 |
|
52 |
+
const embeddingModelOptions = useSelectLlmOptions();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
|
54 |
const onFinish = async (values: any) => {
|
55 |
console.info(values);
|
|
|
74 |
console.log('Failed:', errorInfo);
|
75 |
};
|
76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
useEffect(() => {
|
78 |
const avatar = knowledgeDetails.avatar;
|
79 |
let fileList: UploadFile[] = [];
|
|
|
96 |
useFetchParserList();
|
97 |
useFetchKnowledgeBaseConfiguration();
|
98 |
|
99 |
+
useFetchLlmList(LlmModelType.Embedding);
|
|
|
|
|
100 |
|
101 |
return (
|
102 |
<div className={styles.configurationWrapper}>
|
web/src/pages/add-knowledge/components/knowledge-testing/index.tsx
CHANGED
@@ -16,14 +16,10 @@ const KnowledgeTesting = () => {
|
|
16 |
const handleTesting = async () => {
|
17 |
const values = await form.validateFields();
|
18 |
console.info(values);
|
19 |
-
const similarity_threshold = values.similarity_threshold / 100;
|
20 |
-
const vector_similarity_weight = values.vector_similarity_weight / 100;
|
21 |
dispatch({
|
22 |
type: 'testingModel/testDocumentChunk',
|
23 |
payload: {
|
24 |
...values,
|
25 |
-
similarity_threshold,
|
26 |
-
vector_similarity_weight,
|
27 |
kb_id: knowledgeBaseId,
|
28 |
},
|
29 |
});
|
|
|
16 |
const handleTesting = async () => {
|
17 |
const values = await form.validateFields();
|
18 |
console.info(values);
|
|
|
|
|
19 |
dispatch({
|
20 |
type: 'testingModel/testDocumentChunk',
|
21 |
payload: {
|
22 |
...values,
|
|
|
|
|
23 |
kb_id: knowledgeBaseId,
|
24 |
},
|
25 |
});
|
web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx
CHANGED
@@ -1,3 +1,5 @@
|
|
|
|
|
|
1 |
import {
|
2 |
Button,
|
3 |
Card,
|
@@ -6,22 +8,15 @@ import {
|
|
6 |
Form,
|
7 |
Input,
|
8 |
Slider,
|
9 |
-
SliderSingleProps,
|
10 |
Space,
|
11 |
Tag,
|
12 |
} from 'antd';
|
13 |
-
|
14 |
-
import { DeleteOutlined, HistoryOutlined } from '@ant-design/icons';
|
15 |
import { FormInstance } from 'antd/lib';
|
|
|
16 |
import styles from './index.less';
|
17 |
|
18 |
const list = [1, 2, 3];
|
19 |
|
20 |
-
const marks: SliderSingleProps['marks'] = {
|
21 |
-
0: '0',
|
22 |
-
100: '1',
|
23 |
-
};
|
24 |
-
|
25 |
type FieldType = {
|
26 |
similarity_threshold?: number;
|
27 |
vector_similarity_weight?: number;
|
@@ -29,12 +24,6 @@ type FieldType = {
|
|
29 |
question: string;
|
30 |
};
|
31 |
|
32 |
-
const formatter = (value: number | undefined) => {
|
33 |
-
return typeof value === 'number' ? value / 100 : 0;
|
34 |
-
};
|
35 |
-
|
36 |
-
const tooltip = { formatter };
|
37 |
-
|
38 |
interface IProps {
|
39 |
form: FormInstance;
|
40 |
handleTesting: () => Promise<any>;
|
@@ -59,23 +48,12 @@ const TestingControl = ({ form, handleTesting }: IProps) => {
|
|
59 |
layout="vertical"
|
60 |
form={form}
|
61 |
initialValues={{
|
62 |
-
similarity_threshold:
|
63 |
-
vector_similarity_weight:
|
64 |
top_k: 1024,
|
65 |
}}
|
66 |
>
|
67 |
-
<
|
68 |
-
label="Similarity threshold"
|
69 |
-
name={'similarity_threshold'}
|
70 |
-
>
|
71 |
-
<Slider marks={marks} defaultValue={0} tooltip={tooltip} />
|
72 |
-
</Form.Item>
|
73 |
-
<Form.Item<FieldType>
|
74 |
-
label="Vector similarity weight"
|
75 |
-
name={'vector_similarity_weight'}
|
76 |
-
>
|
77 |
-
<Slider marks={marks} defaultValue={0} tooltip={tooltip} />
|
78 |
-
</Form.Item>
|
79 |
<Form.Item<FieldType> label="Top k" name={'top_k'}>
|
80 |
<Slider marks={{ 0: 0, 2048: 2048 }} defaultValue={0} max={2048} />
|
81 |
</Form.Item>
|
|
|
1 |
+
import SimilaritySlider from '@/components/similarity-slider';
|
2 |
+
import { DeleteOutlined, HistoryOutlined } from '@ant-design/icons';
|
3 |
import {
|
4 |
Button,
|
5 |
Card,
|
|
|
8 |
Form,
|
9 |
Input,
|
10 |
Slider,
|
|
|
11 |
Space,
|
12 |
Tag,
|
13 |
} from 'antd';
|
|
|
|
|
14 |
import { FormInstance } from 'antd/lib';
|
15 |
+
|
16 |
import styles from './index.less';
|
17 |
|
18 |
const list = [1, 2, 3];
|
19 |
|
|
|
|
|
|
|
|
|
|
|
20 |
type FieldType = {
|
21 |
similarity_threshold?: number;
|
22 |
vector_similarity_weight?: number;
|
|
|
24 |
question: string;
|
25 |
};
|
26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
interface IProps {
|
28 |
form: FormInstance;
|
29 |
handleTesting: () => Promise<any>;
|
|
|
48 |
layout="vertical"
|
49 |
form={form}
|
50 |
initialValues={{
|
51 |
+
similarity_threshold: 0.2,
|
52 |
+
vector_similarity_weight: 0.3,
|
53 |
top_k: 1024,
|
54 |
}}
|
55 |
>
|
56 |
+
<SimilaritySlider></SimilaritySlider>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
<Form.Item<FieldType> label="Top k" name={'top_k'}>
|
58 |
<Slider marks={{ 0: 0, 2048: 2048 }} defaultValue={0} max={2048} />
|
59 |
</Form.Item>
|
web/src/pages/chat/chat-configuration-modal/assistant-setting.tsx
CHANGED
@@ -1,11 +1,20 @@
|
|
1 |
-
import { Form, Input } from 'antd';
|
2 |
|
3 |
import classNames from 'classnames';
|
4 |
import { ISegmentedContentProps } from './interface';
|
5 |
|
|
|
6 |
import styles from './index.less';
|
7 |
|
|
|
|
|
8 |
const AssistantSetting = ({ show }: ISegmentedContentProps) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
return (
|
10 |
<section
|
11 |
className={classNames({
|
@@ -19,15 +28,43 @@ const AssistantSetting = ({ show }: ISegmentedContentProps) => {
|
|
19 |
>
|
20 |
<Input placeholder="e.g. Resume Jarvis" />
|
21 |
</Form.Item>
|
22 |
-
<Form.Item name={'
|
23 |
<Input />
|
24 |
</Form.Item>
|
25 |
-
<Form.Item name={'
|
26 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
</Form.Item>
|
28 |
-
<Form.Item name={'
|
29 |
<Input.TextArea autoSize={{ minRows: 5 }} />
|
30 |
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
</section>
|
32 |
);
|
33 |
};
|
|
|
1 |
+
import { Form, Input, Select } from 'antd';
|
2 |
|
3 |
import classNames from 'classnames';
|
4 |
import { ISegmentedContentProps } from './interface';
|
5 |
|
6 |
+
import { useFetchKnowledgeList } from '@/hooks/knowledgeHook';
|
7 |
import styles from './index.less';
|
8 |
|
9 |
+
const { Option } = Select;
|
10 |
+
|
11 |
const AssistantSetting = ({ show }: ISegmentedContentProps) => {
|
12 |
+
const knowledgeList = useFetchKnowledgeList();
|
13 |
+
const knowledgeOptions = knowledgeList.map((x) => ({
|
14 |
+
label: x.name,
|
15 |
+
value: x.id,
|
16 |
+
}));
|
17 |
+
|
18 |
return (
|
19 |
<section
|
20 |
className={classNames({
|
|
|
28 |
>
|
29 |
<Input placeholder="e.g. Resume Jarvis" />
|
30 |
</Form.Item>
|
31 |
+
<Form.Item name={'icon'} label="Assistant avatar">
|
32 |
<Input />
|
33 |
</Form.Item>
|
34 |
+
<Form.Item name={'language'} label="Language" initialValue={'Chinese'}>
|
35 |
+
<Select
|
36 |
+
options={[
|
37 |
+
{ value: 'Chinese', label: 'Chinese' },
|
38 |
+
{ value: 'English', label: 'English' },
|
39 |
+
]}
|
40 |
+
/>
|
41 |
+
</Form.Item>
|
42 |
+
<Form.Item
|
43 |
+
name={['prompt_config', 'empty_response']}
|
44 |
+
label="Empty response"
|
45 |
+
>
|
46 |
+
<Input placeholder="" />
|
47 |
</Form.Item>
|
48 |
+
<Form.Item name={['prompt_config', 'prologue']} label="Set an opener">
|
49 |
<Input.TextArea autoSize={{ minRows: 5 }} />
|
50 |
</Form.Item>
|
51 |
+
<Form.Item
|
52 |
+
label="Select one context"
|
53 |
+
name="kb_ids"
|
54 |
+
rules={[
|
55 |
+
{
|
56 |
+
required: true,
|
57 |
+
message: 'Please select!',
|
58 |
+
type: 'array',
|
59 |
+
},
|
60 |
+
]}
|
61 |
+
>
|
62 |
+
<Select
|
63 |
+
mode="multiple"
|
64 |
+
options={knowledgeOptions}
|
65 |
+
placeholder="Please select"
|
66 |
+
></Select>
|
67 |
+
</Form.Item>
|
68 |
</section>
|
69 |
);
|
70 |
};
|
web/src/pages/chat/chat-configuration-modal/constants.ts
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export const variableEnabledFieldMap = {
|
2 |
+
temperatureEnabled: 'temperature',
|
3 |
+
topPEnabled: 'top_p',
|
4 |
+
presencePenaltyEnabled: 'presence_penalty',
|
5 |
+
frequencyPenaltyEnabled: 'frequency_penalty',
|
6 |
+
maxTokensEnabled: 'max_tokens',
|
7 |
+
};
|
web/src/pages/chat/chat-configuration-modal/index.less
CHANGED
@@ -41,3 +41,10 @@
|
|
41 |
width: 0;
|
42 |
margin: 0;
|
43 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
width: 0;
|
42 |
margin: 0;
|
43 |
}
|
44 |
+
|
45 |
+
.sliderInputNumber {
|
46 |
+
width: 80px;
|
47 |
+
}
|
48 |
+
.variableSlider {
|
49 |
+
width: 100%;
|
50 |
+
}
|
web/src/pages/chat/chat-configuration-modal/index.tsx
CHANGED
@@ -2,17 +2,20 @@ import { ReactComponent as ChatConfigurationAtom } from '@/assets/svg/chat-confi
|
|
2 |
import { IModalManagerChildrenProps } from '@/components/modal-manager';
|
3 |
import { Divider, Flex, Form, Modal, Segmented } from 'antd';
|
4 |
import { SegmentedValue } from 'antd/es/segmented';
|
5 |
-
import
|
|
|
6 |
import AssistantSetting from './assistant-setting';
|
7 |
import ModelSetting from './model-setting';
|
8 |
import PromptEngine from './prompt-engine';
|
9 |
|
|
|
|
|
10 |
import styles from './index.less';
|
11 |
|
12 |
enum ConfigurationSegmented {
|
13 |
AssistantSetting = 'Assistant Setting',
|
14 |
-
ModelSetting = 'Model Setting',
|
15 |
PromptEngine = 'Prompt Engine',
|
|
|
16 |
}
|
17 |
|
18 |
const segmentedMap = {
|
@@ -45,10 +48,24 @@ const ChatConfigurationModal = ({
|
|
45 |
const [value, setValue] = useState<ConfigurationSegmented>(
|
46 |
ConfigurationSegmented.AssistantSetting,
|
47 |
);
|
|
|
|
|
|
|
48 |
|
49 |
const handleOk = async () => {
|
50 |
-
const
|
51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
};
|
53 |
|
54 |
const handleCancel = () => {
|
@@ -97,7 +114,14 @@ const ChatConfigurationModal = ({
|
|
97 |
colon={false}
|
98 |
>
|
99 |
{Object.entries(segmentedMap).map(([key, Element]) => (
|
100 |
-
<Element
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
))}
|
102 |
</Form>
|
103 |
</Modal>
|
|
|
2 |
import { IModalManagerChildrenProps } from '@/components/modal-manager';
|
3 |
import { Divider, Flex, Form, Modal, Segmented } from 'antd';
|
4 |
import { SegmentedValue } from 'antd/es/segmented';
|
5 |
+
import omit from 'lodash/omit';
|
6 |
+
import { useRef, useState } from 'react';
|
7 |
import AssistantSetting from './assistant-setting';
|
8 |
import ModelSetting from './model-setting';
|
9 |
import PromptEngine from './prompt-engine';
|
10 |
|
11 |
+
import { useSetDialog } from '../hooks';
|
12 |
+
import { variableEnabledFieldMap } from './constants';
|
13 |
import styles from './index.less';
|
14 |
|
15 |
enum ConfigurationSegmented {
|
16 |
AssistantSetting = 'Assistant Setting',
|
|
|
17 |
PromptEngine = 'Prompt Engine',
|
18 |
+
ModelSetting = 'Model Setting',
|
19 |
}
|
20 |
|
21 |
const segmentedMap = {
|
|
|
48 |
const [value, setValue] = useState<ConfigurationSegmented>(
|
49 |
ConfigurationSegmented.AssistantSetting,
|
50 |
);
|
51 |
+
const promptEngineRef = useRef(null);
|
52 |
+
|
53 |
+
const setDialog = useSetDialog();
|
54 |
|
55 |
const handleOk = async () => {
|
56 |
+
const values = await form.validateFields();
|
57 |
+
const nextValues: any = omit(values, Object.keys(variableEnabledFieldMap));
|
58 |
+
const finalValues = {
|
59 |
+
...nextValues,
|
60 |
+
prompt_config: {
|
61 |
+
...nextValues.prompt_config,
|
62 |
+
parameters: promptEngineRef.current,
|
63 |
+
},
|
64 |
+
};
|
65 |
+
console.info(promptEngineRef.current);
|
66 |
+
console.info(nextValues);
|
67 |
+
console.info(finalValues);
|
68 |
+
setDialog(finalValues);
|
69 |
};
|
70 |
|
71 |
const handleCancel = () => {
|
|
|
114 |
colon={false}
|
115 |
>
|
116 |
{Object.entries(segmentedMap).map(([key, Element]) => (
|
117 |
+
<Element
|
118 |
+
key={key}
|
119 |
+
show={key === value}
|
120 |
+
form={form}
|
121 |
+
{...(key === ConfigurationSegmented.PromptEngine
|
122 |
+
? { ref: promptEngineRef }
|
123 |
+
: {})}
|
124 |
+
></Element>
|
125 |
))}
|
126 |
</Form>
|
127 |
</Modal>
|
web/src/pages/chat/chat-configuration-modal/interface.ts
CHANGED
@@ -1,3 +1,14 @@
|
|
|
|
|
|
1 |
export interface ISegmentedContentProps {
|
2 |
show: boolean;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
}
|
|
|
1 |
+
import { FormInstance } from 'antd';
|
2 |
+
|
3 |
export interface ISegmentedContentProps {
|
4 |
show: boolean;
|
5 |
+
form: FormInstance;
|
6 |
+
}
|
7 |
+
|
8 |
+
export interface IVariable {
|
9 |
+
temperature: number;
|
10 |
+
top_p: number;
|
11 |
+
frequency_penalty: number;
|
12 |
+
presence_penalty: number;
|
13 |
+
max_tokens: number;
|
14 |
}
|
web/src/pages/chat/chat-configuration-modal/model-setting.tsx
CHANGED
@@ -1,12 +1,48 @@
|
|
1 |
-
import {
|
|
|
|
|
|
|
|
|
|
|
2 |
import classNames from 'classnames';
|
|
|
3 |
import { ISegmentedContentProps } from './interface';
|
4 |
|
|
|
|
|
5 |
import styles from './index.less';
|
6 |
|
7 |
-
const {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
|
9 |
-
const ModelSetting = ({ show }: ISegmentedContentProps) => {
|
10 |
return (
|
11 |
<section
|
12 |
className={classNames({
|
@@ -15,135 +51,170 @@ const ModelSetting = ({ show }: ISegmentedContentProps) => {
|
|
15 |
>
|
16 |
<Form.Item
|
17 |
label="Model"
|
18 |
-
name="
|
19 |
-
|
20 |
>
|
21 |
-
<Select />
|
22 |
</Form.Item>
|
23 |
<Divider></Divider>
|
24 |
<Form.Item
|
25 |
label="Parameters"
|
26 |
name="parameters"
|
|
|
27 |
// rules={[{ required: true, message: 'Please input!' }]}
|
28 |
>
|
29 |
-
<Select
|
|
|
|
|
|
|
30 |
</Form.Item>
|
31 |
-
<Form.Item label="Temperature">
|
32 |
-
<Flex gap={20}>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
<Flex flex={1}>
|
34 |
<Form.Item
|
35 |
-
name={['
|
36 |
noStyle
|
37 |
rules={[{ required: true, message: 'Province is required' }]}
|
38 |
>
|
39 |
-
<Slider
|
40 |
</Form.Item>
|
41 |
</Flex>
|
42 |
<Form.Item
|
43 |
-
name={['
|
44 |
noStyle
|
45 |
rules={[{ required: true, message: 'Street is required' }]}
|
46 |
>
|
47 |
<InputNumber
|
48 |
-
|
49 |
-
|
50 |
-
}
|
|
|
51 |
/>
|
52 |
</Form.Item>
|
53 |
</Flex>
|
54 |
</Form.Item>
|
55 |
-
<Form.Item label="Top P">
|
56 |
-
<Flex gap={20}>
|
|
|
|
|
|
|
57 |
<Flex flex={1}>
|
58 |
<Form.Item
|
59 |
-
name={['
|
60 |
noStyle
|
61 |
rules={[{ required: true, message: 'Province is required' }]}
|
62 |
>
|
63 |
-
<Slider
|
64 |
</Form.Item>
|
65 |
</Flex>
|
66 |
<Form.Item
|
67 |
-
name={['
|
68 |
noStyle
|
69 |
rules={[{ required: true, message: 'Street is required' }]}
|
70 |
>
|
71 |
<InputNumber
|
72 |
-
|
73 |
-
|
74 |
-
}
|
|
|
75 |
/>
|
76 |
</Form.Item>
|
77 |
</Flex>
|
78 |
</Form.Item>
|
79 |
-
<Form.Item label="Presence Penalty">
|
80 |
-
<Flex gap={20}>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
<Flex flex={1}>
|
82 |
<Form.Item
|
83 |
-
name={['
|
84 |
noStyle
|
85 |
rules={[{ required: true, message: 'Province is required' }]}
|
86 |
>
|
87 |
-
<Slider
|
88 |
</Form.Item>
|
89 |
</Flex>
|
90 |
<Form.Item
|
91 |
-
name={['
|
92 |
noStyle
|
93 |
rules={[{ required: true, message: 'Street is required' }]}
|
94 |
>
|
95 |
<InputNumber
|
96 |
-
|
97 |
-
|
98 |
-
}
|
|
|
99 |
/>
|
100 |
</Form.Item>
|
101 |
</Flex>
|
102 |
</Form.Item>
|
103 |
-
<Form.Item label="Frequency Penalty">
|
104 |
-
<Flex gap={20}>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
<Flex flex={1}>
|
106 |
<Form.Item
|
107 |
-
name={['
|
108 |
noStyle
|
109 |
rules={[{ required: true, message: 'Province is required' }]}
|
110 |
>
|
111 |
-
<Slider
|
112 |
</Form.Item>
|
113 |
</Flex>
|
114 |
<Form.Item
|
115 |
-
name={['
|
116 |
noStyle
|
117 |
rules={[{ required: true, message: 'Street is required' }]}
|
118 |
>
|
119 |
<InputNumber
|
120 |
-
|
121 |
-
|
122 |
-
}
|
|
|
123 |
/>
|
124 |
</Form.Item>
|
125 |
</Flex>
|
126 |
</Form.Item>
|
127 |
-
<Form.Item label="Max Tokens">
|
128 |
-
<Flex gap={20}>
|
|
|
|
|
|
|
129 |
<Flex flex={1}>
|
130 |
<Form.Item
|
131 |
-
name={['
|
132 |
noStyle
|
133 |
rules={[{ required: true, message: 'Province is required' }]}
|
134 |
>
|
135 |
-
<Slider
|
136 |
</Form.Item>
|
137 |
</Flex>
|
138 |
<Form.Item
|
139 |
-
name={['
|
140 |
noStyle
|
141 |
rules={[{ required: true, message: 'Street is required' }]}
|
142 |
>
|
143 |
<InputNumber
|
144 |
-
|
145 |
-
|
146 |
-
}
|
147 |
/>
|
148 |
</Form.Item>
|
149 |
</Flex>
|
|
|
1 |
+
import {
|
2 |
+
LlmModelType,
|
3 |
+
ModelVariableType,
|
4 |
+
settledModelVariableMap,
|
5 |
+
} from '@/constants/knowledge';
|
6 |
+
import { Divider, Flex, Form, InputNumber, Select, Slider, Switch } from 'antd';
|
7 |
import classNames from 'classnames';
|
8 |
+
import { useEffect } from 'react';
|
9 |
import { ISegmentedContentProps } from './interface';
|
10 |
|
11 |
+
import { useFetchLlmList, useSelectLlmOptions } from '@/hooks/llmHooks';
|
12 |
+
import { variableEnabledFieldMap } from './constants';
|
13 |
import styles from './index.less';
|
14 |
|
15 |
+
const ModelSetting = ({ show, form }: ISegmentedContentProps) => {
|
16 |
+
const parameterOptions = Object.values(ModelVariableType).map((x) => ({
|
17 |
+
label: x,
|
18 |
+
value: x,
|
19 |
+
}));
|
20 |
+
|
21 |
+
const parameters: ModelVariableType = Form.useWatch('parameters', form);
|
22 |
+
|
23 |
+
const modelOptions = useSelectLlmOptions();
|
24 |
+
|
25 |
+
const handleParametersChange = (value: ModelVariableType) => {
|
26 |
+
console.info(value);
|
27 |
+
};
|
28 |
+
|
29 |
+
useEffect(() => {
|
30 |
+
const variable = settledModelVariableMap[parameters];
|
31 |
+
form.setFieldsValue({ llm_setting: variable });
|
32 |
+
}, [parameters, form]);
|
33 |
+
|
34 |
+
useEffect(() => {
|
35 |
+
const values = Object.keys(variableEnabledFieldMap).reduce<
|
36 |
+
Record<string, boolean>
|
37 |
+
>((pre, field) => {
|
38 |
+
pre[field] = true;
|
39 |
+
return pre;
|
40 |
+
}, {});
|
41 |
+
form.setFieldsValue(values);
|
42 |
+
}, [form]);
|
43 |
+
|
44 |
+
useFetchLlmList(LlmModelType.Chat);
|
45 |
|
|
|
46 |
return (
|
47 |
<section
|
48 |
className={classNames({
|
|
|
51 |
>
|
52 |
<Form.Item
|
53 |
label="Model"
|
54 |
+
name="llm_id"
|
55 |
+
rules={[{ required: true, message: 'Please select!' }]}
|
56 |
>
|
57 |
+
<Select options={modelOptions} />
|
58 |
</Form.Item>
|
59 |
<Divider></Divider>
|
60 |
<Form.Item
|
61 |
label="Parameters"
|
62 |
name="parameters"
|
63 |
+
initialValue={ModelVariableType.Precise}
|
64 |
// rules={[{ required: true, message: 'Please input!' }]}
|
65 |
>
|
66 |
+
<Select<ModelVariableType>
|
67 |
+
options={parameterOptions}
|
68 |
+
onChange={handleParametersChange}
|
69 |
+
/>
|
70 |
</Form.Item>
|
71 |
+
<Form.Item label="Temperature" tooltip={'xx'}>
|
72 |
+
<Flex gap={20} align="center">
|
73 |
+
<Form.Item
|
74 |
+
name={'temperatureEnabled'}
|
75 |
+
valuePropName="checked"
|
76 |
+
noStyle
|
77 |
+
>
|
78 |
+
<Switch size="small" />
|
79 |
+
</Form.Item>
|
80 |
<Flex flex={1}>
|
81 |
<Form.Item
|
82 |
+
name={['llm_setting', 'temperature']}
|
83 |
noStyle
|
84 |
rules={[{ required: true, message: 'Province is required' }]}
|
85 |
>
|
86 |
+
<Slider className={styles.variableSlider} max={1} step={0.01} />
|
87 |
</Form.Item>
|
88 |
</Flex>
|
89 |
<Form.Item
|
90 |
+
name={['llm_setting', 'temperature']}
|
91 |
noStyle
|
92 |
rules={[{ required: true, message: 'Street is required' }]}
|
93 |
>
|
94 |
<InputNumber
|
95 |
+
className={styles.sliderInputNumber}
|
96 |
+
max={1}
|
97 |
+
min={0}
|
98 |
+
step={0.01}
|
99 |
/>
|
100 |
</Form.Item>
|
101 |
</Flex>
|
102 |
</Form.Item>
|
103 |
+
<Form.Item label="Top P" tooltip={'xx'}>
|
104 |
+
<Flex gap={20} align="center">
|
105 |
+
<Form.Item name={'topPEnabled'} valuePropName="checked" noStyle>
|
106 |
+
<Switch size="small" />
|
107 |
+
</Form.Item>
|
108 |
<Flex flex={1}>
|
109 |
<Form.Item
|
110 |
+
name={['llm_setting', 'top_p']}
|
111 |
noStyle
|
112 |
rules={[{ required: true, message: 'Province is required' }]}
|
113 |
>
|
114 |
+
<Slider className={styles.variableSlider} max={1} step={0.01} />
|
115 |
</Form.Item>
|
116 |
</Flex>
|
117 |
<Form.Item
|
118 |
+
name={['llm_setting', 'top_p']}
|
119 |
noStyle
|
120 |
rules={[{ required: true, message: 'Street is required' }]}
|
121 |
>
|
122 |
<InputNumber
|
123 |
+
className={styles.sliderInputNumber}
|
124 |
+
max={1}
|
125 |
+
min={0}
|
126 |
+
step={0.01}
|
127 |
/>
|
128 |
</Form.Item>
|
129 |
</Flex>
|
130 |
</Form.Item>
|
131 |
+
<Form.Item label="Presence Penalty" tooltip={'xx'}>
|
132 |
+
<Flex gap={20} align="center">
|
133 |
+
<Form.Item
|
134 |
+
name={'presencePenaltyEnabled'}
|
135 |
+
valuePropName="checked"
|
136 |
+
noStyle
|
137 |
+
>
|
138 |
+
<Switch size="small" />
|
139 |
+
</Form.Item>
|
140 |
<Flex flex={1}>
|
141 |
<Form.Item
|
142 |
+
name={['llm_setting', 'presence_penalty']}
|
143 |
noStyle
|
144 |
rules={[{ required: true, message: 'Province is required' }]}
|
145 |
>
|
146 |
+
<Slider className={styles.variableSlider} max={1} step={0.01} />
|
147 |
</Form.Item>
|
148 |
</Flex>
|
149 |
<Form.Item
|
150 |
+
name={['llm_setting', 'presence_penalty']}
|
151 |
noStyle
|
152 |
rules={[{ required: true, message: 'Street is required' }]}
|
153 |
>
|
154 |
<InputNumber
|
155 |
+
className={styles.sliderInputNumber}
|
156 |
+
max={1}
|
157 |
+
min={0}
|
158 |
+
step={0.01}
|
159 |
/>
|
160 |
</Form.Item>
|
161 |
</Flex>
|
162 |
</Form.Item>
|
163 |
+
<Form.Item label="Frequency Penalty" tooltip={'xx'}>
|
164 |
+
<Flex gap={20} align="center">
|
165 |
+
<Form.Item
|
166 |
+
name={'frequencyPenaltyEnabled'}
|
167 |
+
valuePropName="checked"
|
168 |
+
noStyle
|
169 |
+
>
|
170 |
+
<Switch size="small" />
|
171 |
+
</Form.Item>
|
172 |
<Flex flex={1}>
|
173 |
<Form.Item
|
174 |
+
name={['llm_setting', 'frequency_penalty']}
|
175 |
noStyle
|
176 |
rules={[{ required: true, message: 'Province is required' }]}
|
177 |
>
|
178 |
+
<Slider className={styles.variableSlider} max={1} step={0.01} />
|
179 |
</Form.Item>
|
180 |
</Flex>
|
181 |
<Form.Item
|
182 |
+
name={['llm_setting', 'frequency_penalty']}
|
183 |
noStyle
|
184 |
rules={[{ required: true, message: 'Street is required' }]}
|
185 |
>
|
186 |
<InputNumber
|
187 |
+
className={styles.sliderInputNumber}
|
188 |
+
max={1}
|
189 |
+
min={0}
|
190 |
+
step={0.01}
|
191 |
/>
|
192 |
</Form.Item>
|
193 |
</Flex>
|
194 |
</Form.Item>
|
195 |
+
<Form.Item label="Max Tokens" tooltip={'xx'}>
|
196 |
+
<Flex gap={20} align="center">
|
197 |
+
<Form.Item name={'maxTokensEnabled'} valuePropName="checked" noStyle>
|
198 |
+
<Switch size="small" />
|
199 |
+
</Form.Item>
|
200 |
<Flex flex={1}>
|
201 |
<Form.Item
|
202 |
+
name={['llm_setting', 'max_tokens']}
|
203 |
noStyle
|
204 |
rules={[{ required: true, message: 'Province is required' }]}
|
205 |
>
|
206 |
+
<Slider className={styles.variableSlider} max={2048} />
|
207 |
</Form.Item>
|
208 |
</Flex>
|
209 |
<Form.Item
|
210 |
+
name={['llm_setting', 'max_tokens']}
|
211 |
noStyle
|
212 |
rules={[{ required: true, message: 'Street is required' }]}
|
213 |
>
|
214 |
<InputNumber
|
215 |
+
className={styles.sliderInputNumber}
|
216 |
+
max={2048}
|
217 |
+
min={0}
|
218 |
/>
|
219 |
</Form.Item>
|
220 |
</Flex>
|
web/src/pages/chat/chat-configuration-modal/prompt-engine.tsx
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
import { DeleteOutlined } from '@ant-design/icons';
|
2 |
import {
|
3 |
Button,
|
@@ -6,13 +7,19 @@ import {
|
|
6 |
Form,
|
7 |
Input,
|
8 |
Row,
|
9 |
-
|
10 |
Switch,
|
11 |
Table,
|
12 |
TableProps,
|
13 |
} from 'antd';
|
14 |
import classNames from 'classnames';
|
15 |
-
import {
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
import { v4 as uuid } from 'uuid';
|
17 |
import { EditableCell, EditableRow } from './editable-cell';
|
18 |
import { ISegmentedContentProps } from './interface';
|
@@ -21,12 +28,20 @@ import styles from './index.less';
|
|
21 |
|
22 |
interface DataType {
|
23 |
key: string;
|
|
|
24 |
optional: boolean;
|
25 |
}
|
26 |
|
27 |
-
|
|
|
|
|
|
|
|
|
28 |
|
29 |
-
const PromptEngine = (
|
|
|
|
|
|
|
30 |
const [dataSource, setDataSource] = useState<DataType[]>([]);
|
31 |
|
32 |
const components = {
|
@@ -52,6 +67,44 @@ const PromptEngine = ({ show }: ISegmentedContentProps) => {
|
|
52 |
setDataSource(newData);
|
53 |
};
|
54 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
const columns: TableProps<DataType>['columns'] = [
|
56 |
{
|
57 |
title: 'key',
|
@@ -71,8 +124,14 @@ const PromptEngine = ({ show }: ISegmentedContentProps) => {
|
|
71 |
key: 'optional',
|
72 |
width: 40,
|
73 |
align: 'center',
|
74 |
-
render() {
|
75 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
},
|
77 |
},
|
78 |
{
|
@@ -87,17 +146,6 @@ const PromptEngine = ({ show }: ISegmentedContentProps) => {
|
|
87 |
},
|
88 |
];
|
89 |
|
90 |
-
const handleAdd = () => {
|
91 |
-
setDataSource((state) => [
|
92 |
-
...state,
|
93 |
-
{
|
94 |
-
key: uuid(),
|
95 |
-
variable: '',
|
96 |
-
optional: true,
|
97 |
-
},
|
98 |
-
]);
|
99 |
-
};
|
100 |
-
|
101 |
return (
|
102 |
<section
|
103 |
className={classNames({
|
@@ -106,12 +154,20 @@ const PromptEngine = ({ show }: ISegmentedContentProps) => {
|
|
106 |
>
|
107 |
<Form.Item
|
108 |
label="Orchestrate"
|
109 |
-
name="orchestrate"
|
110 |
rules={[{ required: true, message: 'Please input!' }]}
|
|
|
|
|
|
|
|
|
|
|
111 |
>
|
112 |
<Input.TextArea autoSize={{ maxRows: 5, minRows: 5 }} />
|
113 |
</Form.Item>
|
114 |
<Divider></Divider>
|
|
|
|
|
|
|
|
|
115 |
<section className={classNames(styles.variableContainer)}>
|
116 |
<Row align={'middle'} justify="end">
|
117 |
<Col span={6} className={styles.variableAlign}>
|
@@ -139,25 +195,8 @@ const PromptEngine = ({ show }: ISegmentedContentProps) => {
|
|
139 |
</Row>
|
140 |
)}
|
141 |
</section>
|
142 |
-
<Form.Item
|
143 |
-
label="Select one context"
|
144 |
-
name="context"
|
145 |
-
rules={[
|
146 |
-
{
|
147 |
-
required: true,
|
148 |
-
message: 'Please select your favourite colors!',
|
149 |
-
type: 'array',
|
150 |
-
},
|
151 |
-
]}
|
152 |
-
>
|
153 |
-
<Select mode="multiple" placeholder="Please select favourite colors">
|
154 |
-
<Option value="red">Red</Option>
|
155 |
-
<Option value="green">Green</Option>
|
156 |
-
<Option value="blue">Blue</Option>
|
157 |
-
</Select>
|
158 |
-
</Form.Item>
|
159 |
</section>
|
160 |
);
|
161 |
};
|
162 |
|
163 |
-
export default PromptEngine;
|
|
|
1 |
+
import SimilaritySlider from '@/components/similarity-slider';
|
2 |
import { DeleteOutlined } from '@ant-design/icons';
|
3 |
import {
|
4 |
Button,
|
|
|
7 |
Form,
|
8 |
Input,
|
9 |
Row,
|
10 |
+
Slider,
|
11 |
Switch,
|
12 |
Table,
|
13 |
TableProps,
|
14 |
} from 'antd';
|
15 |
import classNames from 'classnames';
|
16 |
+
import {
|
17 |
+
ForwardedRef,
|
18 |
+
forwardRef,
|
19 |
+
useEffect,
|
20 |
+
useImperativeHandle,
|
21 |
+
useState,
|
22 |
+
} from 'react';
|
23 |
import { v4 as uuid } from 'uuid';
|
24 |
import { EditableCell, EditableRow } from './editable-cell';
|
25 |
import { ISegmentedContentProps } from './interface';
|
|
|
28 |
|
29 |
interface DataType {
|
30 |
key: string;
|
31 |
+
variable: string;
|
32 |
optional: boolean;
|
33 |
}
|
34 |
|
35 |
+
type FieldType = {
|
36 |
+
similarity_threshold?: number;
|
37 |
+
vector_similarity_weight?: number;
|
38 |
+
top_n?: number;
|
39 |
+
};
|
40 |
|
41 |
+
const PromptEngine = (
|
42 |
+
{ show, form }: ISegmentedContentProps,
|
43 |
+
ref: ForwardedRef<Array<Omit<DataType, 'variable'>>>,
|
44 |
+
) => {
|
45 |
const [dataSource, setDataSource] = useState<DataType[]>([]);
|
46 |
|
47 |
const components = {
|
|
|
67 |
setDataSource(newData);
|
68 |
};
|
69 |
|
70 |
+
const handleAdd = () => {
|
71 |
+
setDataSource((state) => [
|
72 |
+
...state,
|
73 |
+
{
|
74 |
+
key: uuid(),
|
75 |
+
variable: '',
|
76 |
+
optional: true,
|
77 |
+
},
|
78 |
+
]);
|
79 |
+
};
|
80 |
+
|
81 |
+
const handleOptionalChange = (row: DataType) => (checked: boolean) => {
|
82 |
+
const newData = [...dataSource];
|
83 |
+
const index = newData.findIndex((item) => row.key === item.key);
|
84 |
+
const item = newData[index];
|
85 |
+
newData.splice(index, 1, {
|
86 |
+
...item,
|
87 |
+
optional: checked,
|
88 |
+
});
|
89 |
+
setDataSource(newData);
|
90 |
+
};
|
91 |
+
|
92 |
+
useImperativeHandle(
|
93 |
+
ref,
|
94 |
+
() => {
|
95 |
+
return dataSource
|
96 |
+
.filter((x) => x.variable.trim() !== '')
|
97 |
+
.map((x) => ({ key: x.variable, optional: x.optional }));
|
98 |
+
},
|
99 |
+
[dataSource],
|
100 |
+
);
|
101 |
+
|
102 |
+
useEffect(() => {
|
103 |
+
form.setFieldValue(['prompt_config', 'parameters'], dataSource);
|
104 |
+
const x = form.getFieldValue(['prompt_config', 'parameters']);
|
105 |
+
console.info(x);
|
106 |
+
}, [dataSource, form]);
|
107 |
+
|
108 |
const columns: TableProps<DataType>['columns'] = [
|
109 |
{
|
110 |
title: 'key',
|
|
|
124 |
key: 'optional',
|
125 |
width: 40,
|
126 |
align: 'center',
|
127 |
+
render(text, record) {
|
128 |
+
return (
|
129 |
+
<Switch
|
130 |
+
size="small"
|
131 |
+
checked={text}
|
132 |
+
onChange={handleOptionalChange(record)}
|
133 |
+
/>
|
134 |
+
);
|
135 |
},
|
136 |
},
|
137 |
{
|
|
|
146 |
},
|
147 |
];
|
148 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
return (
|
150 |
<section
|
151 |
className={classNames({
|
|
|
154 |
>
|
155 |
<Form.Item
|
156 |
label="Orchestrate"
|
|
|
157 |
rules={[{ required: true, message: 'Please input!' }]}
|
158 |
+
name={['prompt_config', 'system']}
|
159 |
+
initialValue={`你是一个智能助手,请总结知识库的内容来回答问题,请列举知识库中的数据详细回答。当所有知识库内容都与问题无关时,你的回答必须包括“知识库中未找到您要的答案!”这句话。回答需要考虑聊天历史。
|
160 |
+
以下是知识库:
|
161 |
+
{knowledge}
|
162 |
+
以上是知识库。`}
|
163 |
>
|
164 |
<Input.TextArea autoSize={{ maxRows: 5, minRows: 5 }} />
|
165 |
</Form.Item>
|
166 |
<Divider></Divider>
|
167 |
+
<SimilaritySlider></SimilaritySlider>
|
168 |
+
<Form.Item<FieldType> label="Top n" name={'top_n'} initialValue={0}>
|
169 |
+
<Slider max={30} />
|
170 |
+
</Form.Item>
|
171 |
<section className={classNames(styles.variableContainer)}>
|
172 |
<Row align={'middle'} justify="end">
|
173 |
<Col span={6} className={styles.variableAlign}>
|
|
|
195 |
</Row>
|
196 |
)}
|
197 |
</section>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
198 |
</section>
|
199 |
);
|
200 |
};
|
201 |
|
202 |
+
export default forwardRef(PromptEngine);
|
web/src/pages/chat/hooks.ts
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { IDialog } from '@/interfaces/database/chat';
|
2 |
+
import { useCallback, useEffect } from 'react';
|
3 |
+
import { useDispatch, useSelector } from 'umi';
|
4 |
+
|
5 |
+
export const useFetchDialogList = () => {
|
6 |
+
const dispatch = useDispatch();
|
7 |
+
const dialogList: IDialog[] = useSelector(
|
8 |
+
(state: any) => state.chatModel.dialogList,
|
9 |
+
);
|
10 |
+
|
11 |
+
useEffect(() => {
|
12 |
+
dispatch({ type: 'chatModel/listDialog' });
|
13 |
+
}, [dispatch]);
|
14 |
+
|
15 |
+
return dialogList;
|
16 |
+
};
|
17 |
+
|
18 |
+
export const useSetDialog = () => {
|
19 |
+
const dispatch = useDispatch();
|
20 |
+
|
21 |
+
const setDialog = useCallback(
|
22 |
+
(payload: IDialog) => {
|
23 |
+
dispatch({ type: 'chatModel/setDialog', payload });
|
24 |
+
},
|
25 |
+
[dispatch],
|
26 |
+
);
|
27 |
+
|
28 |
+
return setDialog;
|
29 |
+
};
|
web/src/pages/chat/index.less
CHANGED
@@ -4,6 +4,17 @@
|
|
4 |
.chatAppWrapper {
|
5 |
width: 288px;
|
6 |
padding: 26px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
}
|
8 |
.chatTitleWrapper {
|
9 |
width: 220px;
|
|
|
4 |
.chatAppWrapper {
|
5 |
width: 288px;
|
6 |
padding: 26px;
|
7 |
+
|
8 |
+
.chatAppCard {
|
9 |
+
:global(.ant-card-body) {
|
10 |
+
padding: 10px;
|
11 |
+
}
|
12 |
+
.cubeIcon {
|
13 |
+
&:hover {
|
14 |
+
cursor: pointer;
|
15 |
+
}
|
16 |
+
}
|
17 |
+
}
|
18 |
}
|
19 |
.chatTitleWrapper {
|
20 |
width: 220px;
|
web/src/pages/chat/index.tsx
CHANGED
@@ -1,14 +1,73 @@
|
|
1 |
-
import { FormOutlined } from '@ant-design/icons';
|
2 |
-
import {
|
3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
import ChatContainer from './chat-container';
|
5 |
|
|
|
6 |
import ModalManager from '@/components/modal-manager';
|
|
|
7 |
import ChatConfigurationModal from './chat-configuration-modal';
|
|
|
|
|
|
|
8 |
import styles from './index.less';
|
9 |
|
10 |
const Chat = () => {
|
11 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
return (
|
14 |
<Flex className={styles.chatWrapper}>
|
@@ -32,9 +91,33 @@ const Chat = () => {
|
|
32 |
</ModalManager>
|
33 |
|
34 |
<Divider></Divider>
|
35 |
-
<
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
</Flex>
|
39 |
</Flex>
|
40 |
<Divider type={'vertical'} className={styles.divider}></Divider>
|
@@ -49,7 +132,9 @@ const Chat = () => {
|
|
49 |
<b>Chat</b>
|
50 |
<Tag>25</Tag>
|
51 |
</Space>
|
52 |
-
<
|
|
|
|
|
53 |
</Flex>
|
54 |
<Divider></Divider>
|
55 |
<section className={styles.chatTitleContent}>today</section>
|
|
|
1 |
+
import { DeleteOutlined, EditOutlined, FormOutlined } from '@ant-design/icons';
|
2 |
+
import {
|
3 |
+
Button,
|
4 |
+
Card,
|
5 |
+
Divider,
|
6 |
+
Dropdown,
|
7 |
+
Flex,
|
8 |
+
MenuProps,
|
9 |
+
Space,
|
10 |
+
Tag,
|
11 |
+
} from 'antd';
|
12 |
import ChatContainer from './chat-container';
|
13 |
|
14 |
+
import { ReactComponent as ChatAppCube } from '@/assets/svg/chat-app-cube.svg';
|
15 |
import ModalManager from '@/components/modal-manager';
|
16 |
+
import classNames from 'classnames';
|
17 |
import ChatConfigurationModal from './chat-configuration-modal';
|
18 |
+
import { useFetchDialogList } from './hooks';
|
19 |
+
|
20 |
+
import { useState } from 'react';
|
21 |
import styles from './index.less';
|
22 |
|
23 |
const Chat = () => {
|
24 |
+
const dialogList = useFetchDialogList();
|
25 |
+
const [activated, setActivated] = useState<string>('');
|
26 |
+
|
27 |
+
const handleAppCardEnter = (id: string) => () => {
|
28 |
+
setActivated(id);
|
29 |
+
};
|
30 |
+
|
31 |
+
const handleAppCardLeave = () => {
|
32 |
+
setActivated('');
|
33 |
+
};
|
34 |
+
|
35 |
+
const items: MenuProps['items'] = [
|
36 |
+
{
|
37 |
+
key: '1',
|
38 |
+
label: (
|
39 |
+
<a
|
40 |
+
target="_blank"
|
41 |
+
rel="noopener noreferrer"
|
42 |
+
href="https://www.antgroup.com"
|
43 |
+
>
|
44 |
+
1st menu item
|
45 |
+
</a>
|
46 |
+
),
|
47 |
+
},
|
48 |
+
];
|
49 |
+
|
50 |
+
const appItems: MenuProps['items'] = [
|
51 |
+
{
|
52 |
+
key: '1',
|
53 |
+
label: (
|
54 |
+
<Space>
|
55 |
+
<EditOutlined />
|
56 |
+
Edit
|
57 |
+
</Space>
|
58 |
+
),
|
59 |
+
},
|
60 |
+
{ type: 'divider' },
|
61 |
+
{
|
62 |
+
key: '2',
|
63 |
+
label: (
|
64 |
+
<Space>
|
65 |
+
<DeleteOutlined />
|
66 |
+
Delete chat
|
67 |
+
</Space>
|
68 |
+
),
|
69 |
+
},
|
70 |
+
];
|
71 |
|
72 |
return (
|
73 |
<Flex className={styles.chatWrapper}>
|
|
|
91 |
</ModalManager>
|
92 |
|
93 |
<Divider></Divider>
|
94 |
+
<Space direction={'vertical'} size={'middle'}>
|
95 |
+
{dialogList.map((x) => (
|
96 |
+
<Card
|
97 |
+
key={x.id}
|
98 |
+
className={classNames(styles.chatAppCard)}
|
99 |
+
onMouseEnter={handleAppCardEnter(x.id)}
|
100 |
+
onMouseLeave={handleAppCardLeave}
|
101 |
+
>
|
102 |
+
<Flex justify="space-between" align="center">
|
103 |
+
<Space>
|
104 |
+
{x.icon}
|
105 |
+
<section>
|
106 |
+
<b>{x.name}</b>
|
107 |
+
<div>{x.description}</div>
|
108 |
+
</section>
|
109 |
+
</Space>
|
110 |
+
{activated === x.id && (
|
111 |
+
<section>
|
112 |
+
<Dropdown menu={{ items: appItems }}>
|
113 |
+
<ChatAppCube className={styles.cubeIcon}></ChatAppCube>
|
114 |
+
</Dropdown>
|
115 |
+
</section>
|
116 |
+
)}
|
117 |
+
</Flex>
|
118 |
+
</Card>
|
119 |
+
))}
|
120 |
+
</Space>
|
121 |
</Flex>
|
122 |
</Flex>
|
123 |
<Divider type={'vertical'} className={styles.divider}></Divider>
|
|
|
132 |
<b>Chat</b>
|
133 |
<Tag>25</Tag>
|
134 |
</Space>
|
135 |
+
<Dropdown menu={{ items }}>
|
136 |
+
<FormOutlined />
|
137 |
+
</Dropdown>
|
138 |
</Flex>
|
139 |
<Divider></Divider>
|
140 |
<section className={styles.chatTitleContent}>today</section>
|
web/src/pages/chat/model.ts
CHANGED
@@ -1,13 +1,18 @@
|
|
|
|
|
|
|
|
1 |
import { DvaModel } from 'umi';
|
2 |
|
3 |
export interface ChatModelState {
|
4 |
name: string;
|
|
|
5 |
}
|
6 |
|
7 |
const model: DvaModel<ChatModelState> = {
|
8 |
namespace: 'chatModel',
|
9 |
state: {
|
10 |
name: 'kate',
|
|
|
11 |
},
|
12 |
reducers: {
|
13 |
save(state, action) {
|
@@ -16,16 +21,41 @@ const model: DvaModel<ChatModelState> = {
|
|
16 |
...action.payload,
|
17 |
};
|
18 |
},
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
});
|
25 |
},
|
26 |
},
|
|
|
27 |
effects: {
|
28 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
},
|
30 |
};
|
31 |
|
|
|
1 |
+
import { IDialog } from '@/interfaces/database/chat';
|
2 |
+
import chatService from '@/services/chatService';
|
3 |
+
import { message } from 'antd';
|
4 |
import { DvaModel } from 'umi';
|
5 |
|
6 |
export interface ChatModelState {
|
7 |
name: string;
|
8 |
+
dialogList: IDialog[];
|
9 |
}
|
10 |
|
11 |
const model: DvaModel<ChatModelState> = {
|
12 |
namespace: 'chatModel',
|
13 |
state: {
|
14 |
name: 'kate',
|
15 |
+
dialogList: [],
|
16 |
},
|
17 |
reducers: {
|
18 |
save(state, action) {
|
|
|
21 |
...action.payload,
|
22 |
};
|
23 |
},
|
24 |
+
setDialogList(state, { payload }) {
|
25 |
+
return {
|
26 |
+
...state,
|
27 |
+
dialogList: payload,
|
28 |
+
};
|
|
|
29 |
},
|
30 |
},
|
31 |
+
|
32 |
effects: {
|
33 |
+
*getDialog({ payload }, { call, put }) {
|
34 |
+
const { data } = yield call(chatService.getDialog, payload);
|
35 |
+
},
|
36 |
+
*setDialog({ payload }, { call, put }) {
|
37 |
+
const { data } = yield call(chatService.setDialog, payload);
|
38 |
+
if (data.retcode === 0) {
|
39 |
+
yield put({ type: 'listDialog' });
|
40 |
+
message.success('Created successfully !');
|
41 |
+
}
|
42 |
+
},
|
43 |
+
*listDialog({ payload }, { call, put }) {
|
44 |
+
const { data } = yield call(chatService.listDialog, payload);
|
45 |
+
yield put({ type: 'setDialogList', payload: data.data });
|
46 |
+
},
|
47 |
+
*listConversation({ payload }, { call, put }) {
|
48 |
+
const { data } = yield call(chatService.listConversation, payload);
|
49 |
+
},
|
50 |
+
*getConversation({ payload }, { call, put }) {
|
51 |
+
const { data } = yield call(chatService.getConversation, payload);
|
52 |
+
},
|
53 |
+
*setConversation({ payload }, { call, put }) {
|
54 |
+
const { data } = yield call(chatService.setConversation, payload);
|
55 |
+
},
|
56 |
+
*completeConversation({ payload }, { call, put }) {
|
57 |
+
const { data } = yield call(chatService.completeConversation, payload);
|
58 |
+
},
|
59 |
},
|
60 |
};
|
61 |
|
web/src/pages/knowledge/index.tsx
CHANGED
@@ -2,33 +2,14 @@ import { ReactComponent as FilterIcon } from '@/assets/filter.svg';
|
|
2 |
import ModalManager from '@/components/modal-manager';
|
3 |
import { PlusOutlined } from '@ant-design/icons';
|
4 |
import { Button, Flex, Space } from 'antd';
|
5 |
-
import { useCallback, useEffect } from 'react';
|
6 |
-
import { useDispatch, useNavigate, useSelector } from 'umi';
|
7 |
import KnowledgeCard from './knowledge-card';
|
8 |
import KnowledgeCreatingModal from './knowledge-creating-modal';
|
9 |
|
|
|
10 |
import styles from './index.less';
|
11 |
|
12 |
const Knowledge = () => {
|
13 |
-
const
|
14 |
-
const knowledgeModel = useSelector((state: any) => state.knowledgeModel);
|
15 |
-
const navigate = useNavigate();
|
16 |
-
const { data = [] } = knowledgeModel;
|
17 |
-
|
18 |
-
const fetchList = useCallback(() => {
|
19 |
-
dispatch({
|
20 |
-
type: 'knowledgeModel/getList',
|
21 |
-
payload: {},
|
22 |
-
});
|
23 |
-
}, []);
|
24 |
-
|
25 |
-
// const handleAddKnowledge = () => {
|
26 |
-
// navigate(`/knowledge/${KnowledgeRouteKey.Configuration}`);
|
27 |
-
// };
|
28 |
-
|
29 |
-
useEffect(() => {
|
30 |
-
fetchList();
|
31 |
-
}, [fetchList]);
|
32 |
|
33 |
return (
|
34 |
<div className={styles.knowledge}>
|
|
|
2 |
import ModalManager from '@/components/modal-manager';
|
3 |
import { PlusOutlined } from '@ant-design/icons';
|
4 |
import { Button, Flex, Space } from 'antd';
|
|
|
|
|
5 |
import KnowledgeCard from './knowledge-card';
|
6 |
import KnowledgeCreatingModal from './knowledge-creating-modal';
|
7 |
|
8 |
+
import { useFetchKnowledgeList } from '@/hooks/knowledgeHook';
|
9 |
import styles from './index.less';
|
10 |
|
11 |
const Knowledge = () => {
|
12 |
+
const data = useFetchKnowledgeList();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
return (
|
15 |
<div className={styles.knowledge}>
|
web/src/pages/setting/List.tsx
CHANGED
@@ -37,7 +37,7 @@ const SettingList = () => {
|
|
37 |
type: 'settingModel/my_llm',
|
38 |
payload: {},
|
39 |
});
|
40 |
-
}, []);
|
41 |
|
42 |
return (
|
43 |
<div
|
|
|
37 |
type: 'settingModel/my_llm',
|
38 |
payload: {},
|
39 |
});
|
40 |
+
}, [dispatch]);
|
41 |
|
42 |
return (
|
43 |
<div
|
web/src/services/chatService.ts
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import api from '@/utils/api';
|
2 |
+
import registerServer from '@/utils/registerServer';
|
3 |
+
import request from '@/utils/request';
|
4 |
+
|
5 |
+
const {
|
6 |
+
getDialog,
|
7 |
+
setDialog,
|
8 |
+
listDialog,
|
9 |
+
getConversation,
|
10 |
+
setConversation,
|
11 |
+
completeConversation,
|
12 |
+
listConversation,
|
13 |
+
} = api;
|
14 |
+
|
15 |
+
const methods = {
|
16 |
+
getDialog: {
|
17 |
+
url: getDialog,
|
18 |
+
method: 'get',
|
19 |
+
},
|
20 |
+
setDialog: {
|
21 |
+
url: setDialog,
|
22 |
+
method: 'post',
|
23 |
+
},
|
24 |
+
listDialog: {
|
25 |
+
url: listDialog,
|
26 |
+
method: 'get',
|
27 |
+
},
|
28 |
+
listConversation: {
|
29 |
+
url: listConversation,
|
30 |
+
method: 'get',
|
31 |
+
},
|
32 |
+
getConversation: {
|
33 |
+
url: getConversation,
|
34 |
+
method: 'get',
|
35 |
+
},
|
36 |
+
setConversation: {
|
37 |
+
url: setConversation,
|
38 |
+
method: 'post',
|
39 |
+
},
|
40 |
+
completeConversation: {
|
41 |
+
url: completeConversation,
|
42 |
+
method: 'post',
|
43 |
+
},
|
44 |
+
} as const;
|
45 |
+
|
46 |
+
const chatService = registerServer<keyof typeof methods>(methods, request);
|
47 |
+
|
48 |
+
export default chatService;
|
web/src/utils/api.ts
CHANGED
@@ -42,4 +42,14 @@ export default {
|
|
42 |
document_create: `${api_host}/document/create`,
|
43 |
document_run: `${api_host}/document/run`,
|
44 |
document_change_parser: `${api_host}/document/change_parser`,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
};
|
|
|
42 |
document_create: `${api_host}/document/create`,
|
43 |
document_run: `${api_host}/document/run`,
|
44 |
document_change_parser: `${api_host}/document/change_parser`,
|
45 |
+
|
46 |
+
setDialog: `${api_host}/dialog/set`,
|
47 |
+
getDialog: `${api_host}/dialog/get`,
|
48 |
+
listDialog: `${api_host}/dialog/list`,
|
49 |
+
|
50 |
+
setConversation: `${api_host}/conversation/set`,
|
51 |
+
getConversation: `${api_host}/conversation/get`,
|
52 |
+
listConversation: `${api_host}/conversation/list`,
|
53 |
+
removeConversation: `${api_host}/conversation/rm`,
|
54 |
+
completeConversation: `${api_host}/conversation/completion`,
|
55 |
};
|
web/src/utils/index.ts
CHANGED
@@ -5,22 +5,23 @@
|
|
5 |
*/
|
6 |
// import numeral from 'numeral';
|
7 |
|
8 |
-
import JSEncrypt from 'jsencrypt';
|
9 |
import { Base64 } from 'js-base64';
|
|
|
10 |
|
11 |
export const getWidth = () => {
|
12 |
return { width: window.innerWidth };
|
13 |
};
|
14 |
export const rsaPsw = (password: string) => {
|
15 |
-
const pub =
|
16 |
-
|
|
|
17 |
|
18 |
-
encryptor.setPublicKey(pub)
|
19 |
|
20 |
-
return encryptor.encrypt(Base64.encode(password))
|
21 |
-
}
|
22 |
|
23 |
export default {
|
24 |
getWidth,
|
25 |
-
rsaPsw
|
26 |
};
|
|
|
5 |
*/
|
6 |
// import numeral from 'numeral';
|
7 |
|
|
|
8 |
import { Base64 } from 'js-base64';
|
9 |
+
import JSEncrypt from 'jsencrypt';
|
10 |
|
11 |
export const getWidth = () => {
|
12 |
return { width: window.innerWidth };
|
13 |
};
|
14 |
export const rsaPsw = (password: string) => {
|
15 |
+
const pub =
|
16 |
+
'-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArq9XTUSeYr2+N1h3Afl/z8Dse/2yD0ZGrKwx+EEEcdsBLca9Ynmx3nIB5obmLlSfmskLpBo0UACBmB5rEjBp2Q2f3AG3Hjd4B+gNCG6BDaawuDlgANIhGnaTLrIqWrrcm4EMzJOnAOI1fgzJRsOOUEfaS318Eq9OVO3apEyCCt0lOQK6PuksduOjVxtltDav+guVAA068NrPYmRNabVKRNLJpL8w4D44sfth5RvZ3q9t+6RTArpEtc5sh5ChzvqPOzKGMXW83C95TxmXqpbK6olN4RevSfVjEAgCydH6HN6OhtOQEcnrU97r9H0iZOWwbw3pVrZiUkuRD1R56Wzs2wIDAQAB-----END PUBLIC KEY-----';
|
17 |
+
const encryptor = new JSEncrypt();
|
18 |
|
19 |
+
encryptor.setPublicKey(pub);
|
20 |
|
21 |
+
return encryptor.encrypt(Base64.encode(password));
|
22 |
+
};
|
23 |
|
24 |
export default {
|
25 |
getWidth,
|
26 |
+
rsaPsw,
|
27 |
};
|