|
@@ -0,0 +1,214 @@
|
|
|
+<template>
|
|
|
+ <div class="AIPage">
|
|
|
+ <div class="main">
|
|
|
+ <div class="chatBox" :style="{ height: chatBoxHeight }">
|
|
|
+ <div class="oneChat" v-for="item in msg" :key="item">
|
|
|
+ <template v-if="item.role != 'system'">
|
|
|
+ <div class="top">
|
|
|
+ <img
|
|
|
+ v-if="item.role == 'assistant'"
|
|
|
+ src="@/assets/images/newIndex/aiBot.png"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ <img v-else-if="userInfo.avatar" :src="userInfo.avatar" alt="" />
|
|
|
+ <span v-if="item.role == 'assistant'">智聚AI</span>
|
|
|
+ <span v-else>{{ userInfo.name }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="chat" :class="{ botChat: item.role == 'assistant' }">
|
|
|
+ <span>{{ item.content }}</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="btnBox">
|
|
|
+ <el-input
|
|
|
+ v-model="iptText"
|
|
|
+ style="width: 100%"
|
|
|
+ :autosize="{ minRows: 2, maxRows: 5 }"
|
|
|
+ type="textarea"
|
|
|
+ placeholder="请在此输入关键词"
|
|
|
+ />
|
|
|
+ <div class="chatBtn">
|
|
|
+ <img :src="send" class="send-info" @click="enterChat" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, computed, watch, onMounted } from "vue";
|
|
|
+import { chat } from "@/api/chatglm/chatglm.js";
|
|
|
+import useUserStore from "@/store/modules/user";
|
|
|
+import send from "@/assets/images/send.png";
|
|
|
+import { getToken } from "@/utils/auth";
|
|
|
+const wangzhi = import.meta.env.VITE_APP_BASE_API;
|
|
|
+const iptText = ref("");
|
|
|
+const chatBoxHeight = ref();
|
|
|
+const userInfo = ref({});
|
|
|
+const resultData = ref("");
|
|
|
+const disabled = ref(false);
|
|
|
+const msg = ref([
|
|
|
+ {
|
|
|
+ role: "system",
|
|
|
+ content: "你是智聚AI, 一个大语言模型,用于提供适当的答复和支持。",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ role: "assistant",
|
|
|
+ content: "你好,我是智聚AI, 一个大语言模型,用于提供适当的答复和支持。",
|
|
|
+ },
|
|
|
+]);
|
|
|
+
|
|
|
+// el-input的最小高度为52px(2行),每增加一行高度增加21px,最大为115px(5行)
|
|
|
+// 这里的数值可能需要根据实际的CSS调整
|
|
|
+const baseInputHeight = 52;
|
|
|
+const maxInputHeight = 115;
|
|
|
+const enterChat = () => {
|
|
|
+ if (disabled.value) return;
|
|
|
+ disabled.value = true;
|
|
|
+ const newUser = {
|
|
|
+ role: "user",
|
|
|
+ content: iptText.value,
|
|
|
+ };
|
|
|
+ msg.value.push(newUser); // 添加用户输入
|
|
|
+ resultData.value = ""; // 清空
|
|
|
+ iptText.value = ""; // 清空
|
|
|
+ // 设置传输的上下文
|
|
|
+ let query;
|
|
|
+ if (msg.value.length <= 12) {
|
|
|
+ query = msg.value;
|
|
|
+ } else {
|
|
|
+ const longArr = msg.value.slice(msg.value.length - 11, msg.value.length);
|
|
|
+ query = [msg.value[0], ...longArr];
|
|
|
+ }
|
|
|
+ fetch(`${wangzhi}/chat-glm3`, {
|
|
|
+ method: "post",
|
|
|
+ body: JSON.stringify(query),
|
|
|
+ headers: {
|
|
|
+ "Content-Type": "application/json",
|
|
|
+ Authorization: "Bearer " + getToken(),
|
|
|
+ },
|
|
|
+ })
|
|
|
+ .then((response) => {
|
|
|
+ const newAssistant = {
|
|
|
+ role: "assistant",
|
|
|
+ content: "",
|
|
|
+ }; // 添加智聚AI回复
|
|
|
+ msg.value.push(newAssistant); // 添加智聚AI回复
|
|
|
+ const reader = response.body.getReader();
|
|
|
+ const decoder = new TextDecoder();
|
|
|
+ function processText({ done, value }) {
|
|
|
+ if (done) {
|
|
|
+ disabled.value = false;
|
|
|
+ // console.log("Stream finished");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const message = decoder.decode(value);
|
|
|
+ // console.log("原:", message);
|
|
|
+ let newMsg = message
|
|
|
+ .replace("data:", "")
|
|
|
+ .replace("\n", "")
|
|
|
+ .replace("\n", "")
|
|
|
+ .replace("data:", "")
|
|
|
+ .replace("\n", "")
|
|
|
+ .replace("data:", "");
|
|
|
+ // console.log("改:", newMsg);
|
|
|
+ let v = resultData.value.replace("\n", "") + newMsg.replace("\n", "");
|
|
|
+ resultData.value = v;
|
|
|
+ msg.value[msg.value.length - 1].content = resultData.value;
|
|
|
+ return reader.read().then(processText);
|
|
|
+ }
|
|
|
+ return reader.read().then(processText);
|
|
|
+ })
|
|
|
+ .catch(console.error);
|
|
|
+};
|
|
|
+// 获取用户信息
|
|
|
+const getUserInfo = async () => {
|
|
|
+ const userStore = useUserStore();
|
|
|
+ userInfo.value = userStore;
|
|
|
+};
|
|
|
+// 监听iptText变化,动态调整chatBox和el-input的高度
|
|
|
+watch(
|
|
|
+ iptText,
|
|
|
+ (newValue, oldValue) => {
|
|
|
+ // 计算input高度(根据el-input实际高度调整)
|
|
|
+ const ipt = document.getElementsByClassName("el-textarea__inner")[0];
|
|
|
+ let inputHeight = ipt?.style.height.split("px")[0] || 52;
|
|
|
+ if(newValue == "")inputHeight = 52
|
|
|
+ inputHeight = Math.min(inputHeight, maxInputHeight); // 限制最大高度
|
|
|
+ chatBoxHeight.value = "calc(100% - " + inputHeight + "px - 5px)";
|
|
|
+ },
|
|
|
+ {
|
|
|
+ immediate: true,
|
|
|
+ deep: true,
|
|
|
+ }
|
|
|
+);
|
|
|
+onMounted(() => {
|
|
|
+ getUserInfo();
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.AIPage {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background-color: #eaf1f9;
|
|
|
+}
|
|
|
+.main {
|
|
|
+ width: 565px;
|
|
|
+ height: 100%;
|
|
|
+ padding: 24px 0 16px 0;
|
|
|
+ margin: 0 auto;
|
|
|
+ // border: 1px solid #000;
|
|
|
+ .chatBox {
|
|
|
+ width: 100%;
|
|
|
+ background-color: #eaf1f9;
|
|
|
+ overflow-y: auto;
|
|
|
+ }
|
|
|
+}
|
|
|
+.oneChat {
|
|
|
+ width: 100%;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ .top {
|
|
|
+ width: 100%;
|
|
|
+ height: 28px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ img {
|
|
|
+ width: 28px;
|
|
|
+ height: 28px;
|
|
|
+ }
|
|
|
+ span {
|
|
|
+ margin-left: 8px;
|
|
|
+ font-weight: 500;
|
|
|
+ font-size: 15px;
|
|
|
+ color: #0d0f39;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .chat {
|
|
|
+ margin-left: 32px;
|
|
|
+ padding: 16px;
|
|
|
+ background-color: #dbe4ef;
|
|
|
+ border-radius: 12px 12px 12px 12px;
|
|
|
+ color: #0d0f39;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 400;
|
|
|
+ }
|
|
|
+ .botChat {
|
|
|
+ background-color: #fff !important;
|
|
|
+ }
|
|
|
+}
|
|
|
+.btnBox {
|
|
|
+ position: relative;
|
|
|
+ .chatBtn {
|
|
|
+ position: absolute;
|
|
|
+ top: calc(50% - 20px);
|
|
|
+ right: 20px;
|
|
|
+ }
|
|
|
+ .send-info {
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ border-radius: 16px;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|