Feat : tts
This commit is contained in:
1 parent
39545cf4c8
commit
3c96e8d6d1
40 files changed
+1896
-147
No files matched your search
@@ -0,0 +1,71 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { getProviderConnections } from "@/lib/localDb";
|
||||
import { fetchElevenLabsVoices } from "open-sse/handlers/ttsCore.js";
|
||||
|
||||
const langNames = new Intl.DisplayNames(["en"], { type: "language" });
|
||||
|
||||
/**
|
||||
* GET /api/media-providers/tts/elevenlabs/voices[?lang=en]
|
||||
* Returns { languages, byLang } grouped by language - same format as edge-tts
|
||||
* Uses direct DB read (no mutex) to avoid blocking on concurrent TTS requests
|
||||
*/
|
||||
export async function GET(request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const langFilter = searchParams.get("lang");
|
||||
|
||||
// Direct DB read - bypass auth mutex used for TTS inference
|
||||
const connections = await getProviderConnections({ provider: "elevenlabs", isActive: true });
|
||||
const apiKey = connections[0]?.apiKey;
|
||||
if (!apiKey) {
|
||||
return NextResponse.json({ error: "No ElevenLabs connection found" }, { status: 400 });
|
||||
}
|
||||
|
||||
const voices = await fetchElevenLabsVoices(apiKey);
|
||||
|
||||
// Group by all supported languages (verified_languages + labels.language)
|
||||
const byLang = {};
|
||||
const addToLang = (code, voice) => {
|
||||
if (!byLang[code]) {
|
||||
byLang[code] = {
|
||||
code,
|
||||
name: (() => { try { return langNames.of(code); } catch { return code; } })(),
|
||||
voices: [],
|
||||
};
|
||||
}
|
||||
// Avoid duplicate voice in same lang
|
||||
if (!byLang[code].voices.find((v) => v.id === voice.voice_id)) {
|
||||
byLang[code].voices.push({
|
||||
id: voice.voice_id,
|
||||
name: voice.name,
|
||||
gender: voice.labels?.gender || "",
|
||||
lang: code,
|
||||
// premade voices are free; professional library voices added to account may require paid plan
|
||||
free_users_allowed: voice.category === "premade" || voice.is_owner === true
|
||||
});
|
||||
}
|
||||
};
|
||||
for (const v of voices) {
|
||||
// Add to primary language
|
||||
const primaryLang = v.labels?.language || "en";
|
||||
addToLang(primaryLang, v);
|
||||
// Add to all verified languages
|
||||
for (const vl of v.verified_languages || []) {
|
||||
if (vl.language && vl.language !== primaryLang) {
|
||||
addToLang(vl.language, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const languages = Object.values(byLang).sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
// If lang filter requested, return only that group's voices
|
||||
if (langFilter) {
|
||||
return NextResponse.json({ voices: byLang[langFilter]?.voices || [] });
|
||||
}
|
||||
|
||||
return NextResponse.json({ languages, byLang });
|
||||
} catch (err) {
|
||||
return NextResponse.json({ error: err.message || "Failed to fetch voices" }, { status: 502 });
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user