From 1b6f377ee94a6735194a607d9936cf4fa5add409 Mon Sep 17 00:00:00 2001 From: rio2dev Date: Fri, 6 Dec 2024 17:02:51 +0200 Subject: [PATCH 1/2] feat: Use user_provided API keys for OpenAI and Azure OpenAI TTS --- api/server/services/Files/Audio/TTSService.js | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/api/server/services/Files/Audio/TTSService.js b/api/server/services/Files/Audio/TTSService.js index bfb90843da4..37c6fa8a559 100644 --- a/api/server/services/Files/Audio/TTSService.js +++ b/api/server/services/Files/Audio/TTSService.js @@ -4,6 +4,7 @@ const { getRandomVoiceId, createChunkProcessor, splitTextIntoChunks } = require( const { getCustomConfig } = require('~/server/services/Config'); const { genAzureEndpoint } = require('~/utils'); const { logger } = require('~/config'); +const { getUserKeyValues } = require('~/server/services/UserService'); /** * Service class for handling Text-to-Speech (TTS) operations. @@ -259,13 +260,41 @@ class TTSService { * @returns {Promise} The axios response object. * @throws {Error} If the provider is invalid or the request fails. */ - async ttsRequest(provider, ttsSchema, { input, voice, stream = true }) { + async ttsRequest(provider, ttsSchema, { input, voice, stream = true }, userId) { const strategy = this.providerStrategies[provider]; if (!strategy) { throw new Error('Invalid provider'); } - const [url, data, headers] = strategy.call(this, ttsSchema, input, voice, stream); + let [url, data, headers] = strategy.call(this, ttsSchema, input, voice, stream); + + const schemaApiKey = extractEnvVariable(ttsSchema.apiKey); + + if (schemaApiKey == "user_provided"){ + if (provider == TTSProviders.OPENAI){ + const userValues = await getUserKeyValues({ userId: userId, name: 'openAI' }); + const apiKey = userValues?.apiKey; + if (apiKey){ + headers = { + 'Content-Type': 'application/json', + Authorization: `Bearer ${apiKey}`, + }; + } else { + throw new Error(`Missing ${provider} API key`); + } + } else if (provider == TTSProviders.AZURE_OPENAI){ + const userValues = await getUserKeyValues({ userId: userId, name: 'azureOpenAI' }); + const apiKey = userValues?.apiKey; + if (apiKey){ + headers = { + 'Content-Type': 'application/json', + 'api-key': apiKey, + }; + } else { + throw new Error(`Missing ${provider} API key`); + } + } + } [data, headers].forEach(this.removeUndefined.bind(this)); @@ -298,9 +327,10 @@ class TTSService { const provider = this.getProvider(); const ttsSchema = this.customConfig.speech.tts[provider]; const voice = await this.getVoice(ttsSchema, requestVoice); + const userId = req?.user?.id; if (input.length < 4096) { - const response = await this.ttsRequest(provider, ttsSchema, { input, voice }); + const response = await this.ttsRequest(provider, ttsSchema, { input, voice }, userId); response.data.pipe(res); return; } @@ -313,7 +343,7 @@ class TTSService { voice, input: chunk.text, stream: true, - }); + }, userId); logger.debug(`[textToSpeech] user: ${req?.user?.id} | writing audio stream`); await new Promise((resolve) => { @@ -385,7 +415,7 @@ class TTSService { voice, input: update.text, stream: true, - }); + }, userId); if (!shouldContinue) { break; From 62c49e6514fe14d9776747bcc3d1f68707e83441 Mon Sep 17 00:00:00 2001 From: rio2dev Date: Fri, 6 Dec 2024 17:16:25 +0200 Subject: [PATCH 2/2] Update TTSService.js --- api/server/services/Files/Audio/TTSService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/server/services/Files/Audio/TTSService.js b/api/server/services/Files/Audio/TTSService.js index 37c6fa8a559..b9746b87dea 100644 --- a/api/server/services/Files/Audio/TTSService.js +++ b/api/server/services/Files/Audio/TTSService.js @@ -268,7 +268,7 @@ class TTSService { let [url, data, headers] = strategy.call(this, ttsSchema, input, voice, stream); - const schemaApiKey = extractEnvVariable(ttsSchema.apiKey); + const schemaApiKey = extractEnvVariable(ttsSchema?.apiKey); if (schemaApiKey == "user_provided"){ if (provider == TTSProviders.OPENAI){