index.tsx 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. import * as React from 'react';
  2. import { useLocation } from 'react-router-dom';
  3. import { observer } from 'mobx-react';
  4. import './style.less';
  5. import {
  6. Button, Input, Form, Divider, Splitter, Select, InputNumber, InputNumberProps,
  7. Radio, Switch, Row, Col, Slider, Space, RadioChangeEvent,
  8. Spin, message
  9. } from 'antd';
  10. import { PlusCircleOutlined, MinusCircleOutlined } from '@ant-design/icons';
  11. import { apis } from '@/apis';
  12. import router from '@/router';
  13. const { TextArea } = Input;
  14. const FormItem = Form.Item;
  15. const { Option } = Select;
  16. const MAX_COUNT = 10;
  17. const Index = 1;
  18. const QuestionAnswerInfo: React.FC = () => {
  19. const [form] = Form.useForm();
  20. // top_p
  21. const [topPValue, setTopPValue] = React.useState(0.1);
  22. const TopPDecimalStep: React.FC = () => {
  23. const onChange: InputNumberProps['onChange'] = (value) => {
  24. if (Number.isNaN(value)) {
  25. return;
  26. }
  27. setTopPValue(value as number);
  28. };
  29. return (
  30. <Row>
  31. <Col span={12}>
  32. <Slider
  33. min={0}
  34. max={1}
  35. onChange={onChange}
  36. // value={typeof topPValue === 'number' ? topPValue : 0}
  37. value={topPValue}
  38. step={0.1}
  39. />
  40. </Col>
  41. <Col span={4}>
  42. <InputNumber
  43. min={0}
  44. max={1}
  45. style={{ margin: '0 16px', width: '100px' }}
  46. step={0.01}
  47. value={topPValue}
  48. onChange={onChange}
  49. />
  50. </Col>
  51. </Row>
  52. );
  53. };
  54. const [tempValue, setTempValue] = React.useState(0.01);
  55. // temperature
  56. const TempDecimalStep: React.FC = () => {
  57. const onChange: InputNumberProps['onChange'] = (value) => {
  58. if (Number.isNaN(value)) {
  59. return;
  60. }
  61. setTempValue(value as number);
  62. };
  63. return (
  64. <Row>
  65. <Col span={12}>
  66. <Slider
  67. min={0}
  68. max={1}
  69. onChange={onChange}
  70. // value={typeof tempValue === 'number' ? tempValue : 0}
  71. value={tempValue}
  72. step={0.01}
  73. />
  74. </Col>
  75. <Col span={4}>
  76. <InputNumber
  77. min={0}
  78. max={1}
  79. style={{ margin: '0 16px', width: '100px' }}
  80. step={0.01}
  81. value={tempValue}
  82. onChange={onChange}
  83. />
  84. </Col>
  85. </Row>
  86. );
  87. };
  88. type ModelList = {
  89. label: string,
  90. value: string,
  91. }[];
  92. type KnowledgeList = {
  93. label: string,
  94. value: string,
  95. }[];
  96. const [step, setStep] = React.useState(1);
  97. const [pageLoading, setPageLoading] = React.useState(false);
  98. const [modelList, setModelList] = React.useState<ModelList>([]);
  99. const [knowledgeList, setKnowledgeList] = React.useState<KnowledgeList>([]);
  100. const [isVisible, setIsVisible] = React.useState(false);
  101. const [isVisibleCus, setIsVisibleCus] = React.useState(false);
  102. const [isVisibleSlice, setIsVisibleSlice] = React.useState(false);
  103. const [isVisibleRerank, setIsVisibleRerank] = React.useState(false);
  104. const [name, setName] = React.useState('');
  105. const style: React.CSSProperties = {
  106. display: 'flex',
  107. flexDirection: 'column',
  108. gap: 8,
  109. width: 300,
  110. };
  111. const location = useLocation();
  112. const init = async (id: string) => {
  113. await Promise.all([
  114. api.fetchKnowlegde(),
  115. api.fetchModelList(),
  116. ])
  117. if (id) {
  118. await api.fetchDetail(id);
  119. }
  120. }
  121. React.useEffect(() => {
  122. const id = location?.state?.id;
  123. init(id)
  124. }, []);
  125. // 定义一个状态来存储输入框数组
  126. const [inputs, setInputs] = React.useState([{ id: 1, value: '' }]);
  127. // 添加新输入框的函数
  128. const addInput = () => {
  129. const newId = inputs.length + 1; // 生成新的唯一ID
  130. setInputs([...inputs, { id: newId, value: '' }]);
  131. };
  132. const delInput = () => {
  133. const newId = inputs.length - 1; // 生成新的唯一ID
  134. setInputs(inputs.slice(0, inputs.length - 1));
  135. };
  136. // 处理输入变更的函数
  137. const handleChange = (id: number, value: string) => {
  138. setInputs(inputs.map(input => (input.id === id ? { ...input, value } : input)));
  139. };
  140. // const onChange: InputNumberProps['onChange'] = (value) => {
  141. // console.log('changed', value);
  142. // };
  143. const onChangeShow = (checked: boolean) => {
  144. console.log(`switch to ${checked}`);
  145. };
  146. const onChangeModel = (checked: boolean) => {
  147. setIsVisibleRerank(!isVisibleRerank);
  148. };
  149. const onChangeCount = (value: string) => {
  150. if (value === 'fixed') {
  151. setIsVisibleSlice(!isVisibleSlice);
  152. } else {
  153. setIsVisibleSlice(false);
  154. }
  155. };
  156. // 召回方式
  157. const onChangeRecallMethod = (e: RadioChangeEvent) => {
  158. };
  159. // 获取应用详情
  160. const api = {
  161. fetchDetail: async (app_id: string) => {
  162. setPageLoading(true);
  163. try {
  164. const res = await apis.fetchApplicationDetail(app_id)
  165. console.log(res.data);
  166. const sd = res.data.questionlist.map((item: any, index: number) => {
  167. return {
  168. "id": index + 1,
  169. "value": item.question,
  170. }
  171. });
  172. const info = res.data.detail;
  173. console.log(info, 'info-info');
  174. setTopPValue(info.top_p as number);
  175. setTempValue(info.temperature as number);
  176. setName(info.name);
  177. interface Item2 {
  178. index_type_id: number,
  179. knowledge_id: string
  180. }
  181. interface Item {
  182. show_recall_result: boolean,
  183. recall_method: string,
  184. rerank_status: number,
  185. slice_config_type: string,
  186. slice_count: number,
  187. recall_slice_splicing_method: string,
  188. param_desc: string,
  189. rerank_model_name: string,
  190. rerank_index_type_list: [Item2],
  191. recall_index_type_list: [Item2]
  192. }
  193. const data_info: Item = JSON.parse(info.knowledgeInfo === '' ? '{}' : info.knowledgeInfo);
  194. if (data_info && typeof data_info === 'object' && data_info.param_desc === 'custom') {
  195. setIsVisibleCus(!isVisibleCus); //自定义回答风格
  196. }
  197. if (data_info && typeof data_info === 'object' && data_info.rerank_status === 1) {
  198. console.log('data_info.rerank_status', data_info.rerank_status);
  199. setIsVisibleRerank(!isVisibleRerank) //模型
  200. }
  201. //召回切片数量
  202. if (data_info && typeof data_info === 'object' && data_info.slice_config_type === 'fixed') {
  203. setIsVisibleSlice(!isVisibleSlice);
  204. } else {
  205. setIsVisibleSlice(false);
  206. }
  207. form.setFieldsValue({
  208. id: info.id,
  209. name: info.name, //应用名称
  210. desc: info.desc, //应用描述
  211. prompt: info.prompt, //应用提示语
  212. top_p: info.top_p as number, //topP
  213. temperature: info.temperature as number, //温度
  214. knowledge_ids: info.knowledge_ids,
  215. model: info.model,
  216. icon_color: info.icon_color,
  217. icon_type: info.icon_type,
  218. questionList: sd, //问题列表
  219. max_token: info.maxToken, //应用最大token
  220. updateDate: info.updateDate, // 更新时间
  221. param_desc: data_info && data_info.param_desc, //回答风格
  222. show_recall_result: data_info && data_info.show_recall_result, //是否展示召回结果
  223. recall_method: data_info && data_info.recall_method, //召回方式
  224. rerank_status: data_info && data_info.rerank_status, //开启rerank
  225. rerank_model_name: data_info && data_info.rerank_model_name, //模型名称
  226. slice_config_type: data_info && data_info.slice_config_type, // 召回切片数量
  227. slice_count: data_info && data_info.slice_count, // 切片数量
  228. recall_slice_splicing_method: data_info && data_info.recall_slice_splicing_method, // 切片内容
  229. // rerank_status = 1 rerank_index_type_list
  230. // recall_method = 'embedding' || 'mixed' recall_index_type_list
  231. //recall_index_type_list: info.recall_index_type_list, //知识库id
  232. //rerank_index_type_list: info.rerank_index_type_list, //知识库id
  233. })
  234. if (sd.length > 0) {
  235. setInputs(sd);
  236. }
  237. } catch (error) {
  238. console.error(error);
  239. } finally {
  240. setPageLoading(false);
  241. }
  242. },
  243. //获取知识库列表
  244. fetchKnowlegde: async () => {
  245. try {
  246. const res = await apis.fetchKnowledgeList();
  247. const list = res.data.map((item: any) => {
  248. return {
  249. label: item.name,
  250. value: item.knowledgeId,
  251. }
  252. });
  253. setKnowledgeList(list);
  254. } catch (error: any) {
  255. console.error(error);
  256. }
  257. },
  258. // 获取模型列表
  259. fetchModelList: async () => {
  260. try {
  261. const res = await apis.fetchModelList();
  262. const list = res.data.data.map((item: any) => {
  263. return {
  264. label: item.modelName,
  265. value: item.modelCode,
  266. }
  267. });
  268. setModelList(list);
  269. } catch (error: any) {
  270. console.error(error);
  271. }
  272. },
  273. }
  274. const handleRedioClick = (value: string) => {
  275. setIsVisibleCus(false);
  276. // if (value === 'strict') {
  277. // setTopPValue(0.5);
  278. // setTempValue(0.10);
  279. // } else if (value === 'moderate') {
  280. // setTopPValue(0.7);
  281. // setTempValue(0.50);
  282. // } else if (value === 'flexib') {
  283. // setTopPValue(0.9);
  284. // setTempValue(0.90);
  285. // }
  286. }
  287. return (
  288. <div className='questionAnswerInfo'>
  289. <Spin spinning={pageLoading}>
  290. <Form
  291. style={{ paddingTop: '20px' }}
  292. form={form}
  293. layout='vertical'
  294. initialValues={{
  295. max_token: 1024
  296. }}
  297. >
  298. <div style={{ display: step === 1 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
  299. <FormItem
  300. label='问答应用名称'
  301. name='name'
  302. rules={[{ required: true, message: '问答应用名称不能为空' }]}
  303. >
  304. <Input placeholder="应用名称" style={{ width: 646, padding: 8 }} />
  305. </FormItem>
  306. <FormItem
  307. label='问答应用描述'
  308. name='desc'
  309. rules={[{ required: true, message: '问答应用描述不能为空' }]}
  310. >
  311. <TextArea
  312. showCount
  313. maxLength={500}
  314. placeholder="请输入描述"
  315. style={{ height: 120, resize: 'none', width: 646 }}
  316. />
  317. </FormItem>
  318. <div>
  319. <h4>添加预设问题</h4>
  320. <div>
  321. {
  322. inputs.map(input => (
  323. <div key={input.id} style={{ paddingTop: '10px' }}>
  324. <label>问题 {input.id}</label>
  325. <Input
  326. style={{ width: 300, paddingTop: 8, marginLeft: 20 }}
  327. type="text"
  328. value={input.value}
  329. onChange={e => handleChange(input.id, e.target.value)}
  330. />
  331. <PlusCircleOutlined style={{ marginLeft: 20 }} onClick={addInput} />
  332. <MinusCircleOutlined style={{ marginLeft: 20 }} onClick={delInput} />
  333. </div>
  334. ))}
  335. </div>
  336. </div>
  337. <br />
  338. <Button type='primary' onClick={() => {
  339. form.validateFields(['name', 'desc']).then(async (values) => {
  340. setStep(2);
  341. setInputs(inputs);
  342. console.log(inputs, 'inputs');
  343. }).catch((error) => {
  344. console.error(error);
  345. });
  346. }} >
  347. 下一步
  348. </Button>
  349. </div>
  350. <div style={{ display: step === 2 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
  351. <div style={{ paddingTop: '20px', display: 'flex', justifyContent: 'flex-end' }}>
  352. <div>
  353. <Button
  354. style={{ background: '#f5f5f5' }}
  355. onClick={() => {
  356. setStep(1);
  357. }}
  358. >
  359. 上一步
  360. </Button>
  361. <Button
  362. type='primary'
  363. onClick={() => {
  364. form.validateFields().then(async (values) => {
  365. const data = values;
  366. // 问题列表
  367. const question: string[] = [];
  368. if (inputs) {
  369. inputs.map((item, index) => {
  370. question.push(item.value);
  371. });
  372. }
  373. interface Item {
  374. index_type_id: number,
  375. knowledge_id: string
  376. }
  377. const indexTypeList: Item[] = [];
  378. if (values.knowledge_ids && values.knowledge_ids.length > 0) {
  379. values.knowledge_ids.map((item: string, index: any) => {
  380. console.log(item, 'item');
  381. const index_type: Item = {
  382. index_type_id: index,
  383. knowledge_id: item,
  384. };
  385. indexTypeList.push(index_type);
  386. });
  387. }
  388. console.log(values.rerank_status , 'values.rerank_status ');
  389. const rerankIndexTypeList: Item[] = [];
  390. if (values.rerank_status === 1 || values.rerank_status === true) {
  391. values.knowledge_ids.map((item: string, index: any) => {
  392. console.log(item, 'rerankIndexTypeList');
  393. const index_type: Item = {
  394. index_type_id: index,
  395. knowledge_id: item,
  396. };
  397. rerankIndexTypeList.push(index_type);
  398. });
  399. }
  400. console.log(values.rerank_status , 'values.rerank_status ');
  401. const data_info = {
  402. param_desc: values.param_desc === undefined ? '' : values.param_desc, //回答风格
  403. show_recall_result: values.show_recall_result === undefined ? '' : values.show_recall_result, //是否展示召回结果
  404. recall_method: values.recall_method === undefined ? '' : values.recall_method, //召回方式
  405. rerank_status: values.rerank_status === 1 || values.rerank_status === true ? 1 : 0, //开启rerank
  406. rerank_model_name: values.rerank_status === 1 || values.rerank_status === true ? 'rerank' : '', //模型名称
  407. slice_config_type: values.slice_config_type === undefined ? '' : values.slice_config_type, // 召回切片数量
  408. slice_count: values.slice_count === undefined ? '' : values.slice_count, // 切片数量
  409. recall_slice_splicing_method: values.recall_slice_splicing_method === undefined ? '' : values.recall_slice_splicing_method, // 切片内容
  410. rerank_index_type_list: rerankIndexTypeList, //知识库id
  411. recall_index_type_list: values.recall_method === undefined ? [] : values.recall_method === 'embedding' || 'mixed' ? indexTypeList : [],
  412. embedding_recall_ratio: 0 //向量化检索比例
  413. // rerank_status = 1 rerank_index_type_list
  414. // recall_method = 'embedding' || 'embedding' recall_index_type_list
  415. };
  416. // const knowledgeIds: string[] = [];
  417. // knowledgeIds.push(values.knowledge_ids);
  418. const info = {
  419. id: values.id,
  420. name: values.name, //应用名称
  421. desc: values.desc, //应用描述
  422. prompt: values.prompt, //应用提示语
  423. top_p: topPValue.toString(), //topP
  424. temperature: tempValue.toString(), //温度
  425. knowledge_ids: values.knowledge_ids,
  426. slice_count: values.slice_count,
  427. model: values.model,
  428. icon_color: values.icon_color,
  429. icon_type: values.icon_type,
  430. questionList: question,
  431. knowledge_info: data_info,
  432. max_token: values.max_token, //应用最大token
  433. };
  434. const id = location?.state?.id;
  435. let res = null;
  436. if (id) {
  437. // 编辑应用
  438. res = await apis.modifyApplicationApi(id, info);
  439. } else {
  440. // 创建应用
  441. res = await await apis.createApplicationApi(info);
  442. }
  443. if (res.data.code !== 200) {
  444. message.error(res.data.message);
  445. } else {
  446. message.success('修改成功');
  447. router.navigate({ pathname: '/questionAnswer' });
  448. }
  449. }).catch((error) => {
  450. console.error(error);
  451. error.errorFields && error.errorFields.map((item: any) => {
  452. console.log(item, 'item');
  453. message.error(`字段 ${item.name} ${item.errors[0]}`);
  454. });
  455. });
  456. }}
  457. >发布应用</Button>
  458. </div>
  459. </div>
  460. <Splitter style={{ height: '100%', boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}>
  461. <Splitter.Panel defaultSize="40%">
  462. <div style={{ width: '100%', height: '100%' }}>
  463. <h2>Prompt编写</h2>
  464. <div style={{ paddingTop: '20px' }}>
  465. <TextArea
  466. autoSize
  467. readOnly
  468. placeholder="编写Prompt过程中可以引入2项变量:{{知识}} 代表知识库中检索到的知识内容, {{用户}}代表用户输入的内容。您可以在编写Prompt过程中将变量拼接在合适的位置。插入:{{知识}} 插入:{{用户}}"
  469. style={{ width: '100%', height: '300px' }}
  470. />
  471. </div>
  472. <Divider plain></Divider>
  473. <div >
  474. <FormItem name='prompt' >
  475. <TextArea
  476. placeholder="提示词"
  477. rows={20}
  478. />
  479. </FormItem>
  480. </div>
  481. </div>
  482. </Splitter.Panel>
  483. <Splitter.Panel defaultSize="60%">
  484. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', background: '#f5f5f5', width: '100%', height: '100%' }}>
  485. <div style={{ width: '50%', height: '100%' }}>
  486. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', paddingTop: '50px', fontSize: '16px' }}>
  487. 欢迎使用 {name}
  488. </div>
  489. <div style={{
  490. display: 'flex', justifyContent: 'center', alignItems: 'center',
  491. paddingTop: '20px'
  492. }}>
  493. <FormItem
  494. label='引用知识库'
  495. name='knowledge_ids'
  496. rules={[{ required: true, message: '知识库不能为空' }]}>
  497. <Select
  498. mode='multiple'
  499. maxCount={MAX_COUNT}
  500. // suffixIcon={suffix}
  501. style={{ width: '300px', height: '48px' }}
  502. placeholder='请选择知识库'
  503. >
  504. {
  505. knowledgeList.map((item, index) => {
  506. return <Option value={item.value} key={index}>
  507. {item.label}
  508. </Option>
  509. })
  510. }
  511. </Select>
  512. </FormItem>
  513. </div>
  514. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  515. <FormItem
  516. label='调用模型'
  517. name="model"
  518. rules={[{ required: true, message: '模型不能为空' }]}>
  519. <Select
  520. placeholder='请选择模型'
  521. allowClear={true}
  522. style={{ width: '300px', height: '48px' }}
  523. >
  524. {
  525. modelList.map((item, index) => {
  526. return <Option value={item.value} key={index}>
  527. {item.label}
  528. </Option>
  529. })
  530. }
  531. </Select>
  532. </FormItem>
  533. </div>
  534. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  535. <FormItem
  536. label='max token'
  537. name='max_token'
  538. rules={[{ required: true, message: 'max token不能为空' }]}>
  539. <InputNumber
  540. className='questionAnswerInfo-content-title'
  541. />
  542. </FormItem>
  543. </div>
  544. {
  545. !isVisible &&
  546. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  547. <a onClick={() => {
  548. setIsVisible(!isVisible);
  549. }} className='questionAnswerInfo-content-title'>
  550. 更多设置
  551. </a>
  552. </div>
  553. }
  554. {/* {isVisible && */}
  555. <div style={{ display: isVisible ? 'block' : 'none', paddingTop: '20px' }}>
  556. {isVisibleCus &&
  557. <Space style={{ width: '100%' }} direction="vertical">
  558. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  559. <FormItem
  560. label='Top-p'
  561. name='topP'
  562. style={{ width: '300px' }}
  563. >
  564. <TopPDecimalStep />
  565. </FormItem>
  566. </div>
  567. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  568. <FormItem
  569. label='Temperature'
  570. name='temperature'
  571. style={{ width: '300px' }}
  572. >
  573. <TempDecimalStep />
  574. </FormItem>
  575. </div>
  576. </Space >
  577. }
  578. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  579. <FormItem
  580. label='回答风格'
  581. name='param_desc'
  582. rules={[{ required: true, message: '回答风格不能为空' }]}>
  583. <Radio.Group buttonStyle="solid"
  584. className='questionAnswerInfo-content-title'>
  585. <Radio.Button onClick={() => {
  586. handleRedioClick('strict')
  587. }} value='strict'>严谨</Radio.Button>
  588. <Radio.Button onClick={() => {
  589. handleRedioClick('moderate')
  590. }} value='moderate'>适中</Radio.Button>
  591. <Radio.Button onClick={() => {
  592. handleRedioClick('flexib')
  593. }} value='flexib'>发散</Radio.Button>
  594. <Radio.Button value='custom'
  595. onClick={() => {
  596. setIsVisibleCus(!isVisibleCus);
  597. setTopPValue(0.1);
  598. setTempValue(0.01);
  599. }}
  600. >自定义
  601. </Radio.Button>
  602. </Radio.Group>
  603. </FormItem>
  604. </div>
  605. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  606. <FormItem
  607. label='展示引用知识'
  608. name='show_recall_result'
  609. className='questionAnswerInfo-content-title'>
  610. <Switch onChange={onChangeShow} />
  611. </FormItem>
  612. </div>
  613. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  614. <FormItem
  615. label='召回方式'
  616. name='recall_method'
  617. rules={[{ required: true, message: '召回方式不能为空' }]}>
  618. <Radio.Group
  619. style={style}
  620. onChange={onChangeRecallMethod}
  621. options={[
  622. { value: 'embedding', label: '向量化检索' },
  623. { value: 'keyword', label: '关键词检索' },
  624. { value: 'mixed', label: '混合检索' },
  625. ]}
  626. />
  627. </FormItem>
  628. </div>
  629. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  630. <p className='questionAnswerInfo-content-title'>重排方式</p>
  631. </div>
  632. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  633. <FormItem
  634. label='Rerank模型'
  635. name='rerank_status'
  636. valuePropName='checked'
  637. className='questionAnswerInfo-content-title'
  638. >
  639. <Switch onChange={onChangeModel} />
  640. </FormItem>
  641. </div>
  642. {isVisibleRerank &&
  643. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  644. <FormItem
  645. label='模型选择'
  646. name='rerank_model_name'
  647. >
  648. <Select
  649. style={{ width: '300px', height: '48px' }}
  650. placeholder='请选择模型'
  651. defaultValue={'默认rerank模型'}
  652. >
  653. <Option value='rerank'>默认rerank模型</Option>
  654. </Select>
  655. </FormItem>
  656. </div>
  657. }
  658. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  659. <FormItem
  660. label='召回切片数量'
  661. name='slice_config_type'
  662. rules={[{ required: true, message: '召回方式不能为空' }]}>
  663. <Select
  664. style={{ width: '300px', height: '48px' }}
  665. placeholder='请选择'
  666. onChange={onChangeCount}>
  667. <Option value="fixed">手动设置</Option>
  668. <Option value="customized">自动设置</Option>
  669. </Select>
  670. </FormItem>
  671. </div>
  672. {isVisibleSlice &&
  673. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  674. <FormItem
  675. label='召回切片数'
  676. name='slice_count'
  677. rules={[{ required: true, message: '切片数不能为空' }]}>
  678. <InputNumber max={1024} changeOnWheel className='questionAnswerInfo-content-title' />
  679. </FormItem>
  680. </div>
  681. }
  682. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  683. <FormItem
  684. label='召回切片拼接方式'
  685. name='recall_slice_splicing_method'
  686. >
  687. <TextArea
  688. rows={4}
  689. className='questionAnswerInfo-content-title'
  690. placeholder="请输入内容"
  691. />
  692. </FormItem>
  693. </div>
  694. </div>
  695. {/* } */}
  696. </div>
  697. </div>
  698. </Splitter.Panel>
  699. </Splitter>
  700. </div>
  701. </Form>
  702. </Spin>
  703. </div>
  704. );
  705. };
  706. export default observer(QuestionAnswerInfo);