zhangxiao
2024-08-08 13cc38755055989c86bf16fceaaf5bd3d6c5515a
Merge branch 'master' of http://192.168.5.5:10010/r/web/flow_web
1个文件已添加
11个文件已修改
942 ■■■■ 已修改文件
config/vite.config.prod.ts 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/authority.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/authority/users/index.vue 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dmx/IntelligentAgent/components/agentConfig.vue 80 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dmx/IntelligentAgent/index.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dmx/knowledgeLib/config.vue 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dmx/knowledgeLib/config1.vue 510 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dmx/knowledgeLib/index.vue 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dmx/knowledgeLib/test.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/session/sessionRecordsManager/index.vue 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yarn.lock 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
config/vite.config.prod.ts
@@ -14,29 +14,6 @@
      configArcoResolverPlugin(),
      configImageminPlugin(),
    ],
    server: {
      open: true, // 项目启动后,自动打开
      fs: {
        strict: true,
      },
      proxy: {
        '/base': {
          target: 'http://192.168.20.116:8089',
          changeOrigin: true,
          ws: true,
        },
        '/api': {
          target: 'http://192.168.20.116:8089',
          changeOrigin: true,
          ws: true,
        },
        '/api/v1': {
          target: 'http://192.168.20.116:8089',
          changeOrigin: true,
          ws: true,
        },
      },
    },
    build: {
      rollupOptions: {
        output: {
package.json
@@ -34,6 +34,7 @@
    "axios": "^0.24.0",
    "dayjs": "^1.11.5",
    "echarts": "^5.4.0",
    "eventsource-parser": "^2.0.1",
    "js-base64": "^3.7.5",
    "jsencrypt": "^3.3.2",
    "lodash": "^4.17.21",
src/api/authority.ts
@@ -8,6 +8,7 @@
  email: string;
  phoneNumber: string;
  dept: any;
  deptName:string;
  resources: any;
  knowledges: any;
  dialogs: any;
src/views/authority/users/index.vue
@@ -369,6 +369,7 @@
  let editform = ref<User>({
    createTime: '',
    dept: undefined,
    deptName:"",
    email: '',
    nickName: '',
    phoneNumber: '',
@@ -499,8 +500,8 @@
      slotName: 'index',
    },
    {
      title: t('用户名'),
      dataIndex: 'userName',
      title: t('登录名'),
      dataIndex: 'email',
    },
    {
      title: t('创建时间'),
@@ -508,8 +509,8 @@
    },
    {
      title: t('所属部门'),
      dataIndex: 'dept',
      slotName: 'dept',
      dataIndex: 'deptName',
      slotName: 'deptName',
    },
    {
      title: t('状态'),
@@ -630,7 +631,7 @@
    //删除
    if (t == 3) {
      await UserDelete(record.userId).then((res) => {
        if (res.code == 20000) {
        if (res.code == 200) {
          fetchData();
        }
      });
@@ -646,28 +647,35 @@
      checkStrictlyDialog.value = [];
      checkedKeysDialog.value = [];
      selectUser.value = record;
      record.resources.forEach((val) => {
        checkStrictlyMenu.value.push({
          menuId: val.menuId,
          menuName: val.menuName,
      if (record.resources) {
        record.resources.forEach((val) => {
          checkStrictlyMenu.value.push({
            menuId: val.menuId,
            menuName: val.menuName
          });
          checkedKeysMenu.value.push(val.menuId);
          expandKdysMenu.value.push(val.menuId);
        });
        checkedKeysMenu.value.push(val.menuId);
        expandKdysMenu.value.push(val.menuId);
      });
      record.knowledges.forEach((val) => {
        checkStrictlyKnowledge.value.push({
          knowledgeId: val.id,
          knowledgeName: val.name,
      }
      if (record.knowledges) {
        record.knowledges.forEach((val) => {
          checkStrictlyKnowledge.value.push({
            knowledgeId: val.id,
            knowledgeName: val.name
          });
          checkedKeysKnowledge.value.push(val.id);
        });
        checkedKeysKnowledge.value.push(val.id);
      });
      record.dialogs.forEach((val) => {
        checkStrictlyDialog.value.push({
          dialogId: val.id,
          dialogName: val.name,
      }
      if (record.dialogs) {
        record.dialogs.forEach((val) => {
          checkStrictlyDialog.value.push({
            dialogId: val.id,
            dialogName: val.name
          });
          checkedKeysDialog.value.push(val.id);
        });
        checkedKeysDialog.value.push(val.id);
      });
      }
    }
    //机构
    if (t == 5) {
@@ -677,14 +685,16 @@
      checkStrictly.value = [];
      selectUser.value = record;
      expandKdys.value.push('0');
      record.dept.forEach((val) => {
        checkStrictly.value.push({
          deptId: val.deptId,
          deptName: val.deptName,
      if (record.dept) {
        record.dept.forEach((val) => {
          checkStrictly.value.push({
            deptId: val.deptId,
            deptName: val.deptName
          });
          checkedKeys.value.push(val.deptId);
          expandKdys.value.push(val.deptId);
        });
        checkedKeys.value.push(val.deptId);
        expandKdys.value.push(val.deptId);
      });
      }
    }
  };
@@ -694,6 +704,17 @@
    setLoading(true);
    try {
      await UserList(params).then((res) => {
        for (const user of res.rows) {
          if (user.dept) {
            for (const d of user.dept) {
              if (user.deptName) {
                user.deptName += d.deptName + ",";
              } else {
                user.deptName = d.deptName + ",";
              }
            }
          }
        }
        renderData.value = res.rows;
        console.log(renderData);
        pagination.current = params.current;
src/views/dmx/IntelligentAgent/components/agentConfig.vue
@@ -48,49 +48,13 @@
                </a-form-item>
                <a-form-item label="智能体图标">
                  <a-space direction="vertical" :style="{ width: '100%' }">
                    <a-upload
                      :auto-upload="false"
                      :fileList="file ? [file] : []"
                      :show-file-list="false"
                      @change="onChange"
                      @progress="onProgress"
                    >
                      <template #upload-button>
                        <div
                          :class="`arco-upload-list-item${
                      file && file.status === 'error' ? ' arco-upload-list-item-error' : ''
                    }`"
                        >
                          <div
                            class="arco-upload-list-picture custom-upload-avatar"
                            v-if="file && file.url"
                          >
                            <img :src="file.url" />
                            <div class="arco-upload-list-picture-mask">
                              <IconEdit />
                            </div>
                            <a-progress
                              v-if="file.status === 'uploading' && file.percent < 100"
                              :percent="file.percent"
                              type="circle"
                              size="mini"
                              :style="{
                          position: 'absolute',
                          left: '50%',
                          top: '50%',
                          transform: 'translateX(-50%) translateY(-50%)',
                        }"
                            />
                          </div>
                          <div class="arco-upload-picture-card" v-else>
                            <div class="arco-upload-picture-card-text">
                              <IconPlus />
                              <div style="margin-top: 10px; font-weight: 600">上传</div>
                            </div>
                          </div>
                        </div>
                      </template>
                    </a-upload>
                    <Upload
                      :action="uploadAction"
                      :limit="1"
                      :url="form.icon"
                      @update:fileList="updateFileList"
                      @success="handleSuccess"
                    ></Upload>
                  </a-space>
                </a-form-item>
                <a-form-item label="空回复">
@@ -370,26 +334,18 @@
  return `${(value / 100).toFixed(2)}`
};
const onChange = (_, currentFile) => {
  file.value = currentFile;
  convertImageToBase64(file.value.file).then((result) => {
    form.icon = result;
  });
const uploadAction = '/api/v1/llm/upload'; // 替换为你的上传API
const fileList = ref([]);
const imageUrls = ref([]);
const updateFileList = (newFileList) => {
  fileList.value = newFileList;
  console.log(newFileList, 88);
};
function convertImageToBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = function() {
      resolve(reader.result);
    };
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}
const onProgress = (currentFile) => {
  file.value = currentFile;
const handleSuccess = (urls) => {
  imageUrls.value = urls; // 拿到上传的图片地址
  form.icon = urls[0];
};
const rules = {
@@ -517,7 +473,7 @@
  nextTick(()=>{
    // console.log(props.formData,'传入数据');
    Object.assign(form, props.formData);
    // console.log(form,'表单数据');
    console.log(form,'表单数据');
  })
};
src/views/dmx/IntelligentAgent/index.vue
@@ -15,7 +15,7 @@
          <a-divider style="margin: 10px 0" />
          <a-row justify="space-between">
            <a-col :span="24">
              <div style="display: flex; flex-wrap: wrap">
              <a-spin :loading="loading" style="display: flex; flex-wrap: wrap" :style="{height: documentHeight + 'px'}">
<!--                <div-->
<!--                  class="card-wrap"-->
<!--                  style="cursor: pointer"-->
@@ -56,7 +56,7 @@
                  :key="item.id"
                >
                  <a-card :bordered="false" hoverable>
                    <a-avatar :style="{ backgroundColor: '#3370ff' }">
                    <a-avatar :style="{ backgroundColor: '#5b99da' }">
                      <img
                        :style="{ width: '100%' }"
                        alt="dessert"
@@ -113,7 +113,7 @@
                    </div>
                  </a-card>
                </div>
              </div>
              </a-spin>
            </a-col>
          </a-row>
        </a-card>
@@ -130,7 +130,7 @@
  const { loading, setLoading } = useLoading(true);
  import EventBus from '@/utils/EventBus';
  import AgentConfig from "@/views/dmx/IntelligentAgent/components/agentConfig.vue";
  let documentHeight = window.innerHeight - 360
  let count = 5;
  const activeKey = ref(1);
  const addAgents = ref();
src/views/dmx/knowledgeLib/config.vue
@@ -14,49 +14,14 @@
          </a-form-item>
          <a-form-item field="section" label="知识库图片">
            <a-space direction="vertical" :style="{ width: '100%' }">
              <a-upload
                :auto-upload="false"
                :fileList="file ? [file] : []"
                :show-file-list="false"
                @change="onChange"
                @progress="onProgress"
              >
                <template #upload-button>
                  <div
                    :class="`arco-upload-list-item${
                      file && file.status === 'error' ? ' arco-upload-list-item-error' : ''
                    }`"
                  >
                    <div
                      class="arco-upload-list-picture custom-upload-avatar"
                      v-if="file && file.url"
                    >
                      <img :src="form.avatar" />
                      <div class="arco-upload-list-picture-mask">
                        <IconEdit />
                      </div>
                      <a-progress
                        v-if="file.status === 'uploading' && file.percent < 100"
                        :percent="file.percent"
                        type="circle"
                        size="mini"
                        :style="{
                          position: 'absolute',
                          left: '50%',
                          top: '50%',
                          transform: 'translateX(-50%) translateY(-50%)',
                        }"
                      />
                    </div>
                    <div class="arco-upload-picture-card" v-else>
                      <div class="arco-upload-picture-card-text">
                        <IconPlus />
                        <div style="margin-top: 10px; font-weight: 600">上传</div>
                      </div>
                    </div>
                  </div>
                </template>
              </a-upload>
              <Upload
                v-if="avatarShow"
                :action="uploadAction"
                :limit="1"
                :url="form.avatar"
                @update:fileList="updateFileList"
                @success="handleSuccess"
              ></Upload>
            </a-space>
          </a-form-item>
          <a-form-item field="section" label="描述">
@@ -131,7 +96,7 @@
            <div style="width: 100%;text-align: right">
              <a-space>
                <a-button @click="cancelConfig">取消</a-button>
                <a-button type="primary" html-type="submit">保存</a-button>
                <a-button :loading="loading" type="primary" html-type="submit">保存</a-button>
              </a-space>
            </div>
          </a-form-item>
@@ -208,10 +173,11 @@
});
let kbObj = reactive({});
let avatarShow = ref(true);
const form = reactive({
  name: kbObj.name,
  avatar: '',//
  name: '',
  avatar: '',//头像
  max_token: 600,
  threshold: 0.32,
  max_cluster: 233,
@@ -226,7 +192,7 @@
  language: "English",
  permission: "",
  embd_id: "BAAI/bge-large-zh-v1.5",
  parser_id: kbObj.parser_id,
  parser_id: '',
  layout_recognize: true
});
@@ -261,26 +227,18 @@
const modelList = ref({});
const file = ref();
const onChange = (_, currentFile) => {
  file.value = currentFile;
  convertImageToBase64(file.value.file).then((result)=>{
    form.avatar = result;
  })
const uploadAction = '/api/v1/llm/upload'; // 替换为你的上传API
const fileList = ref([]);
const imageUrls = ref([]);
const updateFileList = (newFileList) => {
  fileList.value = newFileList;
  console.log(newFileList, 88);
};
function convertImageToBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = function() {
      resolve(reader.result);
    };
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}
const onProgress = (currentFile) => {
  file.value = currentFile;
const handleSuccess = (urls) => {
  imageUrls.value = urls; // 拿到上传的图片地址
  form.avatar = urls[0];
};
@@ -313,7 +271,7 @@
     };
   }
   try {
     setLoading(true)
    const data = await kbUpdate(parms);
    if(data.code == '0'){
      Message.success("配置成功");
@@ -321,10 +279,11 @@
      emit('saveConfig')
    }
    // emit('upTabdateItem')
    setLoading(false)
  } catch (err) {
    Message.error(err.message);
     setLoading(false)
  }
@@ -377,15 +336,11 @@
  formRef.value.resetFields();
  kbObj = value;
  console.log(kbObj, 'kbObj');
  if(kbObj.avatar){
    file.value.url = kbObj.avatar
  }else{
    // file.value.url = '';
  }
  let configObj = {
    name: kbObj.name,
    avatar: kbObj.avatar,
    pages:  kbObj.parser_config.pages,
    chunk_token_num:  kbObj.parser_config.chunk_token_num,
    description: kbObj.description,
    language: "English",
    permission: kbObj.permission,
@@ -402,9 +357,17 @@
      use_raptor: kbObj.parser_config.raptor.use_raptor,
    });
  }else{
    Object.assign(form,configObj);
    Object.assign(form,{
      ...configObj,
      use_raptor: false,
    });
  }
  imageUrls.value = [kbObj.avatar];
  console.log(form,'配置页面表单信息');
  avatarShow.value = false;
  setTimeout(() => {
    avatarShow.value = true;
  },100);
}
defineExpose({
@@ -413,6 +376,7 @@
onBeforeMount(()=>{
  setLoading(false)
  queryModel({})
})
onMounted(()=>{
src/views/dmx/knowledgeLib/config1.vue
New file
@@ -0,0 +1,510 @@
<template>
  <div class="main-container">
    <div style="position: absolute;top: 0;left: 0;width: 100%;padding: 0 20px">
      <h4 style="margin-bottom: 10px"></h4>
      <div style="color: #666666;">在这里更新您的知识库详细信息,尤其是解析方法。</div>
      <a-divider style="margin-top: 20px" />
    </div>
    <div class="main-container-lf">
      <div class="main-container-lf-down">
        <a-form ref="formRef" :rules="rules" :model="form" :style="{width:'100%'}" layout="vertical"
                @submit="handleSubmit">
          <a-form-item field="name" label="知识库名称">
            <a-input v-model="form.name" placeholder="请输入" />
          </a-form-item>
          <a-form-item field="section" label="知识库图片">
            <a-space direction="vertical" :style="{ width: '100%' }">
              <a-upload
                :auto-upload="false"
                :fileList="file ? [file] : []"
                :show-file-list="false"
                @change="onChange"
                @progress="onProgress"
              >
                <template #upload-button>
                  <div
                    :class="`arco-upload-list-item${
                      file && file.status === 'error' ? ' arco-upload-list-item-error' : ''
                    }`"
                  >
                    <div
                      class="arco-upload-list-picture custom-upload-avatar"
                      v-if="file && file.url"
                    >
                      <img :src="form.avatar" />
                      <div class="arco-upload-list-picture-mask">
                        <IconEdit />
                      </div>
                      <a-progress
                        v-if="file.status === 'uploading' && file.percent < 100"
                        :percent="file.percent"
                        type="circle"
                        size="mini"
                        :style="{
                          position: 'absolute',
                          left: '50%',
                          top: '50%',
                          transform: 'translateX(-50%) translateY(-50%)',
                        }"
                      />
                    </div>
                    <div class="arco-upload-picture-card" v-else>
                      <div class="arco-upload-picture-card-text">
                        <IconPlus />
                        <div style="margin-top: 10px; font-weight: 600">上传</div>
                      </div>
                    </div>
                  </div>
                </template>
              </a-upload>
            </a-space>
          </a-form-item>
          <a-form-item field="section" label="描述">
            <a-textarea placeholder=""  v-model="form.description" allow-clear />
          </a-form-item>
<!--          <a-form-item field="section" label="语言" :rules="[{match:/section one/,message:'请选择'}]">-->
<!--            <a-select v-model="form.section" placeholder="请选择" allow-clear>-->
<!--              <a-option value="0">中文</a-option>-->
<!--              <a-option value="1">英文</a-option>-->
<!--            </a-select>-->
<!--          </a-form-item>-->
          <a-form-item field="embd_id" label="嵌入模型">
            <a-space direction="vertical" size="large">
              <a-select :size="'large'" v-model="form.embd_id" :style="{width:'100%'}" placeholder="请选择 ..." :disabled="kbObj.chunk_num==0 && kbObj.token_num==0" allow-clear>
                <a-optgroup  :label="index" v-for="(item,index) in modelList" :key=index>
                  <a-option
                    v-for="(obj) in item"
                    :key='obj.fid'
                    :value="obj.llm_name"
                  >
                    {{obj.llm_name}}
                  </a-option>
                </a-optgroup>
              </a-select>
            </a-space>
          </a-form-item>
          <a-form-item field="parser_id" label="解析方法">
            <a-select v-model="form.parser_id" placeholder="请选择" :disabled="kbObj.chunk_num==0 && kbObj.token_num==0" allow-clear>
              <a-option v-for="item in parser_ids" :key="item.value" :label="item.name" :value="item.value"></a-option>
            </a-select>
          </a-form-item>
          <a-form-item field="slider" label="块Token数">
            <a-slider v-model="form.chunk_token_num" :min="0" :max="2048"  show-input />
          </a-form-item>
          <a-form-item  label="布局识别" >
            <a-space direction="vertical">
              <a-switch v-model="form.layout_recognize" size="small" />
            </a-space>
          </a-form-item>
          <a-form-item field="raptor" label="使用召回增强RAPTOR策略">
            <a-space direction="vertical" >
              <a-switch v-model="form.use_raptor" size="small" />
            </a-space>
          </a-form-item>
          <div v-if="form.use_raptor">
            <a-form-item field="prompt" label="提示词">
              <a-textarea
                v-model="form.prompt"
                style="height: 10rem;border: 1px solid  var(--color-fill-3);border-radius: 4px" placeholder="请填写提示词"  />
            </a-form-item>
            <a-form-item field="slider" label="最大token数">
              <a-slider v-model="form.max_token" :min="0" :max="2048" show-input/>
            </a-form-item>
            <a-form-item field="slider" label="阈值" >
              <a-slider v-model="form.threshold"  :step="0.01" :min="0" :max="1"  show-input/>
            </a-form-item>
            <a-form-item field="slider" label="最大聚类数">
              <a-slider v-model="form.max_cluster" :min="1" :max="1024" show-input/>
            </a-form-item>
            <a-form-item field="slider" label="随机种子" v-model="form.random_seed">
              <a-input-number v-model="form.random_seed" :style="{width:'300px',marginRight:'1rem',borderRadius:'4px'}"
                              placeholder="请输入" class="input-demo" :min="10" :max="100" />
              <a-button type="primary" @click="randomNumber">
                <icon-plus />
              </a-button>
            </a-form-item>
          </div>
          <a-form-item>
            <div style="width: 100%;text-align: right">
              <a-space>
                <a-button @click="cancelConfig">取消</a-button>
                <a-button type="primary" html-type="submit">保存</a-button>
              </a-space>
            </div>
          </a-form-item>
        </a-form>
      </div>
    </div>
    <div class="main-container-rt">
      <section data-inspector-line="34" data-inspector-column="4"
               data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx"
               class="categoryPanelWrapper___yI4rY"><h4
        class="ant-typography topTitle___tNiB9 css-dev-only-do-not-override-1wxecgq" data-inspector-line="37"
        data-inspector-column="10"
        data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx">"General"
        分块方法说明</h4>
        <p data-inspector-line="40" data-inspector-column="10"
           data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx"><p>
          支持的文件格式为<b>DOCX、EXCEL、PPT、IMAGE、PDF、TXT</b>。</p>
          <p>此方法将简单的方法应用于块文件:</p>
          <p>
          </p>
          <li>系统将使用视觉检测模型将连续文本分割成多个片段。</li>
          <li>接下来,这些连续的片段被合并成Token数不超过“Token数”的块。</li>
          <p></p></p>
        <h4 class="ant-typography css-dev-only-do-not-override-1wxecgq" data-inspector-line="45"
            data-inspector-column="10"
            data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx">
          "General" 示例</h4><span class="ant-typography css-dev-only-do-not-override-1wxecgq" data-inspector-line="48"
                                   data-inspector-column="10"
                                   data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx">提出以下屏幕截图以促进理解。</span>
        <div data-inspector-line="49" data-inspector-column="10"
             data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx"
             class="ant-row imageRow___C3Xpb css-dev-only-do-not-override-1wxecgq"
             style="margin-left: -5px; margin-right: -5px; row-gap: 10px;display: flex; margin-top: 20px;width: 100%">
          <img
            data-inspector-line="32" data-inspector-column="8"
            data-inspector-relative-path="src\components\svg-icon.tsx" src="../../../assets/images/step1.png" alt=""
            width="50%">
          <img
            data-inspector-line="32" data-inspector-column="8"
            data-inspector-relative-path="src\components\svg-icon.tsx" src="../../../assets/images/step2.png" alt=""
            width="50%">
        </div>
        <h4 class="ant-typography css-dev-only-do-not-override-1wxecgq" data-inspector-line="60"
            data-inspector-column="10"
            data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx">
          General 对话示例</h4>
        <div class="ant-divider css-dev-only-do-not-override-1wxecgq ant-divider-horizontal" data-inspector-line="63"
             data-inspector-column="10"
             data-inspector-relative-path="src\pages\add-knowledge\components\knowledge-setting\category-panel.tsx"
             role="separator"></div>
        <a-divider style="margin-top: 20px" />
      </section>
    </div>
  </div>
</template>
<script lang="ts" setup>
import { onMounted, onBeforeMount, reactive, ref } from "vue";
import { Message } from "@arco-design/web-vue";
import { queryModelList,kbUpdate } from "@/api/kbList";
import message from "@arco-design/web-vue/es/message";
import useLoading from "@/hooks/loading";
const { loading,setLoading } = useLoading(true);
const props =  defineProps(['kbtenantInfo'])
const emit =  defineEmits(['cancleConfig','saveConfig'])
// 解析方法列表
let parser_ids = props.kbtenantInfo.parser_ids.split(",").map((item) => {
  const [value1, value2] = item.split(":");
  return {
    name: value2,
    value: value1
  };
});
let kbObj = reactive({});
const form = reactive({
  name: kbObj.name,
  avatar: '',//
  max_token: 600,
  threshold: 0.32,
  max_cluster: 233,
  random_seed: 1500,
  chunk_token_num: 384,
  use_raptor: false,
  pages: {},
  prompt: "请总结以下段落。 小心数字,不要编造。 段落如下:\n" +
    "      {cluster_content}\n" +
    "以上就是你需要总结的内容。",
  description: "",
  language: "English",
  permission: "",
  embd_id: "BAAI/bge-large-zh-v1.5",
  parser_id: kbObj.parser_id,
  layout_recognize: true
});
const rules = {
  name: [
    {
      required: true,
      message:'知识库名称不允许为空',
    },
  ],
  embd_id: [
    {
      required: true,
      message:'请选择',
    },
  ],
  parser_id: [
    {
      required: true,
      message:'请选择',
    },
  ],
  prompt: [
    {
      required: true,
      message:'提示词不允许为空',
    },
  ],
}
let visible = ref(false);
const formRef = ref(null);
const modelList = ref({});
const file = ref();
const onChange = (_, currentFile) => {
  file.value = currentFile;
  convertImageToBase64(file.value.file).then((result)=>{
    form.avatar = result;
  })
};
function convertImageToBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = function() {
      resolve(reader.result);
    };
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}
const onProgress = (currentFile) => {
  file.value = currentFile;
};
const handleSubmit = async ({ values, errors }) => {
  if (errors){
    return;
  }
  let parms = {
      name: form.name,
      avatar: form.avatar,
      description: form.description,
      language: form.language,
      permission: form.permission,
      embd_id: form.embd_id,
      parser_id: form.parser_id,
      parser_config: {
        chunk_token_num: form.chunk_token_num,
        layout_recognize: form.layout_recognize,
      },
      kb_id: kbObj.id,
   }
   if(form.use_raptor){
     parms.parser_config.raptor = {
       use_raptor: form.use_raptor,
       prompt: form.prompt,
       max_token: form.max_token,
       threshold: form.threshold,
       max_cluster: form.max_cluster,
       random_seed: form.random_seed,
     };
   }
   try {
    const data = await kbUpdate(parms);
    if(data.code == '0'){
      Message.success("配置成功");
      // window.location.reload();
      emit('saveConfig')
    }
    // emit('upTabdateItem')
  } catch (err) {
    Message.error(err.message);
  }
};
const cancelConfig = () => {
    emit('cancleConfig')
}
function randomNumber() {
  // 生成一个介于min和max之间的随机整数(包含min和max)
  const min = 1; // 最小值
  const max = 10000; // 最大值
  form.random_seed = Math.floor(Math.random() * (max - min + 1)) + min;
}
const handleBeforeOk = (done) => {
  formRef.value.validate().then(res => {
    console.log("form:", form);
    if (!form.name) {
      done(false);
    } else {
      console.log("请求数据");
    }
  });
};
const handleOpened =(el) => {
  Object.assign(form,{
  });
  formRef.value.resetFields();
}
const queryModel = async (params) => {
  try {
    const data = await queryModelList(params);
    // console.log(data.data, '大模型列表');
    modelList.value = data.data
  } catch (err) {
    // you can report use errorHandler or other
  } finally {
  }
};
const changekbObj = (value) => {
  formRef.value.resetFields();
  kbObj = value;
  console.log(kbObj, 'kbObj');
  if(kbObj.avatar){
    file.value.url = kbObj.avatar
  }else{
    // file.value.url = '';
  }
  let configObj = {
    name: kbObj.name,
    avatar: kbObj.avatar,
    pages:  kbObj.parser_config.pages,
    description: kbObj.description,
    language: "English",
    permission: kbObj.permission,
    embd_id: props.kbtenantInfo.embd_id || kbObj.embd_id,
    parser_id: kbObj.parser_id,
    layout_recognize: true,
  }
  let raptor = {}
  if(kbObj.parser_config && kbObj.parser_config.raptor){
    raptor = kbObj.parser_config.raptor;
    Object.assign(form,{
      ...configObj,
      ...raptor,
      use_raptor: kbObj.parser_config.raptor.use_raptor,
    });
  }else{
    Object.assign(form,configObj);
  }
  console.log(form,'配置页面表单信息');
}
defineExpose({
  changekbObj
})
onBeforeMount(()=>{
  queryModel({})
})
onMounted(()=>{
})
</script>
<script lang="ts">
import { IconEdit, IconPlus } from "@arco-design/web-vue/es/icon";
export default {
  name: "config",
  components: { IconPlus, IconEdit },
  methods: {}
};
</script>
<style scoped lang="less">
.main-container {
  position: relative;
  display: flex;
  justify-content: space-between;
  height: 100%;
  overflow: auto;
  //background: #626aea;
  background: var(--color-bg-2);
  padding-top: 80px;
  &-lf {
    width: 40%;
    //height: 100%;
    //border: 1px solid #cccccc;
    border-radius: 10px;
    //border: 1px solid var(--color-fill-3);
    &-top {
      width: 100%;
      height: 60px;
      line-height: 60px;
      //background: rgb(var(--primary-6));
      //color: #ffffff;
      //text-align: center;
    }
    &-down {
      padding: 20px;
      width: 100%;
    }
  }
  &-form-item-extra {
    width: 100%;
    height: 20rem;
    border: 1px solid var(--color-fill-3);
    border-radius: 6px;
    overflow: hidden;
    &-top {
      width: 100%;
      height: 40px;
      line-height: 40px;
      border-bottom: 1px solid var(--color-fill-3);
      //background: rgb(var(--primary-6));
      color: #999999;
      text-align: center;
    }
    &-down {
      width: 92%;
      margin-left: 4%;
      margin-top: 30px;
    }
    &-btn {
      width: 96%;
      text-align: right;
      margin-top: 1rem;
    }
  }
  &-rt {
    width: 60%;
    //background: #626aea;
    //border: 1px solid #cccccc;
    border-radius: 10px;
    overflow: hidden;
    padding: 20px;
    section {
      width: 100%;
      //color: #333333;
      color: var(--color-text-1);
    }
  }
}
</style>
src/views/dmx/knowledgeLib/index.vue
@@ -10,7 +10,7 @@
          />
          <addKnow @getknowledge="getknowledge" @getKbdetail="getKbdetail"></addKnow>
        </div>
        <div class="lf-container-down">
        <a-spin :loading="listloading" class="lf-container-down">
          <a-scrollbar style="height:56rem;overflow: auto;">
            <div
              class="tab"
@@ -23,15 +23,15 @@
              <a-popover position="bl">
                <icon-more  :style="{position: 'absolute',top:'10px',right:'20px'}"/>
                <template #content>
                  <a-popconfirm content="确定删除吗?" @ok="deleteKnowledge(tab.id)" type="warning">
                    <span style="cursor: pointer;color: #4977ba;font-size: 12px"><icon-delete style="font-size: 14px"/>删除</span>
                  </a-popconfirm>
<!--                  <span style="cursor: pointer;color: #0960bd;font-size: 12px" @click="deleteKnowledge(tab.id)"><icon-delete />删除</span>-->
<!--                  <a-popconfirm content="确定删除吗?" @ok="deleteKnowledge(tab.id)" type="warning">-->
<!--                    <span style="cursor: pointer;color: #4977ba;font-size: 12px"><icon-delete style="font-size: 14px"/>删除</span>-->
<!--                  </a-popconfirm>-->
                  <span style="cursor: pointer;color: #4977ba;font-size: 12px" @click="deleteKnowledge(tab.id)"><icon-delete style="font-size: 14px" />删除</span>
                </template>
              </a-popover>
            </div>
          </a-scrollbar>
          </div>
          </a-spin>
      </div>
      <div class="rt-container" v-if="tabs.length > 0">
        <a-tabs :activeKey="activeKey" @change="handleTabChange">
@@ -257,7 +257,7 @@
          </a-tab-pane>
          <a-tab-pane key="3" :title="t('dmx.list.disposition')">
            <div class="rt-container-main">
              <config ref="configForm" :kbtenantInfo="kbtenantInfo"  :kbobj="kbobj"  @cancleConfig="cancleConfig" @saveConfig="saveConfig"></config>
              <config ref="configForm" :kbtenantInfo="kbtenantInfo" @cancleConfig="cancleConfig" @saveConfig="saveConfig"></config>
            </div>
          </a-tab-pane>
        </a-tabs>
@@ -335,8 +335,9 @@
  import docx from '@/views/dmx/knowledgeLib/components/docx.vue'
  import excel from '@/views/dmx/knowledgeLib/components/excel.vue'
  import txtPdf from '@/views/dmx/knowledgeLib/components/txtPdf.vue'
  import { Message } from "@arco-design/web-vue";
import { Message, Modal } from "@arco-design/web-vue";
  import { parseTime } from "@/utils";
import { deleteLlm } from "@/api/model";
  type SizeProps = 'mini' | 'small' | 'medium' | 'large';
  type Column = TableColumnData & { checked?: true };
  const account = ref(null)
@@ -359,6 +360,7 @@
  const size = ref<SizeProps>('medium');
  let visible = ref(false)
  let listloading = ref(false)
  let keywords = ref('')
  let activeKey = ref('1')
  let detailsShow = ref(false)
@@ -550,7 +552,7 @@
  const knowledgeData = async (
    params = { page: 1, page_size: 20 }
  ) => {
    setLoading(true);
    listloading.value = true;
    try {
      const { data } = await queryKbList(params);
      // console.log(data, 'data');
@@ -576,7 +578,7 @@
    } catch (err) {
      // you can report use errorHandler or other
    } finally {
      setLoading(false);
      listloading.value = false;
    }
  };
@@ -619,14 +621,24 @@
  }
};
  const deleteKnowledge = async (id) => {
    let data = await deleteKnow({
      kb_id:id
    })
    if(data.code == 0){
      Message.success('删除成功');
      knowledgeData()
    }
  const deleteKnowledge = (id) => {
    Modal.confirm({
      title: '提示信息',
      content: '确认删除吗',
      okText: '确定',
      cancelText: '取消',
      hideTitle: true,
      onOk: async () => {
        let data = await deleteKnow({
          kb_id:id
        })
        if(data.code == 0){
          Message.success('删除成功');
          knowledgeData()
        }
      },
      onCancel: () => {},
    });
  }
  const reset = () => {
    formModel.value = generateFormModel();
src/views/dmx/knowledgeLib/test.vue
@@ -39,7 +39,7 @@
                  <a-textarea v-model="form.question" style="height: 10rem;border: 1px solid  var(--color-fill-3);border-radius: 4px" placeholder="" allow-clear/>
                </div>
                <div class="main-container-form-item-extra-btn">
                  <a-button :disabled="!form.question" type="primary" html-type="submit">测试</a-button>
                  <a-button :disabled="!form.question" :loading="loading" type="primary" html-type="submit">测试</a-button>
                </div>
              </div>
            </a-form-item>
@@ -110,9 +110,17 @@
    delete formObj.rerank_id;
  }
  try {
    loading.value = true;
    const data = await kbretrievalTest(formObj);
    if(data.code == 0){
      Message.success('测试成功');
    }else{
      Message.error('测试失败');
    }
    loading.value = false;
  }catch (err){
    Message.error(err.message);
    loading.value = false;
  }
}
src/views/session/sessionRecordsManager/index.vue
@@ -306,6 +306,7 @@
  import { useAppStore } from '@/store';
  import { computed, nextTick, onMounted, reactive, ref } from 'vue';
  import { Message } from '@arco-design/web-vue';
  import { EventSourceParserStream } from 'eventsource-parser/stream';
  import moment from 'moment';
  import AddSession from '@/views/session/sessionManager/components/addSession.vue';
  import {
@@ -314,6 +315,8 @@
    getSessionDetailsApi,
    sessionListApi,
  } from '@/api/session';
  import { getAuthorization } from "@/utils/auth";
  const sessionDetailList = ref([]); //根据会话id出来的会话详情
  const sessionList = ref([]); //会话列表
@@ -353,30 +356,49 @@
      return;
    }
    if (inputMsg.value) {
      const data = await chatApi({
        conversation_id: activeSessionId.value,
        messages: inputMsg.value,
      sessionDetailList.value.push({ "content": inputMsg.value, "role": "user" });
      sessionDetailList.value.push({  "role": "last" });
      refreshScroll();
      const response = await fetch("/api/tech/cloudminds/query?modeltype=localragflow", {
        method: 'POST',
        headers: {
          'Authorization': getAuthorization(),
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          conversation_id: activeSessionId.value,
          messages: inputMsg.value,
        }),
      });
      if (data) {
        chatDis.value = false;
        // inputMsg.value = '';
        // querySessionDetail({ id: activeSessionId.value });
      }
      const res = await getSessionDetailsApi(activeSessionId.value);
      if (res.code === 200) {
        sessionDetailList.value = res.data.message.map((item, index) => {
          if (index === res.data.message.length - 1) {
            item.role = 'last';
            displayedText.value = '';
            currIndex.value = 0;
            streamStr.value = item.content;
            startDisplayStr();
      const reader = response?.body
        ?.pipeThrough(new TextDecoderStream())
        .pipeThrough(new EventSourceParserStream())
        .getReader();
      currIndex.value = 0;
      while (true) {
        const x = await reader?.read();
        if (x) {
          const { done, value } = x;
          try {
            const val = JSON.parse(value?.data || '');
            const d = val?.data;
            if (typeof d !== "boolean") {
              console.info("data:", d);
              streamStr.value = d.content;
              startDisplayStr();
            }
          } catch (e) {
            console.warn(e);
          }
          return item;
        });
        refreshScroll();
          if (done) {
            console.info('done');
            break;
          }
        }
      }
      chatDis.value=false;
      inputMsg.value = '';
    } else {
      Message.warning('消息不能为空');
@@ -428,6 +450,7 @@
      displayedText.value += res[currIndex.value];
      currIndex.value++;
      setTimeout(startDisplayStr, 100);
      refreshScroll();
    } else {
      clearTimeout(timer!);
      timer = null;
yarn.lock
@@ -3253,6 +3253,11 @@
  resolved "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.1.tgz"
  integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
eventsource-parser@^2.0.1:
  version "2.0.1"
  resolved "https://registry.npmmirror.com/eventsource-parser/-/eventsource-parser-2.0.1.tgz#6464341d64de5bea9f31d8063dd312b616146c7a"
  integrity sha512-gMaRLm5zejEH9mNXC54AnIteFI9YwL/q5JKMdBnoG+lEI1JWVGFVk0Taaj9Xb5SKgzIBDZoQX5IzMe44ILWODg==
exec-buffer@^3.0.0:
  version "3.2.0"
  resolved "https://registry.npmmirror.com/exec-buffer/-/exec-buffer-3.2.0.tgz"