yinbangzhong
2024-08-19 9650fe79e821c69c04bbc27ee32767f7c718a288
src/views/sessionManager/index.vue
@@ -1,14 +1,18 @@
<template>
  <div class="container">
<!--    <AddSession-->
<!--      :modalObj="modalObj"-->
<!--      @addSession="addSession"-->
<!--      :dialogId="dialogId"-->
<!--    ></AddSession>-->
    <!--    <AddSession-->
    <!--      :modalObj="modalObj"-->
    <!--      @addSession="addSession"-->
    <!--      :dialogId="dialogId"-->
    <!--    ></AddSession>-->
    <!--    <a-card class="top-title">AI会话记录</a-card>-->
    <a-row :gutter="[5, 5]" style="margin-top: 3px;">
    <a-row :gutter="[5, 5]" style="margin-top: 3px">
      <a-col :span="1">
        <chatMenu @createSession="createSession" @querySessionDetail="querySessionDetail" @changeAgentType="changeAgentType"></chatMenu>
        <chatMenu
          @createSession="createSession"
          @querySessionDetail="querySessionDetail"
          @changeAgentType="changeAgentType"
        ></chatMenu>
      </a-col>
      <!--      智能体会话-->
      <a-col :span="23" v-show="agentType == '1'">
@@ -16,7 +20,7 @@
          <div class="header___lEPyH">
            <div class="chatHeader">
              <div class="chatHeaderBox">
                <span class="title">{{agentTitle}}</span>
                <span class="title">{{ agentTitle }}</span>
              </div>
            </div>
          </div>
@@ -25,13 +29,13 @@
            id="home"
            class="chat-list"
            style="
              width: 90%;
              width: 80%;
              overflow: auto;
              height: calc(100vh - 300px);
              height: calc(100vh - 380px);
              margin: 0px auto 20px;
            "
          >
            <div class="chat-item" v-for="sessionDetail in sessionDetailList">
            <div class="chat-item" v-for="(sessionDetail,index) in sessionDetailList">
              <a-comment v-if="sessionDetail.role === 'user'">
                <template #avatar>
                  <img
@@ -55,11 +59,30 @@
                  />
                </template>
                <template #content>
                  <a-card :class="{ chatItemAnswer: theme === 'light' }">
                    <div :class="{ light: theme === 'light' }"
                    >{{ sessionDetail.content }}
                    </div>
                  </a-card>
                  <!--                  <a-card :class="{ chatItemAnswer: theme === 'light' }">-->
                  <!--                    <div-->
                  <!--                      :class="{ light: theme === 'light' }"-->
                  <!--                      v-html="sessionDetail.content.replace(/\n/g, '<br/>')"-->
                  <!--                    >-->
                  <!--                    </div>-->
                  <!--                  </a-card>-->
                  <a-textarea
                    readonly
                    auto-size
                    v-model="sessionDetail.content"
                    :class="{ chatItemAnswer: theme === 'light' }"
                    :style="{backgroundColor: theme === 'light' ? '#ffffff' : '#000000'}"
                    style="border: none"
                  >
                  </a-textarea>
                </template>
                <template #actions>
                  <span class="action" v-if="index != 0" @click="copy(sessionDetail.content)">
                     <icon-copy /> 复制
                  </span>
                  <span class="action"  v-if="index != 0 && index == sessionDetailList.length - 1" @click="reGenerate()">
                     <icon-refresh /> 重新生成
                  </span>
                </template>
              </a-comment>
              <a-comment v-else-if="sessionDetail.role === 'last'">
@@ -76,8 +99,18 @@
                    auto-size
                    v-model="displayedText"
                    :class="{ chatItemAnswer: theme === 'light' }"
                    :style="{backgroundColor: theme === 'light' ? '#ffffff' : '#000000'}"
                    style="border: none"
                  >
                  </a-textarea>
                </template>
                <template #actions>
                  <div class="action"
                       @click="stopChat"
                       style="background: var(--color-bg-2);color: var(--color-primary-light-4);" v-if="displayedText != ''">
                     <icon-record-stop />
                    停止生成
                  </div>
                </template>
              </a-comment>
            </div>
