Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
[workspace]
members = [ "crates/tauri-plugin-ipc-audio-transcription-ort", "crates/tauri-plugin-ipc-audio-vad-ort", "crates/tauri-plugin-mcp", "crates/tauri-plugin-rdev", "crates/tauri-plugin-window-pass-through-on-hover", "crates/tauri-plugin-window-router-link" ]
members = [
"crates/tauri-plugin-ipc-audio-transcription-ort",
"crates/tauri-plugin-ipc-audio-vad-ort",
"crates/tauri-plugin-mcp",
"crates/tauri-plugin-rdev",
"crates/tauri-plugin-window-pass-through-on-hover",
"crates/tauri-plugin-window-router-link"
]
resolver = "2"

[workspace.package]
Expand Down
17 changes: 17 additions & 0 deletions apps/stage-tamagotchi/src/renderer/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ import type { Plugin } from 'vue'
import type { RouteRecordRaw } from 'vue-router'

import Tres from '@tresjs/core'
import buildTime from '~build/time'

import { autoAnimatePlugin } from '@formkit/auto-animate/vue'
import { useAnalytics } from '@proj-airi/stage-ui/composables'
import { useSharedAnalyticsStore } from '@proj-airi/stage-ui/stores/analytics/index'
Comment thread
nekomeowww marked this conversation as resolved.
Outdated
import { MotionPlugin } from '@vueuse/motion'
import { abbreviatedSha, branch } from '~build/git'
import { version } from '~build/package'
import { createPinia } from 'pinia'
import { setupLayouts } from 'virtual:generated-layouts'
import { createApp } from 'vue'
Expand Down Expand Up @@ -38,6 +43,18 @@ import '@fontsource/sniglet'

const pinia = createPinia()

// Initialize analytics
const analyticsStore = useSharedAnalyticsStore(pinia)
analyticsStore.initialize({
version: version ?? 'dev',
commit: abbreviatedSha,
branch,
builtOn: buildTime.toISOString(),
})

Comment on lines +45 to +53

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should initialize in App.vue.

const { registerMetadata } = useAnalytics()
registerMetadata()
Comment thread
shinohara-rin marked this conversation as resolved.
Outdated

