tool.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. <template>
  2. <a-button type="text" @click="handleClick" size="small">
  3. <template #icon>
  4. <icon-tool />
  5. </template>
  6. </a-button>
  7. <a-modal
  8. v-model:visible="visible"
  9. title=" "
  10. @before-open="handleOpened"
  11. @cancel="handleCancel"
  12. :footer="false"
  13. title-align="start"
  14. width="900px"
  15. >
  16. <a-tabs default-active-key="1">
  17. <a-tab-pane key="1">
  18. <template #title> <icon-calendar /> 解析方法 </template>
  19. <div style="width: 100%">
  20. <div style="display: flex; align-items: center">
  21. <div> 解析方法: </div>
  22. <div style="margin-left: 10px">
  23. <a-select v-model="form.parser_id" placeholder="请选择">
  24. <a-option
  25. v-for="item in parser_ids"
  26. :key="item.value"
  27. :label="item.name"
  28. :value="item.value"
  29. ></a-option>
  30. </a-select>
  31. </div>
  32. </div>
  33. <div class="parser">
  34. <a-form
  35. ref="formRef"
  36. :rules="rules"
  37. :model="form"
  38. auto-label-width
  39. @submit="handleSubmit"
  40. >
  41. <a-divider style="margin-top: 10px" />
  42. <a-form-item field="slider" label="块Token数">
  43. <a-slider
  44. v-model="form.chunk_token_num"
  45. :min="0"
  46. :max="2048"
  47. show-input
  48. />
  49. </a-form-item>
  50. <a-divider style="margin-top: 10px" />
  51. <a-form-item field="raptor" label="使用召回增强RAPTOR策略">
  52. <a-space direction="vertical" size="large">
  53. <a-switch
  54. v-model="form.use_raptor"
  55. @change="onChangeRAPTOR"
  56. />
  57. </a-space>
  58. </a-form-item>
  59. <div v-if="form.use_raptor">
  60. <a-form-item field="prompt" label="提示词">
  61. <a-textarea
  62. v-model="form.prompt"
  63. style="
  64. height: 10rem;
  65. border: 1px solid var(--color-fill-3);
  66. border-radius: 4px;
  67. "
  68. placeholder="请填写提示词"
  69. />
  70. </a-form-item>
  71. <a-form-item field="slider" label="最大token数">
  72. <a-slider
  73. v-model="form.max_token"
  74. :min="0"
  75. :max="2048"
  76. show-input
  77. />
  78. </a-form-item>
  79. <a-form-item field="slider" label="阈值">
  80. <a-slider
  81. v-model="form.threshold"
  82. :step="0.01"
  83. :min="0"
  84. :max="1"
  85. show-input
  86. />
  87. </a-form-item>
  88. <a-form-item field="slider" label="最大聚类数">
  89. <a-slider
  90. v-model="form.max_cluster"
  91. :min="1"
  92. :max="1024"
  93. show-input
  94. />
  95. </a-form-item>
  96. <a-form-item
  97. field="slider"
  98. label="随机种子"
  99. v-model="form.random_seed"
  100. :rules="[
  101. { type: 'number', min: 5, message: 'slider is min than 5' },
  102. ]"
  103. >
  104. <a-input-number
  105. v-model="form.random_seed"
  106. :style="{
  107. width: '300px',
  108. marginRight: '1rem',
  109. borderRadius: '4px',
  110. }"
  111. placeholder="请输入"
  112. class="input-demo"
  113. :min="10"
  114. :max="100"
  115. />
  116. <a-button type="primary" @click="randomNumber">
  117. <icon-plus />
  118. </a-button>
  119. </a-form-item>
  120. </div>
  121. <a-form-item>
  122. <div style="width: 100%; text-align: right">
  123. <a-button @click="visible = false">取消</a-button>
  124. <a-button
  125. style="margin-left: 10px"
  126. type="primary"
  127. html-type="submit"
  128. >确定</a-button
  129. >
  130. </div>
  131. </a-form-item>
  132. </a-form>
  133. </div>
  134. </div>
  135. </a-tab-pane>
  136. <a-tab-pane key="2">
  137. <template #title> <icon-clock-circle /> 创建解析块 </template>
  138. <div class="details">
  139. <div class="details-header">
  140. <div
  141. style="
  142. display: flex;
  143. align-items: center;
  144. justify-content: flex-end;
  145. "
  146. >
  147. <a-radio-group
  148. v-model="radio"
  149. type="button"
  150. style="margin-right: 10px"
  151. @change="onRadioChange"
  152. >
  153. <a-radio value="1">全文</a-radio>
  154. <a-radio value="2">省略</a-radio>
  155. </a-radio-group>
  156. <a-popover position="bottom">
  157. <a-button
  158. type="outline"
  159. class="button"
  160. style="margin-right: 10px"
  161. >批量<icon-down style="margin-left: 4px"
  162. /></a-button>
  163. <template #content>
  164. <a-space direction="vertical">
  165. <a-checkbox
  166. :model-value="checkedAll"
  167. :indeterminate="indeterminate"
  168. @change="handleChangeAll"
  169. style="margin-left: 10px"
  170. >
  171. 选择所有
  172. </a-checkbox>
  173. </a-space>
  174. <a-divider style="margin: 10px 0" />
  175. <p>
  176. <a-button
  177. type="text"
  178. class="button"
  179. style="color: #2a2a2b"
  180. @click="addBlock(1)"
  181. >
  182. <template #icon>
  183. <icon-check-circle />
  184. </template>
  185. 启用选定的
  186. </a-button>
  187. </p>
  188. <p>
  189. <a-button
  190. type="text"
  191. class="button"
  192. style="color: #2a2a2b"
  193. @click="addBlock(0)"
  194. >
  195. <template #icon>
  196. <icon-close-circle />
  197. </template>
  198. 禁用选定的
  199. </a-button>
  200. </p>
  201. <a-divider style="margin: 10px 0" />
  202. <p>
  203. <a-button
  204. type="text"
  205. class="button"
  206. style="color: #2a2a2b"
  207. @click="addBlock(3)"
  208. >
  209. <template #icon>
  210. <icon-delete />
  211. </template>
  212. 删除选定的
  213. </a-button>
  214. </p>
  215. </template>
  216. </a-popover>
  217. <a-space
  218. direction="vertical"
  219. size="large"
  220. style="margin-right: 10px"
  221. class="space_search"
  222. v-show="!isBtn"
  223. >
  224. <a-input-search
  225. :style="{ width: '220px' }"
  226. v-model="form.keywords"
  227. @input="getList()"
  228. allow-clear
  229. @clear.stop="getList()"
  230. placeholder="搜索"
  231. />
  232. </a-space>
  233. <a-button
  234. type="outline"
  235. class="button"
  236. style="margin-right: 10px"
  237. v-show="isBtn"
  238. @click.stop="isBtn = !isBtn"
  239. >
  240. <template #icon>
  241. <icon-search />
  242. </template>
  243. </a-button>
  244. <a-popover position="bottom">
  245. <a-button
  246. type="outline"
  247. class="button"
  248. style="margin-right: 10px"
  249. ><icon-sort
  250. /></a-button>
  251. <template #content>
  252. <a-radio-group
  253. v-model="available_int"
  254. direction="vertical"
  255. size="large"
  256. @change="onChangeavailable"
  257. >
  258. <a-radio :value="''">所有</a-radio>
  259. <a-radio :value="1">启用</a-radio>
  260. <a-radio :value="0">禁用</a-radio>
  261. </a-radio-group>
  262. </template>
  263. </a-popover>
  264. <addDetails
  265. :item="item"
  266. @canplaythrough="canplaythrough"
  267. ></addDetails>
  268. </div>
  269. </div>
  270. <a-divider style="margin-top: 10px" />
  271. <div class="groupMain">
  272. <a-spin :loading="isLoading" :tip="tip">
  273. <a-checkbox-group v-model="data" @change="handleChange">
  274. <div
  275. class="groupList"
  276. :class="{
  277. groupActive: keyBg == '1',
  278. groupNoActive: keyBg != '1',
  279. }"
  280. v-for="(item, index) in listData"
  281. :key="index"
  282. >
  283. <a-checkbox :value="item.chunk_id"></a-checkbox>
  284. <div
  285. class="groupList-content emphaRed"
  286. @click="groupListContentClick('1')"
  287. @dblclick="contentClick(1)"
  288. v-html="item.content_with_weight"
  289. >
  290. </div>
  291. <div class="groupList-right">
  292. <a-switch
  293. v-model="item.available_int"
  294. :checked-value="1"
  295. :unchecked-value="0"
  296. @change="handleChangeStatus(item)"
  297. />
  298. </div>
  299. </div>
  300. </a-checkbox-group>
  301. </a-spin>
  302. </div>
  303. </div>
  304. <eidtDetails ref="eidtDil"></eidtDetails>
  305. </a-tab-pane>
  306. </a-tabs>
  307. </a-modal>
  308. </template>
  309. <script lang="ts" setup>
  310. import {
  311. onMounted,
  312. onBeforeMount,
  313. reactive,
  314. ref,
  315. computed,
  316. watch,
  317. } from 'vue';
  318. import { Message } from '@arco-design/web-vue';
  319. import {
  320. kbdocumentchangeparser,
  321. achunkCreate,
  322. queryChunkList,
  323. chunkSwitch,
  324. chunkRm,
  325. } from '@/api/kbList';
  326. import addDetails from '@/views/dmx/knowledgeLib/addDetails.vue';
  327. import eidtDetails from '@/views/dmx/knowledgeLib/eidtDetails.vue';
  328. const visible = ref(false);
  329. const loading = ref(false);
  330. const radio = ref('1');
  331. const keyBg = ref('');
  332. const eidtDil = ref();
  333. const props = defineProps(['kbtenantInfo', 'item', 'kbdetail']);
  334. // const emit = defineEmits(['upTabdateItem'])
  335. let threshold = computed(() => {
  336. return form.threshold / 100;
  337. });
  338. const kbtenantInfo = props.kbtenantInfo;
  339. let parser_ids = kbtenantInfo.parser_ids.split(',').map((item) => {
  340. const [value1, value2] = item.split(':');
  341. return {
  342. name: value2,
  343. value: value1,
  344. };
  345. });
  346. const isBtn = ref(true);
  347. const closeSlelct = () => {
  348. window.addEventListener('click', (event) => {
  349. if (!event.target.closest('.space_search') && !isBtn.value) {
  350. isBtn.value = true;
  351. // form.keywords = '';
  352. }
  353. });
  354. };
  355. watch(isBtn, (val) => {
  356. if (!val) {
  357. closeSlelct();
  358. }
  359. });
  360. const form = reactive({
  361. parser_id: props.item.parser_id,
  362. doc_id: props.item.id,
  363. max_token: 698,
  364. threshold: 0.3,
  365. max_cluster: 233,
  366. random_seed: 1500,
  367. chunk_token_num: 128,
  368. use_raptor: false,
  369. keywords: '',
  370. pages: {},
  371. prompt:
  372. '请总结以下段落。 小心数字,不要编造。 段落如下:\n' +
  373. ' {cluster_content}\n' +
  374. '以上就是你需要总结的内容。',
  375. });
  376. const formRef = ref(null);
  377. const rules = {
  378. prompt: [
  379. {
  380. required: true,
  381. message: '提示词不允许为空',
  382. },
  383. ],
  384. };
  385. const listData = ref([]);
  386. const formatter = (value) => {
  387. return value / 100;
  388. };
  389. function randomNumber() {
  390. // 生成一个介于min和max之间的随机整数(包含min和max)
  391. const min = 1; // 最小值
  392. const max = 10000; // 最大值
  393. form.random_seed = Math.floor(Math.random() * (max - min + 1)) + min;
  394. }
  395. const handleSubmit = async ({ values, errors }) => {
  396. if (!errors) {
  397. let data = await kbdocumentchangeparser({
  398. parser_id: form.parser_id,
  399. doc_id: form.doc_id,
  400. parser_config: {
  401. raptor: {
  402. use_raptor: form.use_raptor,
  403. prompt: form.prompt,
  404. max_token: form.max_token,
  405. threshold: form.threshold,
  406. max_cluster: form.max_cluster,
  407. random_seed: form.random_seed,
  408. },
  409. chunk_token_num: form.chunk_token_num,
  410. pages: [],
  411. },
  412. });
  413. if (data.code == 0) {
  414. Message.success('配置成功');
  415. } else {
  416. Message.error('配置失败');
  417. }
  418. visible.value = false;
  419. }
  420. };
  421. const handleClick = () => {
  422. visible.value = true;
  423. };
  424. const handleCancel = () => {
  425. visible.value = false;
  426. };
  427. const contentClick = (done) => {
  428. eidtDil.value.handleClick();
  429. };
  430. const handleOpened = (el) => {
  431. // console.log('props',props.kbtenantInfo);
  432. // console.log('props',props.item);
  433. // console.log('props',props.kbdetail);
  434. console.log(parser_ids, 'parser_ids');
  435. // Object.assign(form,{
  436. // name: '',// 用户名
  437. // nameJoin: '',// 昵称
  438. // post: '',// 岗位
  439. // txt: '',// 备注
  440. // });
  441. // formRef.value.resetFields();
  442. console.log(props.item.id);
  443. };
  444. const onChangeRAPTOR = () => {};
  445. const indeterminate = ref(false);
  446. const checkedAll = ref(false);
  447. const data = ref([]);
  448. const switchType = ref(false);
  449. const available_int = ref('');
  450. const onRadioChange = () => {
  451. console.log(radio.value);
  452. };
  453. //批量操作
  454. const handleChangeAll = (value) => {
  455. indeterminate.value = false;
  456. if (value) {
  457. checkedAll.value = true;
  458. listData.value.forEach((item) => {
  459. data.value.push(item.chunk_id);
  460. });
  461. } else {
  462. checkedAll.value = false;
  463. data.value = [];
  464. }
  465. };
  466. const handleChange = (values) => {
  467. data.value = values;
  468. };
  469. //批量启用删除禁用
  470. const addBlock = (type) => {
  471. if (data.value.length == 0) {
  472. Message.error('请选择要操作的数据');
  473. return;
  474. }
  475. if (type == 3) {
  476. deleteChunk();
  477. } else {
  478. let params = {
  479. chunk_ids: data.value,
  480. available_int: type,
  481. doc_id: props.item.id,
  482. };
  483. chunkSwitch(params).then((res) => {
  484. if (res.code == 0) {
  485. Message.success('操作成功');
  486. getList();
  487. checkedAll.value = false;
  488. data.value = [];
  489. } else {
  490. Message.error('操作失败');
  491. }
  492. });
  493. }
  494. };
  495. const groupListContentClick = (value) => {
  496. keyBg.value = value;
  497. };
  498. const onChangeavailable = () => {
  499. getList();
  500. };
  501. const handleChangeStatus = (val) => {
  502. updateChunkStatus(val);
  503. };
  504. const isLoading = ref(true);
  505. // 自定义加载提示文本
  506. const tip = '加载中,请稍候...';
  507. //获取列表
  508. const getList = async () => {
  509. let params = {
  510. doc_id: props.item.id,
  511. keywords: form.keywords,
  512. page: 1,
  513. size: 10000,
  514. };
  515. if (available_int.value !== '') {
  516. params.available_int = available_int.value;
  517. }
  518. await queryChunkList(params).then((res) => {
  519. if (res.code == 0) {
  520. listData.value = res.data.chunks;
  521. isLoading.value = false;
  522. listData.value = listData.value.map((item) => {
  523. item.available_int = parseInt(item.available_int);
  524. return item;
  525. });
  526. }
  527. });
  528. };
  529. //更新列表
  530. const canplaythrough = () => {
  531. getList();
  532. };
  533. //启用禁用
  534. const updateChunkStatus = (val) => {
  535. let params = {
  536. chunk_ids: [val.chunk_id],
  537. available_int: val.available_int,
  538. doc_id: props.item.id,
  539. };
  540. chunkSwitch(params).then((res) => {
  541. console.log(res);
  542. if (res.code == 0) {
  543. Message.success('更新成功');
  544. getList();
  545. } else {
  546. Message.error('更新失败');
  547. }
  548. });
  549. };
  550. //删除
  551. const deleteChunk = () => {
  552. let params = {
  553. chunk_ids: data.value,
  554. doc_id: props.item.id,
  555. };
  556. chunkRm(params).then((res) => {
  557. console.log(res);
  558. if (res.code == 0) {
  559. Message.success('删除成功');
  560. getList();
  561. } else {
  562. Message.error('删除失败');
  563. }
  564. });
  565. };
  566. onBeforeMount(() => {});
  567. onMounted(() => {
  568. getList();
  569. });
  570. </script>
  571. <style scoped lang="less">
  572. .parser {
  573. width: 100%;
  574. ::v-deep .arco-btn-outline:hover,
  575. .arco-btn-outline,
  576. .arco-btn-outline[type='button'] {
  577. color: #2a2a2b;
  578. border: 1px solid #2a2a2b;
  579. }
  580. .button {
  581. //color: #2a2a2b!important;
  582. }
  583. }
  584. ::-webkit-scrollbar {
  585. display: none;
  586. }
  587. .groupMain {
  588. width: 100%;
  589. height: 500px;
  590. overflow: auto;
  591. display: flex;
  592. justify-content: center;
  593. .groupList {
  594. display: flex;
  595. padding: 24px;
  596. border-radius: 8px;
  597. //background: #eff8ff;
  598. border: 1px solid #f0f0f0;
  599. margin-bottom: 20px;
  600. overflow: auto;
  601. .groupList-content {
  602. width: 700px;
  603. //height: 100px;
  604. overflow: auto;
  605. box-sizing: border-box;
  606. margin: 0;
  607. padding: 0;
  608. color: #2a2a2b;
  609. font-size: 14px;
  610. font-family: Inter;
  611. position: relative;
  612. }
  613. }
  614. }
  615. :deep(.emphaRed em) {
  616. color: red !important;
  617. }
  618. .groupActive {
  619. background: #eff8ff;
  620. }
  621. .groupNoActive {
  622. background: var(--color-bg-1);
  623. color: var(--color-text-1);
  624. }
  625. </style>