openreader/src/hooks/audio/useVoiceManagement.ts
Richard R b4f4d43d6a feat(tts,config,types): migrate to providerRef/providerType model and add centralized TTS provider policy
Transition all TTS-related logic, types, and UI to use the new providerRef/providerType model in place of legacy ttsProvider fields. Introduce a centralized tts-provider-policy module to encapsulate provider/model capability checks, default value resolution, and compatibility logic. Update all API routes, contexts, hooks, components, and tests to use providerRef and providerType, ensuring consistent handling of built-in and shared TTS providers. Remove legacy defaultTtsModel config in favor of per-provider defaults and shared provider admin control. Add the showAllProviderModels runtime flag to restrict users to provider default models when desired.

BREAKING CHANGE: ttsProvider fields are replaced by providerRef/providerType throughout the codebase; defaultTtsModel config is removed in favor of per-provider defaults.
2026-05-13 10:11:05 -06:00

62 lines
2.2 KiB
TypeScript

'use client';
import { useState, useCallback, useRef } from 'react';
import { getVoices } from '@/lib/client/api/audiobooks';
import { type TtsProviderType } from '@/lib/shared/tts-provider-catalog';
import { resolveTtsProviderModelPolicy } from '@/lib/shared/tts-provider-policy';
/**
* Custom hook for managing TTS voices
* @param apiKey OpenAI API key
* @param baseUrl OpenAI API base URL
* @param providerRef TTS provider routing reference (built-in id or shared slug)
* @param providerType Resolved provider type for capability/default logic
* @param ttsModel TTS model name
* @returns Object containing available voices and fetch function
*/
export function useVoiceManagement(
apiKey: string | undefined,
baseUrl: string | undefined,
providerRef: string | undefined,
providerType: TtsProviderType | undefined,
ttsModel: string | undefined
) {
const [availableVoices, setAvailableVoices] = useState<string[]>([]);
const fetchSeqRef = useRef(0);
const fetchVoices = useCallback(async () => {
const fetchSeq = ++fetchSeqRef.current;
try {
console.log('Fetching voices...');
const data = await getVoices({
'x-openai-key': apiKey || '',
'x-openai-base-url': baseUrl || '',
'x-tts-provider': providerRef || 'openai',
'x-tts-model': ttsModel || 'tts-1',
'Content-Type': 'application/json',
});
// Ignore stale responses from older provider/model fetches.
if (fetchSeq !== fetchSeqRef.current) return;
if (data.voices && data.voices.length > 0) {
setAvailableVoices(data.voices);
return;
}
setAvailableVoices(resolveTtsProviderModelPolicy({
providerRef: providerRef || '',
providerType,
model: ttsModel || 'tts-1',
}).defaultVoices);
} catch (error) {
console.error('Error fetching voices:', error);
if (fetchSeq !== fetchSeqRef.current) return;
setAvailableVoices(resolveTtsProviderModelPolicy({
providerRef: providerRef || '',
providerType,
model: ttsModel || 'tts-1',
}).defaultVoices);
}
}, [apiKey, baseUrl, providerRef, providerType, ttsModel]);
return { availableVoices, fetchVoices };
}