feat: add ElevenLabs Firebase token emulation
This commit is contained in:
@@ -5,6 +5,10 @@ import * as https from 'https';
|
||||
|
||||
const ELEVENLABS_API_ENDPOINT = 'api.elevenlabs.io';
|
||||
|
||||
const FIREBASE_API_KEY = "AIzaSyBSsRE_1Os04-bxpd5JTLIniy3UK4OqKys";
|
||||
const FIREBASE_URL = `https://securetoken.googleapis.com/v1/token?key=${FIREBASE_API_KEY}`;
|
||||
|
||||
|
||||
/*
|
||||
TO-DO: Implement previous text
|
||||
*/
|
||||
@@ -39,6 +43,12 @@ interface ElevenLabsStreamRequest {
|
||||
voice_settings: ElevenLabsVoiceSettings;
|
||||
}
|
||||
|
||||
interface FirebaseSession {
|
||||
idToken: string;
|
||||
refreshToken: string;
|
||||
expiresAt: number;
|
||||
}
|
||||
|
||||
export class ElevenLabsTTS implements TTSModule {
|
||||
private voices: Array<ElevenLabsVoice> | undefined = undefined;
|
||||
private models: Array<ElevenLabsModel> | undefined = undefined;
|
||||
@@ -48,29 +58,38 @@ export class ElevenLabsTTS implements TTSModule {
|
||||
public settings: ElevenLabsVoiceSettings;
|
||||
public modelId: string;
|
||||
|
||||
private session: FirebaseSession | undefined = undefined;
|
||||
|
||||
private initializationPromise: Promise<void> | undefined = undefined;
|
||||
|
||||
public static readonly DEFAULT_SETTINGS: ElevenLabsVoiceSettings = {
|
||||
stability: 0.5,
|
||||
stability: 0.0,
|
||||
similarity_boost: 0.5,
|
||||
style: 0.0,
|
||||
style: 1.0,
|
||||
speed: 1.0,
|
||||
user_speaker_boost: true
|
||||
};
|
||||
|
||||
constructor() {
|
||||
if (this.canBeUsed()) {
|
||||
this.fetchVoices();
|
||||
this.fetchModels();
|
||||
}
|
||||
|
||||
this.settings = ElevenLabsTTS.DEFAULT_SETTINGS;
|
||||
|
||||
this.modelId = 'eleven_flash_v2_5';
|
||||
|
||||
if (this.canBeUsed())
|
||||
this.initializationPromise = this.init();
|
||||
|
||||
this.setSettings = this.setSettings.bind(this);
|
||||
this.setModel = this.setModel.bind(this);
|
||||
this.getModels = this.getModels.bind(this);
|
||||
}
|
||||
|
||||
private async init(): Promise<void> {
|
||||
await this.ensureSession();
|
||||
await Promise.all([
|
||||
this.fetchVoices(),
|
||||
this.fetchModels()
|
||||
]);
|
||||
}
|
||||
|
||||
/*
|
||||
TTSModule methods
|
||||
*/
|
||||
@@ -79,7 +98,11 @@ export class ElevenLabsTTS implements TTSModule {
|
||||
}
|
||||
|
||||
async generate(voice: string, text: string): Promise<TTSResponse> {
|
||||
if (!this.voices) return {};
|
||||
await this.initializationPromise;
|
||||
await this.ensureSession();
|
||||
|
||||
if (!this.voices) return { error: 'no voices' };
|
||||
if (!this.session) return { error: 'no session' };
|
||||
|
||||
const voiceData = this.voices.find((entry) => entry.name === voice);
|
||||
if (!voiceData) return { error: 'Invalid voice' };
|
||||
@@ -100,10 +123,8 @@ export class ElevenLabsTTS implements TTSModule {
|
||||
'Sec-Fetch-Site': 'same-site',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
host: 'api.us.elevenlabs.io',
|
||||
...(config.tts_elevenlabs_token
|
||||
? { Authorization: `Bearer ${config.tts_elevenlabs_token}` }
|
||||
: { 'xi-api-key': config.tts_elevenlabs_key })
|
||||
host: 'api.elevenlabs.io',
|
||||
Authorization: `Bearer ${this.session.idToken}`
|
||||
}
|
||||
};
|
||||
|
||||
@@ -132,7 +153,7 @@ export class ElevenLabsTTS implements TTSModule {
|
||||
}
|
||||
|
||||
canBeUsed(): boolean {
|
||||
return config.tts_elevenlabs_key != undefined;
|
||||
return config.tts_elevenlabs_refreshtoken != undefined && config.tts_elevenlabs_key != undefined;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -221,6 +242,35 @@ export class ElevenLabsTTS implements TTSModule {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private async ensureSession(): Promise<void> {
|
||||
if (this.session && Date.now() < this.session.expiresAt - 300000)
|
||||
return;
|
||||
|
||||
const refreshToken = this.session?.refreshToken || config.tts_elevenlabs_refreshtoken;
|
||||
if (!refreshToken) throw new Error("No refresh token available");
|
||||
|
||||
const response = await fetch(FIREBASE_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Referer': 'https://elevenlabs.io/',
|
||||
'Origin': 'https://elevenlabs.io'
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
grant_type: 'refresh_token',
|
||||
refresh_token: refreshToken,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error(`Auth Refresh Failed: ${await response.text()}`);
|
||||
const data = await response.json();
|
||||
this.session = {
|
||||
idToken: data.id_token,
|
||||
refreshToken: data.refresh_token,
|
||||
expiresAt: Date.now() + (parseInt(data.expires_in) * 1000)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default new ElevenLabsTTS();
|
||||
|
||||
Reference in New Issue
Block a user