Added support for openai api tts.

This commit is contained in:
2025-04-05 14:40:56 +00:00
parent b8e2e6e238
commit e8eb93ae1b
11 changed files with 2063 additions and 989 deletions
+273 -25
View File
@@ -35,7 +35,8 @@ class OptionsUIModule extends BaseModule {
'showReloadNotice',
'toggle',
'setupEventListeners',
'saveCurrentSettings'
'saveCurrentSettings',
'setupApiUrlFields'
]);
}
@@ -85,6 +86,9 @@ class OptionsUIModule extends BaseModule {
// Apply settings
this.applySettings();
// Setup API URLs with default values if needed
this.setupApiUrlFields();
console.log('Options UI: Initialization complete');
}, 1000); // 1 second delay
});
@@ -266,6 +270,127 @@ class OptionsUIModule extends BaseModule {
ttsSection.appendChild(ttsVoiceContainer);
// API TTS Provider Settings (ElevenLabs and OpenAI)
// Container for API settings that will be shown/hidden based on selected TTS system
const apiSettingsContainer = document.createElement('div');
apiSettingsContainer.id = 'api-tts-settings';
apiSettingsContainer.className = 'api-settings-container';
apiSettingsContainer.style.display = 'none';
// ElevenLabs API Key
const elevenLabsApiKeyContainer = document.createElement('div');
elevenLabsApiKeyContainer.className = 'options-row elevenlabs-setting';
elevenLabsApiKeyContainer.dataset.provider = 'elevenlabs';
const elevenLabsApiKeyLabel = document.createElement('label');
elevenLabsApiKeyLabel.textContent = 'ElevenLabs API Key:';
elevenLabsApiKeyContainer.appendChild(elevenLabsApiKeyLabel);
const elevenLabsApiKey = document.createElement('input');
elevenLabsApiKey.type = 'password';
elevenLabsApiKey.id = 'elevenlabs-api-key';
elevenLabsApiKey.placeholder = 'Enter your ElevenLabs API key';
elevenLabsApiKey.addEventListener('change', (e) => {
const persistenceManager = this.getModule('persistence-manager');
if (persistenceManager) {
persistenceManager.updatePreference('tts', 'elevenlabs_api_key', e.target.value);
// Notify TTS system that API key has changed
document.dispatchEvent(new CustomEvent('tts:api:keyChanged', {
detail: { provider: 'elevenlabs', key: e.target.value }
}));
}
});
elevenLabsApiKeyContainer.appendChild(elevenLabsApiKey);
apiSettingsContainer.appendChild(elevenLabsApiKeyContainer);
// ElevenLabs API Base URL
const elevenLabsApiUrlContainer = document.createElement('div');
elevenLabsApiUrlContainer.className = 'options-row elevenlabs-setting';
elevenLabsApiUrlContainer.dataset.provider = 'elevenlabs';
const elevenLabsApiUrlLabel = document.createElement('label');
elevenLabsApiUrlLabel.textContent = 'ElevenLabs API URL:';
elevenLabsApiUrlContainer.appendChild(elevenLabsApiUrlLabel);
const elevenLabsApiUrl = document.createElement('input');
elevenLabsApiUrl.type = 'text';
elevenLabsApiUrl.id = 'elevenlabs-api-url';
elevenLabsApiUrl.placeholder = 'https://api.elevenlabs.io/v1';
elevenLabsApiUrl.addEventListener('change', (e) => {
const persistenceManager = this.getModule('persistence-manager');
if (persistenceManager) {
persistenceManager.updatePreference('tts', 'elevenlabs_api_base_url', e.target.value);
// Notify TTS system that API URL has changed
document.dispatchEvent(new CustomEvent('tts:api:urlChanged', {
detail: { provider: 'elevenlabs', url: e.target.value }
}));
}
});
elevenLabsApiUrlContainer.appendChild(elevenLabsApiUrl);
apiSettingsContainer.appendChild(elevenLabsApiUrlContainer);
// OpenAI API Key
const openaiApiKeyContainer = document.createElement('div');
openaiApiKeyContainer.className = 'options-row openai-setting';
openaiApiKeyContainer.dataset.provider = 'openai';
const openaiApiKeyLabel = document.createElement('label');
openaiApiKeyLabel.textContent = 'OpenAI API Key:';
openaiApiKeyContainer.appendChild(openaiApiKeyLabel);
const openaiApiKey = document.createElement('input');
openaiApiKey.type = 'password';
openaiApiKey.id = 'openai-api-key';
openaiApiKey.placeholder = 'Enter your OpenAI API key';
openaiApiKey.addEventListener('change', (e) => {
const persistenceManager = this.getModule('persistence-manager');
if (persistenceManager) {
persistenceManager.updatePreference('tts', 'openai_api_key', e.target.value);
// Notify TTS system that API key has changed
document.dispatchEvent(new CustomEvent('tts:api:keyChanged', {
detail: { provider: 'openai', key: e.target.value }
}));
}
});
openaiApiKeyContainer.appendChild(openaiApiKey);
apiSettingsContainer.appendChild(openaiApiKeyContainer);
// OpenAI API Base URL
const openaiApiUrlContainer = document.createElement('div');
openaiApiUrlContainer.className = 'options-row openai-setting';
openaiApiUrlContainer.dataset.provider = 'openai';
const openaiApiUrlLabel = document.createElement('label');
openaiApiUrlLabel.textContent = 'OpenAI API URL:';
openaiApiUrlContainer.appendChild(openaiApiUrlLabel);
const openaiApiUrl = document.createElement('input');
openaiApiUrl.type = 'text';
openaiApiUrl.id = 'openai-api-url';
openaiApiUrl.placeholder = 'https://api.openai.com/v1';
openaiApiUrl.addEventListener('change', (e) => {
const persistenceManager = this.getModule('persistence-manager');
if (persistenceManager) {
persistenceManager.updatePreference('tts', 'openai_api_base_url', e.target.value);
// Notify TTS system that API URL has changed
document.dispatchEvent(new CustomEvent('tts:api:urlChanged', {
detail: { provider: 'openai', url: e.target.value }
}));
}
});
openaiApiUrlContainer.appendChild(openaiApiUrl);
apiSettingsContainer.appendChild(openaiApiUrlContainer);
ttsSection.appendChild(apiSettingsContainer);
// Speed controls
const speedContainer = document.createElement('div');
speedContainer.className = 'options-row';
@@ -494,7 +619,12 @@ class OptionsUIModule extends BaseModule {
effectsVolume,
reloadNotice,
speechRate: speedSlider,
ttsSpeechToggle
ttsSpeechToggle,
apiSettingsContainer,
elevenLabsApiKey,
elevenLabsApiUrl,
openaiApiKey,
openaiApiUrl
};
}
@@ -542,41 +672,78 @@ class OptionsUIModule extends BaseModule {
// Clear existing options
this.elements.ttsSystem.innerHTML = '';
// Add "None" option first
// Add 'None' option
const noneOption = document.createElement('option');
noneOption.value = 'none';
noneOption.textContent = 'None (Disable TTS)';
noneOption.textContent = 'None';
this.elements.ttsSystem.appendChild(noneOption);
// Get available handlers
// Get available TTS handlers
const handlers = ttsFactory.getAvailableHandlers();
console.log('Options UI: Available TTS handlers:', handlers.map(h => h.id).join(', '));
// Add all registered handlers
for (const id in handlers) {
// Add options for each handler
for (const handler of handlers) {
const option = document.createElement('option');
option.value = id;
option.textContent = this.getTtsSystemName(id);
option.value = handler.id;
option.textContent = this.getTtsSystemName(handler.id);
this.elements.ttsSystem.appendChild(option);
}
// If no handlers available, add a disabled option
if (this.elements.ttsSystem.options.length === 1) {
const option = document.createElement('option');
option.value = '';
option.textContent = 'No TTS systems available';
option.disabled = true;
this.elements.ttsSystem.appendChild(option);
}
// Set the current active handler
const activeHandler = ttsFactory.getActiveHandler();
console.log('Options UI: Active TTS handler:', activeHandler ? (activeHandler.getId ? activeHandler.getId() : activeHandler.id) : 'none');
// Set the current provider value in the dropdown
if (this.persistenceManager) {
const provider = this.persistenceManager.getPreference('tts', 'provider');
if (provider) {
const option = Array.from(this.elements.ttsSystem.options).find(opt => opt.value === provider);
if (option) {
this.elements.ttsSystem.value = provider;
}
if (activeHandler) {
if (typeof activeHandler.getId === 'function') {
// Use getId() if available
this.elements.ttsSystem.value = activeHandler.getId();
} else if (activeHandler.id) {
// Otherwise try to use the id property
this.elements.ttsSystem.value = activeHandler.id;
} else {
// If no id is available, default to 'none'
this.elements.ttsSystem.value = 'none';
console.warn('Options UI: Active TTS handler has no ID');
}
} else {
this.elements.ttsSystem.value = 'none';
}
// Show/hide API settings based on selected TTS system
this.updateApiSettingsVisibility();
// Add change event to show/hide API settings
this.elements.ttsSystem.addEventListener('change', () => {
this.updateApiSettingsVisibility();
});
}
/**
* Update visibility of API settings based on selected TTS system
*/
updateApiSettingsVisibility() {
if (!this.elements || !this.elements.apiSettingsContainer) return;
const selectedProvider = this.elements.ttsSystem.value;
// Show/hide API settings container based on whether an API provider is selected
if (selectedProvider === 'elevenlabs' || selectedProvider === 'openai') {
this.elements.apiSettingsContainer.style.display = 'block';
// Show/hide provider-specific settings
const elevenLabsSettings = document.querySelectorAll('.elevenlabs-setting');
const openaiSettings = document.querySelectorAll('.openai-setting');
elevenLabsSettings.forEach(element => {
element.style.display = selectedProvider === 'elevenlabs' ? 'flex' : 'none';
});
openaiSettings.forEach(element => {
element.style.display = selectedProvider === 'openai' ? 'flex' : 'none';
});
} else {
this.elements.apiSettingsContainer.style.display = 'none';
}
}
@@ -761,6 +928,26 @@ class OptionsUIModule extends BaseModule {
if (this.elements.ttsSpeechToggle) {
this.elements.ttsSpeechToggle.checked = prefs.tts.enabled;
}
// ElevenLabs API Key
if (this.elements.elevenLabsApiKey) {
this.elements.elevenLabsApiKey.value = prefs.tts.elevenlabs_api_key;
}
// ElevenLabs API Base URL
if (this.elements.elevenLabsApiUrl) {
this.elements.elevenLabsApiUrl.value = prefs.tts.elevenlabs_api_base_url;
}
// OpenAI API Key
if (this.elements.openaiApiKey) {
this.elements.openaiApiKey.value = prefs.tts.openai_api_key;
}
// OpenAI API Base URL
if (this.elements.openaiApiUrl) {
this.elements.openaiApiUrl.value = prefs.tts.openai_api_base_url;
}
});
}
@@ -873,6 +1060,22 @@ class OptionsUIModule extends BaseModule {
// Save text speed setting
const textSpeed = parseInt(this.elements.textSpeed.value);
this.persistenceManager.updatePreference('animation', 'speed', textSpeed);
// Save ElevenLabs API Key
const elevenLabsApiKey = this.elements.elevenLabsApiKey.value;
this.persistenceManager.updatePreference('tts', 'elevenlabs_api_key', elevenLabsApiKey);
// Save ElevenLabs API Base URL
const elevenLabsApiUrl = this.elements.elevenLabsApiUrl.value;
this.persistenceManager.updatePreference('tts', 'elevenlabs_api_base_url', elevenLabsApiUrl);
// Save OpenAI API Key
const openaiApiKey = this.elements.openaiApiKey.value;
this.persistenceManager.updatePreference('tts', 'openai_api_key', openaiApiKey);
// Save OpenAI API Base URL
const openaiApiUrl = this.elements.openaiApiUrl.value;
this.persistenceManager.updatePreference('tts', 'openai_api_base_url', openaiApiUrl);
}
setupEventListeners() {
@@ -944,6 +1147,51 @@ class OptionsUIModule extends BaseModule {
}
});
}
setupApiUrlFields() {
if (!this.elements) return;
const persistenceManager = this.getModule('persistence-manager');
if (!persistenceManager) return;
// Set up ElevenLabs API URL
if (this.elements.elevenLabsApiUrl) {
const savedUrl = persistenceManager.getPreference('tts', 'elevenlabs_api_url');
if (!savedUrl) {
const defaultUrl = 'https://api.elevenlabs.io/v1';
console.log('Options UI: Setting default ElevenLabs API URL:', defaultUrl);
this.elements.elevenLabsApiUrl.value = defaultUrl;
persistenceManager.updatePreference('tts', 'elevenlabs_api_url', defaultUrl);
// Also dispatch the change event to notify the handler
window.dispatchEvent(new CustomEvent('tts:api:urlChanged', {
detail: {
provider: 'elevenlabs',
url: defaultUrl
}
}));
}
}
// Set up OpenAI API URL
if (this.elements.openaiApiUrl) {
const savedUrl = persistenceManager.getPreference('tts', 'openai_api_url');
if (!savedUrl) {
const defaultUrl = 'https://api.openai.com/v1';
console.log('Options UI: Setting default OpenAI API URL:', defaultUrl);
this.elements.openaiApiUrl.value = defaultUrl;
persistenceManager.updatePreference('tts', 'openai_api_url', defaultUrl);
// Also dispatch the change event to notify the handler
window.dispatchEvent(new CustomEvent('tts:api:urlChanged', {
detail: {
provider: 'openai',
url: defaultUrl
}
}));
}
}
}
}
// Create the singleton instance