config.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. <template>
  2. <div ref="scrollContainer" class="main-container">
  3. <div style="position: absolute; top: 0; left: 0; width: 100%; padding: 0 20px">
  4. <h4 style="margin-bottom: 10px"></h4>
  5. <!-- 在这里更新您的知识库详细信息,尤其是解析方法。 -->
  6. <div style="color: #666666">{{ $t('knowledgeLib.config_header') }}</div>
  7. <a-divider style="margin-top: 20px" />
  8. </div>
  9. <div class="main-container-lf">
  10. <div class="main-container-lf-down">
  11. <a-form
  12. ref="formRef"
  13. :rules="rules"
  14. :model="form"
  15. :style="{ width: '100%' }"
  16. layout="vertical"
  17. @submit="handleSubmit"
  18. >
  19. <!-- 知识库名称 -->
  20. <a-form-item field="name" :label="$t('knowledgeLib.label_name')">
  21. <a-input v-model="form.name" :placeholder="$t('knowledgeLib.input_placeholder')" />
  22. </a-form-item>
  23. <!-- 描述 -->
  24. <a-form-item field="section" :label="$t('knowledgeLib.label_desc')">
  25. <a-textarea placeholder="" v-model="form.description" allow-clear />
  26. </a-form-item>
  27. <!-- 嵌入模型 -->
  28. <a-form-item field="embd_id" :label="$t('knowledgeLib.label_model')">
  29. <a-select
  30. :size="'large'"
  31. v-model="form.embd_id"
  32. :placeholder="$t('knowledgeLib.input_placeholder')"
  33. :disabled="kbObj.chunk_num && kbObj.token_num"
  34. >
  35. <a-option v-for="(item, index) in mobileData" :key="item.name" :value="item.name">
  36. {{ item.name }}
  37. </a-option>
  38. </a-select>
  39. </a-form-item>
  40. <!-- 解析方法 -->
  41. <a-form-item field="parser_id" :label="$t('knowledgeLib.label_model')">
  42. <a-select
  43. v-model="form.parser_id"
  44. :placeholder="$t('knowledgeLib.input_placeholder')"
  45. :disabled="!!(kbObj.chunk_num && kbObj.token_num)"
  46. >
  47. <a-option v-for="item in parser_ids" :key="item.value" :label="item.name" :value="item.value"></a-option>
  48. </a-select>
  49. </a-form-item>
  50. <!-- 块Token数 -->
  51. <a-form-item field="slider" :label="$t('knowledgeLib.block_token_count')">
  52. <a-slider v-model="form.chunk_token_num" :min="0" :max="2048" show-input />
  53. </a-form-item>
  54. <!-- 布局识别 -->
  55. <a-form-item :label="$t('knowledgeLib.label_layout')">
  56. <a-space direction="vertical">
  57. <a-switch v-model="form.layout_recognize" size="small" />
  58. </a-space>
  59. </a-form-item>
  60. <!-- 使用召回增强RAPTOR策略 -->
  61. <a-form-item field="raptor" :label="$t('knowledgeLib.use_strategy')">
  62. <a-switch v-model="form.use_raptor" size="small" />
  63. </a-form-item>
  64. <div v-if="form.use_raptor">
  65. <!-- 提示词 -->
  66. <a-form-item field="prompt" :label="$t('knowledgeLib.prompt')">
  67. <a-textarea
  68. v-model="form.prompt"
  69. style="height: 10rem; border: 1px solid var(--color-fill-3); border-radius: 4px"
  70. :placeholder="$t('knowledgeLib.label_prompt_placeholder')"
  71. />
  72. </a-form-item>
  73. <!-- 最大token数 -->
  74. <a-form-item field="slider" :label="$t('knowledgeLib.max_token_count')">
  75. <a-slider v-model="form.max_token" :min="0" :max="2048" show-input />
  76. </a-form-item>
  77. <!-- 阈值 -->
  78. <a-form-item field="slider" :label="$t('knowledgeLib.threshold')">
  79. <a-slider v-model="form.threshold" :step="0.01" :min="0" :max="1" show-input />
  80. </a-form-item>
  81. <!-- 最大聚类数 -->
  82. <a-form-item field="slider" :label="$t('knowledgeLib.max_clusters')">
  83. <a-slider v-model="form.max_cluster" :min="1" :max="1024" show-input />
  84. </a-form-item>
  85. <!-- 随机种子 -->
  86. <a-form-item field="slider" :label="$t('knowledgeLib.random_seed')" v-model="form.random_seed">
  87. <a-input-number
  88. v-model="form.random_seed"
  89. :style="{ width: '300px', marginRight: '1rem', borderRadius: '4px' }"
  90. :placeholder="$t('knowledgeLib.input_placeholder')"
  91. class="input-demo"
  92. :min="10"
  93. :max="100"
  94. />
  95. <a-button type="primary" @click="randomNumber">
  96. <icon-plus />
  97. </a-button>
  98. </a-form-item>
  99. </div>
  100. <a-form-item>
  101. <div style="width: 100%; text-align: right">
  102. <a-space>
  103. <a-button @click="cancelConfig"> {{ $t('knowledgeLib.cancel') }} </a-button>
  104. <a-button :loading="loading" type="primary" html-type="submit">{{
  105. $t('knowledgeLib.save_btn')
  106. }}</a-button>
  107. </a-space>
  108. </div>
  109. </a-form-item>
  110. </a-form>
  111. </div>
  112. </div>
  113. <div class="main-container-rt">
  114. <section
  115. data-inspector-line="34"
  116. data-inspector-column="4"
  117. data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx"
  118. class="categoryPanelWrapper___yI4rY"
  119. >
  120. <h4
  121. class="ant-typography topTitle___tNiB9 css-dev-only-do-not-override-1wxecgq"
  122. data-inspector-line="37"
  123. data-inspector-column="10"
  124. data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx"
  125. >
  126. "General" 分块方法说明
  127. </h4>
  128. <p
  129. data-inspector-line="40"
  130. data-inspector-column="10"
  131. data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx"
  132. ></p>
  133. <p>支持的文件格式为<b>DOCX、EXCEL、PPT、IMAGE、PDF、TXT</b>。</p>
  134. <p>此方法将简单的方法应用于块文件:</p>
  135. <p></p>
  136. <li>系统将使用视觉检测模型将连续文本分割成多个片段。</li>
  137. <li>接下来,这些连续的片段被合并成Token数不超过“Token数”的块。</li>
  138. <p></p>
  139. <h4
  140. class="ant-typography css-dev-only-do-not-override-1wxecgq"
  141. data-inspector-line="45"
  142. data-inspector-column="10"
  143. data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx"
  144. >
  145. "General" 示例
  146. </h4>
  147. <span
  148. class="ant-typography css-dev-only-do-not-override-1wxecgq"
  149. data-inspector-line="48"
  150. data-inspector-column="10"
  151. data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx"
  152. >提出以下屏幕截图以促进理解。</span
  153. >
  154. <div
  155. data-inspector-line="49"
  156. data-inspector-column="10"
  157. data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx"
  158. class="ant-row imageRow___C3Xpb css-dev-only-do-not-override-1wxecgq"
  159. style="margin-left: -5px; margin-right: -5px; row-gap: 10px; display: flex; margin-top: 20px; width: 100%"
  160. >
  161. <img
  162. data-inspector-line="32"
  163. data-inspector-column="8"
  164. data-inspector-relative-path="src\components\svg-icon.tsx"
  165. src="../../../../assets/image/management/step1.png"
  166. alt=""
  167. width="50%"
  168. />
  169. <img
  170. data-inspector-line="32"
  171. data-inspector-column="8"
  172. data-inspector-relative-path="src\components\svg-icon.tsx"
  173. src="../../../../assets/image/management/step2.png"
  174. alt=""
  175. width="50%"
  176. />
  177. </div>
  178. <h4
  179. class="ant-typography css-dev-only-do-not-override-1wxecgq"
  180. data-inspector-line="60"
  181. data-inspector-column="10"
  182. data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx"
  183. >
  184. General 对话示例
  185. </h4>
  186. <div
  187. class="ant-divider css-dev-only-do-not-override-1wxecgq ant-divider-horizontal"
  188. data-inspector-line="63"
  189. data-inspector-column="10"
  190. data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx"
  191. role="separator"
  192. ></div>
  193. <a-divider style="margin-top: 20px" />
  194. </section>
  195. </div>
  196. </div>
  197. </template>
  198. <script setup>
  199. import { onMounted, onBeforeMount, reactive, ref, nextTick } from 'vue';
  200. import Upload from './components/Upload.vue';
  201. import { Message } from '@arco-design/web-vue';
  202. import { queryModelList, kbUpdate, getKnowledgeBaseModel } from '../../../../apis/rgflow-dify';
  203. import { toSyncOwnKnowledge } from './asyc.js';
  204. import message from '@arco-design/web-vue/es/message';
  205. import useLoading from './loading';
  206. import step1 from '../../../../assets/image/management/step1.png';
  207. import step2 from '../../../../assets/image/management/step2.png';
  208. const { loading, setLoading } = useLoading(true);
  209. const scrollContainer = ref();
  210. const props = defineProps(['kbtenantInfo', 'kb_id']);
  211. const emit = defineEmits(['cancleConfig', 'saveConfig']);
  212. // 解析方法列表
  213. let parser_ids = props.kbtenantInfo.parser_ids.split(',').map((item) => {
  214. const [value1, value2] = item.split(':');
  215. return {
  216. name: value2,
  217. value: value1
  218. };
  219. });
  220. let kbObj = reactive({});
  221. let avatarShow = ref(true);
  222. const form = reactive({
  223. name: '',
  224. avatar: '', //头像
  225. max_token: 600,
  226. threshold: 0.32,
  227. max_cluster: 233,
  228. random_seed: 1500,
  229. chunk_token_num: 384,
  230. use_raptor: false,
  231. pages: {},
  232. prompt:
  233. '请总结以下段落。 小心数字,不要编造。 段落如下:\n' + ' {cluster_content}\n' + '以上就是你需要总结的内容。',
  234. description: '',
  235. language: 'English',
  236. permission: '',
  237. embd_id: '',
  238. parser_id: '',
  239. layout_recognize: true
  240. });
  241. const rules = {
  242. name: [
  243. {
  244. required: true,
  245. message: '知识库名称不允许为空'
  246. }
  247. ],
  248. embd_id: [
  249. {
  250. required: true,
  251. message: '请选择'
  252. }
  253. ],
  254. parser_id: [
  255. {
  256. required: true,
  257. message: '请选择'
  258. }
  259. ],
  260. prompt: [
  261. {
  262. required: true,
  263. message: '提示词不允许为空'
  264. }
  265. ]
  266. };
  267. let visible = ref(false);
  268. const formRef = ref();
  269. const modelList = ref({});
  270. const mobileData = ref([]);
  271. const file = ref();
  272. const uploadAction = '/api/v1/llm/upload'; // 替换为你的上传API
  273. const fileList = ref([]);
  274. const imageUrls = ref([]);
  275. const httpUrl = localStorage.getItem('httpUrl');
  276. const updateFileList = (newFileList) => {
  277. fileList.value = newFileList;
  278. console.log(newFileList, 88);
  279. };
  280. const handleSuccess = (urls) => {
  281. // imageUrls.value = urls; // 拿到上传的图片地址
  282. form.avatar = urls[0];
  283. };
  284. const handleSubmit = async ({ values, errors }) => {
  285. if (errors) {
  286. return;
  287. }
  288. let parms = {
  289. name: form.name,
  290. avatar: form.avatar,
  291. description: form.description,
  292. language: form.language,
  293. permission: form.permission,
  294. embd_id: form.embd_id,
  295. parser_id: form.parser_id,
  296. parser_config: {
  297. chunk_token_num: form.chunk_token_num,
  298. layout_recognize: form.layout_recognize
  299. },
  300. kb_id: kbObj.id
  301. };
  302. if (form.use_raptor) {
  303. parms.parser_config.raptor = {
  304. use_raptor: form.use_raptor,
  305. prompt: form.prompt,
  306. max_token: form.max_token,
  307. threshold: form.threshold,
  308. max_cluster: form.max_cluster,
  309. random_seed: form.random_seed
  310. };
  311. }
  312. try {
  313. setLoading(true);
  314. const data = await kbUpdate(parms);
  315. if (data.retcode == '0') {
  316. Message.success('配置成功');
  317. // window.location.reload();
  318. emit('saveConfig');
  319. //TODO 同步数据
  320. toSyncOwnKnowledge(kbObj.id);
  321. }
  322. setLoading(false);
  323. } catch (err) {
  324. Message.error(err.message);
  325. setLoading(false);
  326. }
  327. };
  328. const cancelConfig = () => {
  329. emit('cancleConfig');
  330. };
  331. function randomNumber() {
  332. // 生成一个介于min和max之间的随机整数(包含min和max)
  333. const min = 1; // 最小值
  334. const max = 10000; // 最大值
  335. form.random_seed = Math.floor(Math.random() * (max - min + 1)) + min;
  336. }
  337. const handleBeforeOk = (done) => {
  338. formRef.value.validate().then((res) => {
  339. // console.log('form:', form);
  340. if (!form.name) {
  341. done(false);
  342. } else {
  343. console.log('请求数据');
  344. }
  345. });
  346. };
  347. const handleOpened = (el) => {
  348. Object.assign(form, {});
  349. // formRef.value.resetFields();
  350. };
  351. const queryModel = async (params) => {
  352. try {
  353. const data = await getKnowledgeBaseModel(params);
  354. // const res =await queryModelList(params)
  355. // console.log(data.data, '大模型列表');
  356. modelList.value = data.data;
  357. for (let key in data.data) {
  358. if (data.data.hasOwnProperty(key)) {
  359. // 确保是对象自有属性,不是原型链上的属性
  360. if (data.data[key].llm.length > 0) {
  361. mobileData.value = data.data[key].llm.filter((item) => item.type == 'embedding');
  362. }
  363. }
  364. }
  365. } catch (err) {
  366. // you can report use errorHandler or other
  367. } finally {
  368. }
  369. };
  370. const changekbObj = (value) => {
  371. formRef.value.resetFields();
  372. nextTick(() => {
  373. kbObj = value;
  374. // console.log(kbObj, 'kbObj');
  375. let configObj = {
  376. name: kbObj.name,
  377. avatar: kbObj.avatar,
  378. pages: kbObj.parser_config.pages,
  379. chunk_token_num: kbObj.parser_config.chunk_token_num,
  380. description: kbObj.description,
  381. language: 'English',
  382. permission: kbObj.permission,
  383. embd_id: kbObj.embd_id || props.kbtenantInfo.embd_id,
  384. parser_id: kbObj.parser_id,
  385. layout_recognize: true
  386. };
  387. let raptor = {};
  388. if (kbObj.parser_config && kbObj.parser_config.raptor) {
  389. raptor = kbObj.parser_config.raptor;
  390. Object.assign(form, {
  391. ...configObj,
  392. ...raptor,
  393. use_raptor: kbObj.parser_config.raptor.use_raptor
  394. });
  395. } else {
  396. Object.assign(form, {
  397. ...configObj,
  398. use_raptor: false
  399. });
  400. }
  401. imageUrls.value = [kbObj.avatar];
  402. // console.log(form, '配置页面表单信息');
  403. avatarShow.value = false;
  404. setTimeout(() => {
  405. avatarShow.value = true;
  406. }, 100);
  407. scrollContainer.value.scrollTop = 0;
  408. });
  409. };
  410. defineExpose({
  411. changekbObj
  412. });
  413. onBeforeMount(() => {
  414. setLoading(false);
  415. queryModel({});
  416. });
  417. onMounted(() => {});
  418. </script>
  419. <script>
  420. import { IconEdit, IconPlus } from '@arco-design/web-vue/es/icon';
  421. export default {
  422. name: 'config',
  423. components: { IconPlus, IconEdit },
  424. methods: {}
  425. };
  426. </script>
  427. <style scoped lang="css">
  428. .main-container {
  429. position: relative;
  430. display: flex;
  431. justify-content: space-between;
  432. height: 100%;
  433. overflow-y: auto;
  434. overflow-x: hidden;
  435. border-radius: 8px;
  436. background: var(--color-bg-2);
  437. padding-top: 80px;
  438. .main-container-lf {
  439. width: calc(40% - 40px);
  440. border-radius: 10px;
  441. .main-container-lf-top {
  442. width: 100%;
  443. height: 60px;
  444. line-height: 60px;
  445. }
  446. .main-container-lf-down {
  447. padding: 20px;
  448. width: 100%;
  449. }
  450. }
  451. .main-container-form-item-extra {
  452. width: 100%;
  453. height: 20rem;
  454. border: 1px solid var(--color-fill-3);
  455. border-radius: 6px;
  456. overflow: hidden;
  457. .main-container-form-item-extra-top {
  458. width: 100%;
  459. height: 40px;
  460. line-height: 40px;
  461. border-bottom: 1px solid var(--color-fill-3);
  462. //background: rgb(var(--primary-6));
  463. color: #999999;
  464. text-align: center;
  465. }
  466. .main-container-form-item-extra-down {
  467. width: 92%;
  468. margin-left: 4%;
  469. margin-top: 30px;
  470. }
  471. .main-container-form-item-extra-btn {
  472. width: 96%;
  473. text-align: right;
  474. margin-top: 1rem;
  475. }
  476. }
  477. .main-container-rt {
  478. width: calc(60% - 40px);
  479. border-radius: 10px;
  480. overflow: hidden;
  481. padding: 20px;
  482. section {
  483. width: 100%;
  484. color: var(--color-text-1);
  485. }
  486. }
  487. }
  488. .arco-form .arco-slider {
  489. display: flex;
  490. }
  491. </style>