Speex: debug instrumentation

This commit is contained in:
Enrico Ros
2025-11-27 03:16:11 -08:00
parent c84b2df3fa
commit a7dee0002d
5 changed files with 20 additions and 2 deletions
@@ -17,6 +17,7 @@ import { AudioPlayer } from '~/common/util/audio/AudioPlayer';
import type { DSpeexEngine, SpeexSpeakResult } from '../../speex.types';
import type { SpeexWire_Access, SpeexWire_ListVoices_Output, SpeexWire_Voice } from './rpc.wiretypes';
import { SPEEX_DEBUG } from '../../speex.config';
type _DSpeexEngineRPC = DSpeexEngine<'elevenlabs'> | DSpeexEngine<'localai'> | DSpeexEngine<'openai'>;
@@ -44,6 +45,7 @@ export async function speexSynthesize_RPC(
): Promise<SpeexSpeakResult> {
// engine credentials (DCredentials..) -> wire Access
if (SPEEX_DEBUG) console.log(`[Speex RPC] Synthesize request (engine: ${engine.engineId}, ${text.length} chars) - options:`, options);
const access = _buildRPCWireAccess(engine);
if (!access) {
const error = new Error(`Failed to resolve credentials for engine ${engine.engineId}`);
@@ -72,6 +74,7 @@ export async function speexSynthesize_RPC(
// process streaming particles
for await (const particle of particleStream) {
if (SPEEX_DEBUG) console.log('[Speex RPC] <-', particle);
switch (particle.t) {
case 'start':
callbacks?.onStart?.();
@@ -134,7 +137,9 @@ export async function speexSynthesize_RPC(
return result;
} catch (error: any) {
// Cleanup
if (SPEEX_DEBUG) console.error('[Speex RPC] Synthesis error:', { error });
// cleanup
if (audioPlayer)
void audioPlayer.stop();
@@ -4,6 +4,7 @@ import { fetchJsonOrTRPCThrow, fetchResponseOrTRPCThrow } from '~/server/trpc/tr
import type { SpeexSpeechParticle, SpeexWire_Access_ElevenLabs, SpeexWire_ListVoices_Output } from './rpc.wiretypes';
import type { SynthesizeBackendFn } from './rpc.router';
import { SPEEX_DEBUG } from '../../speex.config';
import { returnAudioWholeOrThrow, streamAudioChunksOrThrow } from './rpc.streaming';
@@ -53,6 +54,7 @@ export const synthesizeElevenLabs: SynthesizeBackendFn<SpeexWire_Access_ElevenLa
// Fetch
let response: Response;
try {
if (SPEEX_DEBUG) console.log(`[Speex][ElevenLabs] POST (stream=${streaming})`, { url, headers, body });
response = await fetchResponseOrTRPCThrow({
url,
method: 'POST',
@@ -6,6 +6,7 @@ import { fetchJsonOrTRPCThrow, fetchResponseOrTRPCThrow } from '~/server/trpc/tr
import type { SpeexWire_Access_OpenAI, SpeexWire_ListVoices_Output } from './rpc.wiretypes';
import type { SynthesizeBackendFn } from './rpc.router';
import { SPEEX_DEBUG } from '../../speex.config';
import { returnAudioWholeOrThrow, streamAudioChunksOrThrow } from './rpc.streaming';
@@ -56,6 +57,7 @@ export const synthesizeOpenAIProtocol: SynthesizeBackendFn<SpeexWire_Access_Open
// request.headers
const { host, apiKey } = _resolveAccess(access);
const url = `${host}/v1/audio/speech`;
const headers: HeadersInit = {
'Content-Type': 'application/json',
...(!apiKey ? {} : { 'Authorization': `Bearer ${apiKey}` }),
@@ -95,8 +97,9 @@ export const synthesizeOpenAIProtocol: SynthesizeBackendFn<SpeexWire_Access_Open
const dialectName = access.dialect === 'localai' ? 'LocalAI' : 'OpenAI';
let response: Response;
try {
if (SPEEX_DEBUG) console.log(`[Speex][OpenAI] POST (stream=${streaming})`, { url, headers, body });
response = await fetchResponseOrTRPCThrow({
url: `${host}/v1/audio/speech`,
url,
method: 'POST',
headers,
body,
@@ -9,6 +9,8 @@ import * as React from 'react';
import type { DVoiceWebSpeech, SpeexListVoiceOption, SpeexSpeakResult } from '../../speex.types';
import { SPEEX_DEBUG } from '~/modules/speex/speex.config';
function _webspeechVoicesToVoiceOptions(browserVoices: ReadonlyArray<SpeechSynthesisVoice>): SpeexListVoiceOption[] {
return browserVoices.map(v => ({
@@ -128,6 +130,7 @@ export function speexSynthesize_WebSpeech(
speechSynthesis.cancel(); // safe
// create utterance
if (SPEEX_DEBUG) console.debug(`[Speex][WebSpeech] New utterance (${text.length} chars, voice: ${voice.ttsVoiceURI}, s=${voice.ttsSpeed}, p=${voice.ttsPitch})`);
const utterance = new SpeechSynthesisUtterance(text);
// find and set voice by URI
@@ -144,15 +147,18 @@ export function speexSynthesize_WebSpeech(
// set up event handlers
utterance.onstart = () => {
if (SPEEX_DEBUG) console.debug(`[Speex][WebSpeech] Utterance started`);
callbacks?.onStart?.();
};
utterance.onend = () => {
if (SPEEX_DEBUG) console.debug(`[Speex][WebSpeech] Utterance completed`);
callbacks?.onComplete?.();
resolve({ success: true });
};
utterance.onerror = (event) => {
if (SPEEX_DEBUG) console.error(`[Speex][WebSpeech] Utterance error`, event.error);
const errorMessage = event.error || 'Speech synthesis failed';
const error = new Error(errorMessage);
callbacks?.onError?.(error);
+2
View File
@@ -0,0 +1,2 @@
// configuration
export const SPEEX_DEBUG = false;