Skip to content

Commit

Permalink
feat: integrated to @xsai/generate-speech (#9)
Browse files Browse the repository at this point in the history
* feat: integrated to @xsai/generate-speech
* chore: updated impl
* feat: done integrations
* chore: remove llm-proxy package, remove unused eslint config
  • Loading branch information
nekomeowww authored Jan 5, 2025
1 parent d825992 commit 86fac7d
Show file tree
Hide file tree
Showing 17 changed files with 394 additions and 1,352 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"@antfu/eslint-config": "^3.12.1",
"@antfu/ni": "^0.23.2",
"@cspell/dict-ru_ru": "^2.2.4",
"@types/node": "^22.10.3",
"@types/node": "^22.10.5",
"@unocss/eslint-config": "^0.65.3",
"@unocss/eslint-plugin": "^0.65.3",
"bumpp": "^9.9.2",
Expand All @@ -48,7 +48,7 @@
"typescript": "~5.7.2",
"unbuild": "3.0.0-rc.11",
"unocss": "^0.65.3",
"vite": "^6.0.6",
"vite": "^6.0.7",
"vite-plugin-inspect": "^0.10.6",
"vitest": "^2.1.8"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/hfup/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@
"dependencies": {
"defu": "^6.1.4",
"gray-matter": "^4.0.3",
"vite": "^6.0.6"
"vite": "^6.0.7"
}
}
33 changes: 0 additions & 33 deletions packages/llm-proxy/.gitignore

This file was deleted.

8 changes: 0 additions & 8 deletions packages/llm-proxy/README.md

This file was deleted.

18 changes: 0 additions & 18 deletions packages/llm-proxy/package.json

This file was deleted.

49 changes: 0 additions & 49 deletions packages/llm-proxy/src/index.ts

This file was deleted.

17 changes: 0 additions & 17 deletions packages/llm-proxy/tsconfig.json

This file was deleted.

28 changes: 0 additions & 28 deletions packages/llm-proxy/wrangler.toml

This file was deleted.

