feat: 对接星火大模型

feat: 大模型选择器
feat: 聊天页面适配手机端
This commit is contained in:
2024-04-03 15:51:51 +08:00
parent a10e492922
commit e02b0ffcc6
6 changed files with 497 additions and 445 deletions

View File

@@ -1,7 +1,14 @@
<script lang="ts" setup>
import ChatItem from "~/components/aigc/chat/ChatItem.vue";
import Message from "~/components/aigc/chat/Message.vue";
import type {ChatMessage, ChatMessageId, ChatSessionId} from "~/typings/llm";
import {
type ChatMessage,
type ChatMessageId,
type ChatSession,
type ChatSessionId,
llmModels,
type ModelTag
} from "~/typings/llm";
import {useHistory} from "~/composables/useHistory";
import {uuidv4} from "@uniiem/uuid";
import {useLLM} from "~/composables/useLLM";
@@ -17,18 +24,22 @@ const historyStore = useHistory()
const {chatSessions} = storeToRefs(historyStore)
const {setChatSessions} = historyStore
// const chatSessions = ref<ChatSession[]>([])
const currentSessionId = ref<ChatSessionId | null>(null)
const messagesWrapperRef = ref<HTMLDivElement | null>(null)
const showSidebar = ref(false)
const user_input = ref('')
const responding = ref(false)
const currentModel = ref<ModelTag>('spark3_5')
const modals = reactive({
modelSelect: false
})
/**
* 获取指定 ID 的会话数据
* @param chatSessionId
*/
const getSessionCopyById = (chatSessionId: ChatSessionId) => chatSessions.value.find(s => s.id === chatSessionId);
const getSessionCopyById = (chatSessionId: ChatSessionId): ChatSession | undefined => chatSessions.value.find(s => s.id === chatSessionId);
/**
* 切换当前会话
* @param chatSessionId 指定会话 ID不传则切换到列表中第一个会话
@@ -58,6 +69,7 @@ const selectCurrentSessionId = (chatSessionId?: ChatSessionId) => {
handleClickCreateSession()
}
nextTick(() => {
showSidebar.value = false
scrollToMessageListBottom()
})
}
@@ -80,6 +92,7 @@ const handleClickCreateSession = () => {
])
// 切换到新的会话
selectCurrentSessionId(sessionId)
modals.modelSelect = true
nextTick(() => {
insetMessage({
id: uuidv4(),
@@ -129,7 +142,7 @@ const handleClickSend = (event: any) => {
keys: ['content']
})
useLLM(trimmedMessages, {
modelTag: 'spark3_5'
modelTag: currentModel.value
}).then(reply => {
modifyMessageContent(assistantReplyId, reply)
}).catch(err => {
@@ -188,8 +201,11 @@ onMounted(() => {
<template>
<div class="w-full flex relative">
<div class="h-[calc(100vh-4rem)] bg-neutral-100 dark:bg-neutral-900 p-4 flex flex-col w-[300px]
shadow-sidebar border-r border-transparent dark:border-neutral-700">
<div
class="absolute -translate-x-full md:sticky md:translate-x-0 z-10 flex flex-col h-[calc(100vh-4rem)] bg-neutral-100 dark:bg-neutral-900 p-4 w-full md:w-[300px]
shadow-sidebar border-r border-transparent dark:border-neutral-700 transition-all duration-300 ease-out"
:class="{'translate-x-0': showSidebar}"
>
<div class="flex-1 flex flex-col overflow-auto overflow-x-hidden">
<!-- list -->
<div class="flex flex-col gap-3 relative">
@@ -225,8 +241,16 @@ onMounted(() => {
</div>
</div>
<div class="h-[calc(100vh-4rem)] bg-white dark:bg-neutral-900 flex-1 flex flex-col">
<div class="w-full p-4 bg-neutral-50 dark:bg-neutral-800/50 border-b dark:border-neutral-700/50">
{{ getSessionCopyById(currentSessionId!)?.subject || '新对话' }}
<div class="w-full p-4 bg-neutral-50 dark:bg-neutral-800/50 border-b dark:border-neutral-700/50 flex items-center gap-2">
<UButton
class="md:hidden"
color="black"
variant="ghost"
icon="i-tabler-menu-2"
@click="showSidebar = !showSidebar"
>
</UButton>
<h1 class="font-medium">{{ getSessionCopyById(currentSessionId!)?.subject || '新对话' }}</h1>
</div>
<div ref="messagesWrapperRef" class="flex-1 flex flex-col overflow-auto overflow-x-hidden">
<div class="flex flex-col gap-8 px-4 py-8">
@@ -241,7 +265,14 @@ onMounted(() => {
</div>
<div
class="w-full p-4 pt-2 flex flex-col gap-2 bg-neutral-50 dark:bg-neutral-800/50 border-t dark:border-neutral-700/50">
<div>action bar</div>
<div class="flex items-center gap-2 overflow-auto overflow-y-hidden">
<button class="chat-option-btn" @click="modals.modelSelect = true">
<Icon name="tabler:robot-face"/>
<span class="text-xs">
{{ llmModels.find(m => m.tag === currentModel)?.name.toUpperCase() || '模型' }}
</span>
</button>
</div>
<div class="relative">
<UTextarea
v-model="user_input"
@@ -266,6 +297,41 @@ onMounted(() => {
</div>
</div>
</div>
<!-- Modals -->
<UModal v-model="modals.modelSelect">
<UCard>
<template #header>
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
选择大语言模型
</h3>
</template>
<div class="grid grid-cols-3 gap-4">
<div
v-for="(llm, index) in llmModels"
:key="index"
@click="currentModel = llm.tag"
class="flex flex-col gap-2 justify-center items-center w-full aspect-[1/1] border-2 rounded-xl cursor-pointer transition duration-150 select-none"
:class="llm.tag === currentModel ? 'border-primary shadow-xl bg-primary text-white' : 'dark:border-neutral-800 bg-white dark:bg-black shadow-card'"
>
<Icon :name="llm?.icon" class="text-4xl opacity-80"/>
<div class="flex flex-col gap-0.5 items-center">
<h1 class="font-bold drop-shadow opacity-90">{{ llm.name || 'unknown' }}</h1>
<p class="text-xs opacity-60">{{ llm.description }}</p>
</div>
</div>
</div>
<template #footer>
<div class="flex justify-end items-center" @click="modals.modelSelect = false">
<UButton>
确定
</UButton>
</div>
</template>
</UCard>
</UModal>
</div>
</template>
@@ -293,4 +359,10 @@ onMounted(() => {
.chat-item-leave-active {
@apply absolute inset-x-0;
}
.chat-option-btn {
@apply text-lg px-2 py-1.5 flex gap-1 justify-center items-center rounded-lg;
@apply bg-white border border-neutral-300 shadow-sm hover:shadow-card;
@apply dark:bg-neutral-800 dark:border-neutral-600;
}
</style>