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:
@@ -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,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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user