@@ -86,7 +119,8 @@
            >
            <div class="chartStart v-else" @click="stopChat">重新生成</div> -->
          </a-scrollbar>
          <div class="chat_bottom">
          <div class="chat_bottom" >
            <div class="center-bottom">
              <!-- <a-textarea
              v-model="inputMsg"
@@ -107,23 +141,36 @@
                show-word-limit
                :disabled="chatDis"
                :class="{ textItemAnswer: theme === 'dark' }"
                :style="{backgroundColor: theme === 'light' ? '#ffffff' : '#000000'}"
                style="border: none"
                :auto-size="{
                  minRows: 12,
                  maxRows: 5,
                }"
              />
              <div style="margin-left: 20px">
                <a-upload
                  ref="uploadRef"
                  :file-list="uploadList"
                  :disabled="loading1"
                  multiple
                  :custom-request="customRequest"
                          style="font-size: 24px;">
                  <template #upload-button>
                    <icon-attachment style="color: #0960bd"/>
                  </template>
                </a-upload>
              </div>
              <div class="btn-send">
                <!-- <icon-send size="32" /> -->
                <a-button
                  :disabled="chatDis"
                  @click="sentClick"
                  type="primary"
                  type="text"
                  style="border-radius: 24px"
                  :loading="loading"
                  size="large"
                >发送
                </a-button
                >
                ><icon-send size="32" style="color: #0960bd"/>
                </a-button>
              </div>
            </div>
          </div>
@@ -136,12 +183,19 @@
      </a-col>
      <a-col :span="23" v-show="agentType == '3'">
        <div class="center" style="padding: 0">
          <historySession @querySessionDetail="querySessionDetail" @changeAgentType="changeAgentType"></historySession>
          <historySession
            @querySessionDetail="querySessionDetail"
            @changeAgentType="changeAgentType"
          ></historySession>
        </div>
      </a-col>
      <a-col :span="23" v-show="agentType == '4'">
        <div class="center" style="padding: 0">
          <smartAi @createSession="createSession" @querySessionDetail="querySessionDetail" @changeAgentType="changeAgentType"></smartAi>
          <smartAi
            @createSession="createSession"
            @querySessionDetail="querySessionDetail"
            @changeAgentType="changeAgentType"
          ></smartAi>
        </div>
      </a-col>
    </a-row>
