mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-30 06:47:42 +00:00
🎙️ fix: Align Speech Engine Configuration With Runtime (#14736)
* fix: align speech engine configuration with runtime * fix: guard speech recording shortcuts * fix: reconcile speech engine availability --------- Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
parent
92a8058f02
commit
5ff282f900
16 changed files with 858 additions and 84 deletions
|
|
@ -1,6 +1,21 @@
|
|||
const { logger } = require('@librechat/data-schemas');
|
||||
const { getAppConfig } = require('~/server/services/Config');
|
||||
|
||||
const LEGACY_EXTERNAL_STT_ENGINES = new Set(['openai', 'azureOpenAI']);
|
||||
const LEGACY_EXTERNAL_TTS_ENGINES = new Set(['openai', 'azureOpenAI', 'elevenlabs', 'localai']);
|
||||
|
||||
function normalizeSpeechEngine(key, value) {
|
||||
if (key === 'engineSTT' && LEGACY_EXTERNAL_STT_ENGINES.has(value)) {
|
||||
return 'external';
|
||||
}
|
||||
|
||||
if (key === 'engineTTS' && LEGACY_EXTERNAL_TTS_ENGINES.has(value)) {
|
||||
return 'external';
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function retrieves the speechTab settings from the custom configuration
|
||||
* It first fetches the custom configuration
|
||||
|
|
@ -52,7 +67,8 @@ async function getCustomConfigSpeech(req, res) {
|
|||
} else {
|
||||
for (const key in speechTab.speechToText) {
|
||||
if (speechTab.speechToText[key] !== undefined) {
|
||||
settings[key] = speechTab.speechToText[key];
|
||||
const value = speechTab.speechToText[key];
|
||||
settings[key] = normalizeSpeechEngine(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -64,7 +80,8 @@ async function getCustomConfigSpeech(req, res) {
|
|||
} else {
|
||||
for (const key in speechTab.textToSpeech) {
|
||||
if (speechTab.textToSpeech[key] !== undefined) {
|
||||
settings[key] = speechTab.textToSpeech[key];
|
||||
const value = speechTab.textToSpeech[key];
|
||||
settings[key] = normalizeSpeechEngine(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
jest.mock('@librechat/data-schemas', () => ({ logger: { error: jest.fn() } }));
|
||||
jest.mock('~/server/services/Config', () => ({ getAppConfig: jest.fn() }));
|
||||
|
||||
const getCustomConfigSpeech = require('./getCustomConfigSpeech');
|
||||
|
||||
const createResponse = () => {
|
||||
const res = {
|
||||
send: jest.fn(),
|
||||
status: jest.fn(),
|
||||
};
|
||||
res.status.mockReturnValue(res);
|
||||
return res;
|
||||
};
|
||||
|
||||
describe('getCustomConfigSpeech', () => {
|
||||
it.each(['openai', 'azureOpenAI'])(
|
||||
'normalizes the legacy STT provider "%s" to the external engine',
|
||||
async (engineSTT) => {
|
||||
const req = {
|
||||
config: {
|
||||
speech: {
|
||||
stt: { openai: {} },
|
||||
speechTab: { speechToText: { engineSTT } },
|
||||
},
|
||||
},
|
||||
};
|
||||
const res = createResponse();
|
||||
|
||||
await getCustomConfigSpeech(req, res);
|
||||
|
||||
expect(res.status).toHaveBeenCalledWith(200);
|
||||
expect(res.send).toHaveBeenCalledWith({
|
||||
sttExternal: true,
|
||||
ttsExternal: false,
|
||||
engineSTT: 'external',
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it.each(['browser', 'external'])('preserves the runtime STT engine "%s"', async (engineSTT) => {
|
||||
const req = {
|
||||
config: {
|
||||
speech: {
|
||||
stt: { openai: {} },
|
||||
speechTab: { speechToText: { engineSTT } },
|
||||
},
|
||||
},
|
||||
};
|
||||
const res = createResponse();
|
||||
|
||||
await getCustomConfigSpeech(req, res);
|
||||
|
||||
expect(res.send).toHaveBeenCalledWith(expect.objectContaining({ engineSTT }));
|
||||
});
|
||||
|
||||
it.each(['openai', 'azureOpenAI', 'elevenlabs', 'localai'])(
|
||||
'normalizes the legacy TTS provider "%s" to the external engine',
|
||||
async (engineTTS) => {
|
||||
const req = {
|
||||
config: {
|
||||
speech: {
|
||||
tts: { openai: {} },
|
||||
speechTab: { textToSpeech: { engineTTS } },
|
||||
},
|
||||
},
|
||||
};
|
||||
const res = createResponse();
|
||||
|
||||
await getCustomConfigSpeech(req, res);
|
||||
|
||||
expect(res.status).toHaveBeenCalledWith(200);
|
||||
expect(res.send).toHaveBeenCalledWith({
|
||||
sttExternal: false,
|
||||
ttsExternal: true,
|
||||
engineTTS: 'external',
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it.each(['browser', 'external'])('preserves the runtime TTS engine "%s"', async (engineTTS) => {
|
||||
const req = {
|
||||
config: {
|
||||
speech: {
|
||||
tts: { openai: {} },
|
||||
speechTab: { textToSpeech: { engineTTS } },
|
||||
},
|
||||
},
|
||||
};
|
||||
const res = createResponse();
|
||||
|
||||
await getCustomConfigSpeech(req, res);
|
||||
|
||||
expect(res.send).toHaveBeenCalledWith(expect.objectContaining({ engineTTS }));
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue