feat: assistant templates startup
This commit is contained in:
@@ -15,7 +15,7 @@ import {uuidv4} from '@uniiem/uuid'
|
||||
import {useLLM} from '~/composables/useLLM'
|
||||
import {trimObject} from '@uniiem/object-trim'
|
||||
import ModalAuthentication from '~/components/ModalAuthentication.vue'
|
||||
import {useAsyncData} from '#app'
|
||||
import NewSessionScreen from '~/components/aigc/chat/NewSessionScreen.vue'
|
||||
|
||||
useHead({
|
||||
title: '聊天 | XSH AI',
|
||||
@@ -25,7 +25,6 @@ const dayjs = useDayjs()
|
||||
const toast = useToast()
|
||||
const modal = useModal()
|
||||
const loginState = useLoginState()
|
||||
const {token, user, is_logged_in} = storeToRefs(loginState)
|
||||
const historyStore = useHistory()
|
||||
const {chatSessions} = storeToRefs(historyStore)
|
||||
const {setChatSessions} = historyStore
|
||||
@@ -37,32 +36,13 @@ const showSidebar = ref(false)
|
||||
const user_input = ref('')
|
||||
const responding = ref(false)
|
||||
const currentModel = ref<ModelTag>('spark3_5')
|
||||
const currentAssistant = computed<Assistant | null>(() => getSessionCopyById(currentSessionId.value || '')?.assistant || null)
|
||||
const modals = reactive({
|
||||
modelSelect: false,
|
||||
assistantSelect: false,
|
||||
newSessionScreen: false,
|
||||
})
|
||||
|
||||
loginState.$subscribe((mutation, state) => {
|
||||
console.log(mutation, state)
|
||||
})
|
||||
|
||||
const {
|
||||
data: assistantTemplates
|
||||
} = await useAsyncData(
|
||||
'App.Assistant_Template.GetList',
|
||||
() => useFetchWrapped<
|
||||
req.AssistantTemplateList & AuthedRequest, PagedData<Assistant>
|
||||
>('App.Assistant_Template.GetList', {
|
||||
user_id: loginState.user.id,
|
||||
token: loginState.token as string,
|
||||
page: 1,
|
||||
perpage: 20,
|
||||
}),
|
||||
{
|
||||
immediate: true,
|
||||
watch: [is_logged_in],
|
||||
},
|
||||
)
|
||||
|
||||
/**
|
||||
* 获取指定 ID 的会话数据
|
||||
* @param chatSessionId
|
||||
@@ -98,39 +78,79 @@ const selectCurrentSessionId = (chatSessionId?: ChatSessionId) => {
|
||||
}
|
||||
nextTick(() => {
|
||||
showSidebar.value = false
|
||||
modals.newSessionScreen = false
|
||||
scrollToMessageListBottom()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理新建会话操作
|
||||
* 创建新会话处理函数
|
||||
* @param assistant 指定助手,不传或空值则不指定助手
|
||||
*/
|
||||
const handleClickCreateSession = () => {
|
||||
const createSession = (assistant: Assistant | null) => {
|
||||
// 生成一个新的会话 ID
|
||||
const sessionId = uuidv4()
|
||||
// 新会话数据
|
||||
const newChat = !!assistant ? {
|
||||
id: sessionId,
|
||||
subject: '新对话',
|
||||
messages: [],
|
||||
create_at: dayjs().unix(),
|
||||
assistant,
|
||||
} : {
|
||||
id: sessionId,
|
||||
subject: '新对话',
|
||||
messages: [],
|
||||
create_at: dayjs().unix(),
|
||||
}
|
||||
// 插入新会话数据
|
||||
setChatSessions([
|
||||
{
|
||||
id: sessionId,
|
||||
subject: '新对话',
|
||||
messages: [],
|
||||
create_at: dayjs().unix(),
|
||||
},
|
||||
newChat,
|
||||
...chatSessions.value,
|
||||
])
|
||||
// 切换到新的会话
|
||||
selectCurrentSessionId(sessionId)
|
||||
// TODO: Model or Assistant Selection
|
||||
// modals.modelSelect = true
|
||||
// 关闭新建会话屏幕
|
||||
modals.newSessionScreen = false
|
||||
nextTick(() => {
|
||||
insetMessage({
|
||||
id: uuidv4(),
|
||||
role: 'assistant',
|
||||
content: '你好,有什么可以帮助你的吗?',
|
||||
})
|
||||
if (!!currentAssistant.value) {
|
||||
insetMessage({
|
||||
id: uuidv4(),
|
||||
role: 'system',
|
||||
content: currentAssistant.value?.role || '',
|
||||
preset: true,
|
||||
})
|
||||
insetMessage({
|
||||
id: uuidv4(),
|
||||
role: 'user',
|
||||
content: `${currentAssistant.value?.target},${currentAssistant.value?.demand}`,
|
||||
preset: true,
|
||||
})
|
||||
insetMessage({
|
||||
id: uuidv4(),
|
||||
role: 'assistant',
|
||||
content: currentAssistant.value?.input_tpl || '',
|
||||
preset: true,
|
||||
})
|
||||
} else {
|
||||
insetMessage({
|
||||
id: uuidv4(),
|
||||
role: 'assistant',
|
||||
content: '你好,有什么可以帮助你的吗?',
|
||||
preset: true,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理点击新建会话按钮事件
|
||||
*/
|
||||
const handleClickCreateSession = () => {
|
||||
showSidebar.value = false
|
||||
modals.newSessionScreen = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理发送消息操作
|
||||
* @param event
|
||||
@@ -273,83 +293,98 @@ onMounted(() => {
|
||||
</div>
|
||||
</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 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">
|
||||
<TransitionGroup name="message">
|
||||
<Message
|
||||
v-for="message in getMessages() || []"
|
||||
:message="message"
|
||||
:key="message.id"
|
||||
/>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
<pre>{{assistantTemplates}}</pre>
|
||||
</div>
|
||||
<ClientOnly>
|
||||
<div class="h-[calc(100vh-4rem)] flex-1 bg-white dark:bg-neutral-900">
|
||||
|
||||
<Transition name="message" mode="out-in">
|
||||
<NewSessionScreen
|
||||
v-if="modals.newSessionScreen"
|
||||
@select="createSession"
|
||||
@cancel="modals.newSessionScreen = false"
|
||||
/>
|
||||
<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 class="flex items-center gap-2 overflow-auto overflow-y-hidden">
|
||||
<button class="chat-option-btn" @click="modals.modelSelect = true">
|
||||
<Icon name="tabler:box"/>
|
||||
<span class="text-xs">
|
||||
{{ llmModels.find(m => m.tag === currentModel)?.name.toUpperCase() || '模型' }}
|
||||
</span>
|
||||
</button>
|
||||
<button class="chat-option-btn" @click="modals.modelSelect = true">
|
||||
<Icon name="tabler:robot-face"/>
|
||||
<span class="text-xs">
|
||||
助手
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<UTextarea
|
||||
v-model="user_input"
|
||||
size="lg"
|
||||
autoresize
|
||||
:rows="5"
|
||||
:maxrows="12"
|
||||
class="font-sans"
|
||||
placeholder="Enter 发送, Ctrl + Enter 换行"
|
||||
@keydown.ctrl.enter="user_input += '\n'"
|
||||
@keydown.enter.prevent="handleClickSend"
|
||||
/>
|
||||
v-else
|
||||
class="w-full h-full flex flex-col"
|
||||
>
|
||||
<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="solid"
|
||||
icon="i-tabler-send-2"
|
||||
class="absolute bottom-2.5 right-3"
|
||||
@click.stop="handleClickSend"
|
||||
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">
|
||||
<TransitionGroup name="message">
|
||||
<Message
|
||||
v-for="message in getMessages() || []"
|
||||
:message="message"
|
||||
:key="message.id"
|
||||
/>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</div>
|
||||
<ClientOnly>
|
||||
<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 class="flex items-center gap-2 overflow-auto overflow-y-hidden">
|
||||
<button class="chat-option-btn" @click="modals.modelSelect = true">
|
||||
<Icon name="tabler:box"/>
|
||||
<span class="text-xs">
|
||||
{{ llmModels.find(m => m.tag === currentModel)?.name.toUpperCase() || '模型' }}
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="currentAssistant?.tpl_name"
|
||||
class="chat-option-btn"
|
||||
>
|
||||
<Icon name="tabler:robot-face"/>
|
||||
<span class="text-xs">
|
||||
{{ currentAssistant.tpl_name }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<UTextarea
|
||||
v-model="user_input"
|
||||
size="lg"
|
||||
autoresize
|
||||
:rows="5"
|
||||
:maxrows="12"
|
||||
class="font-sans"
|
||||
placeholder="Enter 发送, Ctrl + Enter 换行"
|
||||
@keydown.ctrl.enter="user_input += '\n'"
|
||||
@keydown.enter.prevent="handleClickSend"
|
||||
/>
|
||||
<UButton
|
||||
color="black"
|
||||
variant="solid"
|
||||
icon="i-tabler-send-2"
|
||||
class="absolute bottom-2.5 right-3"
|
||||
@click.stop="handleClickSend"
|
||||
>
|
||||
发送
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
</ClientOnly>
|
||||
</Transition>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Modals -->
|
||||
<UModal prevent-close v-model="modals.modelSelect">
|
||||
<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"
|
||||
@@ -358,14 +393,13 @@ onMounted(() => {
|
||||
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"/>
|
||||
<Icon v-if="llm?.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>
|
||||
@@ -375,6 +409,7 @@ onMounted(() => {
|
||||
</template>
|
||||
</UCard>
|
||||
</UModal>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user