Skip to content

Commit

Permalink
refactor: Update store and locale about ai assistant
Browse files Browse the repository at this point in the history
  • Loading branch information
FU-design committed Dec 3, 2024
1 parent b4acbbc commit 2a81ef9
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 51 deletions.
7 changes: 7 additions & 0 deletions bigtop-manager-ui/src/api/ai-assistant/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export interface ChatThread {
threadId?: number | string
authId?: number | string
platformId?: number | string
platformName?: string
model?: string
name?: string
createTime?: string
updateTime?: string
Expand All @@ -46,3 +48,8 @@ export interface ChatMessageItem {
message: string
createTime?: string
}

export interface ReceivedMessageItem {
content?: string
finishReason?: 'completed' | null
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 39 additions & 18 deletions bigtop-manager-ui/src/components/ai-assistant/empty-content.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,26 @@
import { shallowRef } from 'vue'
import { usePngImage } from '@/utils/tools'
import { useAiChatStore } from '@/store/ai-assistant'
import { storeToRefs } from 'pinia'

interface Emits {
(event: 'goSetUp'): void
}

const emits = defineEmits<Emits>()

const imageStyle = shallowRef({
height: '200px',
marginBottom: '16px'
})
const aiChatStore = useAiChatStore()
const { hasActivePlatform } = storeToRefs(aiChatStore)
const emptyState = usePngImage('ai_helper')
const disabledState = usePngImage('ai_disabled')

const goSetUpLlmConfig = () => {
emits('goSetUp')
}

const quickAsk = (message: string) => {
aiChatStore.setChatRecordForSender('USER', message)
Expand All @@ -36,25 +49,33 @@

<template>
<div class="empty-content">
<a-empty :image="emptyState" :image-style="imageStyle">
<a-empty :image="hasActivePlatform ? emptyState : disabledState" :image-style="imageStyle">
<template #description>
<div class="say-hello">
<a-typography-title :level="5">
<div> {{ $t('aiAssistant.greeting') }} </div>
<div> {{ $t('aiAssistant.help') }} </div>
</a-typography-title>
</div>
<div class="feature-desc">
<a-typography-link underline @click="quickAsk($t('aiAssistant.bigtop_manager'))">
{{ $t('aiAssistant.bigtop_manager') }}
</a-typography-link>
<a-typography-link underline @click="quickAsk($t('aiAssistant.can_do_for_you'))">
{{ $t('aiAssistant.can_do_for_you') }}
</a-typography-link>
<a-typography-link underline @click="quickAsk($t('aiAssistant.big_data_news'))">
{{ $t('aiAssistant.big_data_news') }}
</a-typography-link>
</div>
<template v-if="hasActivePlatform">
<div class="say-hello">
<a-typography-title :level="5">
<div> {{ $t('aiAssistant.greeting') }} </div>
<div> {{ $t('aiAssistant.help') }} </div>
</a-typography-title>
</div>
<div class="feature-desc">
<a-typography-link underline @click="quickAsk($t('aiAssistant.bigtop_manager'))">
{{ $t('aiAssistant.bigtop_manager') }}
</a-typography-link>
<a-typography-link underline @click="quickAsk($t('aiAssistant.can_do_for_you'))">
{{ $t('aiAssistant.can_do_for_you') }}
</a-typography-link>
<a-typography-link underline @click="quickAsk($t('aiAssistant.big_data_news'))">
{{ $t('aiAssistant.big_data_news') }}
</a-typography-link>
</div>
</template>
<template v-else>
<a-typography-text>
<div> {{ $t('aiAssistant.ai_disabled_msg') }} </div>
</a-typography-text>
<a-typography-link underline @click="goSetUpLlmConfig"> {{ $t('aiAssistant.go_set_up') }} </a-typography-link>
</template>
</template>
</a-empty>
</div>
Expand Down
60 changes: 36 additions & 24 deletions bigtop-manager-ui/src/components/ai-assistant/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import ChatMessage from './chat-message.vue'
import type { ChatMessageItem } from '@/api/ai-assistant/types'
import type { GroupItem } from '@/components/common/button-group/types'
import { useRouter } from 'vue-router'

enum Action {
ADD,
Expand All @@ -39,10 +40,11 @@

type ActionType = keyof typeof Action

const router = useRouter()
const aiChatStore = useAiChatStore()
const llmConfigStore = useLlmConfigStore()
const { currThread, chatRecords, threads, messageReceiver, loadingChatRecords } = storeToRefs(aiChatStore)
const { currAuthPlatform: currPlatform } = storeToRefs(llmConfigStore)
const { currThread, chatRecords, threads, messageReceiver, hasActivePlatform, loadingChatRecords } =
storeToRefs(aiChatStore)

const open = ref(false)
const title = ref('aiAssistant.ai_assistant')
Expand All @@ -54,28 +56,43 @@
const noChat = computed(() => Object.keys(currThread.value).length === 0 || chatRecords.value.length === 0)
const historyVisible = computed(() => fullScreen.value && open.value)
const historyType = computed(() => (historyVisible.value ? 'large' : 'small'))
const authPlatformCached = computed(() => Object.keys(currPlatform.value || {}).length > 0)
const recordReceiver = computed((): ChatMessageItem => ({ sender: 'AI', message: messageReceiver.value }))
const checkActions = computed(() =>
fullScreen.value ? filterActions(['EXITSCREEN', 'CLOSE']) : filterActions(['ADD', 'RECORDS', 'FULLSCREEN', 'CLOSE'])
)
const checkActions = computed(() => {
if (!hasActivePlatform.value) {
return filterActions(['CLOSE'])
}
return fullScreen.value
? filterActions(['EXITSCREEN', 'CLOSE'])
: filterActions(['ADD', 'RECORDS', 'FULLSCREEN', 'CLOSE'])
})
const addIcon = computed(() => (threads.value.length >= 10 ? 'plus_gray' : 'plus'))
const addState = computed(() => threads.value.length >= 10 || loadingChatRecords.value || !hasActivePlatform.value)
const actionGroup = computed((): GroupItem<ActionType>[] => [
{
tip: 'new_chat',
icon: addIcon.value,
action: 'ADD',
clickEvent: aiChatStore.createChatThread,
disabled: threads.value.length >= 10 || loadingChatRecords.value
disabled: addState.value
},
{
tip: 'history',
icon: 'history',
action: 'RECORDS',
clickEvent: openRecord
},
{ tip: 'full_screen', icon: 'full_screen', action: 'FULLSCREEN', clickEvent: toggleFullScreen },
{ tip: 'exit_screen', icon: 'exit_screen', action: 'EXITSCREEN', clickEvent: toggleFullScreen },
{
tip: 'full_screen',
icon: 'full_screen',
action: 'FULLSCREEN',
clickEvent: toggleFullScreen
},
{
tip: 'exit_screen',
icon: 'exit_screen',
action: 'EXITSCREEN',
clickEvent: toggleFullScreen
},
{ icon: 'close', action: 'CLOSE', clickEvent: () => controlVisible(false) }
])

Expand Down Expand Up @@ -112,18 +129,8 @@
actionGroup.value.forEach(({ action, clickEvent }) => {
action && actionHandlers.value.set(action, clickEvent || (() => {}))
})
!authPlatformCached.value && (await llmConfigStore.getAuthorizedPlatforms())
if (Object.keys(currThread.value).length == 0) {
if (threads.value.length === 0) {
aiChatStore.createChatThread()
} else {
currThread.value = threads.value[0]
aiChatStore.getThreadRecords()
}
} else {
aiChatStore.getThreadsFromAuthPlatform()
aiChatStore.getThreadRecords()
}
!hasActivePlatform.value && (await llmConfigStore.getAuthorizedPlatforms())
aiChatStore.initCurrThread()
}

const filterActions = (showActions?: ActionType[]) => {
Expand All @@ -136,6 +143,11 @@
handler ? handler() : console.warn(`Unknown action: ${item.action}`)
}

const goSetUpLlmConfig = () => {
controlVisible(false)
router.push('/system-mange/llm-config')
}

defineExpose({
controlVisible
})
Expand Down Expand Up @@ -163,7 +175,7 @@
<chat-history ref="smallChatHistoryRef" :history-type="historyType" />
<div class="chat">
<a-spin :spinning="loadingChatRecords">
<empty-content v-if="noChat" />
<empty-content v-if="noChat" @go-set-up="goSetUpLlmConfig" />
<template v-else>
<div v-if="open" v-auto-scroll class="chat-content">
<chat-message v-for="(record, idx) in chatRecords" :key="idx" :record="record" />
Expand All @@ -172,10 +184,10 @@
</template>
</a-spin>
</div>
<template #footer>
<template v-if="hasActivePlatform" #footer>
<chat-input />
<a-typography-text type="secondary" class="ai-assistant-desc">
{{ currPlatform?.platformName }} {{ currPlatform?.model }}
{{ currThread?.platformName }} {{ currThread?.model }}
</a-typography-text>
</template>
</a-drawer>
Expand Down
4 changes: 3 additions & 1 deletion bigtop-manager-ui/src/locales/en_US/ai-assistant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@ export default {
help: 'How can I assist you today?',
bigtop_manager: 'What is Bigtop Manager?',
can_do_for_you: 'What can you do for me?',
big_data_news: 'What interesting things are happening in the field of Big Data?'
big_data_news: 'What interesting things are happening in the field of Big Data?',
ai_disabled_msg: 'Sorry, the large model is not set up, so the AI assistant is not available.',
go_set_up: 'Go to set it up'
}
4 changes: 3 additions & 1 deletion bigtop-manager-ui/src/locales/zh_CN/ai-assistant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@ export default {
help: '请问有什么可以帮助你的吗?',
bigtop_manager: '什么是Bigtop Manager?',
can_do_for_you: '你可以为我做什么?',
big_data_news: '大数据领域最近有什么有趣的事?'
big_data_news: '大数据领域最近有什么有趣的事?',
ai_disabled_msg: '抱歉,你还没有配置大模型,无法使用 AI 助理',
go_set_up: '前往配置'
}
48 changes: 41 additions & 7 deletions bigtop-manager-ui/src/store/ai-assistant/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { SenderType } from '@/api/ai-assistant/types'
import { getRandomFromTimestamp } from '@/utils/tools'
import { useLlmConfigStore } from '../llm-config'
import type { AxiosProgressEvent, Canceler } from 'axios'
import type { ChatMessageItem, ChatThread, ThreadId } from '@/api/ai-assistant/types'
import type { ChatMessageItem, ChatThread, ReceivedMessageItem, ThreadId } from '@/api/ai-assistant/types'

export const useAiChatStore = defineStore(
'ai-assistant',
Expand All @@ -41,6 +41,7 @@ export const useAiChatStore = defineStore(
const isSending = ref(false)
const loadingChatRecords = ref(false)

const hasActivePlatform = computed(() => Object.keys(currAuthPlatform.value || {}).length > 0)
const threadLimit = computed(() => threads.value.length >= 10)

watch(currAuthPlatform, (val, oldVal) => {
Expand All @@ -59,11 +60,31 @@ export const useAiChatStore = defineStore(
loadingChatRecords.value = false
}

const initCurrThread = () => {
if (Object.keys(currThread.value).length == 0) {
if (threads.value.length === 0) {
createChatThread()
} else {
currThread.value = threads.value[0]
getThreadRecords()
}
} else {
getThreadsFromAuthPlatform()
getThreadRecords()
}
}

const createChatThread = async () => {
const tempName = `thread-${getRandomFromTimestamp()}`
const data = await ai.createChatThread({ id: null, name: tempName })
getThread(data.threadId as ThreadId)
getThreadsFromAuthPlatform()
try {
const tempName = `thread-${getRandomFromTimestamp()}`
const data = await ai.createChatThread({ id: null, name: tempName })
if (data) {
getThread(data.threadId as ThreadId)
getThreadsFromAuthPlatform()
}
} catch (error) {
console.log('error :>> ', error)
}
}

const updateChatThread = async (thread: ChatThread, newName: string) => {
Expand Down Expand Up @@ -142,11 +163,22 @@ export const useAiChatStore = defineStore(
}
}

const checkReceiveMessageError = (item: ReceivedMessageItem) => {
if (item.content != undefined) {
return item.content
} else if (item.finishReason && item.finishReason != 'completed') {
return item.finishReason
}
}

const onMessageReceive = ({ event }: AxiosProgressEvent) => {
messageReceiver.value = event.target.responseText
.split('data:')
.map((s: string) => {
return s.trimEnd()
.map((stream: string) => {
if (stream.length > 0) {
const parsedMsgInfo = JSON.parse(stream.trimEnd())
return checkReceiveMessageError(parsedMsgInfo)
}
})
.join('')
}
Expand Down Expand Up @@ -182,6 +214,8 @@ export const useAiChatStore = defineStore(
isSending,
loadingChatRecords,
threadLimit,
hasActivePlatform,
initCurrThread,
talkWithChatbot,
createChatThread,
updateChatThread,
Expand Down

0 comments on commit 2a81ef9

Please sign in to comment.