balibabu
commited on
Commit
·
058cd84
1
Parent(s):
cdba7f7
feat: fetch conversation and delete chat dialog (#69)
Browse files* feat: set chat configuration to backend
* feat: exclude unEnabled variables
* feat: delete chat dialog
* feat: fetch conversation
- web/src/constants/chat.ts +4 -0
- web/src/hooks/commonHooks.ts +34 -0
- web/src/hooks/knowledgeHook.ts +9 -2
- web/src/interfaces/database/chat.ts +19 -0
- web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.tsx +1 -3
- web/src/pages/chat/chat-configuration-modal/assistant-setting.tsx +2 -4
- web/src/pages/chat/chat-configuration-modal/index.tsx +39 -10
- web/src/pages/chat/chat-configuration-modal/model-setting.tsx +2 -2
- web/src/pages/chat/chat-configuration-modal/prompt-engine.tsx +15 -17
- web/src/pages/chat/chat-container/index.less +15 -0
- web/src/pages/chat/chat-container/index.tsx +34 -2
- web/src/pages/chat/{chat-configuration-modal/constants.ts → constants.ts} +7 -0
- web/src/pages/chat/hooks.ts +339 -3
- web/src/pages/chat/index.less +23 -0
- web/src/pages/chat/index.tsx +108 -56
- web/src/pages/chat/{chat-configuration-modal/interface.ts → interface.ts} +17 -0
- web/src/pages/chat/model.ts +82 -1
- web/src/pages/chat/utils.ts +12 -0
- web/src/pages/knowledge/model.ts +1 -1
- web/src/services/chatService.ts +5 -0
- web/src/utils/api.ts +1 -0
web/src/constants/chat.ts
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export enum MessageType {
|
2 |
+
Assistant = 'assistant',
|
3 |
+
User = 'user',
|
4 |
+
}
|
web/src/hooks/commonHooks.ts
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import isEqual from 'lodash/isEqual';
|
2 |
+
import { useEffect, useRef, useState } from 'react';
|
3 |
+
|
4 |
+
export const useSetModalState = () => {
|
5 |
+
const [visible, setVisible] = useState(false);
|
6 |
+
|
7 |
+
const showModal = () => {
|
8 |
+
setVisible(true);
|
9 |
+
};
|
10 |
+
const hideModal = () => {
|
11 |
+
setVisible(false);
|
12 |
+
};
|
13 |
+
|
14 |
+
return { visible, showModal, hideModal };
|
15 |
+
};
|
16 |
+
|
17 |
+
export const useDeepCompareEffect = (
|
18 |
+
effect: React.EffectCallback,
|
19 |
+
deps: React.DependencyList,
|
20 |
+
) => {
|
21 |
+
const ref = useRef<React.DependencyList>();
|
22 |
+
let callback: ReturnType<React.EffectCallback> = () => {};
|
23 |
+
if (!isEqual(deps, ref.current)) {
|
24 |
+
callback = effect();
|
25 |
+
ref.current = deps;
|
26 |
+
}
|
27 |
+
useEffect(() => {
|
28 |
+
return () => {
|
29 |
+
if (callback) {
|
30 |
+
callback();
|
31 |
+
}
|
32 |
+
};
|
33 |
+
}, []);
|
34 |
+
};
|
web/src/hooks/knowledgeHook.ts
CHANGED
@@ -125,11 +125,18 @@ export const useFetchKnowledgeBaseConfiguration = () => {
|
|
125 |
}, [fetchKnowledgeBaseConfiguration]);
|
126 |
};
|
127 |
|
128 |
-
export const useFetchKnowledgeList = (
|
|
|
|
|
129 |
const dispatch = useDispatch();
|
130 |
|
131 |
const knowledgeModel = useSelector((state: any) => state.knowledgeModel);
|
132 |
const { data = [] } = knowledgeModel;
|
|
|
|
|
|
|
|
|
|
|
133 |
|
134 |
const fetchList = useCallback(() => {
|
135 |
dispatch({
|
@@ -141,5 +148,5 @@ export const useFetchKnowledgeList = (): IKnowledge[] => {
|
|
141 |
fetchList();
|
142 |
}, [fetchList]);
|
143 |
|
144 |
-
return
|
145 |
};
|
|
|
125 |
}, [fetchKnowledgeBaseConfiguration]);
|
126 |
};
|
127 |
|
128 |
+
export const useFetchKnowledgeList = (
|
129 |
+
shouldFilterListWithoutDocument: boolean = false,
|
130 |
+
): IKnowledge[] => {
|
131 |
const dispatch = useDispatch();
|
132 |
|
133 |
const knowledgeModel = useSelector((state: any) => state.knowledgeModel);
|
134 |
const { data = [] } = knowledgeModel;
|
135 |
+
const list = useMemo(() => {
|
136 |
+
return shouldFilterListWithoutDocument
|
137 |
+
? data.filter((x: IKnowledge) => x.doc_num > 0)
|
138 |
+
: data;
|
139 |
+
}, [data, shouldFilterListWithoutDocument]);
|
140 |
|
141 |
const fetchList = useCallback(() => {
|
142 |
dispatch({
|
|
|
148 |
fetchList();
|
149 |
}, [fetchList]);
|
150 |
|
151 |
+
return list;
|
152 |
};
|
web/src/interfaces/database/chat.ts
CHANGED
@@ -1,3 +1,5 @@
|
|
|
|
|
|
1 |
export interface PromptConfig {
|
2 |
empty_response: string;
|
3 |
parameters: Parameter[];
|
@@ -45,3 +47,20 @@ export interface IDialog {
|
|
45 |
update_date: string;
|
46 |
update_time: number;
|
47 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { MessageType } from '@/constants/chat';
|
2 |
+
|
3 |
export interface PromptConfig {
|
4 |
empty_response: string;
|
5 |
parameters: Parameter[];
|
|
|
47 |
update_date: string;
|
48 |
update_time: number;
|
49 |
}
|
50 |
+
|
51 |
+
export interface IConversation {
|
52 |
+
create_date: string;
|
53 |
+
create_time: number;
|
54 |
+
dialog_id: string;
|
55 |
+
id: string;
|
56 |
+
message: Message[];
|
57 |
+
reference: any[];
|
58 |
+
name: string;
|
59 |
+
update_date: string;
|
60 |
+
update_time: number;
|
61 |
+
}
|
62 |
+
|
63 |
+
export interface Message {
|
64 |
+
content: string;
|
65 |
+
role: MessageType;
|
66 |
+
}
|
web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.tsx
CHANGED
@@ -75,9 +75,7 @@ export const ParsingStatusCell = ({ record }: IProps) => {
|
|
75 |
|
76 |
return (
|
77 |
<Flex justify={'space-between'}>
|
78 |
-
<Popover
|
79 |
-
content={isRunning && <PopoverContent record={record}></PopoverContent>}
|
80 |
-
>
|
81 |
<Tag color={runningStatus.color}>
|
82 |
{isRunning ? (
|
83 |
<Space>
|
|
|
75 |
|
76 |
return (
|
77 |
<Flex justify={'space-between'}>
|
78 |
+
<Popover content={<PopoverContent record={record}></PopoverContent>}>
|
|
|
|
|
79 |
<Tag color={runningStatus.color}>
|
80 |
{isRunning ? (
|
81 |
<Space>
|
web/src/pages/chat/chat-configuration-modal/assistant-setting.tsx
CHANGED
@@ -1,15 +1,13 @@
|
|
1 |
import { Form, Input, Select } from 'antd';
|
2 |
|
3 |
import classNames from 'classnames';
|
4 |
-
import { ISegmentedContentProps } from '
|
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,
|
|
|
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 AssistantSetting = ({ show }: ISegmentedContentProps) => {
|
10 |
+
const knowledgeList = useFetchKnowledgeList(true);
|
11 |
const knowledgeOptions = knowledgeList.map((x) => ({
|
12 |
label: x.name,
|
13 |
value: x.id,
|
web/src/pages/chat/chat-configuration-modal/index.tsx
CHANGED
@@ -3,13 +3,16 @@ 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 {
|
12 |
-
import { variableEnabledFieldMap } from '
|
|
|
|
|
|
|
13 |
import styles from './index.less';
|
14 |
|
15 |
enum ConfigurationSegmented {
|
@@ -40,32 +43,46 @@ const validateMessages = {
|
|
40 |
},
|
41 |
};
|
42 |
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
|
|
47 |
const [form] = Form.useForm();
|
48 |
const [value, setValue] = useState<ConfigurationSegmented>(
|
49 |
ConfigurationSegmented.AssistantSetting,
|
50 |
);
|
51 |
-
const promptEngineRef = useRef(
|
|
|
52 |
|
53 |
const setDialog = useSetDialog();
|
|
|
|
|
54 |
|
55 |
const handleOk = async () => {
|
56 |
const values = await form.validateFields();
|
57 |
-
const nextValues: any = omit(values,
|
|
|
|
|
|
|
|
|
|
|
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 = () => {
|
@@ -76,6 +93,11 @@ const ChatConfigurationModal = ({
|
|
76 |
setValue(val as ConfigurationSegmented);
|
77 |
};
|
78 |
|
|
|
|
|
|
|
|
|
|
|
79 |
const title = (
|
80 |
<Flex gap={16}>
|
81 |
<ChatConfigurationAtom></ChatConfigurationAtom>
|
@@ -89,6 +111,10 @@ const ChatConfigurationModal = ({
|
|
89 |
</Flex>
|
90 |
);
|
91 |
|
|
|
|
|
|
|
|
|
92 |
return (
|
93 |
<Modal
|
94 |
title={title}
|
@@ -96,6 +122,9 @@ const ChatConfigurationModal = ({
|
|
96 |
open={visible}
|
97 |
onOk={handleOk}
|
98 |
onCancel={handleCancel}
|
|
|
|
|
|
|
99 |
>
|
100 |
<Segmented
|
101 |
size={'large'}
|
|
|
3 |
import { Divider, Flex, Form, Modal, Segmented } from 'antd';
|
4 |
import { SegmentedValue } from 'antd/es/segmented';
|
5 |
import omit from 'lodash/omit';
|
6 |
+
import { useEffect, 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 { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
|
12 |
+
import { variableEnabledFieldMap } from '../constants';
|
13 |
+
import { useFetchDialog, useResetCurrentDialog, useSetDialog } from '../hooks';
|
14 |
+
import { IPromptConfigParameters } from '../interface';
|
15 |
+
import { excludeUnEnabledVariables } from '../utils';
|
16 |
import styles from './index.less';
|
17 |
|
18 |
enum ConfigurationSegmented {
|
|
|
43 |
},
|
44 |
};
|
45 |
|
46 |
+
interface IProps extends IModalManagerChildrenProps {
|
47 |
+
id: string;
|
48 |
+
}
|
49 |
+
|
50 |
+
const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => {
|
51 |
const [form] = Form.useForm();
|
52 |
const [value, setValue] = useState<ConfigurationSegmented>(
|
53 |
ConfigurationSegmented.AssistantSetting,
|
54 |
);
|
55 |
+
const promptEngineRef = useRef<Array<IPromptConfigParameters>>([]);
|
56 |
+
const loading = useOneNamespaceEffectsLoading('chatModel', ['setDialog']);
|
57 |
|
58 |
const setDialog = useSetDialog();
|
59 |
+
const currentDialog = useFetchDialog(id, visible);
|
60 |
+
const { resetCurrentDialog } = useResetCurrentDialog();
|
61 |
|
62 |
const handleOk = async () => {
|
63 |
const values = await form.validateFields();
|
64 |
+
const nextValues: any = omit(values, [
|
65 |
+
...Object.keys(variableEnabledFieldMap),
|
66 |
+
'parameters',
|
67 |
+
...excludeUnEnabledVariables(values),
|
68 |
+
]);
|
69 |
+
const emptyResponse = nextValues.prompt_config?.empty_response ?? '';
|
70 |
const finalValues = {
|
71 |
+
dialog_id: id,
|
72 |
...nextValues,
|
73 |
prompt_config: {
|
74 |
...nextValues.prompt_config,
|
75 |
parameters: promptEngineRef.current,
|
76 |
+
empty_response: emptyResponse,
|
77 |
},
|
78 |
};
|
79 |
console.info(promptEngineRef.current);
|
80 |
console.info(nextValues);
|
81 |
console.info(finalValues);
|
82 |
+
const retcode: number = await setDialog(finalValues);
|
83 |
+
if (retcode === 0) {
|
84 |
+
hideModal();
|
85 |
+
}
|
86 |
};
|
87 |
|
88 |
const handleCancel = () => {
|
|
|
93 |
setValue(val as ConfigurationSegmented);
|
94 |
};
|
95 |
|
96 |
+
const handleModalAfterClose = () => {
|
97 |
+
resetCurrentDialog();
|
98 |
+
form.resetFields();
|
99 |
+
};
|
100 |
+
|
101 |
const title = (
|
102 |
<Flex gap={16}>
|
103 |
<ChatConfigurationAtom></ChatConfigurationAtom>
|
|
|
111 |
</Flex>
|
112 |
);
|
113 |
|
114 |
+
useEffect(() => {
|
115 |
+
form.setFieldsValue(currentDialog);
|
116 |
+
}, [currentDialog, form]);
|
117 |
+
|
118 |
return (
|
119 |
<Modal
|
120 |
title={title}
|
|
|
122 |
open={visible}
|
123 |
onOk={handleOk}
|
124 |
onCancel={handleCancel}
|
125 |
+
confirmLoading={loading}
|
126 |
+
destroyOnClose
|
127 |
+
afterClose={handleModalAfterClose}
|
128 |
>
|
129 |
<Segmented
|
130 |
size={'large'}
|
web/src/pages/chat/chat-configuration-modal/model-setting.tsx
CHANGED
@@ -6,10 +6,10 @@ import {
|
|
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 '
|
10 |
|
11 |
import { useFetchLlmList, useSelectLlmOptions } from '@/hooks/llmHooks';
|
12 |
-
import { variableEnabledFieldMap } from '
|
13 |
import styles from './index.less';
|
14 |
|
15 |
const ModelSetting = ({ show, form }: ISegmentedContentProps) => {
|
|
|
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) => {
|
web/src/pages/chat/chat-configuration-modal/prompt-engine.tsx
CHANGED
@@ -21,17 +21,16 @@ import {
|
|
21 |
useState,
|
22 |
} from 'react';
|
23 |
import { v4 as uuid } from 'uuid';
|
|
|
|
|
|
|
|
|
|
|
24 |
import { EditableCell, EditableRow } from './editable-cell';
|
25 |
-
import { ISegmentedContentProps } from './interface';
|
26 |
|
|
|
27 |
import styles from './index.less';
|
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;
|
@@ -39,10 +38,11 @@ type FieldType = {
|
|
39 |
};
|
40 |
|
41 |
const PromptEngine = (
|
42 |
-
{ show
|
43 |
-
ref: ForwardedRef<Array<
|
44 |
) => {
|
45 |
const [dataSource, setDataSource] = useState<DataType[]>([]);
|
|
|
46 |
|
47 |
const components = {
|
48 |
body: {
|
@@ -99,12 +99,6 @@ const PromptEngine = (
|
|
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',
|
@@ -146,6 +140,10 @@ const PromptEngine = (
|
|
146 |
},
|
147 |
];
|
148 |
|
|
|
|
|
|
|
|
|
149 |
return (
|
150 |
<section
|
151 |
className={classNames({
|
@@ -153,7 +151,7 @@ const PromptEngine = (
|
|
153 |
})}
|
154 |
>
|
155 |
<Form.Item
|
156 |
-
label="
|
157 |
rules={[{ required: true, message: 'Please input!' }]}
|
158 |
name={['prompt_config', 'system']}
|
159 |
initialValue={`你是一个智能助手,请总结知识库的内容来回答问题,请列举知识库中的数据详细回答。当所有知识库内容都与问题无关时,你的回答必须包括“知识库中未找到您要的答案!”这句话。回答需要考虑聊天历史。
|
@@ -161,7 +159,7 @@ const PromptEngine = (
|
|
161 |
{knowledge}
|
162 |
以上是知识库。`}
|
163 |
>
|
164 |
-
<Input.TextArea autoSize={{ maxRows:
|
165 |
</Form.Item>
|
166 |
<Divider></Divider>
|
167 |
<SimilaritySlider></SimilaritySlider>
|
|
|
21 |
useState,
|
22 |
} from 'react';
|
23 |
import { v4 as uuid } from 'uuid';
|
24 |
+
import {
|
25 |
+
VariableTableDataType as DataType,
|
26 |
+
IPromptConfigParameters,
|
27 |
+
ISegmentedContentProps,
|
28 |
+
} from '../interface';
|
29 |
import { EditableCell, EditableRow } from './editable-cell';
|
|
|
30 |
|
31 |
+
import { useSelectPromptConfigParameters } from '../hooks';
|
32 |
import styles from './index.less';
|
33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
type FieldType = {
|
35 |
similarity_threshold?: number;
|
36 |
vector_similarity_weight?: number;
|
|
|
38 |
};
|
39 |
|
40 |
const PromptEngine = (
|
41 |
+
{ show }: ISegmentedContentProps,
|
42 |
+
ref: ForwardedRef<Array<IPromptConfigParameters>>,
|
43 |
) => {
|
44 |
const [dataSource, setDataSource] = useState<DataType[]>([]);
|
45 |
+
const parameters = useSelectPromptConfigParameters();
|
46 |
|
47 |
const components = {
|
48 |
body: {
|
|
|
99 |
[dataSource],
|
100 |
);
|
101 |
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
const columns: TableProps<DataType>['columns'] = [
|
103 |
{
|
104 |
title: 'key',
|
|
|
140 |
},
|
141 |
];
|
142 |
|
143 |
+
useEffect(() => {
|
144 |
+
setDataSource(parameters);
|
145 |
+
}, [parameters]);
|
146 |
+
|
147 |
return (
|
148 |
<section
|
149 |
className={classNames({
|
|
|
151 |
})}
|
152 |
>
|
153 |
<Form.Item
|
154 |
+
label="System"
|
155 |
rules={[{ required: true, message: 'Please input!' }]}
|
156 |
name={['prompt_config', 'system']}
|
157 |
initialValue={`你是一个智能助手,请总结知识库的内容来回答问题,请列举知识库中的数据详细回答。当所有知识库内容都与问题无关时,你的回答必须包括“知识库中未找到您要的答案!”这句话。回答需要考虑聊天历史。
|
|
|
159 |
{knowledge}
|
160 |
以上是知识库。`}
|
161 |
>
|
162 |
+
<Input.TextArea autoSize={{ maxRows: 8, minRows: 5 }} />
|
163 |
</Form.Item>
|
164 |
<Divider></Divider>
|
165 |
<SimilaritySlider></SimilaritySlider>
|
web/src/pages/chat/chat-container/index.less
CHANGED
@@ -1,3 +1,18 @@
|
|
1 |
.chatContainer {
|
2 |
padding: 0 24px 24px;
|
3 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
.chatContainer {
|
2 |
padding: 0 24px 24px;
|
3 |
}
|
4 |
+
|
5 |
+
.messageItem {
|
6 |
+
.messageItemContent {
|
7 |
+
display: inline-block;
|
8 |
+
width: 300px;
|
9 |
+
}
|
10 |
+
}
|
11 |
+
|
12 |
+
.messageItemLeft {
|
13 |
+
text-align: left;
|
14 |
+
}
|
15 |
+
|
16 |
+
.messageItemRight {
|
17 |
+
text-align: right;
|
18 |
+
}
|
web/src/pages/chat/chat-container/index.tsx
CHANGED
@@ -1,13 +1,41 @@
|
|
1 |
-
import { Button, Flex, Input } from 'antd';
|
2 |
import { ChangeEventHandler, useState } from 'react';
|
3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
import styles from './index.less';
|
5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
const ChatContainer = () => {
|
7 |
const [value, setValue] = useState('');
|
|
|
|
|
8 |
|
9 |
const handlePressEnter = () => {
|
10 |
console.info(value);
|
|
|
11 |
};
|
12 |
|
13 |
const handleInputChange: ChangeEventHandler<HTMLInputElement> = (e) => {
|
@@ -16,7 +44,11 @@ const ChatContainer = () => {
|
|
16 |
|
17 |
return (
|
18 |
<Flex flex={1} className={styles.chatContainer} vertical>
|
19 |
-
<Flex flex={1}>
|
|
|
|
|
|
|
|
|
20 |
<Input
|
21 |
size="large"
|
22 |
placeholder="Message Resume Assistant..."
|
|
|
1 |
+
import { Button, Flex, Input, Typography } from 'antd';
|
2 |
import { ChangeEventHandler, useState } from 'react';
|
3 |
|
4 |
+
import { Message } from '@/interfaces/database/chat';
|
5 |
+
import classNames from 'classnames';
|
6 |
+
import { useFetchConversation, useSendMessage } from '../hooks';
|
7 |
+
|
8 |
+
import { MessageType } from '@/constants/chat';
|
9 |
+
import { IClientConversation } from '../interface';
|
10 |
import styles from './index.less';
|
11 |
|
12 |
+
const { Paragraph } = Typography;
|
13 |
+
|
14 |
+
const MessageItem = ({ item }: { item: Message }) => {
|
15 |
+
return (
|
16 |
+
<div
|
17 |
+
className={classNames(styles.messageItem, {
|
18 |
+
[styles.messageItemLeft]: item.role === MessageType.Assistant,
|
19 |
+
[styles.messageItemRight]: item.role === MessageType.User,
|
20 |
+
})}
|
21 |
+
>
|
22 |
+
<span className={styles.messageItemContent}>
|
23 |
+
<Paragraph ellipsis={{ tooltip: item.content, rows: 3 }}>
|
24 |
+
{item.content}
|
25 |
+
</Paragraph>
|
26 |
+
</span>
|
27 |
+
</div>
|
28 |
+
);
|
29 |
+
};
|
30 |
+
|
31 |
const ChatContainer = () => {
|
32 |
const [value, setValue] = useState('');
|
33 |
+
const conversation: IClientConversation = useFetchConversation();
|
34 |
+
const { sendMessage } = useSendMessage();
|
35 |
|
36 |
const handlePressEnter = () => {
|
37 |
console.info(value);
|
38 |
+
sendMessage(value);
|
39 |
};
|
40 |
|
41 |
const handleInputChange: ChangeEventHandler<HTMLInputElement> = (e) => {
|
|
|
44 |
|
45 |
return (
|
46 |
<Flex flex={1} className={styles.chatContainer} vertical>
|
47 |
+
<Flex flex={1} vertical>
|
48 |
+
{conversation?.message?.map((message) => (
|
49 |
+
<MessageItem key={message.id} item={message}></MessageItem>
|
50 |
+
))}
|
51 |
+
</Flex>
|
52 |
<Input
|
53 |
size="large"
|
54 |
placeholder="Message Resume Assistant..."
|
web/src/pages/chat/{chat-configuration-modal/constants.ts → constants.ts}
RENAMED
@@ -5,3 +5,10 @@ export const variableEnabledFieldMap = {
|
|
5 |
frequencyPenaltyEnabled: 'frequency_penalty',
|
6 |
maxTokensEnabled: 'max_tokens',
|
7 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
frequencyPenaltyEnabled: 'frequency_penalty',
|
6 |
maxTokensEnabled: 'max_tokens',
|
7 |
};
|
8 |
+
|
9 |
+
export enum ChatSearchParams {
|
10 |
+
DialogId = 'dialogId',
|
11 |
+
ConversationId = 'conversationId',
|
12 |
+
}
|
13 |
+
|
14 |
+
export const EmptyConversationId = 'empty';
|
web/src/pages/chat/hooks.ts
CHANGED
@@ -1,6 +1,16 @@
|
|
|
|
|
|
1 |
import { IDialog } from '@/interfaces/database/chat';
|
2 |
-
import
|
3 |
-
import {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
export const useFetchDialogList = () => {
|
6 |
const dispatch = useDispatch();
|
@@ -20,10 +30,336 @@ export const useSetDialog = () => {
|
|
20 |
|
21 |
const setDialog = useCallback(
|
22 |
(payload: IDialog) => {
|
23 |
-
dispatch({ type: 'chatModel/setDialog', payload });
|
24 |
},
|
25 |
[dispatch],
|
26 |
);
|
27 |
|
28 |
return setDialog;
|
29 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import showDeleteConfirm from '@/components/deleting-confirm';
|
2 |
+
import { MessageType } from '@/constants/chat';
|
3 |
import { IDialog } from '@/interfaces/database/chat';
|
4 |
+
import omit from 'lodash/omit';
|
5 |
+
import { useCallback, useEffect, useMemo } from 'react';
|
6 |
+
import { useDispatch, useSearchParams, useSelector } from 'umi';
|
7 |
+
import { v4 as uuid } from 'uuid';
|
8 |
+
import { ChatSearchParams, EmptyConversationId } from './constants';
|
9 |
+
import {
|
10 |
+
IClientConversation,
|
11 |
+
IMessage,
|
12 |
+
VariableTableDataType,
|
13 |
+
} from './interface';
|
14 |
|
15 |
export const useFetchDialogList = () => {
|
16 |
const dispatch = useDispatch();
|
|
|
30 |
|
31 |
const setDialog = useCallback(
|
32 |
(payload: IDialog) => {
|
33 |
+
return dispatch<any>({ type: 'chatModel/setDialog', payload });
|
34 |
},
|
35 |
[dispatch],
|
36 |
);
|
37 |
|
38 |
return setDialog;
|
39 |
};
|
40 |
+
|
41 |
+
export const useFetchDialog = (dialogId: string, visible: boolean): IDialog => {
|
42 |
+
const dispatch = useDispatch();
|
43 |
+
const currentDialog: IDialog = useSelector(
|
44 |
+
(state: any) => state.chatModel.currentDialog,
|
45 |
+
);
|
46 |
+
|
47 |
+
const fetchDialog = useCallback(() => {
|
48 |
+
if (dialogId) {
|
49 |
+
dispatch({
|
50 |
+
type: 'chatModel/getDialog',
|
51 |
+
payload: { dialog_id: dialogId },
|
52 |
+
});
|
53 |
+
}
|
54 |
+
}, [dispatch, dialogId]);
|
55 |
+
|
56 |
+
useEffect(() => {
|
57 |
+
if (dialogId && visible) {
|
58 |
+
fetchDialog();
|
59 |
+
}
|
60 |
+
}, [dialogId, fetchDialog, visible]);
|
61 |
+
|
62 |
+
return currentDialog;
|
63 |
+
};
|
64 |
+
|
65 |
+
export const useSetCurrentDialog = () => {
|
66 |
+
const dispatch = useDispatch();
|
67 |
+
|
68 |
+
const currentDialog: IDialog = useSelector(
|
69 |
+
(state: any) => state.chatModel.currentDialog,
|
70 |
+
);
|
71 |
+
|
72 |
+
const setCurrentDialog = useCallback(
|
73 |
+
(dialogId: string) => {
|
74 |
+
if (dialogId) {
|
75 |
+
dispatch({
|
76 |
+
type: 'chatModel/setCurrentDialog',
|
77 |
+
payload: { id: dialogId },
|
78 |
+
});
|
79 |
+
}
|
80 |
+
},
|
81 |
+
[dispatch],
|
82 |
+
);
|
83 |
+
|
84 |
+
return { currentDialog, setCurrentDialog };
|
85 |
+
};
|
86 |
+
|
87 |
+
export const useResetCurrentDialog = () => {
|
88 |
+
const dispatch = useDispatch();
|
89 |
+
|
90 |
+
const resetCurrentDialog = useCallback(() => {
|
91 |
+
dispatch({
|
92 |
+
type: 'chatModel/setCurrentDialog',
|
93 |
+
payload: {},
|
94 |
+
});
|
95 |
+
}, [dispatch]);
|
96 |
+
|
97 |
+
return { resetCurrentDialog };
|
98 |
+
};
|
99 |
+
|
100 |
+
export const useSelectPromptConfigParameters = (): VariableTableDataType[] => {
|
101 |
+
const currentDialog: IDialog = useSelector(
|
102 |
+
(state: any) => state.chatModel.currentDialog,
|
103 |
+
);
|
104 |
+
|
105 |
+
const finalParameters: VariableTableDataType[] = useMemo(() => {
|
106 |
+
const parameters = currentDialog?.prompt_config?.parameters ?? [];
|
107 |
+
if (!currentDialog.id) {
|
108 |
+
// The newly created chat has a default parameter
|
109 |
+
return [{ key: uuid(), variable: 'knowledge', optional: false }];
|
110 |
+
}
|
111 |
+
return parameters.map((x) => ({
|
112 |
+
key: uuid(),
|
113 |
+
variable: x.key,
|
114 |
+
optional: x.optional,
|
115 |
+
}));
|
116 |
+
}, [currentDialog]);
|
117 |
+
|
118 |
+
return finalParameters;
|
119 |
+
};
|
120 |
+
|
121 |
+
export const useRemoveDialog = () => {
|
122 |
+
const dispatch = useDispatch();
|
123 |
+
|
124 |
+
const removeDocument = (dialogIds: Array<string>) => () => {
|
125 |
+
return dispatch({
|
126 |
+
type: 'chatModel/removeDialog',
|
127 |
+
payload: {
|
128 |
+
dialog_ids: dialogIds,
|
129 |
+
},
|
130 |
+
});
|
131 |
+
};
|
132 |
+
|
133 |
+
const onRemoveDialog = (dialogIds: Array<string>) => {
|
134 |
+
showDeleteConfirm({ onOk: removeDocument(dialogIds) });
|
135 |
+
};
|
136 |
+
|
137 |
+
return { onRemoveDialog };
|
138 |
+
};
|
139 |
+
|
140 |
+
export const useClickDialogCard = () => {
|
141 |
+
const [currentQueryParameters, setSearchParams] = useSearchParams();
|
142 |
+
|
143 |
+
const newQueryParameters: URLSearchParams = useMemo(() => {
|
144 |
+
return new URLSearchParams(currentQueryParameters.toString());
|
145 |
+
}, [currentQueryParameters]);
|
146 |
+
|
147 |
+
const handleClickDialog = useCallback(
|
148 |
+
(dialogId: string) => {
|
149 |
+
newQueryParameters.set(ChatSearchParams.DialogId, dialogId);
|
150 |
+
setSearchParams(newQueryParameters);
|
151 |
+
},
|
152 |
+
[newQueryParameters, setSearchParams],
|
153 |
+
);
|
154 |
+
|
155 |
+
return { handleClickDialog };
|
156 |
+
};
|
157 |
+
|
158 |
+
export const useGetChatSearchParams = () => {
|
159 |
+
const [currentQueryParameters] = useSearchParams();
|
160 |
+
|
161 |
+
return {
|
162 |
+
dialogId: currentQueryParameters.get(ChatSearchParams.DialogId) || '',
|
163 |
+
conversationId:
|
164 |
+
currentQueryParameters.get(ChatSearchParams.ConversationId) || '',
|
165 |
+
};
|
166 |
+
};
|
167 |
+
|
168 |
+
export const useSelectFirstDialogOnMount = () => {
|
169 |
+
const dialogList = useFetchDialogList();
|
170 |
+
const { dialogId } = useGetChatSearchParams();
|
171 |
+
|
172 |
+
const { handleClickDialog } = useClickDialogCard();
|
173 |
+
|
174 |
+
useEffect(() => {
|
175 |
+
if (dialogList.length > 0 && !dialogId) {
|
176 |
+
handleClickDialog(dialogList[0].id);
|
177 |
+
}
|
178 |
+
}, [dialogList, handleClickDialog, dialogId]);
|
179 |
+
|
180 |
+
return dialogList;
|
181 |
+
};
|
182 |
+
|
183 |
+
//#region conversation
|
184 |
+
|
185 |
+
export const useFetchConversationList = (dialogId?: string) => {
|
186 |
+
const dispatch = useDispatch();
|
187 |
+
const conversationList: any[] = useSelector(
|
188 |
+
(state: any) => state.chatModel.conversationList,
|
189 |
+
);
|
190 |
+
|
191 |
+
const fetchConversationList = useCallback(() => {
|
192 |
+
if (dialogId) {
|
193 |
+
dispatch({
|
194 |
+
type: 'chatModel/listConversation',
|
195 |
+
payload: { dialog_id: dialogId },
|
196 |
+
});
|
197 |
+
}
|
198 |
+
}, [dispatch, dialogId]);
|
199 |
+
|
200 |
+
useEffect(() => {
|
201 |
+
fetchConversationList();
|
202 |
+
}, [fetchConversationList]);
|
203 |
+
|
204 |
+
return conversationList;
|
205 |
+
};
|
206 |
+
|
207 |
+
export const useClickConversationCard = () => {
|
208 |
+
const [currentQueryParameters, setSearchParams] = useSearchParams();
|
209 |
+
const newQueryParameters: URLSearchParams = new URLSearchParams(
|
210 |
+
currentQueryParameters.toString(),
|
211 |
+
);
|
212 |
+
|
213 |
+
const handleClickConversation = (conversationId: string) => {
|
214 |
+
newQueryParameters.set(ChatSearchParams.ConversationId, conversationId);
|
215 |
+
setSearchParams(newQueryParameters);
|
216 |
+
};
|
217 |
+
|
218 |
+
return { handleClickConversation };
|
219 |
+
};
|
220 |
+
|
221 |
+
export const useCreateTemporaryConversation = () => {
|
222 |
+
const dispatch = useDispatch();
|
223 |
+
const { dialogId } = useGetChatSearchParams();
|
224 |
+
const { handleClickConversation } = useClickConversationCard();
|
225 |
+
let chatModel = useSelector((state: any) => state.chatModel);
|
226 |
+
let currentConversation: Pick<
|
227 |
+
IClientConversation,
|
228 |
+
'id' | 'message' | 'name' | 'dialog_id'
|
229 |
+
> = chatModel.currentConversation;
|
230 |
+
let conversationList: IClientConversation[] = chatModel.conversationList;
|
231 |
+
|
232 |
+
const createTemporaryConversation = (message: string) => {
|
233 |
+
const messages = [...(currentConversation?.message ?? [])];
|
234 |
+
if (messages.some((x) => x.id === EmptyConversationId)) {
|
235 |
+
return;
|
236 |
+
}
|
237 |
+
messages.unshift({
|
238 |
+
id: EmptyConversationId,
|
239 |
+
content: message,
|
240 |
+
role: MessageType.Assistant,
|
241 |
+
});
|
242 |
+
|
243 |
+
// It’s the back-end data.
|
244 |
+
if ('id' in currentConversation) {
|
245 |
+
currentConversation = { ...currentConversation, message: messages };
|
246 |
+
} else {
|
247 |
+
// client data
|
248 |
+
currentConversation = {
|
249 |
+
id: EmptyConversationId,
|
250 |
+
name: 'New conversation',
|
251 |
+
dialog_id: dialogId,
|
252 |
+
message: messages,
|
253 |
+
};
|
254 |
+
}
|
255 |
+
|
256 |
+
const nextConversationList = [...conversationList];
|
257 |
+
|
258 |
+
nextConversationList.push(currentConversation as IClientConversation);
|
259 |
+
|
260 |
+
dispatch({
|
261 |
+
type: 'chatModel/setCurrentConversation',
|
262 |
+
payload: currentConversation,
|
263 |
+
});
|
264 |
+
|
265 |
+
dispatch({
|
266 |
+
type: 'chatModel/setConversationList',
|
267 |
+
payload: nextConversationList,
|
268 |
+
});
|
269 |
+
handleClickConversation(EmptyConversationId);
|
270 |
+
};
|
271 |
+
|
272 |
+
return { createTemporaryConversation };
|
273 |
+
};
|
274 |
+
|
275 |
+
export const useSetConversation = () => {
|
276 |
+
const dispatch = useDispatch();
|
277 |
+
const { dialogId } = useGetChatSearchParams();
|
278 |
+
|
279 |
+
const setConversation = (message: string) => {
|
280 |
+
return dispatch<any>({
|
281 |
+
type: 'chatModel/setConversation',
|
282 |
+
payload: {
|
283 |
+
// conversation_id: '',
|
284 |
+
dialog_id: dialogId,
|
285 |
+
name: message,
|
286 |
+
message: [
|
287 |
+
{
|
288 |
+
role: MessageType.Assistant,
|
289 |
+
content: message,
|
290 |
+
},
|
291 |
+
],
|
292 |
+
},
|
293 |
+
});
|
294 |
+
};
|
295 |
+
|
296 |
+
return { setConversation };
|
297 |
+
};
|
298 |
+
|
299 |
+
export const useFetchConversation = () => {
|
300 |
+
const dispatch = useDispatch();
|
301 |
+
const { conversationId } = useGetChatSearchParams();
|
302 |
+
const conversation = useSelector(
|
303 |
+
(state: any) => state.chatModel.currentConversation,
|
304 |
+
);
|
305 |
+
|
306 |
+
const fetchConversation = useCallback(() => {
|
307 |
+
if (conversationId !== EmptyConversationId && conversationId !== '') {
|
308 |
+
dispatch({
|
309 |
+
type: 'chatModel/getConversation',
|
310 |
+
payload: {
|
311 |
+
conversation_id: conversationId,
|
312 |
+
},
|
313 |
+
});
|
314 |
+
}
|
315 |
+
}, [dispatch, conversationId]);
|
316 |
+
|
317 |
+
useEffect(() => {
|
318 |
+
fetchConversation();
|
319 |
+
}, [fetchConversation]);
|
320 |
+
|
321 |
+
return conversation;
|
322 |
+
};
|
323 |
+
|
324 |
+
export const useSendMessage = () => {
|
325 |
+
const dispatch = useDispatch();
|
326 |
+
const { setConversation } = useSetConversation();
|
327 |
+
const { conversationId } = useGetChatSearchParams();
|
328 |
+
const conversation = useSelector(
|
329 |
+
(state: any) => state.chatModel.currentConversation,
|
330 |
+
);
|
331 |
+
const { handleClickConversation } = useClickConversationCard();
|
332 |
+
|
333 |
+
const sendMessage = (message: string, id?: string) => {
|
334 |
+
dispatch({
|
335 |
+
type: 'chatModel/completeConversation',
|
336 |
+
payload: {
|
337 |
+
conversation_id: id ?? conversationId,
|
338 |
+
messages: [
|
339 |
+
...(conversation?.message ?? []).map((x: IMessage) => omit(x, 'id')),
|
340 |
+
{
|
341 |
+
role: MessageType.User,
|
342 |
+
content: message,
|
343 |
+
},
|
344 |
+
],
|
345 |
+
},
|
346 |
+
});
|
347 |
+
};
|
348 |
+
|
349 |
+
const handleSendMessage = async (message: string) => {
|
350 |
+
if (conversationId !== EmptyConversationId) {
|
351 |
+
sendMessage(message);
|
352 |
+
} else {
|
353 |
+
const data = await setConversation(message);
|
354 |
+
if (data.retcode === 0) {
|
355 |
+
const id = data.data.id;
|
356 |
+
handleClickConversation(id);
|
357 |
+
sendMessage(message, id);
|
358 |
+
}
|
359 |
+
}
|
360 |
+
};
|
361 |
+
|
362 |
+
return { sendMessage: handleSendMessage };
|
363 |
+
};
|
364 |
+
|
365 |
+
//#endregion
|
web/src/pages/chat/index.less
CHANGED
@@ -5,6 +5,10 @@
|
|
5 |
width: 288px;
|
6 |
padding: 26px;
|
7 |
|
|
|
|
|
|
|
|
|
8 |
.chatAppCard {
|
9 |
:global(.ant-card-body) {
|
10 |
padding: 10px;
|
@@ -15,6 +19,12 @@
|
|
15 |
}
|
16 |
}
|
17 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
}
|
19 |
.chatTitleWrapper {
|
20 |
width: 220px;
|
@@ -29,6 +39,19 @@
|
|
29 |
padding: 5px 10px;
|
30 |
}
|
31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
.divider {
|
33 |
margin: 0;
|
34 |
height: 100%;
|
|
|
5 |
width: 288px;
|
6 |
padding: 26px;
|
7 |
|
8 |
+
.chatAppContent {
|
9 |
+
overflow-y: auto;
|
10 |
+
}
|
11 |
+
|
12 |
.chatAppCard {
|
13 |
:global(.ant-card-body) {
|
14 |
padding: 10px;
|
|
|
19 |
}
|
20 |
}
|
21 |
}
|
22 |
+
.chatAppCardSelected {
|
23 |
+
:global(.ant-card-body) {
|
24 |
+
background-color: @gray11;
|
25 |
+
border-radius: 8px;
|
26 |
+
}
|
27 |
+
}
|
28 |
}
|
29 |
.chatTitleWrapper {
|
30 |
width: 220px;
|
|
|
39 |
padding: 5px 10px;
|
40 |
}
|
41 |
|
42 |
+
.chatTitleCard {
|
43 |
+
:global(.ant-card-body) {
|
44 |
+
padding: 8px;
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
.chatTitleCardSelected {
|
49 |
+
:global(.ant-card-body) {
|
50 |
+
background-color: @gray11;
|
51 |
+
border-radius: 8px;
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
.divider {
|
56 |
margin: 0;
|
57 |
height: 100%;
|
web/src/pages/chat/index.tsx
CHANGED
@@ -1,3 +1,5 @@
|
|
|
|
|
|
1 |
import { DeleteOutlined, EditOutlined, FormOutlined } from '@ant-design/icons';
|
2 |
import {
|
3 |
Button,
|
@@ -9,20 +11,39 @@ import {
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
-
import { useState } from 'react';
|
21 |
import styles from './index.less';
|
22 |
|
23 |
const Chat = () => {
|
24 |
-
const dialogList =
|
25 |
const [activated, setActivated] = useState<string>('');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
|
27 |
const handleAppCardEnter = (id: string) => () => {
|
28 |
setActivated(id);
|
@@ -32,72 +53,84 @@ const Chat = () => {
|
|
32 |
setActivated('');
|
33 |
};
|
34 |
|
35 |
-
const
|
36 |
-
{
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
|
|
|
|
|
|
|
|
49 |
|
50 |
-
const
|
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}>
|
74 |
<Flex className={styles.chatAppWrapper}>
|
75 |
<Flex flex={1} vertical>
|
76 |
-
<
|
77 |
-
|
78 |
-
|
79 |
-
<>
|
80 |
-
<Button type="primary" onClick={() => showModal()}>
|
81 |
-
Create an Assistant
|
82 |
-
</Button>
|
83 |
-
<ChatConfigurationModal
|
84 |
-
visible={visible}
|
85 |
-
showModal={showModal}
|
86 |
-
hideModal={hideModal}
|
87 |
-
></ChatConfigurationModal>
|
88 |
-
</>
|
89 |
-
);
|
90 |
-
}}
|
91 |
-
</ModalManager>
|
92 |
-
|
93 |
<Divider></Divider>
|
94 |
-
<
|
95 |
{dialogList.map((x) => (
|
96 |
<Card
|
97 |
key={x.id}
|
98 |
-
|
|
|
|
|
|
|
99 |
onMouseEnter={handleAppCardEnter(x.id)}
|
100 |
onMouseLeave={handleAppCardLeave}
|
|
|
101 |
>
|
102 |
<Flex justify="space-between" align="center">
|
103 |
<Space>
|
@@ -109,7 +142,7 @@ const Chat = () => {
|
|
109 |
</Space>
|
110 |
{activated === x.id && (
|
111 |
<section>
|
112 |
-
<Dropdown menu={{ items:
|
113 |
<ChatAppCube className={styles.cubeIcon}></ChatAppCube>
|
114 |
</Dropdown>
|
115 |
</section>
|
@@ -117,7 +150,7 @@ const Chat = () => {
|
|
117 |
</Flex>
|
118 |
</Card>
|
119 |
))}
|
120 |
-
</
|
121 |
</Flex>
|
122 |
</Flex>
|
123 |
<Divider type={'vertical'} className={styles.divider}></Divider>
|
@@ -137,11 +170,30 @@ const Chat = () => {
|
|
137 |
</Dropdown>
|
138 |
</Flex>
|
139 |
<Divider></Divider>
|
140 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
141 |
</Flex>
|
142 |
</Flex>
|
143 |
<Divider type={'vertical'} className={styles.divider}></Divider>
|
144 |
<ChatContainer></ChatContainer>
|
|
|
|
|
|
|
|
|
|
|
|
|
145 |
</Flex>
|
146 |
);
|
147 |
};
|
|
|
1 |
+
import { ReactComponent as ChatAppCube } from '@/assets/svg/chat-app-cube.svg';
|
2 |
+
import { useSetModalState } from '@/hooks/commonHooks';
|
3 |
import { DeleteOutlined, EditOutlined, FormOutlined } from '@ant-design/icons';
|
4 |
import {
|
5 |
Button,
|
|
|
11 |
Space,
|
12 |
Tag,
|
13 |
} from 'antd';
|
|
|
|
|
|
|
|
|
14 |
import classNames from 'classnames';
|
15 |
+
import { useCallback, useState } from 'react';
|
16 |
import ChatConfigurationModal from './chat-configuration-modal';
|
17 |
+
import ChatContainer from './chat-container';
|
18 |
+
import {
|
19 |
+
useClickConversationCard,
|
20 |
+
useClickDialogCard,
|
21 |
+
useCreateTemporaryConversation,
|
22 |
+
useFetchConversationList,
|
23 |
+
useFetchDialog,
|
24 |
+
useGetChatSearchParams,
|
25 |
+
useRemoveDialog,
|
26 |
+
useSelectFirstDialogOnMount,
|
27 |
+
useSetCurrentDialog,
|
28 |
+
} from './hooks';
|
29 |
|
|
|
30 |
import styles from './index.less';
|
31 |
|
32 |
const Chat = () => {
|
33 |
+
const dialogList = useSelectFirstDialogOnMount();
|
34 |
const [activated, setActivated] = useState<string>('');
|
35 |
+
const { visible, hideModal, showModal } = useSetModalState();
|
36 |
+
const { setCurrentDialog, currentDialog } = useSetCurrentDialog();
|
37 |
+
const { onRemoveDialog } = useRemoveDialog();
|
38 |
+
const { handleClickDialog } = useClickDialogCard();
|
39 |
+
const { handleClickConversation } = useClickConversationCard();
|
40 |
+
const { dialogId, conversationId } = useGetChatSearchParams();
|
41 |
+
const list = useFetchConversationList(dialogId);
|
42 |
+
const { createTemporaryConversation } = useCreateTemporaryConversation();
|
43 |
+
|
44 |
+
const selectedDialog = useFetchDialog(dialogId, true);
|
45 |
+
|
46 |
+
const prologue = selectedDialog?.prompt_config?.prologue || '';
|
47 |
|
48 |
const handleAppCardEnter = (id: string) => () => {
|
49 |
setActivated(id);
|
|
|
53 |
setActivated('');
|
54 |
};
|
55 |
|
56 |
+
const handleShowChatConfigurationModal = (dialogId?: string) => () => {
|
57 |
+
if (dialogId) {
|
58 |
+
setCurrentDialog(dialogId);
|
59 |
+
}
|
60 |
+
showModal();
|
61 |
+
};
|
62 |
+
|
63 |
+
const handleDialogCardClick = (dialogId: string) => () => {
|
64 |
+
handleClickDialog(dialogId);
|
65 |
+
};
|
66 |
+
|
67 |
+
const handleConversationCardClick = (dialogId: string) => () => {
|
68 |
+
handleClickConversation(dialogId);
|
69 |
+
};
|
70 |
+
|
71 |
+
const handleCreateTemporaryConversation = useCallback(() => {
|
72 |
+
createTemporaryConversation(prologue);
|
73 |
+
}, [createTemporaryConversation, prologue]);
|
74 |
|
75 |
+
const items: MenuProps['items'] = [
|
76 |
{
|
77 |
key: '1',
|
78 |
+
onClick: handleCreateTemporaryConversation,
|
79 |
label: (
|
80 |
<Space>
|
81 |
+
<EditOutlined /> New chat
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
</Space>
|
83 |
),
|
84 |
},
|
85 |
];
|
86 |
|
87 |
+
const buildAppItems = (dialogId: string) => {
|
88 |
+
const appItems: MenuProps['items'] = [
|
89 |
+
{
|
90 |
+
key: '1',
|
91 |
+
onClick: handleShowChatConfigurationModal(dialogId),
|
92 |
+
label: (
|
93 |
+
<Space>
|
94 |
+
<EditOutlined />
|
95 |
+
Edit
|
96 |
+
</Space>
|
97 |
+
),
|
98 |
+
},
|
99 |
+
{ type: 'divider' },
|
100 |
+
{
|
101 |
+
key: '2',
|
102 |
+
onClick: () => onRemoveDialog([dialogId]),
|
103 |
+
label: (
|
104 |
+
<Space>
|
105 |
+
<DeleteOutlined />
|
106 |
+
Delete chat
|
107 |
+
</Space>
|
108 |
+
),
|
109 |
+
},
|
110 |
+
];
|
111 |
+
|
112 |
+
return appItems;
|
113 |
+
};
|
114 |
+
|
115 |
return (
|
116 |
<Flex className={styles.chatWrapper}>
|
117 |
<Flex className={styles.chatAppWrapper}>
|
118 |
<Flex flex={1} vertical>
|
119 |
+
<Button type="primary" onClick={handleShowChatConfigurationModal()}>
|
120 |
+
Create an Assistant
|
121 |
+
</Button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
122 |
<Divider></Divider>
|
123 |
+
<Flex className={styles.chatAppContent} vertical gap={10}>
|
124 |
{dialogList.map((x) => (
|
125 |
<Card
|
126 |
key={x.id}
|
127 |
+
hoverable
|
128 |
+
className={classNames(styles.chatAppCard, {
|
129 |
+
[styles.chatAppCardSelected]: dialogId === x.id,
|
130 |
+
})}
|
131 |
onMouseEnter={handleAppCardEnter(x.id)}
|
132 |
onMouseLeave={handleAppCardLeave}
|
133 |
+
onClick={handleDialogCardClick(x.id)}
|
134 |
>
|
135 |
<Flex justify="space-between" align="center">
|
136 |
<Space>
|
|
|
142 |
</Space>
|
143 |
{activated === x.id && (
|
144 |
<section>
|
145 |
+
<Dropdown menu={{ items: buildAppItems(x.id) }}>
|
146 |
<ChatAppCube className={styles.cubeIcon}></ChatAppCube>
|
147 |
</Dropdown>
|
148 |
</section>
|
|
|
150 |
</Flex>
|
151 |
</Card>
|
152 |
))}
|
153 |
+
</Flex>
|
154 |
</Flex>
|
155 |
</Flex>
|
156 |
<Divider type={'vertical'} className={styles.divider}></Divider>
|
|
|
170 |
</Dropdown>
|
171 |
</Flex>
|
172 |
<Divider></Divider>
|
173 |
+
<Flex vertical gap={10} className={styles.chatTitleContent}>
|
174 |
+
{list.map((x) => (
|
175 |
+
<Card
|
176 |
+
key={x.id}
|
177 |
+
hoverable
|
178 |
+
onClick={handleConversationCardClick(x.id)}
|
179 |
+
className={classNames(styles.chatTitleCard, {
|
180 |
+
[styles.chatTitleCardSelected]: x.id === conversationId,
|
181 |
+
})}
|
182 |
+
>
|
183 |
+
<div>{x.name}</div>
|
184 |
+
</Card>
|
185 |
+
))}
|
186 |
+
</Flex>
|
187 |
</Flex>
|
188 |
</Flex>
|
189 |
<Divider type={'vertical'} className={styles.divider}></Divider>
|
190 |
<ChatContainer></ChatContainer>
|
191 |
+
<ChatConfigurationModal
|
192 |
+
visible={visible}
|
193 |
+
showModal={showModal}
|
194 |
+
hideModal={hideModal}
|
195 |
+
id={currentDialog.id}
|
196 |
+
></ChatConfigurationModal>
|
197 |
</Flex>
|
198 |
);
|
199 |
};
|
web/src/pages/chat/{chat-configuration-modal/interface.ts → interface.ts}
RENAMED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
import { FormInstance } from 'antd';
|
2 |
|
3 |
export interface ISegmentedContentProps {
|
@@ -12,3 +13,19 @@ export interface IVariable {
|
|
12 |
presence_penalty: number;
|
13 |
max_tokens: number;
|
14 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { IConversation, Message } from '@/interfaces/database/chat';
|
2 |
import { FormInstance } from 'antd';
|
3 |
|
4 |
export interface ISegmentedContentProps {
|
|
|
13 |
presence_penalty: number;
|
14 |
max_tokens: number;
|
15 |
}
|
16 |
+
|
17 |
+
export interface VariableTableDataType {
|
18 |
+
key: string;
|
19 |
+
variable: string;
|
20 |
+
optional: boolean;
|
21 |
+
}
|
22 |
+
|
23 |
+
export type IPromptConfigParameters = Omit<VariableTableDataType, 'variable'>;
|
24 |
+
|
25 |
+
export interface IMessage extends Message {
|
26 |
+
id: string;
|
27 |
+
}
|
28 |
+
|
29 |
+
export interface IClientConversation extends IConversation {
|
30 |
+
message: IMessage[];
|
31 |
+
}
|
web/src/pages/chat/model.ts
CHANGED
@@ -1,11 +1,16 @@
|
|
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> = {
|
@@ -13,6 +18,9 @@ const model: DvaModel<ChatModelState> = {
|
|
13 |
state: {
|
14 |
name: 'kate',
|
15 |
dialogList: [],
|
|
|
|
|
|
|
16 |
},
|
17 |
reducers: {
|
18 |
save(state, action) {
|
@@ -27,11 +35,50 @@ const model: DvaModel<ChatModelState> = {
|
|
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);
|
@@ -39,6 +86,15 @@ const model: DvaModel<ChatModelState> = {
|
|
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);
|
@@ -46,15 +102,40 @@ const model: DvaModel<ChatModelState> = {
|
|
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 |
};
|
|
|
1 |
+
import { IConversation, IDialog, Message } from '@/interfaces/database/chat';
|
2 |
import chatService from '@/services/chatService';
|
3 |
import { message } from 'antd';
|
4 |
import { DvaModel } from 'umi';
|
5 |
+
import { v4 as uuid } from 'uuid';
|
6 |
+
import { IClientConversation, IMessage } from './interface';
|
7 |
|
8 |
export interface ChatModelState {
|
9 |
name: string;
|
10 |
dialogList: IDialog[];
|
11 |
+
currentDialog: IDialog;
|
12 |
+
conversationList: IConversation[];
|
13 |
+
currentConversation: IClientConversation;
|
14 |
}
|
15 |
|
16 |
const model: DvaModel<ChatModelState> = {
|
|
|
18 |
state: {
|
19 |
name: 'kate',
|
20 |
dialogList: [],
|
21 |
+
currentDialog: <IDialog>{},
|
22 |
+
conversationList: [],
|
23 |
+
currentConversation: {} as IClientConversation,
|
24 |
},
|
25 |
reducers: {
|
26 |
save(state, action) {
|
|
|
35 |
dialogList: payload,
|
36 |
};
|
37 |
},
|
38 |
+
setCurrentDialog(state, { payload }) {
|
39 |
+
return {
|
40 |
+
...state,
|
41 |
+
currentDialog: payload,
|
42 |
+
};
|
43 |
+
},
|
44 |
+
setConversationList(state, { payload }) {
|
45 |
+
return {
|
46 |
+
...state,
|
47 |
+
conversationList: payload,
|
48 |
+
};
|
49 |
+
},
|
50 |
+
setCurrentConversation(state, { payload }) {
|
51 |
+
const messageList = payload?.message.map((x: Message | IMessage) => ({
|
52 |
+
...x,
|
53 |
+
id: 'id' in x ? x.id : uuid(),
|
54 |
+
}));
|
55 |
+
return {
|
56 |
+
...state,
|
57 |
+
currentConversation: { ...payload, message: messageList },
|
58 |
+
};
|
59 |
+
},
|
60 |
+
addEmptyConversationToList(state, {}) {
|
61 |
+
const list = [...state.conversationList];
|
62 |
+
// if (list.every((x) => x.id !== 'empty')) {
|
63 |
+
// list.push({
|
64 |
+
// id: 'empty',
|
65 |
+
// name: 'New conversation',
|
66 |
+
// message: [],
|
67 |
+
// });
|
68 |
+
// }
|
69 |
+
return {
|
70 |
+
...state,
|
71 |
+
conversationList: list,
|
72 |
+
};
|
73 |
+
},
|
74 |
},
|
75 |
|
76 |
effects: {
|
77 |
*getDialog({ payload }, { call, put }) {
|
78 |
const { data } = yield call(chatService.getDialog, payload);
|
79 |
+
if (data.retcode === 0) {
|
80 |
+
yield put({ type: 'setCurrentDialog', payload: data.data });
|
81 |
+
}
|
82 |
},
|
83 |
*setDialog({ payload }, { call, put }) {
|
84 |
const { data } = yield call(chatService.setDialog, payload);
|
|
|
86 |
yield put({ type: 'listDialog' });
|
87 |
message.success('Created successfully !');
|
88 |
}
|
89 |
+
return data.retcode;
|
90 |
+
},
|
91 |
+
*removeDialog({ payload }, { call, put }) {
|
92 |
+
const { data } = yield call(chatService.removeDialog, payload);
|
93 |
+
if (data.retcode === 0) {
|
94 |
+
yield put({ type: 'listDialog' });
|
95 |
+
message.success('Deleted successfully !');
|
96 |
+
}
|
97 |
+
return data.retcode;
|
98 |
},
|
99 |
*listDialog({ payload }, { call, put }) {
|
100 |
const { data } = yield call(chatService.listDialog, payload);
|
|
|
102 |
},
|
103 |
*listConversation({ payload }, { call, put }) {
|
104 |
const { data } = yield call(chatService.listConversation, payload);
|
105 |
+
if (data.retcode === 0) {
|
106 |
+
yield put({ type: 'setConversationList', payload: data.data });
|
107 |
+
}
|
108 |
+
return data.retcode;
|
109 |
},
|
110 |
*getConversation({ payload }, { call, put }) {
|
111 |
const { data } = yield call(chatService.getConversation, payload);
|
112 |
+
if (data.retcode === 0) {
|
113 |
+
yield put({ type: 'setCurrentConversation', payload: data.data });
|
114 |
+
}
|
115 |
+
return data.retcode;
|
116 |
},
|
117 |
*setConversation({ payload }, { call, put }) {
|
118 |
const { data } = yield call(chatService.setConversation, payload);
|
119 |
+
if (data.retcode === 0) {
|
120 |
+
yield put({
|
121 |
+
type: 'listConversation',
|
122 |
+
payload: {
|
123 |
+
dialog_id: data.data.dialog_id,
|
124 |
+
},
|
125 |
+
});
|
126 |
+
}
|
127 |
+
return data;
|
128 |
},
|
129 |
*completeConversation({ payload }, { call, put }) {
|
130 |
const { data } = yield call(chatService.completeConversation, payload);
|
131 |
+
if (data.retcode === 0) {
|
132 |
+
yield put({
|
133 |
+
type: 'getConversation',
|
134 |
+
payload: {
|
135 |
+
conversation_id: payload.conversation_id,
|
136 |
+
},
|
137 |
+
});
|
138 |
+
}
|
139 |
},
|
140 |
},
|
141 |
};
|
web/src/pages/chat/utils.ts
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { variableEnabledFieldMap } from './constants';
|
2 |
+
|
3 |
+
export const excludeUnEnabledVariables = (values: any) => {
|
4 |
+
const unEnabledFields: Array<keyof typeof variableEnabledFieldMap> =
|
5 |
+
Object.keys(variableEnabledFieldMap).filter((key) => !values[key]) as Array<
|
6 |
+
keyof typeof variableEnabledFieldMap
|
7 |
+
>;
|
8 |
+
|
9 |
+
return unEnabledFields.map(
|
10 |
+
(key) => `llm_setting.${variableEnabledFieldMap[key]}`,
|
11 |
+
);
|
12 |
+
};
|
web/src/pages/knowledge/model.ts
CHANGED
@@ -31,7 +31,7 @@ const model: DvaModel<KnowledgeModelState> = {
|
|
31 |
},
|
32 |
*getList({ payload = {} }, { call, put }) {
|
33 |
const { data } = yield call(kbService.getList, payload);
|
34 |
-
const { retcode, data: res
|
35 |
|
36 |
if (retcode === 0) {
|
37 |
yield put({
|
|
|
31 |
},
|
32 |
*getList({ payload = {} }, { call, put }) {
|
33 |
const { data } = yield call(kbService.getList, payload);
|
34 |
+
const { retcode, data: res } = data;
|
35 |
|
36 |
if (retcode === 0) {
|
37 |
yield put({
|
web/src/services/chatService.ts
CHANGED
@@ -6,6 +6,7 @@ const {
|
|
6 |
getDialog,
|
7 |
setDialog,
|
8 |
listDialog,
|
|
|
9 |
getConversation,
|
10 |
setConversation,
|
11 |
completeConversation,
|
@@ -21,6 +22,10 @@ const methods = {
|
|
21 |
url: setDialog,
|
22 |
method: 'post',
|
23 |
},
|
|
|
|
|
|
|
|
|
24 |
listDialog: {
|
25 |
url: listDialog,
|
26 |
method: 'get',
|
|
|
6 |
getDialog,
|
7 |
setDialog,
|
8 |
listDialog,
|
9 |
+
removeDialog,
|
10 |
getConversation,
|
11 |
setConversation,
|
12 |
completeConversation,
|
|
|
22 |
url: setDialog,
|
23 |
method: 'post',
|
24 |
},
|
25 |
+
removeDialog: {
|
26 |
+
url: removeDialog,
|
27 |
+
method: 'post',
|
28 |
+
},
|
29 |
listDialog: {
|
30 |
url: listDialog,
|
31 |
method: 'get',
|
web/src/utils/api.ts
CHANGED
@@ -45,6 +45,7 @@ export default {
|
|
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`,
|
|
|
45 |
|
46 |
setDialog: `${api_host}/dialog/set`,
|
47 |
getDialog: `${api_host}/dialog/get`,
|
48 |
+
removeDialog: `${api_host}/dialog/rm`,
|
49 |
listDialog: `${api_host}/dialog/list`,
|
50 |
|
51 |
setConversation: `${api_host}/conversation/set`,
|