|
|
@@ -6,13 +6,17 @@ import {
|
|
|
Button, Input, Form, Divider, Splitter, Select, InputNumber, InputNumberProps,
|
|
|
Radio, Switch, Row, Col, Slider, Space, RadioChangeEvent,
|
|
|
Spin, message, Typography, Tooltip,
|
|
|
- Cascader
|
|
|
+ Cascader,
|
|
|
+ Tag, Modal, Table,TablePaginationConfig
|
|
|
} from 'antd';
|
|
|
-import { PlusCircleOutlined, MinusCircleOutlined, ArrowLeftOutlined, InfoCircleOutlined } from '@ant-design/icons';
|
|
|
+import type { TableProps } from 'antd';
|
|
|
+
|
|
|
+import { PlusCircleOutlined, MinusCircleOutlined, ArrowLeftOutlined, InfoCircleOutlined,CloseCircleOutlined } from '@ant-design/icons';
|
|
|
import { apis } from '@/apis';
|
|
|
import router from '@/router';
|
|
|
import LocalStorage from '@/LocalStorage';
|
|
|
import Chat from '@/components/chat';
|
|
|
+import store from './store';
|
|
|
|
|
|
const { TextArea } = Input;
|
|
|
const FormItem = Form.Item;
|
|
|
@@ -22,6 +26,10 @@ const Index = 1;
|
|
|
|
|
|
const QuestionAnswerInfo: React.FC = () => {
|
|
|
|
|
|
+ const { state,onChangePagination,onFetchUserListApi } = store;
|
|
|
+ const { page,sourceData } = state;
|
|
|
+
|
|
|
+
|
|
|
const [form] = Form.useForm();
|
|
|
|
|
|
// top_p
|
|
|
@@ -133,7 +141,11 @@ const QuestionAnswerInfo: React.FC = () => {
|
|
|
const [appProjectList, setAppProjectList] = React.useState<AppTypeList>([]);
|
|
|
const [isAppPro, setIsAppPro] = React.useState<boolean>(false);
|
|
|
const [appId, setAppId] = React.useState<string>('');
|
|
|
-
|
|
|
+ const [fetchUserTypeList, setFetchUserTypeList] = React.useState<AppTypeList>([]); // 用户类型
|
|
|
+ const [userName, setUserName] = React.useState<string>(''); // 用户名
|
|
|
+ const [userNickName, setUserNickName] = React.useState<string>(''); // 用户昵称
|
|
|
+ const [userType, setUserType] = React.useState<string>(''); // 用户类型
|
|
|
+ const [vipList, setVipList] = React.useState<any>([]); // 用户列表
|
|
|
const style: React.CSSProperties = {
|
|
|
display: 'flex',
|
|
|
flexDirection: 'column',
|
|
|
@@ -141,6 +153,7 @@ const QuestionAnswerInfo: React.FC = () => {
|
|
|
width: 300,
|
|
|
};
|
|
|
|
|
|
+
|
|
|
const location = useLocation();
|
|
|
|
|
|
const init = async (id: string) => {
|
|
|
@@ -154,6 +167,8 @@ const QuestionAnswerInfo: React.FC = () => {
|
|
|
if (id) {
|
|
|
await api.fetchDetail(id);
|
|
|
}
|
|
|
+ onFetchUserListApi('','','');
|
|
|
+ await api.fetchUserType();
|
|
|
}
|
|
|
React.useEffect(() => {
|
|
|
const id = location?.state?.id;
|
|
|
@@ -196,10 +211,6 @@ const QuestionAnswerInfo: React.FC = () => {
|
|
|
};
|
|
|
|
|
|
|
|
|
- // const onChange: InputNumberProps['onChange'] = (value) => {
|
|
|
- // console.log('changed', value);
|
|
|
- // };
|
|
|
-
|
|
|
const onChangeShow = (checked: boolean) => {
|
|
|
console.log(`switch to ${checked}`);
|
|
|
};
|
|
|
@@ -306,7 +317,7 @@ const QuestionAnswerInfo: React.FC = () => {
|
|
|
updateDate: info.updateDate, // 更新时间
|
|
|
appProId: info.appProId,// 项目
|
|
|
typeId: info.typeId, //应用类型
|
|
|
- visible: info.visible||'0', //是否公开
|
|
|
+ visible: info.visible || '0', //是否公开
|
|
|
param_desc: data_info.param_desc, //回答风格
|
|
|
show_recall_result: data_info.show_recall_result, //是否展示召回结果
|
|
|
recall_method: data_info.recall_method, //召回方式
|
|
|
@@ -320,6 +331,9 @@ const QuestionAnswerInfo: React.FC = () => {
|
|
|
//recall_index_type_list: info.recall_index_type_list, //知识库id
|
|
|
//rerank_index_type_list: info.rerank_index_type_list, //知识库id
|
|
|
})
|
|
|
+ if(info.vipList&&info.vipList.length>0){
|
|
|
+ setVipList(info.vipList);
|
|
|
+ }
|
|
|
if (sd.length > 0) {
|
|
|
setInputs(sd);
|
|
|
}
|
|
|
@@ -340,8 +354,6 @@ const QuestionAnswerInfo: React.FC = () => {
|
|
|
value: item.knowledgeId,
|
|
|
}
|
|
|
});
|
|
|
- console.log(list, 'list')
|
|
|
-
|
|
|
|
|
|
setKnowledgeList(list);
|
|
|
} catch (error: any) {
|
|
|
@@ -365,10 +377,9 @@ const QuestionAnswerInfo: React.FC = () => {
|
|
|
}
|
|
|
},
|
|
|
// 获取是否公开类型
|
|
|
- fetchAppVisible: async (id:string) => {
|
|
|
+ fetchAppVisible: async (id: string) => {
|
|
|
try {
|
|
|
const res = await apis.fetchTakaiAppTypeList('app_visible');
|
|
|
- console.log('res.data',res.data)
|
|
|
const list = res.data.map((item: any) => {
|
|
|
return {
|
|
|
label: item.dictLabel,
|
|
|
@@ -376,15 +387,31 @@ const QuestionAnswerInfo: React.FC = () => {
|
|
|
}
|
|
|
});
|
|
|
setAppVisibleList(list);
|
|
|
- if(!id){
|
|
|
+ if (!id) {
|
|
|
form.setFieldsValue({
|
|
|
- visible: list[0].value
|
|
|
+ visible: list[0]?.value
|
|
|
});
|
|
|
}
|
|
|
} catch (error: any) {
|
|
|
console.error(error);
|
|
|
}
|
|
|
},
|
|
|
+ // 获取用户类型
|
|
|
+ fetchUserType: async () => {
|
|
|
+ try {
|
|
|
+ const res = await apis.fetchTakaiAppTypeList('sys_user_type');
|
|
|
+ const list = res.data.map((item: any) => {
|
|
|
+ return {
|
|
|
+ label: item.dictLabel,
|
|
|
+ value: item.dictValue,
|
|
|
+ }
|
|
|
+ });
|
|
|
+ setFetchUserTypeList(list);
|
|
|
+
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error(error);
|
|
|
+ }
|
|
|
+ },
|
|
|
|
|
|
// 获取模型列表
|
|
|
fetchModelList: async () => {
|
|
|
@@ -401,7 +428,6 @@ const QuestionAnswerInfo: React.FC = () => {
|
|
|
console.error(error);
|
|
|
}
|
|
|
},
|
|
|
-
|
|
|
// 项目级应用下的类型
|
|
|
fetchAppProType: async () => {
|
|
|
try {
|
|
|
@@ -412,6 +438,21 @@ const QuestionAnswerInfo: React.FC = () => {
|
|
|
console.error(error);
|
|
|
}
|
|
|
},
|
|
|
+ // 获取用户列表信息
|
|
|
+ fetchUserListApi: async () => {
|
|
|
+ try {
|
|
|
+ const res = await apis.fetchUserListApi({
|
|
|
+ pageNum:page.pageNumber,
|
|
|
+ pageSize: page.pageSize,
|
|
|
+ userName:userName,
|
|
|
+ nickName:userNickName,
|
|
|
+ userType:userType
|
|
|
+ });
|
|
|
+ // setSourceData(res.rows)
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
const handleRedioClick = (value: string) => {
|
|
|
@@ -490,6 +531,7 @@ const QuestionAnswerInfo: React.FC = () => {
|
|
|
max_token: values.max_token, //应用最大token
|
|
|
typeId: values.typeId, // 应用类型
|
|
|
visible: values.visible, // 是否公开
|
|
|
+ vipList: vipList, // vip用户列表
|
|
|
appProId: values.appProId,// 项目
|
|
|
userId: userId, // 用户id
|
|
|
};
|
|
|
@@ -522,529 +564,695 @@ const QuestionAnswerInfo: React.FC = () => {
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
+ /*
|
|
|
+ 选择VIP用户弹窗start
|
|
|
+ */
|
|
|
+ const [isModalOpen, setIsModalOpen] = React.useState(false);
|
|
|
+ let falgVipList:any = [];
|
|
|
+ const handleOk = () => {
|
|
|
+ setIsModalOpen(false);
|
|
|
+ let vipListFalg:any = [...vipList];
|
|
|
+ const vipIds = new Set(vipListFalg.map((vip:any) => vip.userId));
|
|
|
+ const merged = [...vipListFalg];
|
|
|
+
|
|
|
+ falgVipList.forEach((item:any) => {
|
|
|
+ if (!vipIds.has(item.userId)) {
|
|
|
+ merged.push(item);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ setVipList([...merged]);
|
|
|
+ };
|
|
|
|
|
|
- return (
|
|
|
- <div className='questionAnswerInfo'>
|
|
|
- <Spin spinning={pageLoading}>
|
|
|
- <Form
|
|
|
- form={form}
|
|
|
- layout='vertical'
|
|
|
- initialValues={{
|
|
|
- isDeepThink: false,
|
|
|
- max_token: 1024
|
|
|
- }}
|
|
|
+ const handleCancel = async () => {
|
|
|
+ setIsModalOpen(false);
|
|
|
+ };
|
|
|
+ interface DataType {
|
|
|
+ name: string;
|
|
|
+ key: string;
|
|
|
+ nickName: string;
|
|
|
+ userName: string;
|
|
|
+ deptName: string;
|
|
|
+ userTypeName: string;
|
|
|
+ }
|
|
|
+ // const [sourceData, setSourceData] = React.useState<DataType[]>([]);
|
|
|
+ const paginationConfig: TablePaginationConfig = {
|
|
|
+ // 显示数据总量
|
|
|
+ showTotal: (total: number) => {
|
|
|
+ return `共 ${total} 条`;
|
|
|
+ },
|
|
|
+ // 展示分页条数切换
|
|
|
+ showSizeChanger: false,
|
|
|
+ // 指定每页显示条数
|
|
|
+ // 快速跳转至某页
|
|
|
+ showQuickJumper: false,
|
|
|
+ current: page.pageNumber,
|
|
|
+ pageSize: page.pageSize,
|
|
|
+ total: page.total,
|
|
|
+ onChange: async (page, pageSize) => {
|
|
|
+ await onChangePagination(page, pageSize,userName,userNickName,userType);
|
|
|
+ },
|
|
|
+ };
|
|
|
+
|
|
|
+ const vipModal = () => {
|
|
|
+ const columns: TableProps<DataType>['columns'] = [
|
|
|
+ {
|
|
|
+ title: '昵称',
|
|
|
+ dataIndex: 'nickName',
|
|
|
+ render: (text) => <p>{text}</p>,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '用户名称',
|
|
|
+ dataIndex: 'userName',
|
|
|
+ render: (text) => <p>{text}</p>,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '部门',
|
|
|
+ dataIndex: 'deptName',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '用户类型',
|
|
|
+ dataIndex: 'userTypeName',
|
|
|
+ },
|
|
|
+ ];
|
|
|
+ const rowSelection: TableProps<DataType>['rowSelection'] = {
|
|
|
+ type: 'checkbox',
|
|
|
+ onChange: (selectedRowKeys: React.Key[], selectedRows: DataType[]) => {
|
|
|
+ console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
|
|
|
+ falgVipList = selectedRows
|
|
|
+ },
|
|
|
+ getCheckboxProps: (record: DataType) => ({
|
|
|
+ disabled: record.name === 'Disabled User', // Column configuration not to be checked
|
|
|
+ name: record.name,
|
|
|
+ }),
|
|
|
+ };
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <Modal
|
|
|
+ title="请选择VIP用户"
|
|
|
+ open={isModalOpen}
|
|
|
+ onOk={handleOk}
|
|
|
+ onCancel={handleCancel}
|
|
|
+ width='80%'
|
|
|
>
|
|
|
- <div style={{ display: step === 1 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
|
|
|
- <FormItem
|
|
|
- label='问答应用名称'
|
|
|
- name='name'
|
|
|
- rules={[{ required: true, message: '问答应用名称不能为空' }]}
|
|
|
- >
|
|
|
- <Input placeholder="请输入问答应用名称" className='form-input-large' />
|
|
|
- </FormItem>
|
|
|
- <FormItem
|
|
|
- label='应用类型'
|
|
|
- name='typeId'
|
|
|
- >
|
|
|
- <Select
|
|
|
- className='questionAnswerInfo-content-title'
|
|
|
- placeholder='请选择问答应用类型'
|
|
|
- onChange={handleAppChange}
|
|
|
- allowClear={true}
|
|
|
- >
|
|
|
- {
|
|
|
- appTypeList.map((item, index) => {
|
|
|
- return <Option value={item.value} key={index}>
|
|
|
- {item.label}
|
|
|
- </Option>
|
|
|
- })
|
|
|
+ <div className='modal_top'>
|
|
|
+ <Input placeholder="请输入用户昵称" allowClear onChange={(e)=>{
|
|
|
+ setUserNickName(e.target.value)
|
|
|
+ }} />
|
|
|
+ <Input placeholder="请输入用户名称" allowClear onChange={(e)=>{
|
|
|
+ setUserName(e.target.value)
|
|
|
+ }} />
|
|
|
+ <Select
|
|
|
+ placeholder='请选择用户类型'
|
|
|
+ style={{ width: 150 }}
|
|
|
+ onChange={(e) => {
|
|
|
+ if(e === undefined){
|
|
|
+ setUserType('')
|
|
|
+ return
|
|
|
}
|
|
|
- </Select>
|
|
|
- </FormItem>
|
|
|
- {
|
|
|
- isAppPro &&
|
|
|
- <>
|
|
|
- <FormItem
|
|
|
- label='项目'
|
|
|
- name='appProId'
|
|
|
- rules={[{ required: true, message: '项目不能为空' }]}
|
|
|
- >
|
|
|
- <Cascader
|
|
|
- options={appProjectList}
|
|
|
- placeholder="请选择项目"
|
|
|
- showSearch
|
|
|
- className="questionAnswerInfo-content-title"
|
|
|
- />
|
|
|
- </FormItem>
|
|
|
- </>
|
|
|
- }
|
|
|
- <FormItem
|
|
|
- label='是否公开'
|
|
|
- name='visible'
|
|
|
+ setUserType(e)
|
|
|
+ }}
|
|
|
+ allowClear={true}
|
|
|
>
|
|
|
- <Select
|
|
|
- className='questionAnswerInfo-content-title'
|
|
|
- placeholder='请选择是否公开'
|
|
|
- allowClear={true}
|
|
|
+ {
|
|
|
+ fetchUserTypeList.map((item, index) => {
|
|
|
+ return <Option value={item.value} key={index}>
|
|
|
+ {item.label}
|
|
|
+ </Option>
|
|
|
+ })
|
|
|
+ }
|
|
|
+ </Select>
|
|
|
+ <Button value="large" style={{
|
|
|
+ background: 'transparent',
|
|
|
+ border: '1px solid #1677ff',
|
|
|
+ color: '#1677ff'
|
|
|
+ }}
|
|
|
+ onClick={() => { onFetchUserListApi(userName,userNickName,userType) }}
|
|
|
+ > 搜索 </Button>
|
|
|
+ {/* <Button value="large"
|
|
|
+ onClick={() => { api.fetchUserListApi() }}
|
|
|
+ > 重置 </Button> */}
|
|
|
+ </div>
|
|
|
+ <Table<DataType> pagination={paginationConfig} rowKey="userName" rowSelection={rowSelection} columns={columns} dataSource={sourceData} />
|
|
|
+ </Modal>
|
|
|
+ </>
|
|
|
+ )
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ 选择VIP用户弹窗end
|
|
|
+ */
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <div className='questionAnswerInfo'>
|
|
|
+ <Spin spinning={pageLoading}>
|
|
|
+ <Form
|
|
|
+ form={form}
|
|
|
+ layout='vertical'
|
|
|
+ initialValues={{
|
|
|
+ isDeepThink: false,
|
|
|
+ max_token: 1024
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <div style={{ display: step === 1 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
|
|
|
+ <FormItem
|
|
|
+ label='问答应用名称'
|
|
|
+ name='name'
|
|
|
+ rules={[{ required: true, message: '问答应用名称不能为空' }]}
|
|
|
>
|
|
|
- {
|
|
|
- appVisibleList.map((item, index) => {
|
|
|
- return <Option value={item.value} key={index}>
|
|
|
- {item.label}
|
|
|
- </Option>
|
|
|
- })
|
|
|
- }
|
|
|
- </Select>
|
|
|
- </FormItem>
|
|
|
- <FormItem
|
|
|
- label='问答应用描述'
|
|
|
- name='desc'
|
|
|
- rules={[{ required: true, message: '问答应用描述不能为空' }]}
|
|
|
- >
|
|
|
- <TextArea
|
|
|
- showCount
|
|
|
- maxLength={500}
|
|
|
- placeholder="请输入当前应用的描述"
|
|
|
- className='form-textarea-large'
|
|
|
- />
|
|
|
- </FormItem>
|
|
|
-
|
|
|
- <div className='preset-questions'>
|
|
|
- <h4>添加预设问题</h4>
|
|
|
- <div>
|
|
|
- {
|
|
|
- inputs.map(input => (
|
|
|
- <div key={input.id} className='question-item'>
|
|
|
- <label>问题 {input.id}</label>
|
|
|
- <Input
|
|
|
- className='question-input'
|
|
|
- type="text"
|
|
|
- value={input.value}
|
|
|
- onChange={e => handleChange(input.id, e.target.value)}
|
|
|
- />
|
|
|
- <div className='question-actions'>
|
|
|
- <PlusCircleOutlined className='question-icon' onClick={addInput} />
|
|
|
- <MinusCircleOutlined className='question-icon' onClick={() => delInput(input.id)} />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- ))}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div style={{ display: 'flex', gap: '12px', marginTop: '24px', paddingTop: '24px', borderTop: '1px solid #f0f0f0' }}>
|
|
|
- <Button
|
|
|
- className='btn-cancel'
|
|
|
- onClick={() => {
|
|
|
- router.navigate({ pathname: '/deepseek/questionAnswer' });
|
|
|
- }}
|
|
|
+ <Input placeholder="请输入问答应用名称" className='form-input-large' />
|
|
|
+ </FormItem>
|
|
|
+ <FormItem
|
|
|
+ label='应用类型'
|
|
|
+ name='typeId'
|
|
|
>
|
|
|
- 返回
|
|
|
- </Button>
|
|
|
- <Button
|
|
|
- type='primary'
|
|
|
- onClick={() => {
|
|
|
- form.validateFields(['name', 'desc', 'appProId']).then(async (values) => {
|
|
|
- setStep(2);
|
|
|
- setInputs(inputs);
|
|
|
- }).catch((error) => {
|
|
|
- console.error(error);
|
|
|
- });
|
|
|
- }}
|
|
|
+ <Select
|
|
|
+ className='questionAnswerInfo-content-title'
|
|
|
+ placeholder='请选择问答应用类型'
|
|
|
+ onChange={handleAppChange}
|
|
|
+ allowClear={true}
|
|
|
+ >
|
|
|
+ {
|
|
|
+ appTypeList.map((item, index) => {
|
|
|
+ return <Option value={item.value} key={index}>
|
|
|
+ {item.label}
|
|
|
+ </Option>
|
|
|
+ })
|
|
|
+ }
|
|
|
+ </Select>
|
|
|
+ </FormItem>
|
|
|
+ {
|
|
|
+ isAppPro &&
|
|
|
+ <>
|
|
|
+ <FormItem
|
|
|
+ label='项目'
|
|
|
+ name='appProId'
|
|
|
+ rules={[{ required: true, message: '项目不能为空' }]}
|
|
|
+ >
|
|
|
+ <Cascader
|
|
|
+ options={appProjectList}
|
|
|
+ placeholder="请选择项目"
|
|
|
+ showSearch
|
|
|
+ className="questionAnswerInfo-content-title"
|
|
|
+ />
|
|
|
+ </FormItem>
|
|
|
+ </>
|
|
|
+ }
|
|
|
+ <FormItem
|
|
|
+ label='是否公开'
|
|
|
+ name='visible'
|
|
|
>
|
|
|
- 下一步
|
|
|
- </Button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div style={{ display: step === 2 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
|
|
|
- <div className='flex-between padding-bottom-16'>
|
|
|
- <div>
|
|
|
- <Button
|
|
|
- className='btn-back'
|
|
|
- icon={<ArrowLeftOutlined />}
|
|
|
- onClick={() => {
|
|
|
- setStep(1);
|
|
|
- }}
|
|
|
+ <Select
|
|
|
+ className='questionAnswerInfo-content-title'
|
|
|
+ placeholder='请选择是否公开'
|
|
|
+ allowClear={true}
|
|
|
>
|
|
|
- 上一步
|
|
|
- </Button>
|
|
|
+ {
|
|
|
+ appVisibleList.map((item, index) => {
|
|
|
+ return <Option value={item.value} key={index}>
|
|
|
+ {item.label}
|
|
|
+ </Option>
|
|
|
+ })
|
|
|
+ }
|
|
|
+ </Select>
|
|
|
+ </FormItem>
|
|
|
+ {/* VIP用户 */}
|
|
|
+ <FormItem
|
|
|
+ label='VIP用户'
|
|
|
+ >
|
|
|
+ <div className='tags-info'>
|
|
|
+ <p className='tags-list'>
|
|
|
+ {vipList.map((item: any) =>
|
|
|
+ (<Tag key={item.userId} color="blue" closeIcon onClose={(e)=>{
|
|
|
+ const newVipList = vipList.filter((vip:any) => vip.userId !== item.userId);
|
|
|
+ setVipList(newVipList);
|
|
|
+ e.preventDefault();
|
|
|
+ }}>
|
|
|
+ {item.userName}
|
|
|
+ </Tag>)
|
|
|
+ )}
|
|
|
+ </p>
|
|
|
+ <p>
|
|
|
+ {vipList.length>0&&<CloseCircleOutlined className='cup' onClick={()=>{
|
|
|
+ setVipList([]);
|
|
|
+ }} />}
|
|
|
+ <Button style={{
|
|
|
+ background: 'transparent',
|
|
|
+ border: '1px solid #1677ff',
|
|
|
+ color: '#1677ff'
|
|
|
+ }} type="primary" variant="outlined" onClick={() => { setIsModalOpen(true) }}>选择</Button>
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </FormItem>
|
|
|
+ <FormItem
|
|
|
+ label='问答应用描述'
|
|
|
+ name='desc'
|
|
|
+ rules={[{ required: true, message: '问答应用描述不能为空' }]}
|
|
|
+ >
|
|
|
+ <TextArea
|
|
|
+ showCount
|
|
|
+ maxLength={500}
|
|
|
+ placeholder="请输入当前应用的描述"
|
|
|
+ className='form-textarea-large'
|
|
|
+ />
|
|
|
+ </FormItem>
|
|
|
+
|
|
|
+ <div className='preset-questions'>
|
|
|
+ <h4>添加预设问题</h4>
|
|
|
+ <div>
|
|
|
+ {
|
|
|
+ inputs.map(input => (
|
|
|
+ <div key={input.id} className='question-item'>
|
|
|
+ <label>问题 {input.id}</label>
|
|
|
+ <Input
|
|
|
+ className='question-input'
|
|
|
+ type="text"
|
|
|
+ value={input.value}
|
|
|
+ onChange={e => handleChange(input.id, e.target.value)}
|
|
|
+ />
|
|
|
+ <div className='question-actions'>
|
|
|
+ <PlusCircleOutlined className='question-icon' onClick={addInput} />
|
|
|
+ <MinusCircleOutlined className='question-icon' onClick={() => delInput(input.id)} />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div style={{ display: 'flex', gap: '12px' }}>
|
|
|
+
|
|
|
+ <div style={{ display: 'flex', gap: '12px', marginTop: '24px', paddingTop: '24px', borderTop: '1px solid #f0f0f0' }}>
|
|
|
<Button
|
|
|
className='btn-cancel'
|
|
|
onClick={() => {
|
|
|
router.navigate({ pathname: '/deepseek/questionAnswer' });
|
|
|
}}
|
|
|
>
|
|
|
- 取消
|
|
|
+ 返回
|
|
|
</Button>
|
|
|
- {createFlag && appId&&(<Button
|
|
|
+ <Button
|
|
|
type='primary'
|
|
|
- className='btn-cancel'
|
|
|
onClick={() => {
|
|
|
- saveConfig('SAVE');
|
|
|
+ form.validateFields(['name', 'desc', 'appProId']).then(async (values) => {
|
|
|
+ setStep(2);
|
|
|
+ setInputs(inputs);
|
|
|
+ }).catch((error) => {
|
|
|
+ console.error(error);
|
|
|
+ });
|
|
|
}}
|
|
|
>
|
|
|
- 保存
|
|
|
+ 下一步
|
|
|
</Button>
|
|
|
- )}
|
|
|
-
|
|
|
- {createFlag && (
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div style={{ display: step === 2 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
|
|
|
+ <div className='flex-between padding-bottom-16'>
|
|
|
+ <div>
|
|
|
<Button
|
|
|
- type='primary'
|
|
|
+ className='btn-back'
|
|
|
+ icon={<ArrowLeftOutlined />}
|
|
|
onClick={() => {
|
|
|
- saveConfig('SUBMIT');
|
|
|
+ setStep(1);
|
|
|
}}
|
|
|
>
|
|
|
- 提交应用
|
|
|
+ 上一步
|
|
|
</Button>
|
|
|
- )}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className='section-title'>
|
|
|
- Prompt编写与参数配置
|
|
|
- <Tooltip
|
|
|
- title="Prompt用于对大模型的回复做出一些列指令和约束。这段Prompt不会被用户看到。"
|
|
|
- placement="right"
|
|
|
- overlayStyle={{ fontSize: '12px' }}
|
|
|
- >
|
|
|
- <InfoCircleOutlined style={{ marginLeft: '8px', color: '#999', fontSize: '14px' }} />
|
|
|
- </Tooltip>
|
|
|
- </div>
|
|
|
- <Splitter style={{ border: '1px solid #f0f0f0', borderRadius: '6px', height: 550 }}>
|
|
|
- <Splitter.Panel defaultSize="45%">
|
|
|
- <div className='prompt'>
|
|
|
- <div className='prompt-info'>
|
|
|
- <div className='prompt-info-text'>
|
|
|
- <Typography.Paragraph style={{ fontSize: '12px', lineHeight: '1.6', color: '#999', margin: 0 }}>
|
|
|
- 编写Prompt过程中可以引入2项变量:
|
|
|
- <span className='variable-highlight'>{'{{知识}}'}</span>
|
|
|
- 代表知识库中检索到的知识内容,
|
|
|
- <span className='variable-highlight'>{'{{用户}}'}</span>
|
|
|
- 代表用户输入的内容。您可以在编写Prompt过程中将变量拼接在合适的位置。
|
|
|
- <br />
|
|
|
- 插入:
|
|
|
- <span className='variable-highlight'>{'{{知识}}'}</span>,
|
|
|
- 插入:
|
|
|
- <span className='variable-highlight'>{'{{用户}}'}</span>。
|
|
|
- </Typography.Paragraph>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <Divider style={{ margin: '0' }} />
|
|
|
- <div className='prompt-editor-area'>
|
|
|
- <FormItem name='prompt'
|
|
|
- initialValue={
|
|
|
- `你是一位知识检索助手,你必须并且只能从我发送的众多知识片段中寻找能够解决用户输入问题的最优答案,并且在执行任务的过程中严格执行规定的要求。 \n
|
|
|
-知识片段如下:
|
|
|
-{{知识}}
|
|
|
-
|
|
|
-规定要求:
|
|
|
-- 找到答案就仅使用知识片段中的原文回答用户的提问;- 找不到答案就用自身知识并且告诉用户该信息不是来自文档;
|
|
|
-- 所引用的文本片段中所包含的示意图占位符必须进行返回,占位符格式参考:【示意图序号_编号】
|
|
|
-- 严禁输出任何知识片段中不存在的示意图占位符;
|
|
|
-- 输出的内容必须删除其中包含的任何图注、序号等信息。例如:“进入登录页面(图1.1)”需要从文字中删除图序,回复效果为:“进入登录页面”;“如图所示1.1”,回复效果为:“如图所示”;
|
|
|
-
|
|
|
-格式规范:
|
|
|
-- 文档中会出现包含表格的情况,表格是以图片标识符的形式呈现,表格中缺失数据时候返回空单元格;
|
|
|
-- 如果需要用到表格中的数据,以代码块语法输出表格中的数据;
|
|
|
-- 避免使用代码块语法回复信息;
|
|
|
-- 回复的开头语不要输出诸如:“我想”,“我认为”,“think”等相关语义的文本。
|
|
|
-
|
|
|
-严格执行规定要求,不要复述问题,直接开始回答。
|
|
|
-
|
|
|
-用户输入问题:
|
|
|
-{{用户}}`
|
|
|
- }
|
|
|
- rules={[{ required: true, message: '提示词不能为空' }]}>
|
|
|
- <TextArea
|
|
|
- placeholder="提示词"
|
|
|
- rows={50}
|
|
|
- />
|
|
|
- </FormItem>
|
|
|
- </div>
|
|
|
</div>
|
|
|
- </Splitter.Panel>
|
|
|
- <Splitter.Panel defaultSize="25%">
|
|
|
- <div className='flex-center-container'>
|
|
|
- <div className='half-width'>
|
|
|
- <div className='flex-center-top'>
|
|
|
- 欢迎使用 {name}
|
|
|
- </div>
|
|
|
- <div className='flex-center padding-top-20'>
|
|
|
- <FormItem
|
|
|
- label='引用知识库'
|
|
|
- name='knowledge_ids'
|
|
|
- rules={[{ required: true, message: '知识库不能为空' }]}>
|
|
|
- <Select
|
|
|
- mode='multiple'
|
|
|
- maxCount={MAX_COUNT}
|
|
|
- showSearch={true}
|
|
|
- // suffixIcon={suffix}
|
|
|
- // className='questionAnswerInfo-content-title'
|
|
|
- placeholder='请选择知识库'
|
|
|
- >
|
|
|
- {
|
|
|
- knowledgeList.map((item, index) => {
|
|
|
- return <Option value={item.value} key={index}>
|
|
|
- {item.label}
|
|
|
- </Option>
|
|
|
- })
|
|
|
- }
|
|
|
- </Select>
|
|
|
- </FormItem>
|
|
|
- </div>
|
|
|
- <div className='flex-center'>
|
|
|
- <FormItem
|
|
|
- label='调用模型'
|
|
|
- name="model"
|
|
|
- rules={[{ required: true, message: '模型不能为空' }]}>
|
|
|
- <Select
|
|
|
- placeholder='请选择模型'
|
|
|
- allowClear={true}
|
|
|
- className='questionAnswerInfo-content-title'
|
|
|
- onChange={(value) => {
|
|
|
- if (value === 'Qwen3-30B') {
|
|
|
- setIsDeepThinkVisible(true);
|
|
|
- } else {
|
|
|
- setIsDeepThinkVisible(false);
|
|
|
- }
|
|
|
- }}
|
|
|
- >
|
|
|
- <Option value='Qwen3-30B'>Qwen3-30B</Option>
|
|
|
- <Option value='Qwen2-72B'>Qwen2-72B</Option>
|
|
|
- </Select>
|
|
|
-
|
|
|
- </FormItem>
|
|
|
- </div>
|
|
|
- <div className='flex-center' style={{
|
|
|
- display: isDeepThinkVisible ? 'flex' : 'none'
|
|
|
- }}>
|
|
|
- <FormItem
|
|
|
- label='深度思考'
|
|
|
- name='isDeepThink'
|
|
|
- rules={[{ required: true, message: '请选择是否深度思考' }]}>
|
|
|
- <Radio.Group buttonStyle="solid" className='form-control-width'>
|
|
|
- <Radio.Button value='Y'>是</Radio.Button>
|
|
|
- <Radio.Button value='N'>否</Radio.Button>
|
|
|
- </Radio.Group>
|
|
|
- </FormItem>
|
|
|
+ <div style={{ display: 'flex', gap: '12px' }}>
|
|
|
+ <Button
|
|
|
+ className='btn-cancel'
|
|
|
+ onClick={() => {
|
|
|
+ router.navigate({ pathname: '/deepseek/questionAnswer' });
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ 取消
|
|
|
+ </Button>
|
|
|
+ {
|
|
|
+ appId && (<Button
|
|
|
+ type='primary'
|
|
|
+ className='btn-cancel'
|
|
|
+ onClick={() => {
|
|
|
+ saveConfig('SAVE');
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ 保存
|
|
|
+ </Button>)
|
|
|
+ }
|
|
|
+
|
|
|
+ {createFlag && (
|
|
|
+ <Button
|
|
|
+ type='primary'
|
|
|
+ onClick={() => {
|
|
|
+ saveConfig('SUBMIT');
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ 提交应用
|
|
|
+ </Button>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div className='section-title'>
|
|
|
+ Prompt编写与参数配置
|
|
|
+ <Tooltip
|
|
|
+ title="Prompt用于对大模型的回复做出一些列指令和约束。这段Prompt不会被用户看到。"
|
|
|
+ placement="right"
|
|
|
+ overlayStyle={{ fontSize: '12px' }}
|
|
|
+ >
|
|
|
+ <InfoCircleOutlined style={{ marginLeft: '8px', color: '#999', fontSize: '14px' }} />
|
|
|
+ </Tooltip>
|
|
|
+ </div>
|
|
|
+ <Splitter style={{ border: '1px solid #f0f0f0', borderRadius: '6px', height: 550 }}>
|
|
|
+ <Splitter.Panel defaultSize="45%">
|
|
|
+ <div className='prompt'>
|
|
|
+ <div className='prompt-info'>
|
|
|
+ <div className='prompt-info-text'>
|
|
|
+ <Typography.Paragraph style={{ fontSize: '12px', lineHeight: '1.6', color: '#999', margin: 0 }}>
|
|
|
+ 编写Prompt过程中可以引入2项变量:
|
|
|
+ <span className='variable-highlight'>{'{{知识}}'}</span>
|
|
|
+ 代表知识库中检索到的知识内容,
|
|
|
+ <span className='variable-highlight'>{'{{用户}}'}</span>
|
|
|
+ 代表用户输入的内容。您可以在编写Prompt过程中将变量拼接在合适的位置。
|
|
|
+ <br />
|
|
|
+ 插入:
|
|
|
+ <span className='variable-highlight'>{'{{知识}}'}</span>,
|
|
|
+ 插入:
|
|
|
+ <span className='variable-highlight'>{'{{用户}}'}</span>。
|
|
|
+ </Typography.Paragraph>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div className='flex-center'>
|
|
|
- <FormItem
|
|
|
- label='max token'
|
|
|
- name='max_token'
|
|
|
- rules={[{ required: true, message: 'max token不能为空' }]}>
|
|
|
- <InputNumber
|
|
|
- className='questionAnswerInfo-content-title'
|
|
|
+ <Divider style={{ margin: '0' }} />
|
|
|
+ <div className='prompt-editor-area'>
|
|
|
+ <FormItem name='prompt'
|
|
|
+ initialValue={
|
|
|
+ `你是一位知识检索助手,你必须并且只能从我发送的众多知识片段中寻找能够解决用户输入问题的最优答案,并且在执行任务的过程中严格执行规定的要求。 \n
|
|
|
+ 知识片段如下:
|
|
|
+ {{知识}}
|
|
|
+
|
|
|
+ 规定要求:
|
|
|
+ - 找到答案就仅使用知识片段中的原文回答用户的提问;- 找不到答案就用自身知识并且告诉用户该信息不是来自文档;
|
|
|
+ - 所引用的文本片段中所包含的示意图占位符必须进行返回,占位符格式参考:【示意图序号_编号】
|
|
|
+ - 严禁输出任何知识片段中不存在的示意图占位符;
|
|
|
+ - 输出的内容必须删除其中包含的任何图注、序号等信息。例如:“进入登录页面(图1.1)”需要从文字中删除图序,回复效果为:“进入登录页面”;“如图所示1.1”,回复效果为:“如图所示”;
|
|
|
+
|
|
|
+ 格式规范:
|
|
|
+ - 文档中会出现包含表格的情况,表格是以图片标识符的形式呈现,表格中缺失数据时候返回空单元格;
|
|
|
+ - 如果需要用到表格中的数据,以代码块语法输出表格中的数据;
|
|
|
+ - 避免使用代码块语法回复信息;
|
|
|
+ - 回复的开头语不要输出诸如:“我想”,“我认为”,“think”等相关语义的文本。
|
|
|
+
|
|
|
+ 严格执行规定要求,不要复述问题,直接开始回答。
|
|
|
+
|
|
|
+ 用户输入问题:
|
|
|
+ {{用户}}`
|
|
|
+ }
|
|
|
+ rules={[{ required: true, message: '提示词不能为空' }]}>
|
|
|
+ <TextArea
|
|
|
+ placeholder="提示词"
|
|
|
+ rows={50}
|
|
|
/>
|
|
|
</FormItem>
|
|
|
</div>
|
|
|
-
|
|
|
- {
|
|
|
- !isVisible &&
|
|
|
- <div className='flex-center'>
|
|
|
- <a onClick={() => {
|
|
|
- setIsVisible(!isVisible);
|
|
|
- }} className='link-more-settings'>
|
|
|
- 更多设置
|
|
|
- </a>
|
|
|
+ </div>
|
|
|
+ </Splitter.Panel>
|
|
|
+ <Splitter.Panel defaultSize="25%">
|
|
|
+ <div className='flex-center-container'>
|
|
|
+ <div className='half-width'>
|
|
|
+ <div className='flex-center-top'>
|
|
|
+ 欢迎使用 {name}
|
|
|
</div>
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- {/* {isVisible && */}
|
|
|
- <div style={{ display: isVisible ? 'block' : 'none', paddingTop: '20px' }}>
|
|
|
- {isVisibleCus &&
|
|
|
- <Space style={{ width: '100%' }} direction="vertical">
|
|
|
- <div className='flex-center'>
|
|
|
- <FormItem
|
|
|
- label='Top-p'
|
|
|
- name='topP'
|
|
|
- className='form-control-width'
|
|
|
- >
|
|
|
- <TopPDecimalStep />
|
|
|
- </FormItem>
|
|
|
- </div>
|
|
|
- <div className='flex-center'>
|
|
|
- <FormItem
|
|
|
- label='Temperature'
|
|
|
- name='temperature'
|
|
|
- className='form-control-width'
|
|
|
- >
|
|
|
- <TempDecimalStep />
|
|
|
- </FormItem>
|
|
|
- </div>
|
|
|
- </Space>
|
|
|
- }
|
|
|
-
|
|
|
- <div style={{
|
|
|
- display: 'flex',
|
|
|
- justifyContent: 'center',
|
|
|
- alignItems: 'center'
|
|
|
- }}>
|
|
|
+ <div className='flex-center padding-top-20'>
|
|
|
<FormItem
|
|
|
- label='回答风格'
|
|
|
- name='param_desc'
|
|
|
- rules={[{ required: true, message: '回答风格不能为空' }]}>
|
|
|
- <Radio.Group buttonStyle="solid"
|
|
|
- className='form-control-width'>
|
|
|
- <Radio.Button onClick={() => {
|
|
|
- handleRedioClick('strict')
|
|
|
- }} value='strict'>严谨</Radio.Button>
|
|
|
- <Radio.Button onClick={() => {
|
|
|
- handleRedioClick('moderate')
|
|
|
- }} value='moderate'>适中</Radio.Button>
|
|
|
- <Radio.Button onClick={() => {
|
|
|
- handleRedioClick('flexib')
|
|
|
- }} value='flexib'>发散</Radio.Button>
|
|
|
- <Radio.Button value='custom'
|
|
|
- onClick={() => {
|
|
|
- setIsVisibleCus(!isVisibleCus);
|
|
|
- setTopPValue(0.1);
|
|
|
- setTempValue(0.01);
|
|
|
- }}
|
|
|
- >自定义
|
|
|
- </Radio.Button>
|
|
|
- </Radio.Group>
|
|
|
+ label='引用知识库'
|
|
|
+ name='knowledge_ids'
|
|
|
+ rules={[{ required: true, message: '知识库不能为空' }]}>
|
|
|
+ <Select
|
|
|
+ mode='multiple'
|
|
|
+ maxCount={MAX_COUNT}
|
|
|
+ showSearch={true}
|
|
|
+ // suffixIcon={suffix}
|
|
|
+ // className='questionAnswerInfo-content-title'
|
|
|
+ placeholder='请选择知识库'
|
|
|
+ >
|
|
|
+ {
|
|
|
+ knowledgeList.map((item, index) => {
|
|
|
+ return <Option value={item.value} key={index}>
|
|
|
+ {item.label}
|
|
|
+ </Option>
|
|
|
+ })
|
|
|
+ }
|
|
|
+ </Select>
|
|
|
</FormItem>
|
|
|
</div>
|
|
|
- <div style={{
|
|
|
- display: 'flex',
|
|
|
- justifyContent: 'center',
|
|
|
- alignItems: 'center'
|
|
|
- }}>
|
|
|
+ <div className='flex-center'>
|
|
|
<FormItem
|
|
|
- label='展示引用知识'
|
|
|
- name='show_recall_result'
|
|
|
- className='form-control-width'>
|
|
|
- <Switch onChange={onChangeShow} />
|
|
|
+ label='调用模型'
|
|
|
+ name="model"
|
|
|
+ rules={[{ required: true, message: '模型不能为空' }]}>
|
|
|
+ <Select
|
|
|
+ placeholder='请选择模型'
|
|
|
+ allowClear={true}
|
|
|
+ className='questionAnswerInfo-content-title'
|
|
|
+ onChange={(value) => {
|
|
|
+ if (value === 'Qwen3-30B') {
|
|
|
+ setIsDeepThinkVisible(true);
|
|
|
+ } else {
|
|
|
+ setIsDeepThinkVisible(false);
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Option value='Qwen3-30B'>Qwen3-30B</Option>
|
|
|
+ <Option value='Qwen2-72B'>Qwen2-72B</Option>
|
|
|
+ </Select>
|
|
|
+
|
|
|
</FormItem>
|
|
|
</div>
|
|
|
- <div style={{
|
|
|
- display: 'flex',
|
|
|
- justifyContent: 'center',
|
|
|
- alignItems: 'center'
|
|
|
+ <div className='flex-center' style={{
|
|
|
+ display: isDeepThinkVisible ? 'flex' : 'none'
|
|
|
}}>
|
|
|
<FormItem
|
|
|
- label='召回方式'
|
|
|
- name='recall_method'
|
|
|
- rules={[{ required: true, message: '召回方式不能为空' }]}>
|
|
|
-
|
|
|
- <Radio.Group
|
|
|
- style={style}
|
|
|
- onChange={onChangeRecallMethod}
|
|
|
- options={[
|
|
|
- { value: 'embedding', label: '向量化检索' },
|
|
|
- { value: 'keyword', label: '关键词检索' },
|
|
|
- { value: 'mixed', label: '混合检索' },
|
|
|
- ]}
|
|
|
- />
|
|
|
+ label='深度思考'
|
|
|
+ name='isDeepThink'
|
|
|
+ rules={[{ required: true, message: '请选择是否深度思考' }]}>
|
|
|
+ <Radio.Group buttonStyle="solid" className='form-control-width'>
|
|
|
+ <Radio.Button value='Y'>是</Radio.Button>
|
|
|
+ <Radio.Button value='N'>否</Radio.Button>
|
|
|
+ </Radio.Group>
|
|
|
</FormItem>
|
|
|
</div>
|
|
|
- <div style={{
|
|
|
- display: 'flex',
|
|
|
- justifyContent: 'center',
|
|
|
- alignItems: 'center'
|
|
|
- }}>
|
|
|
- <div className='section-title'>重排方式</div>
|
|
|
- </div>
|
|
|
- <div style={{
|
|
|
- display: 'flex',
|
|
|
- justifyContent: 'center',
|
|
|
- alignItems: 'center'
|
|
|
- }}>
|
|
|
+ <div className='flex-center'>
|
|
|
<FormItem
|
|
|
- label='Rerank模型'
|
|
|
- name='rerank_status'
|
|
|
- valuePropName='checked'
|
|
|
- className='form-control-width'
|
|
|
- >
|
|
|
- <Switch onChange={onChangeModel} />
|
|
|
+ label='max token'
|
|
|
+ name='max_token'
|
|
|
+ rules={[{ required: true, message: 'max token不能为空' }]}>
|
|
|
+ <InputNumber
|
|
|
+ className='questionAnswerInfo-content-title'
|
|
|
+ />
|
|
|
</FormItem>
|
|
|
</div>
|
|
|
- {isVisibleRerank &&
|
|
|
+
|
|
|
+ {
|
|
|
+ !isVisible &&
|
|
|
+ <div className='flex-center'>
|
|
|
+ <a onClick={() => {
|
|
|
+ setIsVisible(!isVisible);
|
|
|
+ }} className='link-more-settings'>
|
|
|
+ 更多设置
|
|
|
+ </a>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ {/* {isVisible && */}
|
|
|
+ <div style={{ display: isVisible ? 'block' : 'none', paddingTop: '20px' }}>
|
|
|
+ {isVisibleCus &&
|
|
|
+ <Space style={{ width: '100%' }} direction="vertical">
|
|
|
+ <div className='flex-center'>
|
|
|
+ <FormItem
|
|
|
+ label='Top-p'
|
|
|
+ name='topP'
|
|
|
+ className='form-control-width'
|
|
|
+ >
|
|
|
+ <TopPDecimalStep />
|
|
|
+ </FormItem>
|
|
|
+ </div>
|
|
|
+ <div className='flex-center'>
|
|
|
+ <FormItem
|
|
|
+ label='Temperature'
|
|
|
+ name='temperature'
|
|
|
+ className='form-control-width'
|
|
|
+ >
|
|
|
+ <TempDecimalStep />
|
|
|
+ </FormItem>
|
|
|
+ </div>
|
|
|
+ </Space>
|
|
|
+ }
|
|
|
+
|
|
|
<div style={{
|
|
|
display: 'flex',
|
|
|
justifyContent: 'center',
|
|
|
alignItems: 'center'
|
|
|
}}>
|
|
|
<FormItem
|
|
|
- label='模型选择'
|
|
|
- name='rerank_model_name'
|
|
|
+ label='回答风格'
|
|
|
+ name='param_desc'
|
|
|
+ rules={[{ required: true, message: '回答风格不能为空' }]}>
|
|
|
+ <Radio.Group buttonStyle="solid"
|
|
|
+ className='form-control-width'>
|
|
|
+ <Radio.Button onClick={() => {
|
|
|
+ handleRedioClick('strict')
|
|
|
+ }} value='strict'>严谨</Radio.Button>
|
|
|
+ <Radio.Button onClick={() => {
|
|
|
+ handleRedioClick('moderate')
|
|
|
+ }} value='moderate'>适中</Radio.Button>
|
|
|
+ <Radio.Button onClick={() => {
|
|
|
+ handleRedioClick('flexib')
|
|
|
+ }} value='flexib'>发散</Radio.Button>
|
|
|
+ <Radio.Button value='custom'
|
|
|
+ onClick={() => {
|
|
|
+ setIsVisibleCus(!isVisibleCus);
|
|
|
+ setTopPValue(0.1);
|
|
|
+ setTempValue(0.01);
|
|
|
+ }}
|
|
|
+ >自定义
|
|
|
+ </Radio.Button>
|
|
|
+ </Radio.Group>
|
|
|
+ </FormItem>
|
|
|
+ </div>
|
|
|
+ <div style={{
|
|
|
+ display: 'flex',
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignItems: 'center'
|
|
|
+ }}>
|
|
|
+ <FormItem
|
|
|
+ label='展示引用知识'
|
|
|
+ name='show_recall_result'
|
|
|
+ className='form-control-width'>
|
|
|
+ <Switch onChange={onChangeShow} />
|
|
|
+ </FormItem>
|
|
|
+ </div>
|
|
|
+ <div style={{
|
|
|
+ display: 'flex',
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignItems: 'center'
|
|
|
+ }}>
|
|
|
+ <FormItem
|
|
|
+ label='召回方式'
|
|
|
+ name='recall_method'
|
|
|
+ rules={[{ required: true, message: '召回方式不能为空' }]}>
|
|
|
+
|
|
|
+ <Radio.Group
|
|
|
+ style={style}
|
|
|
+ onChange={onChangeRecallMethod}
|
|
|
+ options={[
|
|
|
+ { value: 'embedding', label: '向量化检索' },
|
|
|
+ { value: 'keyword', label: '关键词检索' },
|
|
|
+ { value: 'mixed', label: '混合检索' },
|
|
|
+ ]}
|
|
|
+ />
|
|
|
+ </FormItem>
|
|
|
+ </div>
|
|
|
+ <div style={{
|
|
|
+ display: 'flex',
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignItems: 'center'
|
|
|
+ }}>
|
|
|
+ <div className='section-title'>重排方式</div>
|
|
|
+ </div>
|
|
|
+ <div style={{
|
|
|
+ display: 'flex',
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignItems: 'center'
|
|
|
+ }}>
|
|
|
+ <FormItem
|
|
|
+ label='Rerank模型'
|
|
|
+ name='rerank_status'
|
|
|
+ valuePropName='checked'
|
|
|
+ className='form-control-width'
|
|
|
>
|
|
|
+ <Switch onChange={onChangeModel} />
|
|
|
+ </FormItem>
|
|
|
+ </div>
|
|
|
+ {isVisibleRerank &&
|
|
|
+ <div style={{
|
|
|
+ display: 'flex',
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignItems: 'center'
|
|
|
+ }}>
|
|
|
+ <FormItem
|
|
|
+ label='模型选择'
|
|
|
+ name='rerank_model_name'
|
|
|
+ >
|
|
|
+ <Select
|
|
|
+ className='questionAnswerInfo-content-title'
|
|
|
+ placeholder='请选择模型'
|
|
|
+ // defaultValue={'rerank'}
|
|
|
+ >
|
|
|
+ <Option value='rerank'>默认rerank模型</Option>
|
|
|
+ </Select>
|
|
|
+ </FormItem>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ <div style={{
|
|
|
+ display: 'flex',
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignItems: 'center'
|
|
|
+ }}>
|
|
|
+ <FormItem
|
|
|
+ label='召回切片数量'
|
|
|
+ name='slice_config_type'
|
|
|
+ rules={[{ required: true, message: '召回方式不能为空' }]}>
|
|
|
<Select
|
|
|
className='questionAnswerInfo-content-title'
|
|
|
- placeholder='请选择模型'
|
|
|
- // defaultValue={'rerank'}
|
|
|
- >
|
|
|
- <Option value='rerank'>默认rerank模型</Option>
|
|
|
+ placeholder='请选择'
|
|
|
+ onChange={onChangeCount}>
|
|
|
+ <Option value="fixed">手动设置</Option>
|
|
|
+ <Option value="customized">自动设置</Option>
|
|
|
</Select>
|
|
|
</FormItem>
|
|
|
</div>
|
|
|
- }
|
|
|
- <div style={{
|
|
|
- display: 'flex',
|
|
|
- justifyContent: 'center',
|
|
|
- alignItems: 'center'
|
|
|
- }}>
|
|
|
- <FormItem
|
|
|
- label='召回切片数量'
|
|
|
- name='slice_config_type'
|
|
|
- rules={[{ required: true, message: '召回方式不能为空' }]}>
|
|
|
- <Select
|
|
|
- className='questionAnswerInfo-content-title'
|
|
|
- placeholder='请选择'
|
|
|
- onChange={onChangeCount}>
|
|
|
- <Option value="fixed">手动设置</Option>
|
|
|
- <Option value="customized">自动设置</Option>
|
|
|
- </Select>
|
|
|
- </FormItem>
|
|
|
- </div>
|
|
|
|
|
|
- {isVisibleSlice &&
|
|
|
+ {isVisibleSlice &&
|
|
|
+ <div style={{
|
|
|
+ display: 'flex',
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignItems: 'center'
|
|
|
+ }}>
|
|
|
+ <FormItem
|
|
|
+ label='召回切片数'
|
|
|
+ name='slice_count'
|
|
|
+ rules={[{ required: true, message: '切片数不能为空' }]}>
|
|
|
+ <InputNumber max={1024} changeOnWheel
|
|
|
+ className='questionAnswerInfo-content-title' />
|
|
|
+ </FormItem>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
<div style={{
|
|
|
display: 'flex',
|
|
|
justifyContent: 'center',
|
|
|
alignItems: 'center'
|
|
|
}}>
|
|
|
<FormItem
|
|
|
- label='召回切片数'
|
|
|
- name='slice_count'
|
|
|
- rules={[{ required: true, message: '切片数不能为空' }]}>
|
|
|
- <InputNumber max={1024} changeOnWheel
|
|
|
- className='questionAnswerInfo-content-title' />
|
|
|
+ label='召回切片拼接方式'
|
|
|
+ name='recall_slice_splicing_method'
|
|
|
+ >
|
|
|
+ <TextArea
|
|
|
+ rows={4}
|
|
|
+ className='form-textarea-large'
|
|
|
+ placeholder="请输入内容"
|
|
|
+ />
|
|
|
</FormItem>
|
|
|
</div>
|
|
|
- }
|
|
|
- <div style={{
|
|
|
- display: 'flex',
|
|
|
- justifyContent: 'center',
|
|
|
- alignItems: 'center'
|
|
|
- }}>
|
|
|
- <FormItem
|
|
|
- label='召回切片拼接方式'
|
|
|
- name='recall_slice_splicing_method'
|
|
|
- >
|
|
|
- <TextArea
|
|
|
- rows={4}
|
|
|
- className='form-textarea-large'
|
|
|
- placeholder="请输入内容"
|
|
|
- />
|
|
|
- </FormItem>
|
|
|
</div>
|
|
|
+ {/* } */}
|
|
|
</div>
|
|
|
- {/* } */}
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </Splitter.Panel>
|
|
|
- { appId&&(<Splitter.Panel defaultSize="30%">
|
|
|
- <Chat appId={appId} />
|
|
|
- </Splitter.Panel>)}
|
|
|
- </Splitter>
|
|
|
- </div>
|
|
|
- </Form>
|
|
|
- </Spin>
|
|
|
- </div >
|
|
|
+ </Splitter.Panel>
|
|
|
+ {appId && (<Splitter.Panel defaultSize="30%">
|
|
|
+ <Chat appId={appId} />
|
|
|
+ </Splitter.Panel>)}
|
|
|
+ </Splitter>
|
|
|
+ </div>
|
|
|
+ </Form>
|
|
|
+ </Spin>
|
|
|
+ </div >
|
|
|
+ {isModalOpen && vipModal()}
|
|
|
+ </>
|
|
|
);
|
|
|
};
|
|
|
|