4 changes: 2 additions & 2 deletions packages/moonshine-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
"typecheck": "vue-tsc --noEmit"
},
"dependencies": {
"@tresjs/core": "^4.3.1",
"@tresjs/core": "^4.3.2",
"@unocss/reset": "^0.65.3",
"@vueuse/core": "^12.2.0",
"@vueuse/core": "^12.3.0",
"@vueuse/motion": "^2.2.6",
"ofetch": "^1.4.1",
"three": "^0.172.0",
Expand Down
24 changes: 12 additions & 12 deletions packages/stage/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,20 @@
"@pixiv/three-vrm-core": "^3.3.2",
"@ricky0123/vad-web": "^0.0.22",
"@tresjs/cientos": "^4.0.3",
"@tresjs/core": "^4.3.1",
"@tresjs/core": "^4.3.2",
"@types/yauzl": "^2.10.3",
"@typeschema/valibot": "^0.14.0",
"@unhead/vue": "^1.11.14",
"@unocss/reset": "^0.65.3",
"@vueuse/core": "^12.2.0",
"@vueuse/core": "^12.3.0",
"@vueuse/head": "^2.0.0",
"@vueuse/shared": "^12.2.0",
"@xsai/generate-speech": "^0.0.22",
"@xsai/generate-text": "^0.0.22",
"@xsai/model": "^0.0.22",
"@xsai/providers": "^0.0.22",
"@xsai/shared-chat": "^0.0.22",
"@xsai/stream-text": "^0.0.22",
"@vueuse/shared": "^12.3.0",
"@xsai/generate-speech": "^0.0.23",
"@xsai/generate-text": "^0.0.23",
"@xsai/model": "^0.0.23",
"@xsai/providers": "^0.0.23",
"@xsai/shared-chat": "^0.0.23",
"@xsai/stream-text": "^0.0.23",
"defu": "^6.1.4",
"jszip": "^3.10.1",
"nprogress": "^0.2.0",
Expand All @@ -66,7 +66,7 @@
"rehype-stringify": "^10.0.1",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.1.1",
"shiki": "^1.24.4",
"shiki": "^1.26.1",
"three": "^0.172.0",
"unified": "^11.0.5",
"valibot": "1.0.0-beta.9",
Expand All @@ -81,13 +81,13 @@
"devDependencies": {
"@iconify-json/carbon": "^1.2.5",
"@iconify-json/eos-icons": "^1.2.2",
"@iconify-json/lucide": "^1.2.20",
"@iconify-json/lucide": "^1.2.21",
"@iconify-json/mingcute": "^1.2.3",
"@iconify-json/solar": "^1.2.2",
"@iconify-json/svg-spinners": "^1.2.2",
"@intlify/unplugin-vue-i18n": "^6.0.3",
"@proj-airi/elevenlabs": "workspace:^",
"@shikijs/markdown-it": "^1.24.4",
"@shikijs/markdown-it": "^1.26.1",
"@types/markdown-it-link-attributes": "^3.0.5",
"@types/nprogress": "^0.2.3",
"@types/three": "^0.171.0",
Expand Down
38 changes: 21 additions & 17 deletions packages/stage/src/components/Widgets/Stage.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
<script setup lang="ts">
import type { Emotion } from '../../constants/emotions'
import { storeToRefs } from 'pinia'
import { generateSpeech } from '@xsai/generate-speech'
import { createUnElevenLabs } from '@xsai/providers'
import { storeToRefs } from 'pinia'
import { onUnmounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useMarkdown } from '../../composables/markdown'
import { useQueue } from '../../composables/queue'
import { useDelayMessageQueue, useEmotionsMessageQueue, useMessageContentQueue } from '../../composables/queues'
import { llmInferenceEndToken } from '../../constants'
import { Voice } from '../../constants/elevenlabs'
import { Voice, voiceMap } from '../../constants/elevenlabs'
import { EMOTION_EmotionMotionName_value, EMOTION_VRMExpressionName_value, EmotionThinkMotionName } from '../../constants/emotions'
import { useAudioContext, useSpeakingStore } from '../../stores/audio'
import { useChatStore } from '../../stores/chat'
import { useLLM } from '../../stores/llm'
import { useSettings } from '../../stores/settings'
import Live2DScene from '../Scenes/Live2D.vue'
import Live2DScene from '../Scenes/Live2D.vue'
import VRMScene from '../Scenes/VRM.vue'
import '../../utils/live2d-zip-loader'
Expand All @@ -27,7 +28,6 @@ const vrmViewerRef = ref<{ setExpression: (expression: string) => void }>()
const { stageView, elevenLabsApiKey, elevenlabsVoiceEnglish, elevenlabsVoiceJapanese } = storeToRefs(useSettings())
const { mouthOpenSize } = storeToRefs(useSpeakingStore())
const { audioContext, calculateVolume } = useAudioContext()
const { streamSpeech } = useLLM()
const { onBeforeMessageComposed, onBeforeSend, onTokenLiteral, onTokenSpecial, onStreamEnd, streamingMessage } = useChatStore()
const { process } = useMarkdown()
const { locale } = useI18n()
Expand Down Expand Up @@ -71,17 +71,21 @@ const ttsQueue = useQueue<string>({
voice = elevenlabsVoiceEnglish.value
const now = Date.now()
const res = await streamSpeech('https://airi-api.ayaka.io', elevenLabsApiKey.value, ctx.data, {
// voice: 'ShanShan',
// Quite good for English
voice,
// Beatrice is not 'childish' like the others
// voice: 'Beatrice',
model_id: 'eleven_multilingual_v2',
voice_settings: {
stability: 0.4,
similarity_boost: 0.5,
},
const elevenlabs = createUnElevenLabs({
apiKey: elevenLabsApiKey.value,
baseURL: 'https://unspeech.hyp3r.link/v1/',
})
const res = await generateSpeech({
...elevenlabs.speech({
model: 'elevenlabs/eleven_multilingual_v2',
voice: voiceMap[voice],
voiceSettings: {
stability: 0.4,
similarityBoost: 0.5,
},
}),
input: ctx.data,
})
const elapsed = Date.now() - now
Expand Down
5 changes: 5 additions & 0 deletions packages/stage/src/constants/elevenlabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export enum Voice {
export const voiceMap: Record<Voice, string> = {
// English
[Voice.Myriam]: 'lNxY9WuCBCZCISASyJ55',
// Beatrice is not 'childish' like the others
// voice: 'Beatrice',
[Voice.Beatrice]: 'KAsXoQDshjF6ehsWa1mF',
[Voice.Camilla_KM]: 'dLhSyo03JRp5WkGpUlz1',
[Voice.SallySunshine]: 'qswttdunP3b44zVZKMRB',
Expand All @@ -22,6 +24,9 @@ export const voiceMap: Record<Voice, string> = {
[Voice.Morioki]: '8EkOjt4xTPGMclNlh1pk',
}

// voice: 'ShanShan',
// Quite good for English

export const enVoiceList = [
Voice.Myriam,
Voice.Beatrice,
Expand Down
22 changes: 0 additions & 22 deletions packages/stage/src/stores/llm.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import type { GenerateAudioStream } from '@proj-airi/elevenlabs/types'
import type { Message } from '@xsai/shared-chat'
import { listModels } from '@xsai/model'
import { streamText } from '@xsai/stream-text'
import { ofetch } from 'ofetch'
import { defineStore } from 'pinia'

export const useLLM = defineStore('llm', () => {
Expand Down Expand Up @@ -38,28 +36,8 @@ export const useLLM = defineStore('llm', () => {
}
}

async function streamSpeech(baseUrl: string, apiKey: string, text: string, options: Omit<Omit<GenerateAudioStream, 'stream'> & { voice: string }, 'text'>) {
if (!text || !text.trim())
throw new Error('Text is required')

return await ofetch(`${baseUrl}/api/v1/llm/voice/elevenlabs`, {
body: {
...options,
stream: true,
text,
},
method: 'POST',
cache: 'no-cache',
responseType: 'arrayBuffer',
headers: {
Authorization: `Bearer ${apiKey}`,
},
})
}

return {
models,
stream,
streamSpeech,
}
})
2 changes: 1 addition & 1 deletion packages/stage/src/stores/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const useSettings = defineStore('settings', () => {
const selectedAudioDeviceId = computed(() => selectedAudioDevice.value?.deviceId)
const { audioInputs } = useDevicesList({ constraints: { audio: true }, requestPermissions: true })

const elevenlabsVoiceEnglish = useLocalStorage<Voice>('settings/llm/elevenlabs/voice/en', Voice.Camilla_KM)
const elevenlabsVoiceEnglish = useLocalStorage<Voice>('settings/llm/elevenlabs/voice/en', Voice.Myriam)
const elevenlabsVoiceJapanese = useLocalStorage<Voice>('settings/llm/elevenlabs/voice/ja', Voice.Morioki)

watch(isAudioInputOn, (value) => {
Expand Down
Loading

0 comments on commit 86fac7d

Please sign in to comment.