export class ElevenLabsClient { private apiKey: string; private baseUrl = "https://api.elevenlabs.io/v1"; constructor(apiKey: string) { this.apiKey = apiKey; } async getVoices(): Promise { const response = await fetch(`${this.baseUrl}/voices`, { headers: { "xi-api-key": this.apiKey, }, }); if (!response.ok) { throw new Error(`Failed to get voices: ${response.statusText}`); } const data = await response.json(); return data.voices; } async deleteVoice(voiceId: string): Promise { const response = await fetch(`${this.baseUrl}/voices/${voiceId}`, { method: "DELETE", headers: { "xi-api-key": this.apiKey, }, }); if (!response.ok) { console.error("ElevenLabs error:", await response.text()); throw new Error(`Failed to delete voice: ${response.statusText}`); } } async addVoice(name: string, audioFile: File): Promise { const formData = new FormData(); formData.append("name", name); formData.append("files", audioFile); formData.append("description", "Voice generated for NotMe game"); const response = await fetch(`${this.baseUrl}/voices/add`, { method: "POST", headers: { "xi-api-key": this.apiKey, }, body: formData, }); if (!response.ok) { console.error("ElevenLabs error:", await response.text()); throw new Error(`Failed to add voice: ${response.statusText}`); } const data = await response.json(); return data.voice_id; } async generateSpeech(voiceId: string, text: string): Promise { const response = await fetch( `${this.baseUrl}/text-to-speech/${voiceId}/stream`, { method: "POST", headers: { "xi-api-key": this.apiKey, "Content-Type": "application/json", }, body: JSON.stringify({ text, model_id: "eleven_monolingual_v1", voice_settings: { stability: 0.5, similarity_boost: 0.75, }, }), } ); if (!response.ok) { throw new Error(`Failed to generate speech: ${response.statusText}`); } const arrayBuffer = await response.arrayBuffer(); return Buffer.from(arrayBuffer); } }