mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
🔊 fix: Validate language format for OpenAI STT model (#10875)
Some checks are pending
Publish `@librechat/client` to NPM / build-and-publish (push) Waiting to run
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions
Some checks are pending
Publish `@librechat/client` to NPM / build-and-publish (push) Waiting to run
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions
* 🔊 fix: Validate language format for OpenAI STT model
* fix: Normalize input language model assignment in STTService
* refactor: Enhance error logging and language validation in STT and TTS services
* fix: Improve language validation in getValidatedLanguageCode function
This commit is contained in:
parent
11923b9b96
commit
5879b3f518
2 changed files with 49 additions and 17 deletions
|
|
@ -3,8 +3,8 @@ const fs = require('fs').promises;
|
|||
const FormData = require('form-data');
|
||||
const { Readable } = require('stream');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { genAzureEndpoint } = require('@librechat/api');
|
||||
const { HttpsProxyAgent } = require('https-proxy-agent');
|
||||
const { genAzureEndpoint, logAxiosError } = require('@librechat/api');
|
||||
const { extractEnvVariable, STTProviders } = require('librechat-data-provider');
|
||||
const { getAppConfig } = require('~/server/services/Config');
|
||||
|
||||
|
|
@ -35,6 +35,34 @@ const MIME_TO_EXTENSION_MAP = {
|
|||
'audio/x-flac': 'flac',
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates and extracts ISO-639-1 language code from a locale string.
|
||||
* @param {string} language - The language/locale string (e.g., "en-US", "en", "zh-CN")
|
||||
* @returns {string|null} The ISO-639-1 language code (e.g., "en") or null if invalid
|
||||
*/
|
||||
function getValidatedLanguageCode(language) {
|
||||
try {
|
||||
if (!language) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const normalizedLanguage = language.toLowerCase();
|
||||
const isValidLocaleCode = /^[a-z]{2}(-[a-z]{2})?$/.test(normalizedLanguage);
|
||||
|
||||
if (isValidLocaleCode) {
|
||||
return normalizedLanguage.split('-')[0];
|
||||
}
|
||||
|
||||
logger.warn(
|
||||
`[STT] Invalid language format "${language}". Expected ISO-639-1 locale code like "en-US" or "en". Skipping language parameter.`,
|
||||
);
|
||||
return null;
|
||||
} catch (error) {
|
||||
logger.error(`[STT] Error validating language code "${language}":`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file extension from the MIME type.
|
||||
* @param {string} mimeType - The MIME type.
|
||||
|
|
@ -173,10 +201,9 @@ class STTService {
|
|||
model: sttSchema.model,
|
||||
};
|
||||
|
||||
if (language) {
|
||||
/** Converted locale code (e.g., "en-US") to ISO-639-1 format (e.g., "en") */
|
||||
const isoLanguage = language.split('-')[0];
|
||||
data.language = isoLanguage;
|
||||
const validLanguage = getValidatedLanguageCode(language);
|
||||
if (validLanguage) {
|
||||
data.language = validLanguage;
|
||||
}
|
||||
|
||||
const headers = {
|
||||
|
|
@ -221,10 +248,9 @@ class STTService {
|
|||
contentType: audioFile.mimetype,
|
||||
});
|
||||
|
||||
if (language) {
|
||||
/** Converted locale code (e.g., "en-US") to ISO-639-1 format (e.g., "en") */
|
||||
const isoLanguage = language.split('-')[0];
|
||||
formData.append('language', isoLanguage);
|
||||
const validLanguage = getValidatedLanguageCode(language);
|
||||
if (validLanguage) {
|
||||
formData.append('language', validLanguage);
|
||||
}
|
||||
|
||||
const headers = {
|
||||
|
|
@ -286,7 +312,7 @@ class STTService {
|
|||
|
||||
return response.data.text.trim();
|
||||
} catch (error) {
|
||||
logger.error(`STT request failed for provider ${provider}:`, error);
|
||||
logAxiosError({ message: `STT request failed for provider ${provider}:`, error });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
@ -316,7 +342,7 @@ class STTService {
|
|||
const text = await this.sttRequest(provider, sttSchema, { audioBuffer, audioFile, language });
|
||||
res.json({ text });
|
||||
} catch (error) {
|
||||
logger.error('An error occurred while processing the audio:', error);
|
||||
logAxiosError({ message: 'An error occurred while processing the audio:', error });
|
||||
res.sendStatus(500);
|
||||
} finally {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
const axios = require('axios');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { genAzureEndpoint } = require('@librechat/api');
|
||||
const { HttpsProxyAgent } = require('https-proxy-agent');
|
||||
const { genAzureEndpoint, logAxiosError } = require('@librechat/api');
|
||||
const { extractEnvVariable, TTSProviders } = require('librechat-data-provider');
|
||||
const { getRandomVoiceId, createChunkProcessor, splitTextIntoChunks } = require('./streamAudio');
|
||||
const { getAppConfig } = require('~/server/services/Config');
|
||||
|
|
@ -274,7 +274,7 @@ class TTSService {
|
|||
try {
|
||||
return await axios.post(url, data, options);
|
||||
} catch (error) {
|
||||
logger.error(`TTS request failed for provider ${provider}:`, error);
|
||||
logAxiosError({ message: `TTS request failed for provider ${provider}:`, error });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
@ -330,7 +330,10 @@ class TTSService {
|
|||
break;
|
||||
}
|
||||
} catch (innerError) {
|
||||
logger.error('Error processing manual update:', chunk, innerError);
|
||||
logAxiosError({
|
||||
message: `[TTS] Error processing manual update for chunk: ${chunk?.text?.substring(0, 50)}...`,
|
||||
error: innerError,
|
||||
});
|
||||
if (!res.headersSent) {
|
||||
return res.status(500).end();
|
||||
}
|
||||
|
|
@ -342,7 +345,7 @@ class TTSService {
|
|||
res.end();
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error creating the audio stream:', error);
|
||||
logAxiosError({ message: '[TTS] Error creating the audio stream:', error });
|
||||
if (!res.headersSent) {
|
||||
return res.status(500).send('An error occurred');
|
||||
}
|
||||
|
|
@ -412,7 +415,10 @@ class TTSService {
|
|||
break;
|
||||
}
|
||||
} catch (innerError) {
|
||||
logger.error('Error processing audio stream update:', update, innerError);
|
||||
logAxiosError({
|
||||
message: `[TTS] Error processing audio stream update: ${update?.text?.substring(0, 50)}...`,
|
||||
error: innerError,
|
||||
});
|
||||
if (!res.headersSent) {
|
||||
return res.status(500).end();
|
||||
}
|
||||
|
|
@ -429,7 +435,7 @@ class TTSService {
|
|||
res.end();
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to fetch audio:', error);
|
||||
logAxiosError({ message: '[TTS] Failed to fetch audio:', error });
|
||||
if (!res.headersSent) {
|
||||
res.status(500).end();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue