perf: use shallow-ref for web audio api class (#623)

* perf: use shallow-ref for web audio api class

* Update packages/stage-ui/src/stores/audio.ts
This commit is contained in:
藍+85CD
2025-10-01 14:46:36 +08:00
committed by GitHub
parent c3e37a9444
commit b6497dcc33
5 changed files with 18 additions and 21 deletions
+4 -6
View File
@@ -11,7 +11,7 @@ import type {
import { useLocalStorage, useWebSocket } from '@vueuse/core'
import { streamText } from '@xsai/stream-text'
import { computed, ref, toRaw, watch } from 'vue'
import { computed, ref, shallowRef, toRaw, watch } from 'vue'
import { useQueue } from '../composables/queue'
@@ -21,7 +21,7 @@ const model = useLocalStorage('settings/llm/model', 'openai/gpt-4o-mini')
const sendingMessage = ref('')
const messages = ref<Message[]>([])
const streamingMessage = ref<AssistantMessage>({ role: 'assistant', content: '' })
const audioContext = ref<AudioContext>()
const audioContext = shallowRef<AudioContext>()
const voiceId = useLocalStorage('settings/voiceId', 'lNxY9WuCBCZCISASyJ55')
const voiceApiKey = useLocalStorage('settings/voiceApiKey', '')
@@ -46,16 +46,14 @@ async function handleChatSendMessage() {
messages.value.push({ role: 'user', content: sendingMessage.value })
messages.value.push(streamingMessage.value)
const response = await streamText({
const response = streamText({
baseURL: baseUrl.value,
apiKey: apiKey.value,
model: model.value,
messages: messages.value.slice(0, messages.value.length - 1).map(msg => toRaw(msg)),
})
for await (const chunk of response.chunkStream) {
const text = chunk.choices[0].delta.content || ''
for await (const text of response.textStream) {
if (text !== '') {
sendPayload({
'xi-api-key': voiceApiKey.value,
@@ -1,14 +1,14 @@
<script setup lang="ts">
import { FieldRange, Radio } from '@proj-airi/ui'
import { onBeforeUnmount, ref, watch } from 'vue'
import { onBeforeUnmount, ref, shallowRef, watch } from 'vue'
import AudioSpectrum from './AudioSpectrum.vue'
import AudioSpectrumVisualizer from './AudioSpectrumVisualizer.vue'
// Create a mock oscillator to generate audio for demonstration
const audioContext = ref<AudioContext>()
const oscillator = ref<OscillatorNode>()
const mediaStream = ref<MediaStream>()
const audioContext = shallowRef<AudioContext>()
const oscillator = shallowRef<OscillatorNode>()
const mediaStream = shallowRef<MediaStream>()
const isPlaying = ref(false)
const frequency = ref(440) // A4 note
const waveform = ref<OscillatorType>('sine')
@@ -19,7 +19,7 @@ const waveforms: OscillatorType[] = ['sine', 'square', 'sawtooth', 'triangle']
function createMockAudioStream() {
try {
// Create audio context
audioContext.value = new (window.AudioContext || (window as any).webkitAudioContext)()
audioContext.value = new AudioContext()
// Create oscillator
oscillator.value = audioContext.value.createOscillator()
@@ -3,7 +3,7 @@ import type { GenerateTranscriptionResult } from '@xsai/generate-transcription'
import { FieldRange, FieldSelect } from '@proj-airi/ui'
import { until } from '@vueuse/core'
import { computed, onUnmounted, ref, watch } from 'vue'
import { computed, onUnmounted, ref, shallowRef, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useAudioAnalyzer } from '../../../composables/audio/audio-analyzer'
@@ -30,7 +30,7 @@ const isSpeaking = ref(false)
const errorMessage = ref<string>('')
const audioContext = ref<AudioContext>()
const audioContext = shallowRef<AudioContext>()
const dataArray = ref<Uint8Array<ArrayBuffer>>()
const animationFrame = ref<number>()
+4 -4
View File
@@ -4,7 +4,7 @@ import type { UseQueueReturn } from '../utils/queue'
import { sleep } from '@moeru/std'
import { invoke } from '@vueuse/core'
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { ref, shallowRef } from 'vue'
import { EMOTION_VALUES } from '../constants/emotions'
import { createQueue } from '../utils/queue'
@@ -116,10 +116,10 @@ export const usePipelineCharacterSpeechPlaybackQueueStore = defineStore('pipelin
onPlaybackFinishedHooks.value.push(hook)
}
const currentAudioSource = ref<AudioBufferSourceNode>()
const currentAudioSource = shallowRef<AudioBufferSourceNode>()
const audioContext = ref<AudioContext>()
const audioAnalyser = ref<AnalyserNode>()
const audioContext = shallowRef<AudioContext>()
const audioAnalyser = shallowRef<AnalyserNode>()
function connectAudioContext(context: AudioContext) {
audioContext.value = context
+3 -4
View File
@@ -1,6 +1,6 @@
import { useDevicesList, useUserMedia } from '@vueuse/core'
import { defineStore } from 'pinia'
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { computed, nextTick, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'
function calculateVolumeWithLinearNormalize(analyser: AnalyserNode) {
const dataBuffer = new Uint8Array(analyser.frequencyBinCount)
@@ -66,13 +66,12 @@ function calculateVolume(analyser: AnalyserNode, mode: 'linear' | 'minmax' = 'li
}
export const useAudioContext = defineStore('audio-context', () => {
const audioContext = ref<AudioContext>(new AudioContext())
const audioContext = shallowRef<AudioContext>(new AudioContext())
onUnmounted(async () => {
// Close audio context
if (audioContext) {
if (audioContext)
await audioContext.value.suspend()
}
})
return {