feat: 添加环境变量示例,更新样式和依赖,增强全局状态管理
This commit is contained in:
parent
e3e1a28462
commit
bdafa2d083
2
.env.example
Normal file
2
.env.example
Normal file
@ -0,0 +1,2 @@
|
||||
DIFY_BASE_URL=
|
||||
DIFY_API_KEY=
|
@ -1,4 +1,5 @@
|
||||
@import "tailwindcss" theme(static);
|
||||
@plugin "@tailwindcss/typography";
|
||||
@import "@nuxt/ui";
|
||||
|
||||
@theme static {
|
||||
|
51
components/ChatMessage.vue
Normal file
51
components/ChatMessage.vue
Normal file
@ -0,0 +1,51 @@
|
||||
<script lang="ts" setup>
|
||||
import type { LocalMessage } from "~/types";
|
||||
|
||||
defineProps({
|
||||
message: {
|
||||
type: Object as PropType<LocalMessage>,
|
||||
default: null,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: "AI 智慧校园",
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: "tabler:robot-face",
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="message.role === 'user'" class="flex flex-col items-end gap-2">
|
||||
<div
|
||||
class="rounded-2xl rounded-br-none bg-primary-400 px-3 py-2 text-sm w-fit max-w-8/12 break-all text-justify text-white font-medium dark:bg-primary-500"
|
||||
>
|
||||
{{ message.message }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="message.role === 'bot'" class="flex flex-col gap-2">
|
||||
<div class="flex gap-1.5 items-center">
|
||||
<div
|
||||
class="w-7 h-7 rounded-lg border border-neutral-200 bg-white shadow-sm flex justify-center items-center dark:bg-neutral-700 dark:border-neutral-600"
|
||||
>
|
||||
<UIcon :name="icon" />
|
||||
</div>
|
||||
<span class="text-sm font-medium">{{ name }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="rounded-lg bg-white/50 p-2 text-sm dark:bg-neutral-800/50 break-all text-justify"
|
||||
>
|
||||
<div v-if="message.message" class="prose prose-sm">
|
||||
{{ message.message }}
|
||||
</div>
|
||||
<span v-else class="flex items-center gap-1.5">
|
||||
<UIcon name="svg-spinners:3-dots-scale" class="text-lg -mt-0.5" />
|
||||
<p class="text-xs">思考中</p>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
@ -8,6 +8,10 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits({
|
||||
"select-inquiry": (inquiry: string) => true,
|
||||
});
|
||||
|
||||
const activeTab = ref("0");
|
||||
</script>
|
||||
|
||||
@ -37,6 +41,7 @@ const activeTab = ref("0");
|
||||
size="sm"
|
||||
block
|
||||
:key="inquiry.question"
|
||||
@click="() => emit('select-inquiry', inquiry.question)"
|
||||
>
|
||||
{{ inquiry.question }}
|
||||
</UButton>
|
||||
|
@ -1,11 +1,54 @@
|
||||
<script lang="ts" setup></script>
|
||||
<script lang="ts" setup>
|
||||
import type { VisitorRole } from "~/types";
|
||||
|
||||
const route = useRoute();
|
||||
const gstate = useGState();
|
||||
|
||||
onMounted(() => {
|
||||
if (route.query?.role) {
|
||||
if (
|
||||
route.query.role !== "stu" &&
|
||||
route.query.role !== "tea" &&
|
||||
route.query.role !== "fans"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
gstate.setCurrentRole(route.query.role as VisitorRole);
|
||||
}
|
||||
});
|
||||
|
||||
// const items = ref([
|
||||
// {
|
||||
// label: 'Backlog',
|
||||
// value: 'backlog',
|
||||
// icon: 'i-lucide-circle-help'
|
||||
// },
|
||||
// {
|
||||
// label: 'Todo',
|
||||
// value: 'todo',
|
||||
// icon: 'i-lucide-circle-plus'
|
||||
// },
|
||||
// {
|
||||
// label: 'In Progress',
|
||||
// value: 'in_progress',
|
||||
// icon: 'i-lucide-circle-arrow-up'
|
||||
// },
|
||||
// {
|
||||
// label: 'Done',
|
||||
// value: 'done',
|
||||
// icon: 'i-lucide-circle-check'
|
||||
// }
|
||||
// ])
|
||||
// const value = ref(items.value[0])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full h-full flex flex-col dark:bg-neutral-900/80">
|
||||
<div
|
||||
class="sticky top-0 w-full px-4 py-3 bg-white/30 backdrop-blur-2xl z-30 dark:bg-neutral-900/80"
|
||||
>
|
||||
<h1 class="font-medium">AI 智慧校园</h1>
|
||||
<h1 class="font-medium">{{ gstate.botName }}</h1>
|
||||
<!-- <USelectMenu v-model="value" color="primary" variant="none" :items="items" class="w-48" size="lg" :ui="{base: 'w-fit'}" /> -->
|
||||
</div>
|
||||
<slot></slot>
|
||||
</div>
|
||||
@ -14,5 +57,9 @@
|
||||
<style>
|
||||
body {
|
||||
background-image: url("~/assets/image/pattern/mesh-7.png");
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-attachment: fixed;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
</style>
|
||||
|
@ -4,9 +4,15 @@ import tailwindcss from "@tailwindcss/vite";
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: "2024-11-01",
|
||||
devtools: { enabled: true },
|
||||
modules: ["@nuxt/ui"],
|
||||
modules: ["@nuxt/ui", "@pinia/nuxt"],
|
||||
css: ["~/assets/css/main.css"],
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
DifyBaseURL: process.env.DIFY_BASE_URL,
|
||||
DifyApiKey: process.env.DIFY_API_KEY,
|
||||
},
|
||||
},
|
||||
vite: {
|
||||
plugins: [tailwindcss()],
|
||||
},
|
||||
});
|
||||
});
|
@ -10,8 +10,13 @@
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pinia/nuxt": "0.10.1",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@tailwindcss/vite": "^4.0.14",
|
||||
"@uniiem/uuid": "^0.2.1",
|
||||
"dotenv": "^16.4.7",
|
||||
"nuxt": "^3.16.0",
|
||||
"pinia": "^3.0.1",
|
||||
"tailwindcss": "^4.0.14",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.0"
|
||||
|
232
pages/index.vue
232
pages/index.vue
@ -1,73 +1,207 @@
|
||||
<script lang="ts" setup>
|
||||
import { uuidv4 } from "@uniiem/uuid";
|
||||
import type { IWorkflowResponse, LocalMessage, VisitorRole } from "~/types";
|
||||
|
||||
const gstate = useGState();
|
||||
const runtimeConfig = useRuntimeConfig();
|
||||
|
||||
const getPopularInquiriesByRole = () => {
|
||||
return [
|
||||
{
|
||||
label: "新生入学",
|
||||
inquiries: [
|
||||
{
|
||||
question: "新生报到时间",
|
||||
},
|
||||
{
|
||||
question: "新生报到流程",
|
||||
},
|
||||
{
|
||||
question: "如何到达学院",
|
||||
},
|
||||
{
|
||||
question: "如何办理户口迁移",
|
||||
},
|
||||
{
|
||||
question: "学院 VPN 使用方法",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "学校概况",
|
||||
},
|
||||
{
|
||||
label: "学术学习",
|
||||
},
|
||||
{
|
||||
label: "生活服务",
|
||||
},
|
||||
{
|
||||
label: "就业辅导",
|
||||
},
|
||||
];
|
||||
return {
|
||||
stu: [
|
||||
{
|
||||
label: "新生入学",
|
||||
inquiries: [
|
||||
{
|
||||
question: "新生报到时间",
|
||||
},
|
||||
{
|
||||
question: "新生报到流程",
|
||||
},
|
||||
{
|
||||
question: "如何到达学院",
|
||||
},
|
||||
{
|
||||
question: "如何办理户口迁移",
|
||||
},
|
||||
{
|
||||
question: "学院 VPN 使用方法",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "学校概况",
|
||||
},
|
||||
{
|
||||
label: "学术学习",
|
||||
},
|
||||
{
|
||||
label: "生活服务",
|
||||
},
|
||||
{
|
||||
label: "就业辅导",
|
||||
},
|
||||
],
|
||||
tea: [
|
||||
{
|
||||
label: "教学管理",
|
||||
},
|
||||
{
|
||||
label: "科研管理",
|
||||
},
|
||||
{
|
||||
label: "学生管理",
|
||||
},
|
||||
{
|
||||
label: "教学资源",
|
||||
},
|
||||
{
|
||||
label: "教学评价",
|
||||
},
|
||||
],
|
||||
fans: [
|
||||
{
|
||||
label: "校园风光",
|
||||
},
|
||||
{
|
||||
label: "校园活动",
|
||||
},
|
||||
{
|
||||
label: "校园新闻",
|
||||
},
|
||||
{
|
||||
label: "校园文化",
|
||||
},
|
||||
{
|
||||
label: "校园历史",
|
||||
},
|
||||
],
|
||||
} as Record<
|
||||
VisitorRole,
|
||||
{ label: string; inquiries?: Array<{ question: string }> }[]
|
||||
>;
|
||||
};
|
||||
|
||||
const inquiries = computed(() => getPopularInquiriesByRole());
|
||||
const scrollArea = ref<HTMLDivElement | null>(null);
|
||||
// 滤除 details 标签正则
|
||||
const regex = /(?<=<\/details>\n\n)[\s\S]*/gm;
|
||||
|
||||
// 常见问题
|
||||
const inquiries = computed(
|
||||
() => getPopularInquiriesByRole()[gstate.currentRole]
|
||||
);
|
||||
|
||||
const responding = ref(false);
|
||||
const inquiryInput = ref("");
|
||||
const onInquirySubmit = async () => {
|
||||
if (inquiryInput.value) {
|
||||
gstate.insertOrUpdateMessage({
|
||||
id: uuidv4(),
|
||||
role: "user",
|
||||
message: inquiryInput.value,
|
||||
});
|
||||
responding.value = true;
|
||||
|
||||
scrollLastMessageIntoView();
|
||||
|
||||
let botMessageId = uuidv4();
|
||||
gstate.insertOrUpdateMessage({
|
||||
id: botMessageId,
|
||||
role: "bot",
|
||||
});
|
||||
|
||||
try {
|
||||
const resp = await useFetch<IWorkflowResponse>(
|
||||
`${runtimeConfig.public.DifyBaseURL}/workflows/run`,
|
||||
{
|
||||
method: "post",
|
||||
headers: {
|
||||
Authorization: `Bearer ${runtimeConfig.public.DifyApiKey}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
inputs: {
|
||||
question: inquiryInput.value,
|
||||
role: gstate.currentRole,
|
||||
},
|
||||
response_mode: "blocking",
|
||||
user: "abc-123",
|
||||
}),
|
||||
}
|
||||
);
|
||||
gstate.insertOrUpdateMessage({
|
||||
id: botMessageId,
|
||||
role: "bot",
|
||||
message:
|
||||
resp.data.value?.data.outputs.message.match(regex)?.[0] ||
|
||||
"网络繁忙,请稍后再试",
|
||||
});
|
||||
} catch (error) {
|
||||
gstate.insertOrUpdateMessage({
|
||||
id: botMessageId,
|
||||
role: "bot",
|
||||
message: "网络繁忙,请稍后再试",
|
||||
});
|
||||
}
|
||||
inquiryInput.value = "";
|
||||
|
||||
responding.value = false;
|
||||
scrollLastMessageIntoView();
|
||||
}
|
||||
};
|
||||
|
||||
const scrollLastMessageIntoView = () => {
|
||||
nextTick(() => {
|
||||
scrollArea.value?.scrollTo({
|
||||
top: scrollArea.value?.scrollHeight,
|
||||
behavior: "smooth",
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="p-4 h-full flex flex-col gap-4 mb-20">
|
||||
<PopularInquiries :inquiries-list="inquiries" />
|
||||
|
||||
<ChatUserMessage message="眩生花是什么?" />
|
||||
<ChatBotMessage
|
||||
name="AI 辅导员"
|
||||
message="眩生花是一家科技公司,全称为重庆眩生花科技有限公司。它专注于新一代人工智能技术的研发与应用,包括AI大模型、AIGC(生成式人工智能)、AI Agent、AI-First以及AGI(通用人工智能)等领域的创新解决方案。公司的目标是通过这些先进技术为高等教育、职业教育和基础教育等行业提供变革性的服务,助力教育生态的重塑。
|
||||
|
||||
眩生花秉承“以人为本、抱诚守真、求实创新”的价值观,致力于成为AI教育时代的变革者,推动教育方式的革新与进步。"
|
||||
<div ref="scrollArea" class="h-full overflow-auto overflow-x-hidden mb-20">
|
||||
<div class="p-4 h-full flex flex-col gap-4">
|
||||
<PopularInquiries
|
||||
:inquiries-list="inquiries"
|
||||
@select-inquiry="
|
||||
(inquiry) => {
|
||||
if (responding) return;
|
||||
inquiryInput = inquiry;
|
||||
onInquirySubmit();
|
||||
}
|
||||
"
|
||||
/>
|
||||
|
||||
<ChatMessage
|
||||
v-for="message in gstate.messages"
|
||||
:name="gstate.botName"
|
||||
:key="message.id"
|
||||
:message="message"
|
||||
/>
|
||||
<ChatUserMessage message="这是前端测试示例消息" />
|
||||
<ChatBotMessage name="AI 辅导员" />
|
||||
</div>
|
||||
<div
|
||||
class="fixed inset-x-0 bottom-0 p-4 bg-white/90 rounded-t-2xl shadow-2xl dark:bg-neutral-800/90 backdrop-blur-2xl"
|
||||
>
|
||||
<img
|
||||
src="~/assets/image/pattern/ai_glow.png"
|
||||
class="absolute top-0 inset-x-0 opacity-50"
|
||||
class="absolute top-0 inset-x-0 opacity-50 pointer-events-none"
|
||||
/>
|
||||
<div class="w-full flex justify-between items-center gap-2">
|
||||
<UInput placeholder="请输入问题" class="flex-1" size="xl" />
|
||||
<UInput
|
||||
placeholder="请输入问题"
|
||||
class="flex-1"
|
||||
size="xl"
|
||||
v-model="inquiryInput"
|
||||
/>
|
||||
<UButton
|
||||
color="primary"
|
||||
variant="solid"
|
||||
size="xl"
|
||||
trailing
|
||||
trailing-icon="tabler:send-2"
|
||||
:loading="responding"
|
||||
loading-icon="svg-spinners:tadpole"
|
||||
@click="onInquirySubmit"
|
||||
>提问</UButton
|
||||
>
|
||||
</div>
|
||||
|
92
pnpm-lock.yaml
generated
92
pnpm-lock.yaml
generated
@ -8,12 +8,27 @@ importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@pinia/nuxt':
|
||||
specifier: 0.10.1
|
||||
version: 0.10.1(magicast@0.3.5)(pinia@3.0.1(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2)))
|
||||
'@tailwindcss/typography':
|
||||
specifier: ^0.5.16
|
||||
version: 0.5.16(tailwindcss@4.0.14)
|
||||
'@tailwindcss/vite':
|
||||
specifier: ^4.0.14
|
||||
version: 4.0.14(vite@6.2.1(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.39.0)(yaml@2.7.0))
|
||||
'@uniiem/uuid':
|
||||
specifier: ^0.2.1
|
||||
version: 0.2.1
|
||||
dotenv:
|
||||
specifier: ^16.4.7
|
||||
version: 16.4.7
|
||||
nuxt:
|
||||
specifier: ^3.16.0
|
||||
version: 3.16.0(@parcel/watcher@2.5.1)(@types/node@22.13.10)(db0@0.3.1)(ioredis@5.6.0)(lightningcss@1.29.2)(magicast@0.3.5)(rollup@4.35.0)(terser@5.39.0)(typescript@5.8.2)(vite@6.2.1(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.39.0)(yaml@2.7.0))(yaml@2.7.0)
|
||||
pinia:
|
||||
specifier: ^3.0.1
|
||||
version: 3.0.1(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2))
|
||||
tailwindcss:
|
||||
specifier: ^4.0.14
|
||||
version: 4.0.14
|
||||
@ -638,6 +653,11 @@ packages:
|
||||
resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
|
||||
'@pinia/nuxt@0.10.1':
|
||||
resolution: {integrity: sha512-xrpkKZHSmshPK6kQzboJ+TZiZ5zj73gBCI5SfiUaJkKKS9gx4B1hLEzJIjxZl0/HS5jRWrIvQ+u9ulvIRlNiow==}
|
||||
peerDependencies:
|
||||
pinia: ^3.0.1
|
||||
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
@ -1003,6 +1023,11 @@ packages:
|
||||
'@tailwindcss/postcss@4.0.13':
|
||||
resolution: {integrity: sha512-zTmnPGDYb2HKClTBTBwB+lLQH+Rq4etnQXFXs2lisRyXryUnoJIBByFTljkaK9F1d7o14h6t4NJIlfbZuOHR+A==}
|
||||
|
||||
'@tailwindcss/typography@0.5.16':
|
||||
resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==}
|
||||
peerDependencies:
|
||||
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
|
||||
|
||||
'@tailwindcss/vite@4.0.14':
|
||||
resolution: {integrity: sha512-y69ztPTRFy+13EPS/7dEFVl7q2Goh1pQueVO8IfGeyqSpcx/joNJXFk0lLhMgUbF0VFJotwRSb9ZY7Xoq3r26Q==}
|
||||
peerDependencies:
|
||||
@ -1059,6 +1084,9 @@ packages:
|
||||
peerDependencies:
|
||||
vue: '>=3.5.13'
|
||||
|
||||
'@uniiem/uuid@0.2.1':
|
||||
resolution: {integrity: sha512-p8DOA3BTkZgvgtOCtK5x7Y2l+GRTFhYrOua70YPiEEUomQFirwxpWrQBst+7oB/iPTeY1zHuF6MKl+mxi0R00A==}
|
||||
|
||||
'@vercel/nft@0.29.2':
|
||||
resolution: {integrity: sha512-A/Si4mrTkQqJ6EXJKv5EYCDQ3NL6nJXxG8VGXePsaiQigsomHYQC9xSpX8qGk7AEZk4b1ssbYIqJ0ISQQ7bfcA==}
|
||||
engines: {node: '>=18'}
|
||||
@ -1118,6 +1146,9 @@ packages:
|
||||
'@vue/devtools-api@6.6.4':
|
||||
resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
|
||||
|
||||
'@vue/devtools-api@7.7.2':
|
||||
resolution: {integrity: sha512-1syn558KhyN+chO5SjlZIwJ8bV/bQ1nOVTG66t2RbG66ZGekyiYNmRO7X9BJCXQqPsFHlnksqvPhce2qpzxFnA==}
|
||||
|
||||
'@vue/devtools-core@7.7.2':
|
||||
resolution: {integrity: sha512-lexREWj1lKi91Tblr38ntSsy6CvI8ba7u+jmwh2yruib/ltLUcsIzEjCnrkh1yYGGIKXbAuYV2tOG10fGDB9OQ==}
|
||||
peerDependencies:
|
||||
@ -2250,15 +2281,24 @@ packages:
|
||||
resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
lodash.castarray@4.4.0:
|
||||
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
|
||||
|
||||
lodash.defaults@4.2.0:
|
||||
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
|
||||
|
||||
lodash.isarguments@3.1.0:
|
||||
resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
|
||||
|
||||
lodash.isplainobject@4.0.6:
|
||||
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
|
||||
|
||||
lodash.memoize@4.1.2:
|
||||
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
|
||||
|
||||
lodash.merge@4.6.2:
|
||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||
|
||||
lodash.uniq@4.5.0:
|
||||
resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
|
||||
|
||||
@ -2567,6 +2607,15 @@ packages:
|
||||
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
pinia@3.0.1:
|
||||
resolution: {integrity: sha512-WXglsDzztOTH6IfcJ99ltYZin2mY8XZCXujkYWVIJlBjqsP6ST7zw+Aarh63E1cDVYeyUcPCxPHzJpEOmzB6Wg==}
|
||||
peerDependencies:
|
||||
typescript: '>=4.4.4'
|
||||
vue: ^2.7.0 || ^3.5.11
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
pkg-types@1.3.1:
|
||||
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
|
||||
|
||||
@ -2727,6 +2776,10 @@ packages:
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
|
||||
postcss-selector-parser@6.0.10:
|
||||
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
postcss-selector-parser@6.1.2:
|
||||
resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
|
||||
engines: {node: '>=4'}
|
||||
@ -4429,6 +4482,13 @@ snapshots:
|
||||
'@parcel/watcher-win32-ia32': 2.5.1
|
||||
'@parcel/watcher-win32-x64': 2.5.1
|
||||
|
||||
'@pinia/nuxt@0.10.1(magicast@0.3.5)(pinia@3.0.1(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2)))':
|
||||
dependencies:
|
||||
'@nuxt/kit': 3.16.0(magicast@0.3.5)
|
||||
pinia: 3.0.1(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2))
|
||||
transitivePeerDependencies:
|
||||
- magicast
|
||||
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
optional: true
|
||||
|
||||
@ -4718,6 +4778,14 @@ snapshots:
|
||||
postcss: 8.5.3
|
||||
tailwindcss: 4.0.13
|
||||
|
||||
'@tailwindcss/typography@0.5.16(tailwindcss@4.0.14)':
|
||||
dependencies:
|
||||
lodash.castarray: 4.4.0
|
||||
lodash.isplainobject: 4.0.6
|
||||
lodash.merge: 4.6.2
|
||||
postcss-selector-parser: 6.0.10
|
||||
tailwindcss: 4.0.14
|
||||
|
||||
'@tailwindcss/vite@4.0.14(vite@6.2.1(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.39.0)(yaml@2.7.0))':
|
||||
dependencies:
|
||||
'@tailwindcss/node': 4.0.14
|
||||
@ -4771,6 +4839,8 @@ snapshots:
|
||||
unhead: 2.0.0-rc.10
|
||||
vue: 3.5.13(typescript@5.8.2)
|
||||
|
||||
'@uniiem/uuid@0.2.1': {}
|
||||
|
||||
'@vercel/nft@0.29.2(rollup@4.35.0)':
|
||||
dependencies:
|
||||
'@mapbox/node-pre-gyp': 2.0.0
|
||||
@ -4877,6 +4947,10 @@ snapshots:
|
||||
|
||||
'@vue/devtools-api@6.6.4': {}
|
||||
|
||||
'@vue/devtools-api@7.7.2':
|
||||
dependencies:
|
||||
'@vue/devtools-kit': 7.7.2
|
||||
|
||||
'@vue/devtools-core@7.7.2(vite@6.2.1(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.39.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2))':
|
||||
dependencies:
|
||||
'@vue/devtools-kit': 7.7.2
|
||||
@ -5986,12 +6060,18 @@ snapshots:
|
||||
pkg-types: 2.1.0
|
||||
quansync: 0.2.8
|
||||
|
||||
lodash.castarray@4.4.0: {}
|
||||
|
||||
lodash.defaults@4.2.0: {}
|
||||
|
||||
lodash.isarguments@3.1.0: {}
|
||||
|
||||
lodash.isplainobject@4.0.6: {}
|
||||
|
||||
lodash.memoize@4.1.2: {}
|
||||
|
||||
lodash.merge@4.6.2: {}
|
||||
|
||||
lodash.uniq@4.5.0: {}
|
||||
|
||||
lodash@4.17.21: {}
|
||||
@ -6474,6 +6554,13 @@ snapshots:
|
||||
|
||||
picomatch@4.0.2: {}
|
||||
|
||||
pinia@3.0.1(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2)):
|
||||
dependencies:
|
||||
'@vue/devtools-api': 7.7.2
|
||||
vue: 3.5.13(typescript@5.8.2)
|
||||
optionalDependencies:
|
||||
typescript: 5.8.2
|
||||
|
||||
pkg-types@1.3.1:
|
||||
dependencies:
|
||||
confbox: 0.1.8
|
||||
@ -6626,6 +6713,11 @@ snapshots:
|
||||
postcss: 8.5.3
|
||||
postcss-value-parser: 4.2.0
|
||||
|
||||
postcss-selector-parser@6.0.10:
|
||||
dependencies:
|
||||
cssesc: 3.0.0
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
postcss-selector-parser@6.1.2:
|
||||
dependencies:
|
||||
cssesc: 3.0.0
|
||||
|
51
stores/state.ts
Normal file
51
stores/state.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import type { LocalMessage, VisitorRole } from "~/types";
|
||||
|
||||
export const useGState = defineStore("global_state", () => {
|
||||
const currentRole = ref<VisitorRole>("stu");
|
||||
const botName = computed(() => {
|
||||
switch (currentRole.value) {
|
||||
case "stu":
|
||||
return "AI 辅导员";
|
||||
case "tea":
|
||||
return "AI 教研专家";
|
||||
case "fans":
|
||||
return "校园百事通";
|
||||
default:
|
||||
return "AI 智慧校园";
|
||||
}
|
||||
});
|
||||
|
||||
const setCurrentRole = (role: VisitorRole) => {
|
||||
currentRole.value = role;
|
||||
};
|
||||
|
||||
const messagesByRole = ref<Record<VisitorRole, LocalMessage[]>>({
|
||||
stu: [],
|
||||
tea: [],
|
||||
fans: [],
|
||||
});
|
||||
const messages = computed({
|
||||
get: () => messagesByRole.value[currentRole.value],
|
||||
set: (value: LocalMessage[]) => {
|
||||
messagesByRole.value[currentRole.value] = value;
|
||||
},
|
||||
});
|
||||
|
||||
const insertOrUpdateMessage = (message: LocalMessage) => {
|
||||
const index = messages.value.findIndex((m) => m.id === message.id);
|
||||
if (index >= 0) {
|
||||
messages.value.splice(index, 1, message);
|
||||
} else {
|
||||
messages.value.push(message);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
currentRole,
|
||||
botName,
|
||||
setCurrentRole,
|
||||
messagesByRole,
|
||||
messages,
|
||||
insertOrUpdateMessage,
|
||||
};
|
||||
});
|
@ -1 +1,30 @@
|
||||
export type VisitorRole = "stu" | "tea" | "fans";
|
||||
|
||||
export type LocalMessage = {
|
||||
id: string;
|
||||
role: "bot" | "user";
|
||||
message?: string;
|
||||
};
|
||||
|
||||
export interface IWorkflowResponse {
|
||||
task_id: string;
|
||||
workflow_run_id: string;
|
||||
data: IWorkflowResponseData;
|
||||
}
|
||||
|
||||
export interface IWorkflowResponseData {
|
||||
id: string;
|
||||
workflow_id: string;
|
||||
status: string;
|
||||
outputs: IWorkflowInquiryOutputs;
|
||||
error: null;
|
||||
elapsed_time: number;
|
||||
total_tokens: number;
|
||||
total_steps: number;
|
||||
created_at: number;
|
||||
finished_at: number;
|
||||
}
|
||||
|
||||
export interface IWorkflowInquiryOutputs {
|
||||
message: string;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user