index.tsx 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  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.fetchTakaiApplicationDetail(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. setTopPValue(info.topP as number);
  174. setTempValue(info.temperature as number);
  175. setName(info.name);
  176. interface Item2 {
  177. index_type_id: number,
  178. knowledge_id: string
  179. }
  180. interface Item {
  181. show_recall_result: boolean,
  182. recall_method: string,
  183. rerank_status: boolean,
  184. slice_config_type: string,
  185. slice_count: number,
  186. recall_slice_splicing_method: string,
  187. param_desc: string,
  188. rerank_model_name: string,
  189. rerank_index_type_list: [Item2],
  190. recall_index_type_list: [Item2]
  191. }
  192. const data_info: Item = JSON.parse(info.knowledgeInfo);
  193. if (data_info.param_desc === 'custom') {
  194. setIsVisibleCus(!isVisibleCus); //自定义回答风格
  195. }
  196. if (data_info.rerank_status === true) {
  197. setIsVisibleRerank(!isVisibleRerank) //模型
  198. }
  199. //召回切片数量
  200. if (data_info.slice_config_type === 'fixed') {
  201. setIsVisibleSlice(!isVisibleSlice);
  202. } else {
  203. setIsVisibleSlice(false);
  204. }
  205. form.setFieldsValue({
  206. id: info.id,
  207. name: info.name, //应用名称
  208. desc: info.desc, //应用描述
  209. prompt: info.prompt, //应用提示语
  210. top_p: info.topP as number, //topP
  211. temperature: info.temperature as number, //温度
  212. knowledge_ids: info.knowledgeIds,
  213. model: info.model,
  214. icon_color: info.icon_color,
  215. icon_type: info.icon_type,
  216. questionList: sd, //问题列表
  217. max_token: info.maxToken, //应用最大token
  218. updateDate: info.updateDate, // 更新时间
  219. param_desc: data_info.param_desc, //回答风格
  220. show_recall_result: data_info.show_recall_result, //是否展示召回结果
  221. recall_method: data_info.recall_method, //召回方式
  222. rerank_status: data_info.rerank_status, //开启rerank
  223. rerank_model_name: data_info.rerank_model_name, //模型名称
  224. slice_config_type: data_info.slice_config_type, // 召回切片数量
  225. slice_count: data_info.slice_count, // 切片数量
  226. recall_slice_splicing_method: data_info.recall_slice_splicing_method, // 切片内容
  227. // rerank_status = 1 rerank_index_type_list
  228. // recall_method = 'embedding' || 'mixed' recall_index_type_list
  229. //recall_index_type_list: info.recall_index_type_list, //知识库id
  230. //rerank_index_type_list: info.rerank_index_type_list, //知识库id
  231. })
  232. if (sd.length > 0) {
  233. setInputs(sd);
  234. }
  235. } catch (error) {
  236. console.error(error);
  237. } finally {
  238. setPageLoading(false);
  239. }
  240. },
  241. //获取知识库列表
  242. fetchKnowlegde: async () => {
  243. try {
  244. const res = await apis.fetchTakaiKnowledgeList();
  245. const list = res.data.map((item: any) => {
  246. return {
  247. label: item.name,
  248. value: item.knowledgeId,
  249. }
  250. });
  251. setKnowledgeList(list);
  252. } catch (error: any) {
  253. console.error(error);
  254. }
  255. },
  256. // 获取模型列表
  257. fetchModelList: async () => {
  258. try {
  259. const res = await apis.fetchModelList();
  260. const list = res.data.data.map((item: any) => {
  261. return {
  262. label: item.modelName,
  263. value: item.modelCode,
  264. }
  265. });
  266. setModelList(list);
  267. } catch (error: any) {
  268. console.error(error);
  269. }
  270. },
  271. }
  272. const handleRedioClick = (value: string) => {
  273. setIsVisibleCus(false);
  274. if (value === 'strict') {
  275. setTopPValue(0.5);
  276. setTempValue(0.01);
  277. } else if (value === 'moderate') {
  278. setTopPValue(0.7);
  279. setTempValue(0.50);
  280. } else if (value === 'flexib') {
  281. setTopPValue(0.9);
  282. setTempValue(0.90);
  283. }
  284. }
  285. return (
  286. <div className='questionAnswerInfo'>
  287. <Spin spinning={pageLoading}>
  288. <Form
  289. form={form}
  290. layout='vertical'
  291. initialValues={{
  292. max_token: 1024
  293. }}
  294. >
  295. <div style={{ display: step === 1 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
  296. <FormItem
  297. label='问答应用名称'
  298. name='name'
  299. rules={[{ required: true, message: '问答应用名称不能为空' }]}
  300. >
  301. <Input placeholder="应用名称" style={{ width: 646, padding: 8 }} />
  302. </FormItem>
  303. <FormItem
  304. label='问答应用描述'
  305. name='desc'
  306. rules={[{ required: true, message: '问答应用描述不能为空' }]}
  307. >
  308. <TextArea
  309. showCount
  310. maxLength={500}
  311. placeholder="请输入描述"
  312. style={{ height: 120, resize: 'none', width: 646 }}
  313. />
  314. </FormItem>
  315. <div>
  316. <h4>添加预设问题</h4>
  317. <div>
  318. {
  319. inputs.map(input => (
  320. <div key={input.id} style={{ paddingTop: '10px' }}>
  321. <label>问题 {input.id}</label>
  322. <Input
  323. style={{ width: 300, paddingTop: 8, marginLeft: 20 }}
  324. type="text"
  325. value={input.value}
  326. onChange={e => handleChange(input.id, e.target.value)}
  327. />
  328. <PlusCircleOutlined style={{ marginLeft: 20 }} onClick={addInput} />
  329. <MinusCircleOutlined style={{ marginLeft: 20 }} onClick={delInput} />
  330. </div>
  331. ))}
  332. </div>
  333. </div>
  334. <br />
  335. <Button type='primary' onClick={() => {
  336. form.validateFields(['name', 'desc']).then(async (values) => {
  337. setStep(2);
  338. setInputs(inputs);
  339. }).catch((error) => {
  340. console.error(error);
  341. });
  342. }} >
  343. 下一步
  344. </Button>
  345. </div>
  346. <div style={{ display: step === 2 ? 'block' : 'none' }} className='questionAnswerInfo-content'>
  347. <div style={{ paddingBottom: '10px', display: 'flex', justifyContent: 'flex-end' }}>
  348. <div>
  349. <Button
  350. style={{ background: '#f5f5f5' }}
  351. onClick={() => {
  352. setStep(1);
  353. }}
  354. >
  355. 上一步
  356. </Button>
  357. <Button
  358. type='primary'
  359. onClick={() => {
  360. form.validateFields().then(async (values) => {
  361. const data = values;
  362. console.log(values, 'values');
  363. // 问题列表
  364. const question: string[] = [];
  365. if (inputs) {
  366. inputs.map((item, index) => {
  367. question.push(item.value);
  368. });
  369. }
  370. console.log(question, 'question');
  371. interface Item {
  372. index_type_id: number,
  373. knowledge_id: string
  374. }
  375. const indexTypeList: Item[] = [];
  376. if (values.knowledge_ids && values.knowledge_ids.length > 0) {
  377. const index_type: Item = {
  378. index_type_id: 0,
  379. knowledge_id: values.knowledge_ids
  380. };
  381. indexTypeList.push(index_type);
  382. }
  383. const data_info = {
  384. param_desc: values.param_desc, //回答风格
  385. show_recall_result: values.show_recall_result, //是否展示召回结果
  386. recall_method: values.recall_method, //召回方式
  387. rerank_status: values.rerank_status, //开启rerank
  388. rerank_model_name: values.rerank_model_name, //模型名称
  389. slice_config_type: values.slice_config_type, // 召回切片数量
  390. slice_count: values.slice_count, // 切片数量
  391. recall_slice_splicing_method: values.recall_slice_splicing_method, // 切片内容
  392. rerank_index_type_list: values.rerank_status === true ? indexTypeList : [], //知识库id
  393. recall_index_type_list: values.recall_method === 'embedding' || 'mixed' ? indexTypeList : []
  394. // rerank_status = 1 rerank_index_type_list
  395. // recall_method = 'embedding' || 'embedding' recall_index_type_list
  396. };
  397. // const knowledgeIds: string[] = [];
  398. // knowledgeIds.push(values.knowledge_ids);
  399. const info = {
  400. id: values.id,
  401. name: values.name, //应用名称
  402. desc: values.desc, //应用描述
  403. prompt: values.prompt, //应用提示语
  404. top_p: topPValue.toString(), //topP
  405. temperature: tempValue.toString(), //温度
  406. knowledge_ids: values.knowledge_ids,
  407. slice_count: values.slice_count,
  408. model: values.model,
  409. icon_color: values.icon_color,
  410. icon_type: values.icon_type,
  411. questionList: question,
  412. knowledge_info: JSON.stringify(data_info),
  413. max_token: values.max_token, //应用最大token
  414. };
  415. const id = location?.state?.id;
  416. let res = null;
  417. if (id) {
  418. // 编辑应用
  419. console.log(info, 'info data');
  420. res = await apis.modifyTakaiApplicationApi(id, info);
  421. } else {
  422. // 创建应用
  423. res = await await apis.createTakaiApplicationApi(info);
  424. }
  425. if (res.code !== 200) {
  426. message.error(res.data.message);
  427. } else {
  428. message.success('操作成功')
  429. router.navigate({ pathname: '/deepseek/questionAnswer' });
  430. }
  431. }).catch((error) => {
  432. console.error(error);
  433. error.errorFields && error.errorFields.map((item: any) => {
  434. console.log(item, 'item');
  435. message.error(`字段 ${item.name} ${item.errors[0]}`);
  436. });
  437. });
  438. }}
  439. >发布应用</Button>
  440. </div>
  441. </div>
  442. <Splitter style={{ height: '100%', boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}>
  443. <Splitter.Panel defaultSize="40%">
  444. <div style={{ width: '100%', height: '100%' }}>
  445. <h2>Prompt编写</h2>
  446. <div style={{ paddingTop: '20px' }}>
  447. <TextArea
  448. autoSize
  449. readOnly
  450. placeholder="编写Prompt过程中可以引入2项变量:{{知识}} 代表知识库中检索到的知识内容, {{用户}}代表用户输入的内容。您可以在编写Prompt过程中将变量拼接在合适的位置。插入:{{知识}} 插入:{{用户}}"
  451. style={{ width: '100%', height: '300px' }}
  452. />
  453. </div>
  454. <Divider plain></Divider>
  455. <div >
  456. <FormItem name='prompt'
  457. initialValue={`你是一位知识检索助手,你必须并且只能从我发送的众多知识片段中寻找能够解决用户输入问题的最优答案,并且在执行任务的过程中严格执行规定的要求。
  458. 知识片段如下:
  459. {{知识}}
  460. 规定要求:
  461. - 找到答案就仅使用知识片段中的原文回答用户的提问;
  462. - 找不到答案就用自身知识并且告诉用户该信息不是来自文档;
  463. - 所引用的文本片段中所包含的示意图占位符必须进行返回,占位符格式参考:【示意图序号_编号】
  464. - 严禁输出任何知识片段中不存在的示意图占位符;
  465. - 输出的内容必须删除其中包含的任何图注、序号等信息。例如:“进入登录页面(图1.1)”需要从文字中删除图序,回复效果为:“进入登录页面”;“如图所示1.1”,回复效果为:“如图所示”;
  466. - 格式规范
  467. - 文档中会出现包含表格的情况,表格是以图片标识符的形式呈现,表格中缺失数据时候返回空单元格;
  468. - 如果需要用到表格中的数据,以markdown格式输出表格中的数据;
  469. - 避免使用代码块语法回复信息;
  470. - 回复的开头语不要输出诸如:“我想”,“我认为”,“think”等相关语义的文本。
  471. 严格执行规定要求,不要复述问题,直接开始回答。
  472. 用户输入问题:
  473. {{用户}}`}
  474. rules={[{ required: true, message: '提示词不能为空' }]}>
  475. <TextArea
  476. placeholder="提示词"
  477. rows={50}
  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. <Option value='DeepSeek-R1-Distill-Llama-70B'>DeepSeek-R1-Distill-Llama-70B</Option>
  525. <Option value='Qwen2-72B'>Qwen2-72B</Option>
  526. {/* {
  527. modelList.map((item, index) => {
  528. return <Option value={item.value} key={index}>
  529. {item.label}
  530. </Option>
  531. })
  532. } */}
  533. </Select>
  534. </FormItem>
  535. </div>
  536. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  537. <FormItem
  538. label='max token'
  539. name='max_token'
  540. rules={[{ required: true, message: 'max token不能为空' }]}>
  541. <InputNumber
  542. className='questionAnswerInfo-content-title'
  543. />
  544. </FormItem>
  545. </div>
  546. {
  547. !isVisible &&
  548. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  549. <a onClick={() => {
  550. setIsVisible(!isVisible);
  551. }} className='questionAnswerInfo-content-title'>
  552. 更多设置
  553. </a>
  554. </div>
  555. }
  556. {/* {isVisible && */}
  557. <div style={{ display: isVisible ? 'block' : 'none', paddingTop: '20px' }}>
  558. {isVisibleCus &&
  559. <Space style={{ width: '100%' }} direction="vertical">
  560. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  561. <FormItem
  562. label='Top-p'
  563. name='topP'
  564. style={{ width: '300px' }}
  565. >
  566. <TopPDecimalStep />
  567. </FormItem>
  568. </div>
  569. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  570. <FormItem
  571. label='Temperature'
  572. name='temperature'
  573. style={{ width: '300px' }}
  574. >
  575. <TempDecimalStep />
  576. </FormItem>
  577. </div>
  578. </Space >
  579. }
  580. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  581. <FormItem
  582. label='回答风格'
  583. name='param_desc'
  584. rules={[{ required: true, message: '回答风格不能为空' }]}>
  585. <Radio.Group buttonStyle="solid"
  586. className='questionAnswerInfo-content-title'>
  587. <Radio.Button onClick={() => {
  588. handleRedioClick('strict')
  589. }} value='strict'>严谨</Radio.Button>
  590. <Radio.Button onClick={() => {
  591. handleRedioClick('moderate')
  592. }} value='moderate'>适中</Radio.Button>
  593. <Radio.Button onClick={() => {
  594. handleRedioClick('flexib')
  595. }} value='flexib'>发散</Radio.Button>
  596. <Radio.Button value='custom'
  597. onClick={() => {
  598. setIsVisibleCus(!isVisibleCus);
  599. setTopPValue(0.1);
  600. setTempValue(0.01);
  601. }}
  602. >自定义
  603. </Radio.Button>
  604. </Radio.Group>
  605. </FormItem>
  606. </div>
  607. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  608. <FormItem
  609. label='展示引用知识'
  610. name='show_recall_result'
  611. className='questionAnswerInfo-content-title'>
  612. <Switch onChange={onChangeShow} />
  613. </FormItem>
  614. </div>
  615. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  616. <FormItem
  617. label='召回方式'
  618. name='recall_method'
  619. rules={[{ required: true, message: '召回方式不能为空' }]}>
  620. <Radio.Group
  621. style={style}
  622. onChange={onChangeRecallMethod}
  623. options={[
  624. { value: 'embedding', label: '向量化检索' },
  625. { value: 'keyword', label: '关键词检索' },
  626. { value: 'mixed', label: '混合检索' },
  627. ]}
  628. />
  629. </FormItem>
  630. </div>
  631. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  632. <div className='questionAnswerInfo-content-title'>重排方式</div>
  633. </div>
  634. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  635. <FormItem
  636. label='Rerank模型'
  637. name='rerank_status'
  638. valuePropName='checked'
  639. className='questionAnswerInfo-content-title'
  640. >
  641. <Switch onChange={onChangeModel} />
  642. </FormItem>
  643. </div>
  644. {isVisibleRerank &&
  645. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  646. <FormItem
  647. label='模型选择'
  648. name='rerank_model_name'
  649. >
  650. <Select
  651. style={{ width: '300px', height: '48px' }}
  652. placeholder='请选择模型'
  653. // defaultValue={'rerank'}
  654. >
  655. <Option value='rerank'>默认rerank模型</Option>
  656. </Select>
  657. </FormItem>
  658. </div>
  659. }
  660. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  661. <FormItem
  662. label='召回切片数量'
  663. name='slice_config_type'
  664. rules={[{ required: true, message: '召回方式不能为空' }]}>
  665. <Select
  666. style={{ width: '300px', height: '48px' }}
  667. placeholder='请选择'
  668. onChange={onChangeCount}>
  669. <Option value="fixed">手动设置</Option>
  670. <Option value="customized">自动设置</Option>
  671. </Select>
  672. </FormItem>
  673. </div>
  674. {isVisibleSlice &&
  675. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  676. <FormItem
  677. label='召回切片数'
  678. name='slice_count'
  679. rules={[{ required: true, message: '切片数不能为空' }]}>
  680. <InputNumber max={1024} changeOnWheel className='questionAnswerInfo-content-title' />
  681. </FormItem>
  682. </div>
  683. }
  684. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  685. <FormItem
  686. label='召回切片拼接方式'
  687. name='recall_slice_splicing_method'
  688. >
  689. <TextArea
  690. rows={4}
  691. className='questionAnswerInfo-content-title'
  692. placeholder="请输入内容"
  693. />
  694. </FormItem>
  695. </div>
  696. </div>
  697. {/* } */}
  698. </div>
  699. </div>
  700. </Splitter.Panel>
  701. </Splitter>
  702. </div>
  703. </Form>
  704. </Spin>
  705. </div >
  706. );
  707. };
  708. export default observer(QuestionAnswerInfo);