const router = createRouter({
history: createWebHashHistory(),
// TODO: vite-plugin-vue-layouts is long deprecated, replace with another layout solution
Expand Down
10 changes: 1 addition & 9 deletions apps/stage-tamagotchi/src/renderer/modules/posthog.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import buildTime from '~build/time'
import posthog from 'posthog-js'

import { abbreviatedSha } from '~build/git'
import { version } from '~build/package'

posthog.init('phc_rljw376z5gt6vXJlc3sTr7hFbXodciY9THEQXIRnW53', {
api_host: 'https://us.i.posthog.com',
person_profiles: 'identified_only', // or 'always' to create profiles for anonymous users as well
})

posthog.register({
app_version: version ?? 'dev',
app_commit: abbreviatedSha,
app_build_time: buildTime,
})
export default posthog
15 changes: 4 additions & 11 deletions apps/stage-tamagotchi/src/renderer/pages/about.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
<script setup lang="ts">
import { UTCDate } from '@date-fns/utc'
import { MarkdownRenderer, Progress } from '@proj-airi/stage-ui/components'
import { useSharedAnalyticsStore } from '@proj-airi/stage-ui/stores/analytics/index'
import { Button, DoubleCheckButton } from '@proj-airi/ui'
import { useMediaQuery } from '@vueuse/core'
import { abbreviatedSha, branch, committerDate } from '~build/git'
import { formatISO9075 } from 'date-fns'
import { storeToRefs } from 'pinia'
import { DialogContent, DialogDescription, DialogOverlay, DialogPortal, DialogRoot, DialogTitle } from 'reka-ui'
import { DrawerContent, DrawerDescription, DrawerHandle, DrawerOverlay, DrawerPortal, DrawerRoot, DrawerTitle } from 'vaul-vue'
import { computed, ref } from 'vue'

import packageJson from '../../../package.json'

import { useElectronAutoUpdater } from '../composables/electron-vueuse'

const buildInfo = computed(() => ({
version: packageJson.version,
branch,
commit: abbreviatedSha.substring(0, 7),
builtOn: formatISO9075(new UTCDate(committerDate)),
}))
const analyticsStore = useSharedAnalyticsStore()
const { buildInfo } = storeToRefs(analyticsStore)

const {
state: updateState,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
<script setup lang="ts">
import { UTCDate } from '@date-fns/utc'
import { AboutContent, AboutDialog } from '@proj-airi/stage-ui/components'
import { abbreviatedSha, branch, committerDate } from '~build/git'
import { formatISO9075 } from 'date-fns'
import { computed, ref } from 'vue'
import { useSharedAnalyticsStore } from '@proj-airi/stage-ui/stores/analytics/index'
import { storeToRefs } from 'pinia'
import { ref } from 'vue'

const show = ref(false)
const localDate = formatISO9075(new UTCDate(committerDate))
const buildInfo = computed(() => ({
branch,
commit: abbreviatedSha.substring(0, 7),
builtOn: localDate,
}))
const analyticsStore = useSharedAnalyticsStore()
const { buildInfo } = storeToRefs(analyticsStore)

const aboutLinks = [
{ label: 'Home', href: 'https://airi.moeru.ai/docs/', icon: 'i-solar:home-smile-outline' },
{ label: 'Documentations', href: 'https://airi.moeru.ai/docs/en/docs/overview/', icon: 'i-solar:document-add-outline' },
Expand Down
18 changes: 18 additions & 0 deletions apps/stage-web/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ import type { Plugin } from 'vue'
import type { Router, RouteRecordRaw } from 'vue-router'

import Tres from '@tresjs/core'
import buildTime from '~build/time'
import NProgress from 'nprogress'

import { autoAnimatePlugin } from '@formkit/auto-animate/vue'
import { useAnalytics } from '@proj-airi/stage-ui/composables'
import { useSharedAnalyticsStore } from '@proj-airi/stage-ui/stores/analytics/index'
Comment thread
nekomeowww marked this conversation as resolved.
Outdated
import { MotionPlugin } from '@vueuse/motion'
import { abbreviatedSha, branch } from '~build/git'
import { version } from '~build/package'
import { createPinia } from 'pinia'
import { setupLayouts } from 'virtual:generated-layouts'
import { createApp } from 'vue'
Expand All @@ -26,6 +31,19 @@ import './styles/main.css'
import 'uno.css'

const pinia = createPinia()

// Initialize analytics
const analyticsStore = useSharedAnalyticsStore(pinia)
analyticsStore.initialize({
version: version ?? 'dev',
commit: abbreviatedSha,
branch,
builtOn: buildTime.toISOString(),
})

Comment on lines +33 to +42

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should initialize in App.vue.

const { registerMetadata } = useAnalytics()
registerMetadata()
Comment thread
shinohara-rin marked this conversation as resolved.
Outdated

// TODO: vite-plugin-vue-layouts is long deprecated, replace with another layout solution
const routeRecords = setupLayouts(routes as RouteRecordRaw[])

Expand Down
10 changes: 1 addition & 9 deletions apps/stage-web/src/modules/posthog.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import buildTime from '~build/time'
import posthog from 'posthog-js'

import { abbreviatedSha } from '~build/git'
import { version } from '~build/package'

posthog.init('phc_pzjziJjrVZpa9SqnQqq0QEKvkmuCPH7GDTA6TbRTEf9', {
api_host: 'https://us.i.posthog.com',
person_profiles: 'identified_only', // or 'always' to create profiles for anonymous users as well
})

posthog.register({
app_version: version ?? 'dev',
app_commit: abbreviatedSha,
app_build_time: buildTime,
})
export default posthog
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { Alert, ErrorContainer, RadioCardManySelect, RadioCardSimple } from '@proj-airi/stage-ui/components'
import { useAnalytics } from '@proj-airi/stage-ui/composables/use-analytics'
Comment thread
nekomeowww marked this conversation as resolved.
Outdated
import { useConsciousnessStore } from '@proj-airi/stage-ui/stores/modules/consciousness'
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
import { storeToRefs } from 'pinia'
Expand All @@ -22,6 +23,7 @@ const {
} = storeToRefs(consciousnessStore)

const { t } = useI18n()
const { trackProviderClick } = useAnalytics()

watch(activeProvider, async (provider) => {
if (!provider)
Expand Down Expand Up @@ -76,6 +78,7 @@ function handleDeleteProvider(providerId: string) {
:value="metadata.id"
:title="metadata.localizedName || 'Unknown'"
:description="metadata.localizedDescription"
@click="trackProviderClick(metadata.id, 'consciousness')"
>
<template #topRight>
<button
Expand Down
4 changes: 3 additions & 1 deletion packages/stage-pages/src/pages/settings/modules/hearing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import workletUrl from '@proj-airi/stage-ui/workers/vad/process.worklet?worker&url'

import { Alert, ErrorContainer, LevelMeter, RadioCardManySelect, RadioCardSimple, TestDummyMarker, ThresholdMeter, TimeSeriesChart } from '@proj-airi/stage-ui/components'
import { useAudioAnalyzer, useAudioRecorder } from '@proj-airi/stage-ui/composables'
import { useAnalytics, useAudioAnalyzer, useAudioRecorder } from '@proj-airi/stage-ui/composables'
import { useVAD } from '@proj-airi/stage-ui/stores/ai/models/vad'
import { useAudioContext } from '@proj-airi/stage-ui/stores/audio'
import { useHearingSpeechInputPipeline, useHearingStore } from '@proj-airi/stage-ui/stores/modules/hearing'
Expand All @@ -29,6 +29,7 @@ const {
const providersStore = useProvidersStore()
const { configuredTranscriptionProvidersMetadata } = storeToRefs(providersStore)

const { trackProviderClick } = useAnalytics()
const { stopStream, startStream } = useSettingsAudioDevice()
const { audioInputs, selectedAudioInput, stream } = storeToRefs(useSettingsAudioDevice())
const { startRecord, stopRecord, onStopRecord } = useAudioRecorder(stream)
Expand Down Expand Up @@ -290,6 +291,7 @@ onUnmounted(() => {
:value="metadata.id"
:title="metadata.localizedName || 'Unknown'"
:description="metadata.localizedDescription"
@click="trackProviderClick(metadata.id, 'hearing')"
/>
<RouterLink
to="/settings/providers#transcription"
Expand Down
4 changes: 4 additions & 0 deletions packages/stage-pages/src/pages/settings/modules/speech.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
TestDummyMarker,
VoiceCardManySelect,
} from '@proj-airi/stage-ui/components'
import { useAnalytics } from '@proj-airi/stage-ui/composables/use-analytics'
Comment thread
nekomeowww marked this conversation as resolved.
Outdated
import { useSpeechStore } from '@proj-airi/stage-ui/stores/modules/speech'
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
import {
Expand Down Expand Up @@ -45,6 +46,8 @@ const {
availableVoices,
} = storeToRefs(speechStore)

const { trackProviderClick } = useAnalytics()

const voiceSearchQuery = ref('')
const useSSML = ref(false)
const testText = ref('Hello, my name is AI Assistant')
Expand Down Expand Up @@ -198,6 +201,7 @@ function updateCustomModelName(value: string) {
:value="metadata.id"
:title="metadata.localizedName || 'Unknown'"
:description="metadata.localizedDescription"
@click="trackProviderClick(metadata.id, 'speech')"
/>
<RouterLink
to="/settings/providers#speech"
Expand Down
3 changes: 3 additions & 0 deletions packages/stage-pages/src/pages/settings/providers/index.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { IconStatusItem, RippleGrid } from '@proj-airi/stage-ui/components'
import { useAnalytics } from '@proj-airi/stage-ui/composables'
import { useRippleGridState } from '@proj-airi/stage-ui/composables/use-ripple-grid-state'
import { useScrollToHash } from '@proj-airi/stage-ui/composables/useScrollToHash'
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
Expand All @@ -10,6 +11,7 @@ import { useRoute } from 'vue-router'
const route = useRoute()
const providersStore = useProvidersStore()
const { lastClickedIndex, setLastClickedIndex } = useRippleGridState()
const { trackProviderClick } = useAnalytics()

const {
allChatProvidersMetadata,
Expand Down Expand Up @@ -114,6 +116,7 @@ useScrollToHash(() => route.hash, {
:icon-image="provider.iconImage"
:to="`/settings/providers/${provider.category}/${provider.id}`"
:configured="provider.configured"
@click="trackProviderClick(provider.id, provider.category)"
/>
</template>
</RippleGrid>
Expand Down
1 change: 1 addition & 0 deletions packages/stage-ui/src/composables/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export * from './llmmarkerParser'
export * from './markdown'
export * from './micvad'
export * from './queues'
export * from './use-analytics'
export * from './whisper'
42 changes: 42 additions & 0 deletions packages/stage-ui/src/composables/use-analytics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import posthog from 'posthog-js'

import { useSharedAnalyticsStore } from '../stores/analytics'

export function useAnalytics() {
const analyticsStore = useSharedAnalyticsStore()

function trackProviderClick(providerId: string, module: string) {
posthog.capture('provider_card_clicked', {
provider_id: providerId,
module,
})
}

function trackFirstMessage(success: boolean, messageSentAt: number) {
// Only track the first message once
if (analyticsStore.firstMessageTracked)
return

// Calculate time from app start to message sent
const timeToFirstMessageMs = analyticsStore.appStartTime
? messageSentAt - analyticsStore.appStartTime
: null

posthog.capture('first_message_sent', {
time_to_first_message_ms: timeToFirstMessageMs,
success,
})

analyticsStore.markFirstMessageTracked()
}

function registerMetadata() {
posthog.register(analyticsStore.versionMeta)
}

return {
trackProviderClick,
trackFirstMessage,
registerMetadata,
}
}
45 changes: 45 additions & 0 deletions packages/stage-ui/src/stores/analytics/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { AboutBuildInfo } from '../../components/scenarios/about/types'

import { defineStore } from 'pinia'
import { computed, ref } from 'vue'

export const useSharedAnalyticsStore = defineStore('shared_analytics', () => {
Comment thread
nekomeowww marked this conversation as resolved.
Outdated
const isInitialized = ref(false)
const buildInfo = ref<AboutBuildInfo>({
version: '',
commit: '',
branch: '',
builtOn: '',
})
const appStartTime = ref<number | null>(null)
const firstMessageTracked = ref(false)

const versionMeta = computed(() => ({
app_version: buildInfo.value.version === '0.0.0' ? 'dev' : buildInfo.value.version,
app_commit: buildInfo.value.commit,
app_branch: buildInfo.value.branch,
app_build_time: buildInfo.value.builtOn,
}))
Comment thread
shinohara-rin marked this conversation as resolved.
Outdated

function initialize(info: AboutBuildInfo) {
if (isInitialized.value)
return

buildInfo.value = info
appStartTime.value = Date.now()
isInitialized.value = true
}

function markFirstMessageTracked() {
firstMessageTracked.value = true
}

return {
buildInfo,
versionMeta,
Comment thread
shinohara-rin marked this conversation as resolved.
Outdated
appStartTime,
firstMessageTracked,
initialize,
markFirstMessageTracked,
}
})
Loading
Loading