zhangxiao
2024-08-26 d70dde0930d7bfd5ba8c3b4279bf310ec0b60283
fix: 修改上传
2个文件已修改
3个文件已添加
694 ■■■■ 已修改文件
src/assets/images/icon-histy.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/icon-new.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/icon-zhi.png 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sessionManager/components/updataFile.vue 693 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sessionManager/index.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/icon-histy.png
src/assets/images/icon-new.png
src/assets/images/icon-zhi.png
src/views/sessionManager/components/updataFile.vue
@@ -1,18 +1,7 @@
<template>
  <a-popover
    :popup-visible="visible"
    title=""
    trigger="click"
    position="tl">
    <a-button
      type="text"
      style="border-radius: 24px"
      @click="visibleChange"
    >
      <icon-attachment
        size="28"
        style="color: #0960bd"
      />
  <a-popover :popup-visible="visible" title="" trigger="click" position="tl">
    <a-button type="text" style="border-radius: 24px" @click="visibleChange">
      <icon-attachment size="28" style="color: #0960bd" />
    </a-button>
    <template #title>
      <div style="display: flex; justify-content: space-between">
@@ -33,26 +22,45 @@
        multiple
        :limit="1"
      />
      <div style="width: 100%;margin-top: 10px;display: flex; justify-content: space-between;" class="upload-wrap">
      <div
        style="
          width: 100%;
          margin-top: 10px;
          display: flex;
          justify-content: space-between;
        "
        class="upload-wrap"
      >
        <div>
          <span>解析方法: </span>
          <a-radio-group v-model="parser_id" style="width: 400px;" @change="parserChange">
            <a-popover title=""
             v-for="item in filterData"
             :key="item.value"
            >
              <a-radio
                :value="item.value"
                style="margin-right: 10px"
              >{{item.name}}</a-radio>
          <a-radio-group
            v-model="parser_id"
            style="width: 400px"
            @change="parserChange"
          >
            <a-popover v-for="item in filterData" :key="item.value">
              <a-radio :value="item.value" style="margin-right: 10px">{{
                item.name
              }}</a-radio>
              <!-- <template #content>
                <p style="max-width: 300px">{{ item.parser_config_str }}</p>
              </template> -->
              <template #content>
                <p style="max-width: 300px">{{item.parser_config_str}}</p>
                <p>{{ item.parser_config_str }}</p>
              </template>
            </a-popover>
          </a-radio-group>
        </div>
        <a-select :style="{width:'100px', margin: '0 10px'}" :default-value="['通用', '多模态']" v-model="parser_configs" multiple size="small">
          <a-option v-for="item in parser_ids" :key="item.value">{{ item.name }}</a-option>
        <a-select
          :style="{ width: '100px', margin: '0 10px' }"
          :default-value="['通用', '多模态']"
          v-model="parser_configs"
          multiple
          size="small"
        >
          <a-option v-for="item in parser_ids" :key="item.value">{{
            item.name
          }}</a-option>
        </a-select>
        <p class="config-text">更多配置</p>
        <a-button
@@ -60,11 +68,9 @@
          @click="upDataFile"
          type="primary"
          size="mini"
          style="border-radius: 24px;"
          style="border-radius: 24px"
        >
          <span style="font-size: 12px;">
            上传
          </span>
          <span style="font-size: 12px"> 上传 </span>
        </a-button>
      </div>
    </template>
@@ -72,336 +78,333 @@
</template>
<script lang="ts" setup>
import { onMounted, onBeforeMount, reactive, ref, computed, watch } from "vue";
import axios from "axios";
import { Message } from "@arco-design/web-vue";
import { addSessionApi, getParseMethodsListApi, getSessionDetailsApi, uploadWithoutKb } from "@/api/session";
  import {
    onMounted,
    onBeforeMount,
    reactive,
    ref,
    computed,
    watch,
  } from 'vue';
  import axios from 'axios';
  import { Message } from '@arco-design/web-vue';
  import {
    addSessionApi,
    getParseMethodsListApi,
    getSessionDetailsApi,
    uploadWithoutKb,
  } from '@/api/session';
