refactor(stage-ui,stage-web,stage-tamagotchi): rename as useContextBridgeStore
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { defineInvoke, defineInvokeHandler } from '@moeru/eventa'
|
||||
import { useContextBridge } from '@proj-airi/stage-ui/composables'
|
||||
import { useSharedAnalyticsStore } from '@proj-airi/stage-ui/stores/analytics'
|
||||
import { useDisplayModelsStore } from '@proj-airi/stage-ui/stores/display-models'
|
||||
import { useModsServerChannelStore } from '@proj-airi/stage-ui/stores/mods/api/channel-server'
|
||||
import { useContextBridgeStore } from '@proj-airi/stage-ui/stores/mods/api/context-bridge'
|
||||
import { useAiriCardStore } from '@proj-airi/stage-ui/stores/modules/airi-card'
|
||||
import { useOnboardingStore } from '@proj-airi/stage-ui/stores/onboarding'
|
||||
import { useSettings } from '@proj-airi/stage-ui/stores/settings'
|
||||
@@ -19,7 +19,7 @@ import { themeColorFromValue, useThemeColor } from './composables/theme-color'
|
||||
|
||||
const { isDark: dark } = useTheme()
|
||||
const i18n = useI18n()
|
||||
const contextBridge = useContextBridge()
|
||||
const contextBridgeStore = useContextBridgeStore()
|
||||
const displayModelsStore = useDisplayModelsStore()
|
||||
const settingsStore = useSettings()
|
||||
const { language, themeColorsHue, themeColorsHueDynamic } = storeToRefs(settingsStore)
|
||||
@@ -49,7 +49,7 @@ onMounted(async () => {
|
||||
await settingsStore.initializeStageModel()
|
||||
|
||||
await serverChannelStore.initialize({ possibleEvents: ['ui:configure'] }).catch((err) => { console.error('Failed to initialize Mods Server Channel in App.vue:', err) })
|
||||
await contextBridge.initialize()
|
||||
await contextBridgeStore.initialize()
|
||||
|
||||
const context = useElectronEventaContext()
|
||||
const startTrackingCursorPoint = defineInvoke(context.value, electronStartTrackMousePosition)
|
||||
@@ -67,7 +67,7 @@ watch(themeColorsHueDynamic, () => {
|
||||
document.documentElement.classList.toggle('dynamic-hue', themeColorsHueDynamic.value)
|
||||
}, { immediate: true })
|
||||
|
||||
onUnmounted(() => contextBridge.dispose())
|
||||
onUnmounted(() => contextBridgeStore.dispose())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { OnboardingDialog, ToasterRoot } from '@proj-airi/stage-ui/components'
|
||||
import { useContextBridge } from '@proj-airi/stage-ui/composables'
|
||||
import { useSharedAnalyticsStore } from '@proj-airi/stage-ui/stores/analytics'
|
||||
import { useDisplayModelsStore } from '@proj-airi/stage-ui/stores/display-models'
|
||||
import { useModsServerChannelStore } from '@proj-airi/stage-ui/stores/mods/api/channel-server'
|
||||
import { useContextBridgeStore } from '@proj-airi/stage-ui/stores/mods/api/context-bridge'
|
||||
import { useAiriCardStore } from '@proj-airi/stage-ui/stores/modules/airi-card'
|
||||
import { useOnboardingStore } from '@proj-airi/stage-ui/stores/onboarding'
|
||||
import { useSettings } from '@proj-airi/stage-ui/stores/settings'
|
||||
@@ -21,7 +21,7 @@ import 'vue-sonner/style.css'
|
||||
|
||||
usePWAStore()
|
||||
|
||||
const contextBridge = useContextBridge()
|
||||
const contextBridgeStore = useContextBridgeStore()
|
||||
const i18n = useI18n()
|
||||
const displayModelsStore = useDisplayModelsStore()
|
||||
const settingsStore = useSettings()
|
||||
@@ -75,14 +75,14 @@ onMounted(async () => {
|
||||
onboardingStore.initializeSetupCheck()
|
||||
|
||||
await serverChannelStore.initialize({ possibleEvents: ['ui:configure'] }).catch((err) => { console.error('Failed to initialize Mods Server Channel in App.vue:', err) })
|
||||
await contextBridge.initialize()
|
||||
await contextBridgeStore.initialize()
|
||||
|
||||
await displayModelsStore.loadDisplayModelsFromIndexedDB()
|
||||
await settingsStore.initializeStageModel()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
contextBridge.dispose()
|
||||
contextBridgeStore.dispose()
|
||||
})
|
||||
|
||||
// Handle first-time setup events
|
||||
|
||||
@@ -6,5 +6,4 @@ export * from './micvad'
|
||||
export * from './queues'
|
||||
export * from './use-analytics'
|
||||
export * from './use-build-info'
|
||||
export * from './use-context-bridge'
|
||||
export * from './whisper'
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
import type { ChatStreamEvent, ContextMessage } from '../types/chat'
|
||||
|
||||
import { useBroadcastChannel } from '@vueuse/core'
|
||||
import { Mutex } from 'es-toolkit'
|
||||
import { watch } from 'vue'
|
||||
|
||||
import { CHAT_STREAM_CHANNEL_NAME, CONTEXT_CHANNEL_NAME, useChatStore } from '../stores/chat'
|
||||
import { useModsServerChannelStore } from '../stores/mods/api/channel-server'
|
||||
|
||||
const mutex = new Mutex()
|
||||
|
||||
export function useContextBridge() {
|
||||
const chatStore = useChatStore()
|
||||
const serverChannelStore = useModsServerChannelStore()
|
||||
|
||||
const { post: broadcastContext, data: incomingContext } = useBroadcastChannel<ContextMessage, ContextMessage>({ name: CONTEXT_CHANNEL_NAME })
|
||||
const { post: broadcastStreamEvent, data: incomingStreamEvent } = useBroadcastChannel<ChatStreamEvent, ChatStreamEvent>({ name: CHAT_STREAM_CHANNEL_NAME })
|
||||
|
||||
let disposeHookFns = [] as Array<() => void>
|
||||
|
||||
return {
|
||||
initialize: async () => {
|
||||
await mutex.acquire()
|
||||
|
||||
try {
|
||||
let isProcessingRemoteStream = false
|
||||
|
||||
const { stop } = watch(incomingContext, (event) => {
|
||||
if (event)
|
||||
chatStore.ingestContextMessage(event)
|
||||
})
|
||||
disposeHookFns.push(stop)
|
||||
|
||||
disposeHookFns.push(serverChannelStore.onContextUpdate((event) => {
|
||||
chatStore.ingestContextMessage({ source: event.source, createdAt: Date.now(), ...event.data })
|
||||
broadcastContext(event.data as ContextMessage)
|
||||
}))
|
||||
|
||||
disposeHookFns.push(
|
||||
chatStore.onBeforeMessageComposed(async (message) => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'before-compose', message, sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
chatStore.onAfterMessageComposed(async (message) => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'after-compose', message, sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
chatStore.onBeforeSend(async (message) => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'before-send', message, sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
chatStore.onAfterSend(async (message) => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'after-send', message, sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
chatStore.onTokenLiteral(async (literal) => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'token-literal', literal, sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
chatStore.onTokenSpecial(async (special) => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'token-special', special, sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
chatStore.onStreamEnd(async () => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'stream-end', sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
chatStore.onAssistantResponseEnd(async (message) => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'assistant-end', message, sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
)
|
||||
|
||||
const { stop: stopIncomingStreamWatch } = watch(incomingStreamEvent, async (event) => {
|
||||
if (!event)
|
||||
return
|
||||
|
||||
isProcessingRemoteStream = true
|
||||
try {
|
||||
if (event.sessionId && chatStore.activeSessionId !== event.sessionId)
|
||||
chatStore.setActiveSession(event.sessionId)
|
||||
|
||||
switch (event.type) {
|
||||
case 'before-compose':
|
||||
await chatStore.emitBeforeMessageComposedHooks(event.message)
|
||||
break
|
||||
case 'after-compose':
|
||||
await chatStore.emitAfterMessageComposedHooks(event.message)
|
||||
break
|
||||
case 'before-send':
|
||||
await chatStore.emitBeforeSendHooks(event.message)
|
||||
break
|
||||
case 'after-send':
|
||||
await chatStore.emitAfterSendHooks(event.message)
|
||||
break
|
||||
case 'token-literal':
|
||||
await chatStore.emitTokenLiteralHooks(event.literal)
|
||||
break
|
||||
case 'token-special':
|
||||
await chatStore.emitTokenSpecialHooks(event.special)
|
||||
break
|
||||
case 'stream-end':
|
||||
await chatStore.emitStreamEndHooks()
|
||||
break
|
||||
case 'assistant-end':
|
||||
await chatStore.emitAssistantResponseEndHooks(event.message)
|
||||
break
|
||||
}
|
||||
}
|
||||
finally {
|
||||
isProcessingRemoteStream = false
|
||||
}
|
||||
})
|
||||
disposeHookFns.push(stopIncomingStreamWatch)
|
||||
}
|
||||
finally {
|
||||
mutex.release()
|
||||
}
|
||||
},
|
||||
|
||||
dispose: async () => {
|
||||
await mutex.acquire()
|
||||
|
||||
try {
|
||||
for (const fn of disposeHookFns) {
|
||||
fn()
|
||||
}
|
||||
}
|
||||
finally {
|
||||
mutex.release()
|
||||
}
|
||||
|
||||
disposeHookFns = []
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
import type { ChatStreamEvent, ContextMessage } from '../../../types/chat'
|
||||
|
||||
import { useBroadcastChannel } from '@vueuse/core'
|
||||
import { Mutex } from 'es-toolkit'
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import { CHAT_STREAM_CHANNEL_NAME, CONTEXT_CHANNEL_NAME, useChatStore } from '../../chat'
|
||||
import { useModsServerChannelStore } from './channel-server'
|
||||
|
||||
export const useContextBridgeStore = defineStore('mods:api:context-bridge', () => {
|
||||
const mutex = new Mutex()
|
||||
|
||||
const chatStore = useChatStore()
|
||||
const serverChannelStore = useModsServerChannelStore()
|
||||
|
||||
const { post: broadcastContext, data: incomingContext } = useBroadcastChannel<ContextMessage, ContextMessage>({ name: CONTEXT_CHANNEL_NAME })
|
||||
const { post: broadcastStreamEvent, data: incomingStreamEvent } = useBroadcastChannel<ChatStreamEvent, ChatStreamEvent>({ name: CHAT_STREAM_CHANNEL_NAME })
|
||||
|
||||
const disposeHookFns = ref<Array<() => void>>([])
|
||||
|
||||
async function initialize() {
|
||||
await mutex.acquire()
|
||||
|
||||
try {
|
||||
let isProcessingRemoteStream = false
|
||||
|
||||
const { stop } = watch(incomingContext, (event) => {
|
||||
if (event)
|
||||
chatStore.ingestContextMessage(event)
|
||||
})
|
||||
disposeHookFns.value.push(stop)
|
||||
|
||||
disposeHookFns.value.push(serverChannelStore.onContextUpdate((event) => {
|
||||
chatStore.ingestContextMessage({ source: event.source, createdAt: Date.now(), ...event.data })
|
||||
broadcastContext(event.data as ContextMessage)
|
||||
}))
|
||||
|
||||
disposeHookFns.value.push(
|
||||
chatStore.onBeforeMessageComposed(async (message) => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'before-compose', message, sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
chatStore.onAfterMessageComposed(async (message) => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'after-compose', message, sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
chatStore.onBeforeSend(async (message) => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'before-send', message, sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
chatStore.onAfterSend(async (message) => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'after-send', message, sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
chatStore.onTokenLiteral(async (literal) => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'token-literal', literal, sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
chatStore.onTokenSpecial(async (special) => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'token-special', special, sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
chatStore.onStreamEnd(async () => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'stream-end', sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
chatStore.onAssistantResponseEnd(async (message) => {
|
||||
if (isProcessingRemoteStream)
|
||||
return
|
||||
broadcastStreamEvent({ type: 'assistant-end', message, sessionId: chatStore.activeSessionId })
|
||||
}),
|
||||
)
|
||||
|
||||
const { stop: stopIncomingStreamWatch } = watch(incomingStreamEvent, async (event) => {
|
||||
if (!event)
|
||||
return
|
||||
|
||||
isProcessingRemoteStream = true
|
||||
try {
|
||||
if (event.sessionId && chatStore.activeSessionId !== event.sessionId)
|
||||
chatStore.setActiveSession(event.sessionId)
|
||||
|
||||
switch (event.type) {
|
||||
case 'before-compose':
|
||||
await chatStore.emitBeforeMessageComposedHooks(event.message)
|
||||
break
|
||||
case 'after-compose':
|
||||
await chatStore.emitAfterMessageComposedHooks(event.message)
|
||||
break
|
||||
case 'before-send':
|
||||
await chatStore.emitBeforeSendHooks(event.message)
|
||||
break
|
||||
case 'after-send':
|
||||
await chatStore.emitAfterSendHooks(event.message)
|
||||
break
|
||||
case 'token-literal':
|
||||
await chatStore.emitTokenLiteralHooks(event.literal)
|
||||
break
|
||||
case 'token-special':
|
||||
await chatStore.emitTokenSpecialHooks(event.special)
|
||||
break
|
||||
case 'stream-end':
|
||||
await chatStore.emitStreamEndHooks()
|
||||
break
|
||||
case 'assistant-end':
|
||||
await chatStore.emitAssistantResponseEndHooks(event.message)
|
||||
break
|
||||
}
|
||||
}
|
||||
finally {
|
||||
isProcessingRemoteStream = false
|
||||
}
|
||||
})
|
||||
disposeHookFns.value.push(stopIncomingStreamWatch)
|
||||
}
|
||||
finally {
|
||||
mutex.release()
|
||||
}
|
||||
}
|
||||
|
||||
async function dispose() {
|
||||
await mutex.acquire()
|
||||
|
||||
try {
|
||||
for (const fn of disposeHookFns.value) {
|
||||
fn()
|
||||
}
|
||||
}
|
||||
finally {
|
||||
mutex.release()
|
||||
}
|
||||
|
||||
disposeHookFns.value = []
|
||||
}
|
||||
|
||||
return {
|
||||
initialize,
|
||||
dispose,
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user