From 4b8cb1b1886719354b79e1320a0acb9a39f8fecd Mon Sep 17 00:00:00 2001 From: tiantian <1012874180@qq.com> Date: Sat, 11 Jan 2025 17:11:50 +0800 Subject: [PATCH] =?UTF-8?q?add:=20=E6=B7=BB=E5=8A=A0=E5=8F=82=E8=80=83?= =?UTF-8?q?=E8=B5=84=E6=96=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/localchat/AiChatMain.vue | 16 +- .../components/localchat/AiChatMessage.vue | 161 ++++++++++++------ 2 files changed, 122 insertions(+), 55 deletions(-) diff --git a/frontend/src/components/localchat/AiChatMain.vue b/frontend/src/components/localchat/AiChatMain.vue index 46cce78..8c4b9c2 100644 --- a/frontend/src/components/localchat/AiChatMain.vue +++ b/frontend/src/components/localchat/AiChatMain.vue @@ -6,7 +6,7 @@ import { notifyError } from "@/util/msg.ts"; import { ElScrollbar } from "element-plus"; import { getSystemConfig } from "@/system/config"; import { Vue3Lottie } from "vue3-lottie"; -import { BrowserWindow } from "@/system"; +import { BrowserWindow, useSystem } from "@/system"; import { isMobileDevice } from "@/util/device"; const chatStore = useAiChatStore(); const modelStore = useModelStore(); @@ -22,6 +22,7 @@ const messageInnerRef = ref(); // User Input Message const userMessage = ref(""); const knowledgeId = ref(0) +const system = useSystem() const promptMessage = computed(() => { return [ { @@ -132,7 +133,7 @@ const createCompletion = async () => { }; const chatConfig = modelStore.chatConfig.chat; - const knowledgeId = chatStore.chatInfo.knowledgeId*1; + const knowledgeId = chatStore.chatInfo.knowledgeId * 1; let postMsg: any = { messages: requestMessages.value, model: chatStore.chatInfo.model, @@ -182,11 +183,17 @@ const createCompletion = async () => { return; } const res = await completion.json(); - //console.log(res) + console.log(res) if (res && res.choices && res.choices.length > 0) { if (res.choices[0].message.content) { const msg = res.choices[0].message.content; saveMessage.content = msg; + if (res.documents && res.documents.length > 0) { + saveMessage.doc = res.documents; + } + if (res.web_search && res.web_search.length > 0) { + saveMessage.web_search = res.web_search; + } chatStore.messageList.push(saveMessage); await chatStore.addMessages(chatStore.activeId, saveMessage); } @@ -275,7 +282,8 @@ const uploadImage = async (event: any) => {
+ :link="message.link" :role="message.role" :createdAt="message.createdAt" :doc="message.doc || []" + :web_search="message.web_search || []" :system="system" />
diff --git a/frontend/src/components/localchat/AiChatMessage.vue b/frontend/src/components/localchat/AiChatMessage.vue index 1622453..91617d5 100644 --- a/frontend/src/components/localchat/AiChatMessage.vue +++ b/frontend/src/components/localchat/AiChatMessage.vue @@ -3,16 +3,33 @@ import { renderMarkdown } from "@/util/markdown.ts"; import moment from "moment"; import { computed, ref } from "vue"; import { getSystemKey } from "@/system/config"; +import { System } from "@/system"; +import { ElMessageBox } from "element-plus"; interface Props { content: string; role?: string; link?: any; createdAt: number | string; + doc: any[]; + web_search: any[]; + system: System; } const props = defineProps(); - -const getDateTime = (t:any) => { +const sourceExpand = ref(false); +const openFile = (filePath: string) => { + props.system.openFile(filePath); +}; +const openlink = (item: any) => { + if (!item.link) return ElMessageBox.alert( + item.content, + { + confirmButtonText: '确定', + } + ) + window.open(item.link) +} +const getDateTime = (t: any) => { return moment(t).format("MM-DD HH:mm"); }; const showLink = ref(false); @@ -36,7 +53,7 @@ const imgList = computed(() => { if (props.link && props.link.length > 0) { const list: any = []; const url = getSystemKey("apiUrl") + "/showimage?path="; - props.link.forEach((item:any) => { + props.link.forEach((item: any) => { if (item.metadata.type === "image") { list.push(url + item.metadata.file); } @@ -47,7 +64,7 @@ const imgList = computed(() => { }); async function showDetail(file: string, type: string) { const filePath = getSystemKey("apiUrl") + "/filedetail?path=" + file - if(type != "image") { + if (type != "image") { const reponse = await fetch(filePath); if (reponse.ok) { const data = await reponse.text(); @@ -55,12 +72,12 @@ async function showDetail(file: string, type: string) { detailTxt.value = data; detailImg.value = ""; } - }else{ - refbox.value = true; - detailTxt.value = ''; - detailImg.value = filePath; + } else { + refbox.value = true; + detailTxt.value = ''; + detailImg.value = filePath; } - + } @@ -76,7 +93,9 @@ async function showDetail(file: string, type: string) {
- + + +
@@ -86,31 +105,13 @@ async function showDetail(file: string, type: string) { {{ getDateTime(props.createdAt) }}
- - + +
- + {{ key + 1 }} @@ -124,35 +125,52 @@ async function showDetail(file: string, type: string) {
- +
+ + +
+
+ + {{ props.doc.length || props.web_search.length }}篇资料作为参考 + + +
+ +
+
    +
  • + {{ item.file_name }}
  • +
+
+ +
+
    +
  • + {{ + item.title + }} +
  • +
+
+
-
+
{{ props.content }}
- + + +
@@ -165,12 +183,14 @@ $win10-blue: #0078d7; $win10-light-blue: #c7e8ff; $win10-grey: #afafaf; $win10-light-grey: #f2f2f2; + .message-container { display: flex; flex-direction: column; align-items: flex-end; width: 99%; } + .message { margin-top: 10px; padding: 8px; @@ -181,9 +201,11 @@ $win10-light-grey: #f2f2f2; text-align: left; margin: 8px; } + .text-grey { color: $win10-grey; } + .user-message { background-color: $win10-blue; border-radius: 12px 0 0 12px; @@ -191,19 +213,25 @@ $win10-light-grey: #f2f2f2; font-size: 14px; color: $win10-light-blue; } + .assistant-message { - background-color: $win10-blue; + flex: 1; + background-color: #fff; border-radius: 0 12px 12px 0; font-weight: 600; font-size: 14px; - color: $win10-light-blue; + color: #333; + box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px; + padding: 10px 20px; } + .avatar { display: flex; align-items: center; width: 50px; height: 50px; } + .assistant-avatar { display: flex; align-items: center; @@ -211,6 +239,7 @@ $win10-light-grey: #f2f2f2; height: 35px; padding-left: 10px; } + .icon-container { display: flex; align-items: center; @@ -225,9 +254,11 @@ $win10-light-grey: #f2f2f2; .rounded-xl { border-radius: 12px 0px 12px 12px; } + .rounded-al { border-radius: 0px 12px 12px 12px; } + .align-start, .align-center { display: flex; @@ -237,6 +268,7 @@ $win10-light-grey: #f2f2f2; .align-center { justify-content: flex-end; } + .image-grid { display: grid; grid-template-columns: repeat(3, 1fr); @@ -245,7 +277,8 @@ $win10-light-grey: #f2f2f2; .image-item { position: relative; - border: 1px solid white; /* 白边效果 */ + border: 1px solid white; + /* 白边效果 */ overflow: hidden; } @@ -253,4 +286,30 @@ $win10-light-grey: #f2f2f2; width: 100%; height: auto; } + +.reference-source { + font-size: 13px; + color: #9b9b9b; + margin-top: 10px; + + .source-title { + display: flex; + align-items: center; + } + + .source-list { + list-style: disc inside none; + margin-top: 5px; + + .source-item { + background-color: #ecebeb; + height: 30px; + padding: 0 10px; + line-height: 30px; + border-radius: 15px; + cursor: pointer; + overflow: hidden; + } + } +}