const visible = ref(false);
const loading = ref(false);
const chatDis = ref(false);
const directory = ref(false);
const filesBtn = ref(null);
const onFileSelectedLoading = ref(false);
const parser_id = ref("");
const parseridConfig = ref(false);
const uploaditemList = ref([]);
const activeSessionId = ref('');
let kbtenantInfo = reactive({
  asr_id: 'paraformer-realtime-8k-v1',
  embd_id: 'BAAI/bge-large-zh-v1.5',
  img2txt_id: 'qwen-vl-max',
  llm_id: 'qwen-plus',
  name: 'wanghaos Kingdom',
  // parser_ids: 'naive:General,qa:Q&A,resume:Resume,manual:Manual,table:Table,paper:Paper,book:Book,laws:Laws,presentation:Presentation,picture:Picture,one:One',
  parser_ids: 'naive:通用,qa:Q&A,resume:简历,manual:说明书,table:表格,paper:多模态,book:书籍,laws:法律文件,presentation:PPT,picture:图片,one:整体',
  rerank_id: 'BAAI/bge-reranker-v2-m3',
  role: 'owner',
  tenant_id: '948fc6fa41ab11ef8fb80242ac120004',
  parser_idObj: {},
});
const parser = reactive({
  naive: {
    "chunk_token_num": 676,
    "layout_recognize": true,
    "raptor": {
      "use_raptor": true,
      "prompt": "请总结以下段落。 小心数字,不要编造。 段落如下:\n      {cluster_content}\n以上就是你需要总结的内容。",
      "max_token": 600,
      "threshold": 0.32,
      "max_cluster": 233,
      "random_seed": 1500
    }
  }, // 用户名
  qa: {
    "entity_types": [
      "organization",
      "person",
      "location",
      "event",
      "time"
    ],
    "raptor": {
      "use_raptor": false
    }
  },
  resume: {},
  manual: {},
  table: {},
  paper: {},
  book: {},
  laws: {},
  presentation: {},
  picture: {},
  one: {},
});
const parser_configs = ref(['通用', '多模态']);
const parser_ids = ref([
  {
    name: '通用',
    value: 'naive',
    parser_config: parser.naive,
    parser_config_str: '支持的文件格式为DOCX、EXCEL、PPT、IMAGE、PDF、TXT'
  },
  {
    name: 'Q&A',
    value: 'qa',
    parser_config: parser.qa,
    parser_config_str: '支持 excel 和 csv/txt 文件格式。 \n' +
      '如果文件以 excel 格式,则应由两个列组成 没有标题:一个提出问题,另一个用于答案, 答案列之前的问题列。\n' +
      '如果文件以 csv/txt 格式为 用作分开问题和答案的定界符。\n'
  },
  {
    name: '简历',
    value: 'resume',
    parser_config: parser.resume,
    parser_config_str: '支持的文件格式为DOCX、PDF、TXT'
  },
  {
    name: '说明书',
    value: 'manual',
    parser_config: parser.manual,
    parser_config_str: '仅支持PDF'
  },
  {
    name: '表格',
    value: 'table',
    parser_config: parser.table,
    parser_config_str: '支持EXCEL和CSV/TXT格式文。 \n' +
      '对于 csv 或 txt 文件,列之间的分隔符为 TAB,\n' +
      '第一行必须是列标题。\n'
  },
  {
    name: '多模态',
    value: 'paper',
    parser_config: parser.paper,
    parser_config_str: '仅支持PDF文件'
  },
  {
    name: '书籍',
    value: 'book',
    parser_config: parser.book,
    parser_config_str: '支持的文件格式为DOCX、PDF、TXT'
  },
  {
    name: '法律文件',
    value: 'laws',
    parser_config: parser.laws,
    parser_config_str: '支持的文件格式为DOCX、PDF、TXT'
  },
  {
    name: 'PPT',
    value: 'presentation',
    parser_config: parser.presentation,
    parser_config_str: '支持的文件格式为PDF、PPTX'
  },
  {
    name: '图片',
    value: 'picture',
    parser_config: parser.picture,
    parser_config_str: '支持图像文件'
  },
  {
    name: '整体',
    value: 'one',
    parser_config: parser.one,
    parser_config_str: '支持的文件格式为DOCX、EXCEL、PDF、TXT'
  },
]);
const parser_idsArr = ref([]);
const uploadList = ref([]);
const props = defineProps(["sessionId"]);
const emit = defineEmits(["selectFileCallback"]);
const uploadRef = ref();
const files = ref([]);
const acceptNameList = computed(() => {
  return ".word, .pdf, .ppt, .excel, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .pptx, .ppt, .pdf, .mp4, .avi, .mp3,.wav, .wma, .wmv, .rm,";
});
const filterData = computed(() => {
  const result = parser_ids.value.filter(val => parser_configs.value.includes(val.name)).reverse().slice(0,4).reverse();
  result.unshift({
    name: '智能识别',
    value: '',
    parser_config_str: '',
    parser_config: ''
  const visible = ref(false);
  const loading = ref(false);
  const chatDis = ref(false);
  const directory = ref(false);
  const filesBtn = ref(null);
  const onFileSelectedLoading = ref(false);
  const parser_id = ref('');
  const parseridConfig = ref(false);
  const uploaditemList = ref([]);
  const activeSessionId = ref('');
  let kbtenantInfo = reactive({
    asr_id: 'paraformer-realtime-8k-v1',
    embd_id: 'BAAI/bge-large-zh-v1.5',
    img2txt_id: 'qwen-vl-max',
    llm_id: 'qwen-plus',
    name: 'wanghaos Kingdom',
    // parser_ids: 'naive:General,qa:Q&A,resume:Resume,manual:Manual,table:Table,paper:Paper,book:Book,laws:Laws,presentation:Presentation,picture:Picture,one:One',
    parser_ids:
      'naive:通用,qa:Q&A,resume:简历,manual:说明书,table:表格,paper:多模态,book:书籍,laws:法律文件,presentation:PPT,picture:图片,one:整体',
    rerank_id: 'BAAI/bge-reranker-v2-m3',
    role: 'owner',
    tenant_id: '948fc6fa41ab11ef8fb80242ac120004',
    parser_idObj: {},
  });
  return result;
});
const init = () => {
  // parser_ids.value = kbtenantInfo.parser_ids.split(",").map((item) => {
  //   const [value1, value2] = item.split(":");
  //   return {
  //     name: value2,
  //     value: value1
  //   };
  // });
  getParseMethodsList();
}
const chooseParser = (item) => {
  console.log(item);
};
const onChange = (fileList) => {
  files.value = fileList;
  files.value.forEach((item) => {
  const parser = reactive({
    naive: {
      chunk_token_num: 676,
      layout_recognize: true,
      raptor: {
        use_raptor: true,
        prompt:
          '请总结以下段落。 小心数字,不要编造。 段落如下:\n      {cluster_content}\n以上就是你需要总结的内容。',
        max_token: 600,
        threshold: 0.32,
        max_cluster: 233,
        random_seed: 1500,
      },
    }, // 用户名
    qa: {
      entity_types: ['organization', 'person', 'location', 'event', 'time'],
      raptor: {
        use_raptor: false,
      },
    },
    resume: {},
    manual: {},
    table: {},
    paper: {},
    book: {},
    laws: {},
    presentation: {},
    picture: {},
    one: {},
  });
  const parser_configs = ref(['通用', '多模态']);
  const parser_ids = ref([
    {
      name: '通用',
      value: 'naive',
      parser_config: parser.naive,
      parser_config_str: '支持的文件格式为DOCX、EXCEL、PPT、IMAGE、PDF、TXT',
    },
    {
      name: 'Q&A',
      value: 'qa',
      parser_config: parser.qa,
      parser_config_str:
        '支持 excel 和 csv/txt 文件格式。 \n' +
        '如果文件以 excel 格式,则应由两个列组成 没有标题:一个提出问题,另一个用于答案, 答案列之前的问题列。\n' +
        '如果文件以 csv/txt 格式为 用作分开问题和答案的定界符。\n',
    },
    {
      name: '简历',
      value: 'resume',
      parser_config: parser.resume,
      parser_config_str: '支持的文件格式为DOCX、PDF、TXT',
    },
    {
      name: '说明书',
      value: 'manual',
      parser_config: parser.manual,
      parser_config_str: '仅支持PDF',
    },
    {
      name: '表格',
      value: 'table',
      parser_config: parser.table,
      parser_config_str:
        '支持EXCEL和CSV/TXT格式文。 \n' +
        '对于 csv 或 txt 文件,列之间的分隔符为 TAB,\n' +
        '第一行必须是列标题。\n',
    },
    {
      name: '多模态',
      value: 'paper',
      parser_config: parser.paper,
      parser_config_str: '仅支持PDF文件',
    },
    {
      name: '书籍',
      value: 'book',
      parser_config: parser.book,
      parser_config_str: '支持的文件格式为DOCX、PDF、TXT',
    },
    {
      name: '法律文件',
      value: 'laws',
      parser_config: parser.laws,
      parser_config_str: '支持的文件格式为DOCX、PDF、TXT',
    },
    {
      name: 'PPT',
      value: 'presentation',
      parser_config: parser.presentation,
      parser_config_str: '支持的文件格式为PDF、PPTX',
    },
    {
      name: '图片',
      value: 'picture',
      parser_config: parser.picture,
      parser_config_str: '支持图像文件',
    },
    {
      name: '整体',
      value: 'one',
      parser_config: parser.one,
      parser_config_str: '支持的文件格式为DOCX、EXCEL、PDF、TXT',
    },
  ]);
  const parser_idsArr = ref([]);
  const uploadList = ref([]);
  const props = defineProps(['sessionId']);
  const emit = defineEmits(['selectFileCallback']);
  const uploadRef = ref();
  const files = ref([]);
  const acceptNameList = computed(() => {
    return '.word, .pdf, .ppt, .excel, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .pptx, .ppt, .pdf, .mp4, .avi, .mp3,.wav, .wma, .wmv, .rm,';
  });
};
const parserChange = ()=>{
  parseridConfig.value = false;
}
const visibleChange = (e) => {
  e.stopPropagation();
  visible.value = !visible.value;
}
const getIconByExtension = (extension) => {
  const fileExtension = ref('');
  fileExtension.value = extension.split('.').pop();
  let type = '';
  parser_idsArr.value.forEach((item)=>{
    // 包含元素
    if (item.formats.includes(fileExtension.value)){
      type = item.id;
    }
  })
  return type;
};
const upDataFile = async () => {
  // if (!activeSessionId.value) {
  //   //新建会话
  //   const res = await addSessionApi({
  //     dialog_id: '',
  //     conversation_desc: '',
  //   });
  //   // console.log(res, "res");
  //   if (res.code == 200) {
  //     // console.log(res.data.conversation_id);
  //     activeSessionId.value = res.data?.conversation_id;
  //     const { code, data } = await getSessionDetailsApi(res.data?.conversation_id);
  //     if (code === 200) {
  //       console.log(data, '新建会话详情');
  //     }
  //   } else {
  //     Message.error('创建会话失败,请重试');
  //   }
  // }
  console.log(files.value, "files");
  console.log(parser_ids.value, "解析方法");
  if(files.value.length == 0){
    Message.warning('请选择文件');
    return;
  }
  uploaditemList.value = files.value.map((item,index)=>{
    return {
      index: index,
      name: item.name,
      size: (item.file.size/1024).toFixed(2) + 'K',
    }
  })
  onFileSelectedLoading.value = true;
  const formData = new FormData();
  for (let i = 0; i < files.value.length; i++) {
    formData.append('file', files.value[i].file);
    formData.append('conversation_id', activeSessionId.value);
    formData.append('parser_config', '');
    if(!parser_id.value){
      formData.append('parser_id', getIconByExtension(files.value[i].name));
    }else{
      formData.append('parser_id', parser_id.value);
    }
  }
  uploadWithoutKb(formData).then((res) => {
    onFileSelectedLoading.value = false;
    if (res.code == 200) {
      cancel();
      // uploaditemList.value = [];
      emit('selectFileCallback', uploaditemList.value);
      Message.success('上传成功');
    } else {
      Message.error('上传失败');
    }
  });
};
const cancel = () => {
  if(!onFileSelectedLoading.value){
    visible.value = false;
    parser_id.value = "";
  }
};
defineExpose({
  cancel
})
const getParseMethodsList = async () => {
  let res = await getParseMethodsListApi();
  parser_ids.value = res.data.map((item) => {
    return {
      name: item.name,
      value: item.id,
  const filterData = computed(() => {
    const result = parser_ids.value
      .filter((val) => parser_configs.value.includes(val.name))
      .reverse()
      .slice(0, 4)
      .reverse();
    result.unshift({
      name: '智能识别',
      value: '',
      parser_config_str: '',
      parser_config: '',
      parser_config_str: item.parser_config_str
    };
    });
    return result;
  });
  parser_idsArr.value = res.data;
}
  const init = () => {
    // parser_ids.value = kbtenantInfo.parser_ids.split(",").map((item) => {
    //   const [value1, value2] = item.split(":");
    //   return {
    //     name: value2,
    //     value: value1
    //   };
    // });
    getParseMethodsList();
  };
onBeforeMount(() => {
  init();
  const chooseParser = (item) => {
    console.log(item);
  };
  const onChange = (fileList) => {
    files.value = fileList;
    files.value.forEach((item) => {});
  };
  const parserChange = () => {
    parseridConfig.value = false;
  };
  const visibleChange = (e) => {
    e.stopPropagation();
    visible.value = !visible.value;
  };
});
onMounted(() => {
});
  const getIconByExtension = (extension) => {
    const fileExtension = ref('');
    fileExtension.value = extension.split('.').pop();
    let type = '';
    parser_idsArr.value.forEach((item) => {
      // 包含元素
      if (item.formats.includes(fileExtension.value)) {
        type = item.id;
      }
    });
    return type;
  };
watch(
  ()=>props.sessionId,
  (value, oldValue)=>{
     activeSessionId.value = value;
  }
)
  const upDataFile = async () => {
    if (!activeSessionId.value) {
      //新建会话
      const res = await addSessionApi({
        dialog_id: '',
        conversation_desc: '',
      });
      // console.log(res, "res");
      if (res.code == 200) {
        // console.log(res.data.conversation_id);
        activeSessionId.value = res.data?.conversation_id;
        const { code, data } = await getSessionDetailsApi(
          res.data?.conversation_id
        );
        if (code === 200) {
          console.log(data, '新建会话详情');
        }
      } else {
        Message.error('创建会话失败,请重试');
      }
    }
    console.log(files.value, 'files');
    console.log(parser_ids.value, '解析方法');
    if (files.value.length == 0) {
      Message.warning('请选择文件');
      return;
    }
    uploaditemList.value = files.value.map((item, index) => {
      return {
        index: index,
        name: item.name,
        size: (item.file.size / 1024).toFixed(2) + 'K',
      };
    });
    onFileSelectedLoading.value = true;
    const formData = new FormData();
    for (let i = 0; i < files.value.length; i++) {
      formData.append('file', files.value[i].file);
      formData.append('conversation_id', activeSessionId.value);
      formData.append('parser_config', '');
      if (!parser_id.value) {
        formData.append('parser_id', getIconByExtension(files.value[i].name));
      } else {
        formData.append('parser_id', parser_id.value);
      }
    }
    uploadWithoutKb(formData).then((res) => {
      onFileSelectedLoading.value = false;
      if (res.code == 200) {
        cancel();
        // uploaditemList.value = [];
        emit('selectFileCallback', uploaditemList.value);
        Message.success('上传成功');
      } else {
        Message.error('上传失败');
      }
    });
  };
  const cancel = () => {
    if (!onFileSelectedLoading.value) {
      visible.value = false;
      parser_id.value = '';
    }
  };
  defineExpose({
    cancel,
  });
  const getParseMethodsList = async () => {
    let res = await getParseMethodsListApi();
    parser_ids.value = res.data.map((item) => {
      return {
        name: item.name,
        value: item.id,
        parser_config: '',
        parser_config_str: item.parser_config_str,
      };
    });
    parser_idsArr.value = res.data;
  };
  onBeforeMount(() => {
    init();
  });
  onMounted(() => {});
  watch(
    () => props.sessionId,
    (value, oldValue) => {
      activeSessionId.value = value;
    }
  );
</script>
<style>
.upload-wrap .arco-select-view-inner{
  display: none;
}
  .upload-wrap .arco-select-view-inner {
    display: none;
  }
</style>
<style scoped lang="less">
.aUpload {
  width: 100%;
  max-height: 500px;
  overflow: hidden;
  overflow-y: auto;
}
.upload-wrap {
  position: relative;
}
.config-text {
  position: absolute;
  right: 70px;
  bottom: -11px;
  font-size: 12px;
}
  .aUpload {
    width: 100%;
    max-height: 500px;
    overflow: hidden;
    overflow-y: auto;
  }
  .upload-wrap {
    position: relative;
  }
  .config-text {
    position: absolute;
    right: 70px;
    bottom: -11px;
    font-size: 12px;
  }
</style>
src/views/sessionManager/index.vue
@@ -729,6 +729,7 @@
  // 发送
  const sentClick = () => {
    sendMessage('click');
    uploaditemList.value = [];
  };
  // 重新生成
  const reGenerate = () => {