fix: bugs introduced by migration
This commit is contained in:
Vendored
+3
-1
@@ -1,7 +1,9 @@
|
||||
{
|
||||
"i18n-ally.sourceLanguage": "en",
|
||||
"i18n-ally.keystyle": "nested",
|
||||
"i18n-ally.localesPaths": "locales",
|
||||
"i18n-ally.localesPaths": [
|
||||
"packages/stage/locales"
|
||||
],
|
||||
"i18n-ally.sortKeys": true,
|
||||
|
||||
// Disable the default formatter
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { Message } from '@xsai/shared-chat-completion'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
import { ref } from 'vue'
|
||||
@@ -7,8 +6,9 @@ import Avatar from '../../assets/live2d/models/hiyori_free_zh/avatar.png'
|
||||
import { useMarkdown } from '../../composables/markdown'
|
||||
import { useSpeakingStore } from '../../stores/audio'
|
||||
|
||||
const messages = ref<Message[]>([])
|
||||
const chatHistoryRef = ref<HTMLDivElement>()
|
||||
|
||||
const { messages } = storeToRefs(useChatStore())
|
||||
const bounding = useElementBounding(chatHistoryRef, { immediate: true, windowScroll: true, windowResize: true })
|
||||
const { y: chatHistoryContainerY } = useScroll(chatHistoryRef)
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@ import { ref } from 'vue'
|
||||
import WhisperWorker from '../../libs/workers/worker?worker&url'
|
||||
import { encodeWAVToBase64 } from '../../utils/binary'
|
||||
|
||||
const messageInput = ref('')
|
||||
const supportedModels = ref<{ id: string, name?: string }[]>([])
|
||||
const listening = ref(false)
|
||||
|
||||
const { audioInputs } = useDevicesList({ constraints: { audio: true }, requestPermissions: true })
|
||||
const { openAiModel, openAiApiBaseURL, openAiApiKey, selectedAudioDevice, isAudioInputOn, selectedAudioDeviceId } = storeToRefs(useSettings())
|
||||
const { models } = useLLM()
|
||||
@@ -13,58 +17,17 @@ const { send, onAfterSend } = useChatStore()
|
||||
const { audioContext } = useAudioContext()
|
||||
const { t } = useI18n()
|
||||
|
||||
const messageInput = ref('')
|
||||
const supportedModels = ref<{ id: string, name?: string }[]>([])
|
||||
const listening = ref(false)
|
||||
|
||||
function handleModelChange(event: Event) {
|
||||
const target = event.target as HTMLSelectElement
|
||||
const found = supportedModels.value.find(m => m.id === target.value)
|
||||
if (!found) {
|
||||
openAiModel.value = undefined
|
||||
return
|
||||
}
|
||||
|
||||
openAiModel.value = found
|
||||
}
|
||||
|
||||
async function handleAudioInputChange(event: Event) {
|
||||
const target = event.target as HTMLSelectElement
|
||||
const found = audioInputs.value.find(d => d.deviceId === target.value)
|
||||
if (!found) {
|
||||
selectedAudioDevice.value = undefined
|
||||
return
|
||||
}
|
||||
|
||||
selectedAudioDevice.value = found
|
||||
}
|
||||
|
||||
const { transcribe: generate, load: loadWhisper, status: whisperStatus, terminate } = useWhisper(WhisperWorker, {
|
||||
onComplete: async (res) => {
|
||||
await send(res)
|
||||
},
|
||||
})
|
||||
|
||||
function handleLoadWhisper() {
|
||||
if (whisperStatus.value === 'loading')
|
||||
return
|
||||
|
||||
loadWhisper()
|
||||
}
|
||||
|
||||
async function handleTranscription(buffer: Float32Array) {
|
||||
await audioContext.resume()
|
||||
|
||||
// Convert Float32Array to WAV format
|
||||
const audioBase64 = await encodeWAVToBase64(buffer, audioContext.sampleRate)
|
||||
generate({ type: 'generate', data: { audio: audioBase64, language: 'en' } })
|
||||
}
|
||||
|
||||
async function handleSend() {
|
||||
await send(messageInput.value)
|
||||
}
|
||||
|
||||
const { destroy } = useMicVAD(selectedAudioDeviceId, {
|
||||
const { destroy, start } = useMicVAD(selectedAudioDeviceId, {
|
||||
onSpeechStart: () => {
|
||||
// TODO: interrupt the playback
|
||||
// TODO: interrupt any of the ongoing TTS
|
||||
@@ -87,8 +50,47 @@ const { destroy } = useMicVAD(selectedAudioDeviceId, {
|
||||
listening.value = false
|
||||
handleTranscription(buffer)
|
||||
},
|
||||
auto: false,
|
||||
})
|
||||
|
||||
function handleLoadWhisper() {
|
||||
if (whisperStatus.value === 'loading')
|
||||
return
|
||||
|
||||
loadWhisper()
|
||||
start()
|
||||
}
|
||||
|
||||
async function handleTranscription(buffer: Float32Array) {
|
||||
await audioContext.resume()
|
||||
|
||||
// Convert Float32Array to WAV format
|
||||
const audioBase64 = await encodeWAVToBase64(buffer, audioContext.sampleRate)
|
||||
generate({ type: 'generate', data: { audio: audioBase64, language: 'en' } })
|
||||
}
|
||||
|
||||
function handleModelChange(event: Event) {
|
||||
const target = event.target as HTMLSelectElement
|
||||
const found = supportedModels.value.find(m => m.id === target.value)
|
||||
if (!found) {
|
||||
openAiModel.value = undefined
|
||||
return
|
||||
}
|
||||
|
||||
openAiModel.value = found
|
||||
}
|
||||
|
||||
async function handleAudioInputChange(event: Event) {
|
||||
const target = event.target as HTMLSelectElement
|
||||
const found = audioInputs.value.find(d => d.deviceId === target.value)
|
||||
if (!found) {
|
||||
selectedAudioDevice.value = undefined
|
||||
return
|
||||
}
|
||||
|
||||
selectedAudioDevice.value = found
|
||||
}
|
||||
|
||||
watch(isAudioInputOn, async (value) => {
|
||||
if (value === 'false') {
|
||||
destroy()
|
||||
|
||||
@@ -105,8 +105,6 @@ export const useChatStore = defineStore('chat', () => {
|
||||
for (const hook of onTokenSpecialHooks.value) {
|
||||
await hook(special)
|
||||
}
|
||||
|
||||
streamingMessage.value.content += special
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { GenerateAudioStream } from '@airi-proj/elevenlabs/types'
|
||||
import type { GenerateAudioStream } from '@proj-airi/elevenlabs/types'
|
||||
import type { Message } from '@xsai/shared-chat-completion'
|
||||
import { listModels } from '@xsai/model'
|
||||
import { streamText } from '@xsai/stream-text'
|
||||
|
||||
@@ -3,6 +3,8 @@ import { defineStore } from 'pinia'
|
||||
import { i18n } from '~/modules/i18n'
|
||||
|
||||
export const useSettings = defineStore('settings', () => {
|
||||
const selectedAudioDevice = ref<MediaDeviceInfo>()
|
||||
|
||||
const openAiApiKey = useLocalStorage('settings/credentials/openai-api-key', '')
|
||||
const openAiApiBaseURL = useLocalStorage('settings/credentials/openai-api-base-url', '')
|
||||
const elevenLabsApiKey = useLocalStorage('settings/credentials/elevenlabs-api-key', '')
|
||||
@@ -11,11 +13,10 @@ export const useSettings = defineStore('settings', () => {
|
||||
const stageView = useLocalStorage('settings/stage/view/model-renderer', '2d')
|
||||
const openAiModel = useLocalStorage<{ id: string, name?: string }>('settings/llm/openai/model', { id: 'openai/gpt-3.5-turbo', name: 'OpenAI GPT3.5 Turbo' })
|
||||
const isAudioInputOn = useLocalStorage('settings/audio/input', 'true')
|
||||
const selectedAudioDevice = useLocalStorage<MediaDeviceInfo | undefined>('settings/audio/input/device', undefined)
|
||||
const selectedAudioDeviceId = computed(() => selectedAudioDevice.value?.deviceId)
|
||||
const { audioInputs } = useDevicesList({ constraints: { audio: true }, requestPermissions: true })
|
||||
|
||||
watch(isAudioInputOn, async (value) => {
|
||||
watch(isAudioInputOn, (value) => {
|
||||
if (value === 'false') {
|
||||
selectedAudioDevice.value = undefined
|
||||
}
|
||||
@@ -24,6 +25,18 @@ export const useSettings = defineStore('settings', () => {
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (isAudioInputOn.value === 'true' && !selectedAudioDevice.value) {
|
||||
selectedAudioDevice.value = audioInputs.value[0]
|
||||
}
|
||||
})
|
||||
|
||||
watch(audioInputs, () => {
|
||||
if (isAudioInputOn.value === 'true' && !selectedAudioDevice.value) {
|
||||
selectedAudioDevice.value = audioInputs.value[0]
|
||||
}
|
||||
})
|
||||
|
||||
watch(language, value => i18n.global.locale.value = value)
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user