@@ -154,7 +208,16 @@
  IconTiktokColor
} from "@arco-design/web-vue/es/icon";
import { useAppStore, useUserStore } from "@/store";
import { computed, nextTick, onMounted, watch, reactive, ref, onBeforeMount, onBeforeUnmount } from "vue";
import {
  computed,
  nextTick,
  onMounted,
  watch,
  reactive,
  ref,
  onBeforeMount,
  onBeforeUnmount
} from "vue";
import { Message } from "@arco-design/web-vue";
import { EventSourceParserStream } from "eventsource-parser/stream";
@@ -170,21 +233,23 @@
  chatApi,
  getDialogListApi,
  getSessionDetailsApi,
  sessionListApi
  sessionListApi, uploadWithoutKb
} from "@/api/session";
import { getAuthorization } from "@/utils/auth";
import { queryCanvasList } from "@/api/Agent";
import { getAgentSessionDetailsApi } from "@/api/agentSession";
import useClipboard from "vue-clipboard3";
const sessionDetailList = ref([]); //根据会话id出来的会话详情
const sessionList = ref([]); //会话列表
const modalObj = reactive({ add: false });
const dialogId = ref("");
const chatDis = ref(false);
const loading = ref(false);
const loading1= ref(false);
const agentType = ref("1");
const agentTitle = ref("未命名会话");
let chatObj = reactive({});
const isStopChat = ref(false)
const currIndex = ref(0);
const displayedText = ref(""); // 正在显示的文字
let timer: number | null = null;
@@ -198,6 +263,51 @@
const agentList = ref([]);
const selectValue = ref("");
const sectionList = ref({});
const uploadList = ref([]);
const uploadRef = ref();
const files = ref([]);
const { toClipboard } = useClipboard();
const copy = async (text) => {
  await toClipboard(text);    //参数为要复制的文本
}
const onChange = (fileList) => {
  // files.value = fileList;
};
const submitOne = (e) => {
  e.stopPropagation();
  console.log(files.value);
  uploadRef.value.submit(files.value.find((x) => x.status === 'init'));
};
// 上传文件
const customRequest = async(option) => {
  loading1.value=true;
  const {onProgress, onError, onSuccess, fileItem, name} = option
  const { code, data } = await getSessionDetailsApi(activeSessionId.value);
  if (code === 200) {
    console.log(data, "详情");
    if (fileItem.file) {
      const formData = new FormData();
      formData.append('file', fileItem.file);
      formData.append('conversation_id', data.id);
      uploadWithoutKb(formData).then((res) => {
        console.log(res);
        uploadList.value = [];
        if (res.code == 200) {
          console.log(res);
          loading1.value=false;
        }
      });
    }
  }
}
const DialogList = async () => {
  const { code, data } = await getDialogListApi();
  if (code === 200) {
@@ -236,18 +346,19 @@
    // }
    //新建会话
    createSession(dialogs.value[0].id);
  } catch (err) {
    // you can report use errorHandler or other
  } finally {
  }
};
// 新建会话
const createSession = async (id) => {
const createSession = async (id, name = "未命名会话") => {
  // 如果有会话id
  console.log(name, "新建会话名称");
  const res = await addSessionApi({
    dialog_id: id,
    conversation_desc: "未命名会话"
    conversation_desc: name
  });
  // console.log(res, "res");
  if (res.code == 200) {
@@ -257,9 +368,7 @@
  } else {
    Message.error("创建会话失败,请重试");
  }
};
const handleShiftEnter = (event) => {
  event.preventDefault();
@@ -276,18 +385,26 @@
  });
  console.log(dialogObj.type, "dialogObj");
  if (dialogObj.type == 1) {
    agentType.value = 1;
    agentType.value = '1';
    querySessionList();
  } else {
    agentType.value = 2;
    agentType.value = '2';
    queryAgentSessionList();
  }
  // querySessionList();
};
// 发送
const sentClick = () => {
  sendMessage("click");
};
// 重新生成
const reGenerate = () => {
  let inputContent = sessionDetailList.value[sessionDetailList.value.length-2].content
  startChat(inputContent)
};
const sendMessage = async (event) => {
  if (event.keyCode == 13 || event === "click") {
    if (!event.shiftKey) {
@@ -296,99 +413,146 @@
        event.preventDefault(); // 阻止默认行为,即不换行
      }
      chatDis.value = true;
      loading.value = true;
      if (!activeSessionId.value) {
        Message.warning("请选择会话");
        chatDis.value = false;
        loading.value = false;
        return;
      }
      // if (!activeSessionId.value) {
      //   Message.warning("请选择会话");
      //   chatDis.value = false;
      //   loading.value = false;
      //   return;
      // }
      // if (displayedText.value) {
      //   querySessionList();
      // }
      if (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
            })
          }
        );
        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;
            console.log(x, 999);
            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);
            }
            if (done) {
              console.info("done");
              displayedText.value = "";
              queryNewSessionDetail(activeSessionId.value);
              EventBus.emit('queryAppUsageList');
              break;
            }
          }
        }
        // querySessionList();
        chatDis.value = false;
        loading.value = false;
        startChat(inputMsg.value)
        inputMsg.value = "";
      } else {
        Message.warning("消息不能为空");
        chatDis.value = false;
        loading.value = false;
      }
    }
  }
};
const startChat = async(valMsg)=>{
  chatDis.value = true;
  loading.value = true;
  sessionDetailList.value.push({
    content: valMsg,
    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: valMsg
      })
    }
  );
  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;
      // console.log(x, 999);
      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);
      }
      if (done) {
        console.info("done");
        displayedText.value = "";
        // if(!isStopChat.value){
        //   queryNewSessionDetail(activeSessionId.value);
        // }
        queryNewSessionDetail(activeSessionId.value);
        EventBus.emit("queryAppUsageList");
        break;
      }
    }
  }
  // querySessionList();
  chatDis.value = false;
  loading.value = false;
}
const stopChat=async()=>{
  // const { code, data } = await stopChatApi(activeSessionId.value);
  // if (code === 200) {
  //   Message.success("已停止");
  //   queryNewSessionDetail(activeSessionId.value);
  // }
  isStopChat.value = true;
  console.log('stopChat');
  console.log(displayedText.value, 'displayedText');
  console.log(sessionDetailList.value, 'sessionDetailList');
  let inputText = sessionDetailList.value[sessionDetailList.value.length-2].content
  // 数组合并
  let lastArr = [{
    content: inputText,
    role: "user"
  },{
    content: displayedText.value,
    role: "assistant"
  }]
  sessionDetailList.value = sessionDetailList.value.splice(0, sessionDetailList.value.length-2).concat(lastArr);
  console.log(sessionDetailList.value, 'sessionDetailList2');
  console.log(chatObj, 'chatObj对象');
  chatObj.message = chatObj.message.concat(lastArr);
    // clearTimeout(timer!);
    // timer = null;
  // const { code, data } = await addSessionApi(chatObj);
  // if (data) {
  //   //停止定时器
  //   clearTimeout(timer!);
  //   timer = null;
  //   displayedText.value = "";
  //   queryNewSessionDetail(activeSessionId.value);
  // }
}
const queryNewSessionDetail = async (id) => {
  activeSessionId.value = id;
  const { code, data } = await getSessionDetailsApi(id);
  if (code === 200) {
    console.log(data, "新建会话详情");
    Object.assign(chatObj, data);
    sessionDetailList.value = data.message;
    agentTitle.value = data.name;
    refreshScroll(); //刷新滚动条位置
    isStopChat.value = false;
  }
};
const changeAgentType = (val,session) => {
const changeAgentType = (val, session) => {
  agentType.value = val;
  console.log(val, "val");
}
};
const querySessionDetail = async (session) => {
  sectionList.value = session;
@@ -444,12 +608,12 @@
onBeforeMount(() => {
  // DialogList();
  //新建会话
  createSession('');
  createSession("");
});
onMounted(() => {
  EventBus.on("newChat", () => {
    agentType.value = 1;
    createSession('');
    agentType.value = "1";
    createSession("");
  });
});
onBeforeUnmount(() => {
@@ -517,8 +681,8 @@
  .left {
    /* height: calc(100vh - 160px);
    overflow-y: auto;
    overflow-x: hidden;*/
  overflow-y: auto;
  overflow-x: hidden;*/
    border: 0px;
    .left-list {
@@ -636,7 +800,8 @@
    .chat_bottom {
      display: flex;
      align-items: center;
      width: 78%;
      margin: 0 auto;
      .center-bottom {
        // position: absolute;
        // width: 90%;
@@ -658,7 +823,7 @@
        .btn-send {
          position: absolute !important;
          right: 10px;
          bottom: 10px;
          top: 110px;
          z-index: 10;
        }
@@ -741,6 +906,7 @@
    }
  }
}
.header___lEPyH {
  width: 100%;
  height: 46px;
@@ -750,6 +916,7 @@
  align-items: center;
  justify-content: center;
  -webkit-backdrop-filter: blur(15px);
  .chatHeaderBox {
    width: auto;
    border-radius: 8px;
@@ -757,14 +924,31 @@
    transition: all var(--animation-duration) var(--animation-transition);
    display: flex;
    align-items: flex-end;
    overflow: hidden;        /* 隐藏超出的内容 */
    overflow: hidden; /* 隐藏超出的内容 */
    text-overflow: ellipsis; /* 使用省略号来代替被隐藏的文字 */
    white-space: nowrap;     /* 不换行,使内容在一行内显示 */
    white-space: nowrap; /* 不换行,使内容在一行内显示 */
    max-width: 200px;
    .title{
    .title {
      color: var(--color-text-1);
      font-size: 12px;
    }
  }
}
.action {
  cursor: pointer;
  display: inline-block;
  padding: 0 10px;
  color: var(--color-text-1);
  line-height: 24px;
  background: transparent;
  border-radius: 2px;
  cursor: pointer;
  transition: all 0.1s ease;
  font-size: 12px;
}
.action:hover {
  background: var(--color-fill-3);
}
</style>