mirror of
https://github.com/pure-admin/pure-admin-thin.git
synced 2025-04-24 23:47:17 +08:00
feat: complete the qa/chat interface
This commit is contained in:
parent
a3887dde7a
commit
8c26178240
BIN
public/chat_background-removebg-preview.png
Normal file
BIN
public/chat_background-removebg-preview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 62 KiB |
BIN
public/chat_background.png
Normal file
BIN
public/chat_background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
@ -1 +1,38 @@
|
||||
// import { http } from "@/utils/http";
|
||||
import { http } from "@/utils/http";
|
||||
|
||||
export type ChatResult = {
|
||||
status: string;
|
||||
chat_history: Array<{
|
||||
role: string;
|
||||
content: string;
|
||||
}>;
|
||||
content: string;
|
||||
};
|
||||
|
||||
export type ModelActionResult = {
|
||||
status: string;
|
||||
message: string;
|
||||
};
|
||||
|
||||
/** 发起聊天请求 */
|
||||
export const chat = (data?: object) => {
|
||||
return http.request<ChatResult>("post", "http://127.0.0.1:5005/qa/chat", {
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
/** 创建模型 */
|
||||
export const createModel = () => {
|
||||
return http.request<ModelActionResult>(
|
||||
"post",
|
||||
"http://127.0.0.1:5005/qa/create_model"
|
||||
);
|
||||
};
|
||||
|
||||
/** 终止模型 */
|
||||
export const terminateModel = () => {
|
||||
return http.request<ModelActionResult>(
|
||||
"post",
|
||||
"http://127.0.0.1:5005/qa/terminate_model"
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
export default {
|
||||
path: "/qa",
|
||||
redirect: "/qa/chat",
|
||||
component: () => import("@/views/qa/index.vue"),
|
||||
component: () => import("@/views/qa/chat/index.vue"),
|
||||
meta: {
|
||||
icon: "lollipop",
|
||||
title: "问答系统",
|
||||
|
@ -17,7 +17,7 @@ import { useUserStoreHook } from "@/store/modules/user";
|
||||
// 相关配置请参考:www.axios-js.com/zh-cn/docs/#axios-request-config-1
|
||||
const defaultConfig: AxiosRequestConfig = {
|
||||
// 请求超时时间
|
||||
timeout: 10000,
|
||||
timeout: 60000,
|
||||
headers: {
|
||||
Accept: "application/json, text/plain, */*",
|
||||
"Content-Type": "application/json",
|
||||
|
@ -1,9 +1,235 @@
|
||||
<template>
|
||||
<div class="qa-chat">
|
||||
<div class="chat-container">
|
||||
<div
|
||||
class="messages"
|
||||
ref="messagesContainer"
|
||||
:style="
|
||||
chatHistory.length === 0
|
||||
? { backgroundImage: 'url(/chat_background-removebg-preview.png)' }
|
||||
: {}
|
||||
"
|
||||
>
|
||||
<div
|
||||
v-for="(message, index) in chatHistory"
|
||||
:key="index"
|
||||
class="message"
|
||||
:class="{
|
||||
'user-message': message.type === 'user',
|
||||
'system-message': message.type === 'system'
|
||||
}"
|
||||
>
|
||||
<strong>{{ message.type.toUpperCase() }}:</strong>
|
||||
{{ message.content }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<button
|
||||
:disabled="modelLoading"
|
||||
:class="{ 'model-button': true, 'model-active': modelActive }"
|
||||
@click="toggleModel"
|
||||
>
|
||||
<span v-if="modelLoading" class="loading-spinner" />
|
||||
<span v-else>{{ modelActive ? "关闭模型" : "创建模型" }}</span>
|
||||
</button>
|
||||
<textarea
|
||||
ref="textareaRef"
|
||||
v-model="userInput"
|
||||
@input="adjustTextareaHeight"
|
||||
@keyup.enter="sendMessage"
|
||||
placeholder="输入问题..."
|
||||
/>
|
||||
<div class="button-container">
|
||||
<button @click="sendMessage">上传</button>
|
||||
<div v-if="isLoading" class="loading-spinner" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineOptions({
|
||||
name: "QAchat"
|
||||
});
|
||||
import { ref, nextTick } from "vue";
|
||||
import { chat, createModel, terminateModel } from "@/api/qa";
|
||||
|
||||
const userInput = ref("");
|
||||
const chatHistory = ref([]);
|
||||
const messagesContainer = ref(null);
|
||||
const textareaRef = ref(null);
|
||||
const isLoading = ref(false);
|
||||
const modelActive = ref(false);
|
||||
const modelLoading = ref(false);
|
||||
|
||||
const sendMessage = async () => {
|
||||
if (userInput.value.trim() === "") return;
|
||||
|
||||
chatHistory.value.push({ content: userInput.value, type: "user" });
|
||||
|
||||
isLoading.value = true;
|
||||
|
||||
try {
|
||||
const response = await chat({ prompt: userInput.value });
|
||||
chatHistory.value.push({ content: response.content, type: "system" });
|
||||
|
||||
await nextTick();
|
||||
messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
|
||||
} catch (error) {
|
||||
console.error("Error sending message:", error);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
userInput.value = "";
|
||||
textareaRef.value.style.height = "auto";
|
||||
};
|
||||
|
||||
const adjustTextareaHeight = () => {
|
||||
textareaRef.value.style.height = "auto";
|
||||
textareaRef.value.style.height =
|
||||
Math.min(textareaRef.value.scrollHeight, 3 * 24) + "px";
|
||||
};
|
||||
|
||||
const toggleModel = async () => {
|
||||
modelLoading.value = true;
|
||||
|
||||
try {
|
||||
if (modelActive.value) {
|
||||
await terminateModel();
|
||||
modelActive.value = false;
|
||||
} else {
|
||||
await createModel();
|
||||
modelActive.value = true;
|
||||
}
|
||||
} catch (error) {
|
||||
alert(`操作失败: ${error.message}`);
|
||||
} finally {
|
||||
modelLoading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>问答系统</h1>
|
||||
</template>
|
||||
<style scoped>
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.qa-chat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.chat-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding-bottom: 60px; /* 调整这个值以适应输入框的高度 */
|
||||
}
|
||||
|
||||
/* .messages {
|
||||
flex-grow: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
} */
|
||||
|
||||
.messages {
|
||||
flex-grow: 1;
|
||||
height: calc(100vh - 200px); /* 根据实际情况调整 */
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
background-repeat: no-repeat; /* 防止背景图片重复 */
|
||||
background-position: center; /* 将背景图片居中 */
|
||||
background-size: 36%; /* 将背景图片缩小到原来的50% */
|
||||
}
|
||||
|
||||
.message {
|
||||
padding: 5px;
|
||||
margin-bottom: 10px;
|
||||
word-wrap: break-word;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.user-message {
|
||||
align-self: flex-end;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.system-message {
|
||||
align-self: flex-start;
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
.input-container {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background-color: white;
|
||||
box-shadow: 0 -2px 5px rgb(0 0 0 / 10%);
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 60%;
|
||||
padding: 5px 10px;
|
||||
margin-right: 10px;
|
||||
overflow-y: auto;
|
||||
resize: none;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 5px 10px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
background-color: #007bff;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 5px;
|
||||
border: 2px solid #f3f3f3; /* Light grey */
|
||||
border-top: 2px solid #3498db; /* Blue */
|
||||
border-radius: 50%;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
|
||||
.model-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 5px 10px;
|
||||
margin-right: 10px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
background-color: #ccc;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.model-active {
|
||||
background-color: #007bff;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
x
Reference in New Issue
Block a user