diff --git a/packages/stage/src/components/MainStage.vue b/packages/stage/src/components/MainStage.vue index 06551d0..a8e478f 100644 --- a/packages/stage/src/components/MainStage.vue +++ b/packages/stage/src/components/MainStage.vue @@ -16,6 +16,7 @@ import { EMOTION_EmotionMotionName_value, EMOTION_VRMExpressionName_value, Emoti import SystemPromptV2 from '../constants/prompts/system-v2' import { useLLM } from '../stores/llm' import { useSettings } from '../stores/settings' +import { asyncIteratorFromReadableStream } from '../utils/iterator' import BasicTextarea from './BasicTextarea.vue' import Live2DViewer from './Live2DViewer.vue' @@ -33,13 +34,10 @@ const { } = storeToRefs(useSettings()) const openAIModel = useLocalStorage<{ id: string, name?: string }>('settings/llm/openai/model', { id: 'openai/gpt-3.5-turbo', name: 'OpenAI GPT3.5 Turbo' }) -const { - streamSpeech, - stream, - models, -} = useLLM() +const { streamSpeech, stream, models } = useLLM() const { audioContext, calculateVolume } = useAudioContext() const { process } = useMarkdown() +const { audioInputs } = useDevicesList({ constraints: { audio: true }, requestPermissions: true }) const listening = ref(false) const live2DViewerRef = ref<{ setMotion: (motionName: string) => Promise }>() @@ -52,10 +50,9 @@ const audioAnalyser = ref() const mouthOpenSize = ref(0) const nowSpeaking = ref(false) const lipSyncStarted = ref(false) -const { audioInputs } = useDevicesList({ constraints: { audio: true }, requestPermissions: true }) const selectedAudioDevice = ref() -const selectedAudioDeviceId = computed(() => selectedAudioDevice.value?.deviceId) +const selectedAudioDeviceId = computed(() => selectedAudioDevice.value?.deviceId) const nowSpeakingAvatarBorderOpacity = computed(() => { if (!nowSpeaking.value) return nowSpeakingAvatarBorderOpacityMin @@ -220,25 +217,6 @@ function setupAnalyser() { audioAnalyser.value = audioContext.createAnalyser() } -async function* asyncIteratorFromReadableStream(res: ReadableStream, func: (value: F) => Promise): AsyncGenerator { - // react js - TS2504: Type 'ReadableStream' must have a '[Symbol.asyncIterator]()' method that returns an async iterator - Stack Overflow - // https://stackoverflow.com/questions/76700924/ts2504-type-readablestreamuint8array-must-have-a-symbol-asynciterator - const reader = res.getReader() - try { - while (true) { - const { done, value } = await reader.read() - if (done) { - return - } - - yield func(value) - } - } - finally { - reader.releaseLock() - } -} - async function onSendMessage(sendingMessage: string) { if (!sendingMessage) return diff --git a/packages/stage/src/utils/iterator.ts b/packages/stage/src/utils/iterator.ts new file mode 100644 index 0000000..b751599 --- /dev/null +++ b/packages/stage/src/utils/iterator.ts @@ -0,0 +1,18 @@ +export async function* asyncIteratorFromReadableStream(res: ReadableStream, func: (value: F) => Promise): AsyncGenerator { + // react js - TS2504: Type 'ReadableStream' must have a '[Symbol.asyncIterator]()' method that returns an async iterator - Stack Overflow + // https://stackoverflow.com/questions/76700924/ts2504-type-readablestreamuint8array-must-have-a-symbol-asynciterator + const reader = res.getReader() + try { + while (true) { + const { done, value } = await reader.read() + if (done) { + return + } + + yield func(value) + } + } + finally { + reader.releaseLock() + } +}