refactor(stage-*): analytics with better structure, added useBuildInfo

This commit is contained in:
Neko Ayaka
2025-12-27 17:03:43 +08:00
parent ca6a0b24fa
commit 0dc4e96663
14 changed files with 199 additions and 294 deletions
+1
View File
@@ -50,6 +50,7 @@
"@proj-airi/stage-shared": "workspace:^",
"@types/audioworklet": "catalog:",
"@types/three": "^0.182.0",
"unplugin-info": "catalog:",
"vue-tsc": "^3.1.8"
}
}
+2 -1
View File
@@ -12,7 +12,8 @@
"resolveJsonModule": true,
"types": [
"vitest",
"vite/client"
"vite/client",
"unplugin-info/client"
],
"allowJs": true,
"strict": true,
+2 -1
View File
@@ -27,6 +27,7 @@
"./libs/*": "./src/libs/*.ts",
"./libs": "./src/libs/index.ts",
"./stores/providers/aliyun": "./src/stores/providers/aliyun/index.ts",
"./stores/analytics": "./src/stores/analytics/index.ts",
"./stores/*": "./src/stores/*.ts",
"./stores": "./src/stores/index.ts",
"./workers/vad": "./src/workers/vad/index.ts",
@@ -173,7 +174,7 @@
"csstype": "^3.2.3",
"histoire": "1.0.0-alpha.2",
"unocss": "^66.5.11",
"unplugin-info": "^1.2.4",
"unplugin-info": "catalog:",
"unplugin-yaml": "^3.0.7",
"vite": "^6.4.1",
"vue": "3.5.25",
@@ -5,5 +5,6 @@ export * from './markdown'
export * from './micvad'
export * from './queues'
export * from './use-analytics'
export * from './use-build-info'
export * from './use-context-bridge'
export * from './whisper'
@@ -0,0 +1,13 @@
import buildTime from '~build/time'
import { abbreviatedSha, branch } from '~build/git'
import { version } from '~build/package'
export function useBuildInfo() {
return {
version: version ?? 'dev',
commit: abbreviatedSha,
branch,
builtOn: buildTime.toISOString(),
}
}
@@ -36,39 +36,48 @@ export function useContextBridge() {
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 })
}))
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)
@@ -5,22 +5,19 @@ import posthog from 'posthog-js'
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { useBuildInfo } from '../../composables'
export const useSharedAnalyticsStore = defineStore('analytics-shared', () => {
const buildInfo = ref<AboutBuildInfo>(useBuildInfo())
const isInitialized = ref(false)
const buildInfo = ref<AboutBuildInfo>({
version: '',
commit: '',
branch: '',
builtOn: '',
})
const appStartTime = ref<number | null>(null)
const firstMessageTracked = ref(false)
function initialize(info: AboutBuildInfo) {
function initialize() {
if (isInitialized.value)
return
buildInfo.value = info
appStartTime.value = Date.now()
// Register metadata with PostHog after buildInfo is set