Add voice + speed to indexedDB and config context

This commit is contained in:
Richard Roberson 2025-01-26 18:39:11 -07:00
parent 55919310a5
commit e830957598
3 changed files with 30 additions and 9 deletions

View file

@ -5,6 +5,7 @@ import {
ListboxOptions,
} from '@headlessui/react';
import { ChevronUpDownIcon } from '@/components/icons/Icons';
import { useConfig } from '@/contexts/ConfigContext';
const speedOptions = [
{ value: 0.5, label: '0.5x' },
@ -22,11 +23,16 @@ export const SpeedControl = ({ speed, setSpeedAndRestart }: {
speed: number;
setSpeedAndRestart: (speed: number) => void;
}) => {
const { voiceSpeed } = useConfig();
// Use voiceSpeed as the source of truth
const currentSpeed = voiceSpeed;
return (
<div className="relative">
<Listbox value={speed} onChange={setSpeedAndRestart}>
<Listbox value={currentSpeed} onChange={setSpeedAndRestart}>
<ListboxButton className="flex items-center space-x-1 bg-transparent text-foreground text-sm focus:outline-none cursor-pointer hover:bg-offbase rounded pl-2 pr-1 py-1">
<span>{speed}x</span>
<span>{currentSpeed}x</span>
<ChevronUpDownIcon className="h-3 w-3" />
</ListboxButton>
<ListboxOptions className="absolute bottom-full mb-1 w-24 overflow-auto rounded-lg bg-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">

View file

@ -5,17 +5,23 @@ import {
ListboxOptions,
} from '@headlessui/react';
import { ChevronUpDownIcon } from '@/components/icons/Icons';
import { useConfig } from '@/contexts/ConfigContext';
export const VoicesControl = ({ voice, availableVoices, setVoiceAndRestart }: {
voice: string;
availableVoices: string[];
setVoiceAndRestart: (voice: string) => void;
}) => {
const { voice: configVoice } = useConfig();
// Use configVoice as the source of truth
const currentVoice = configVoice;
return (
<div className="relative">
<Listbox value={voice} onChange={setVoiceAndRestart}>
<Listbox value={currentVoice} onChange={setVoiceAndRestart}>
<ListboxButton className="flex items-center space-x-1 bg-transparent text-foreground text-sm focus:outline-none cursor-pointer hover:bg-offbase rounded pl-2 pr-1 py-1">
<span>{voice}</span>
<span>{currentVoice}</span>
<ChevronUpDownIcon className="h-3 w-3" />
</ListboxButton>
<ListboxOptions className="absolute bottom-full mb-1 w-32 overflow-auto rounded-lg bg-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">

View file

@ -61,7 +61,14 @@ interface TTSContextType {
const TTSContext = createContext<TTSContextType | undefined>(undefined);
export function TTSProvider({ children }: { children: React.ReactNode }) {
const { apiKey: openApiKey, baseUrl: openApiBaseUrl, isLoading: configIsLoading } = useConfig();
const {
apiKey: openApiKey,
baseUrl: openApiBaseUrl,
isLoading: configIsLoading,
voiceSpeed,
voice: configVoice,
updateConfigKey
} = useConfig();
// Move openai initialization to a ref to avoid breaking hooks rules
const openaiRef = useRef<OpenAI | null>(null);
@ -75,8 +82,8 @@ export function TTSProvider({ children }: { children: React.ReactNode }) {
const [activeHowl, setActiveHowl] = useState<Howl | null>(null);
const [audioQueue] = useState<AudioBuffer[]>([]);
const [isProcessing, setIsProcessing] = useState(false);
const [speed, setSpeed] = useState(1);
const [voice, setVoice] = useState('alloy');
const [speed, setSpeed] = useState(voiceSpeed);
const [voice, setVoice] = useState(configVoice);
const [availableVoices, setAvailableVoices] = useState<string[]>([]);
const [currDocPage, setCurrDocPage] = useState<number>(1);
@ -422,6 +429,7 @@ export function TTSProvider({ children }: { children: React.ReactNode }) {
const setSpeedAndRestart = useCallback((newSpeed: number) => {
setSpeed(newSpeed);
updateConfigKey('voiceSpeed', newSpeed);
// Clear the audio cache since it contains audio at the old speed
audioCacheRef.current.clear();
@ -431,10 +439,11 @@ export function TTSProvider({ children }: { children: React.ReactNode }) {
setCurrentIndex(currentIdx);
setIsPlaying(true);
}
}, [isPlaying, currentIndex, stop]);
}, [isPlaying, currentIndex, stop, updateConfigKey]);
const setVoiceAndRestart = useCallback((newVoice: string) => {
setVoice(newVoice);
updateConfigKey('voice', newVoice);
// Clear the audio cache since it contains audio with the old voice
audioCacheRef.current.clear();
@ -444,7 +453,7 @@ export function TTSProvider({ children }: { children: React.ReactNode }) {
setCurrentIndex(currentIdx);
setIsPlaying(true);
}
}, [isPlaying, currentIndex, stop]);
}, [isPlaying, currentIndex, stop, updateConfigKey]);
const value = {
isPlaying,