feat(#403): add audio playback component for TTS output
All checks were successful
ci/woodpecker/push/web Pipeline was successful
All checks were successful
ci/woodpecker/push/web Pipeline was successful
Implements AudioPlayer inline component with play/pause, progress bar, speed control (0.5x-2x), download, and duration display. Adds TextToSpeechButton "Read aloud" component that synthesizes text via the speech API and integrates AudioPlayer for playback. Includes useTextToSpeech hook with API integration, audio caching, and playback state management. All 32 tests passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
58
apps/web/src/lib/api/speech.ts
Normal file
58
apps/web/src/lib/api/speech.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Speech API client
|
||||
* Handles text-to-speech synthesis and voice listing via /api/speech
|
||||
*/
|
||||
|
||||
import { apiGet } from "./client";
|
||||
import { API_BASE_URL } from "../config";
|
||||
|
||||
export interface VoiceInfo {
|
||||
id: string;
|
||||
name: string;
|
||||
language: string;
|
||||
gender?: string;
|
||||
preview_url?: string;
|
||||
}
|
||||
|
||||
export interface SynthesizeOptions {
|
||||
text: string;
|
||||
voice?: string;
|
||||
speed?: number;
|
||||
format?: string;
|
||||
tier?: string;
|
||||
}
|
||||
|
||||
export interface VoicesResponse {
|
||||
data: VoiceInfo[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch available TTS voices
|
||||
*/
|
||||
export async function getVoices(): Promise<VoicesResponse> {
|
||||
return apiGet<VoicesResponse>("/api/speech/voices");
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthesize text to speech audio
|
||||
* Returns the audio as a Blob since the API returns binary audio data
|
||||
*/
|
||||
export async function synthesizeSpeech(options: SynthesizeOptions): Promise<Blob> {
|
||||
const url = `${API_BASE_URL}/api/speech/synthesize`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
body: JSON.stringify(options),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text().catch(() => "Unknown error");
|
||||
throw new Error(`Speech synthesis failed: ${errorText}`);
|
||||
}
|
||||
|
||||
return response.blob();
|
||||
}
|
||||
Reference in New Issue
Block a user