Refactor API key management in extensions

579ef1e86c3609dcf3d5c998330ecc772e304129

Cohee <18619528+Cohee1207@users.noreply.github.com>

5 files changed, +48 -93Showing whitespace changes
public/scripts/extensions/translate/index.js+2 -2
@@ -768,7 +768,7 @@ jQuery(async () => {
768 return;768 return;
769 }769 }
770770
771 await writeSecret(extension_settings.translate.provider, key);771 await writeSecret(extension_settings.translate.provider, String(key));
772 toastr.success('API Key saved');772 toastr.success('API Key saved');
773 $('#translate_key_button').addClass('success');773 $('#translate_key_button').addClass('success');
774 });774 });
@@ -802,7 +802,7 @@ jQuery(async () => {
802 return;802 return;
803 }803 }
804804
805 await writeSecret(secretKey, url);805 await writeSecret(secretKey, String(url));
806806
807 toastr.success('API URL saved');807 toastr.success('API URL saved');
808 $('#translate_url_button').addClass('success');808 $('#translate_url_button').addClass('success');
public/scripts/extensions/tts/azure.js+19 -31
@@ -1,6 +1,5 @@
1import { getRequestHeaders } from '../../../script.js';1import { event_types, eventSource, getRequestHeaders } from '../../../script.js';
2import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from '../../popup.js';2import { SECRET_KEYS, secret_state } from '../../secrets.js';
3import { SECRET_KEYS, findSecret, secret_state, writeSecret } from '../../secrets.js';
4import { getPreviewString, saveTtsProviderSettings } from './index.js';3import { getPreviewString, saveTtsProviderSettings } from './index.js';
5export { AzureTtsProvider };4export { AzureTtsProvider };
65
@@ -26,7 +25,7 @@ class AzureTtsProvider {
26 <h4 for="azure_tts_key" class="flex1 margin0">25 <h4 for="azure_tts_key" class="flex1 margin0">
27 <a href="https://portal.azure.com/" target="_blank">Azure TTS Key</a>26 <a href="https://portal.azure.com/" target="_blank">Azure TTS Key</a>
28 </h4>27 </h4>
29 <div id="azure_tts_key" class="menu_button menu_button_icon">28 <div id="azure_tts_key" class="menu_button menu_button_icon manage-api-keys" data-key="api_key_azure_tts">
30 <i class="fa-solid fa-key"></i>29 <i class="fa-solid fa-key"></i>
31 <span>Click to set</span>30 <span>Click to set</span>
32 </div>31 </div>
@@ -39,6 +38,20 @@ class AzureTtsProvider {
39 return html;38 return html;
40 }39 }
4140
41 constructor() {
42 this.handler = async function (/** @type {string} */ key) {
43 if (key !== SECRET_KEYS.AZURE_TTS) return;
44 $('#azure_tts_key').toggleClass('success', !!secret_state[SECRET_KEYS.AZURE_TTS]);
45 await this.onRefreshClick();
46 }.bind(this);
47 }
48
49 dispose() {
50 [event_types.SECRET_WRITTEN, event_types.SECRET_DELETED, event_types.SECRET_ROTATED].forEach(event => {
51 eventSource.removeListener(event, this.handler);
52 });
53 }
54
42 onSettingsChange() {55 onSettingsChange() {
43 // Update dynamically56 // Update dynamically
44 this.settings.region = String($('#azure_tts_region').val());57 this.settings.region = String($('#azure_tts_region').val());
@@ -65,34 +78,9 @@ class AzureTtsProvider {
65 }78 }
6679
67 $('#azure_tts_region').val(this.settings.region).on('input', () => this.onSettingsChange());80 $('#azure_tts_region').val(this.settings.region).on('input', () => this.onSettingsChange());
68 $('#azure_tts_key').toggleClass('success', secret_state[SECRET_KEYS.AZURE_TTS]);
69 $('#azure_tts_key').on('click', async () => {
70 const popupText = 'Azure TTS API Key';
71 const savedKey = secret_state[SECRET_KEYS.AZURE_TTS] ? await findSecret(SECRET_KEYS.AZURE_TTS) : '';
72
73 const key = await callGenericPopup(popupText, POPUP_TYPE.INPUT, savedKey, {
74 customButtons: [{
75 text: 'Remove Key',
76 appendAtEnd: true,
77 result: POPUP_RESULT.NEGATIVE,
78 action: async () => {
79 await writeSecret(SECRET_KEYS.AZURE_TTS, '');
80 $('#azure_tts_key').toggleClass('success', !!secret_state[SECRET_KEYS.AZURE_TTS]);81 $('#azure_tts_key').toggleClass('success', !!secret_state[SECRET_KEYS.AZURE_TTS]);
81 toastr.success('API Key removed');82 [event_types.SECRET_WRITTEN, event_types.SECRET_DELETED, event_types.SECRET_ROTATED].forEach(event => {
82 await this.onRefreshClick();83 eventSource.on(event, this.handler);
83 },
84 }],
85 });
86
87 if (!key) {
88 return;
89 }
90
91 await writeSecret(SECRET_KEYS.AZURE_TTS, String(key));
92
93 toastr.success('API Key saved');
94 $('#azure_tts_key').addClass('success');
95 await this.onRefreshClick();
96 });84 });
9785
98 try {86 try {
public/scripts/extensions/tts/openai-compatible.js+19 -31
@@ -1,6 +1,5 @@
1import { getRequestHeaders } from '../../../script.js';1import { event_types, eventSource, getRequestHeaders } from '../../../script.js';
2import { callGenericPopup, POPUP_RESULT, POPUP_TYPE } from '../../popup.js';2import { SECRET_KEYS, secret_state } from '../../secrets.js';
3import { findSecret, SECRET_KEYS, secret_state, writeSecret } from '../../secrets.js';
4import { getPreviewString, saveTtsProviderSettings } from './index.js';3import { getPreviewString, saveTtsProviderSettings } from './index.js';
54
6export { OpenAICompatibleTtsProvider };5export { OpenAICompatibleTtsProvider };
@@ -27,7 +26,7 @@ class OpenAICompatibleTtsProvider {
27 <div class="flex1">26 <div class="flex1">
28 <input id="openai_compatible_tts_endpoint" type="text" class="text_pole" maxlength="500" value="${this.defaultSettings.provider_endpoint}"/>27 <input id="openai_compatible_tts_endpoint" type="text" class="text_pole" maxlength="500" value="${this.defaultSettings.provider_endpoint}"/>
29 </div>28 </div>
30 <div id="openai_compatible_tts_key" class="menu_button menu_button_icon">29 <div id="openai_compatible_tts_key" class="menu_button menu_button_icon manage-api-keys" data-key="api_key_custom_openai_tts">
31 <i class="fa-solid fa-key"></i>30 <i class="fa-solid fa-key"></i>
32 <span>API Key</span>31 <span>API Key</span>
33 </div>32 </div>
@@ -41,6 +40,20 @@ class OpenAICompatibleTtsProvider {
41 return html;40 return html;
42 }41 }
4342
43 constructor() {
44 this.handler = async function (/** @type {string} */ key) {
45 if (key !== SECRET_KEYS.CUSTOM_OPENAI_TTS) return;
46 $('#openai_compatible_tts_key').toggleClass('success', !!secret_state[SECRET_KEYS.CUSTOM_OPENAI_TTS]);
47 await this.onRefreshClick();
48 }.bind(this);
49 }
50
51 dispose() {
52 [event_types.SECRET_WRITTEN, event_types.SECRET_DELETED, event_types.SECRET_ROTATED].forEach(event => {
53 eventSource.removeListener(event, this.handler);
54 });
55 }
56
44 async loadSettings(settings) {57 async loadSettings(settings) {
45 // Populate Provider UI given input settings58 // Populate Provider UI given input settings
46 if (Object.keys(settings).length == 0) {59 if (Object.keys(settings).length == 0) {
@@ -74,34 +87,9 @@ class OpenAICompatibleTtsProvider {
7487
75 $('#openai_compatible_tts_speed_output').text(this.settings.speed);88 $('#openai_compatible_tts_speed_output').text(this.settings.speed);
7689
77 $('#openai_compatible_tts_key').toggleClass('success', secret_state[SECRET_KEYS.CUSTOM_OPENAI_TTS]);
78 $('#openai_compatible_tts_key').on('click', async () => {
79 const popupText = 'OpenAI-compatible TTS API Key';
80 const savedKey = secret_state[SECRET_KEYS.CUSTOM_OPENAI_TTS] ? await findSecret(SECRET_KEYS.CUSTOM_OPENAI_TTS) : '';
81
82 const key = await callGenericPopup(popupText, POPUP_TYPE.INPUT, savedKey, {
83 customButtons: [{
84 text: 'Remove Key',
85 appendAtEnd: true,
86 result: POPUP_RESULT.NEGATIVE,
87 action: async () => {
88 await writeSecret(SECRET_KEYS.CUSTOM_OPENAI_TTS, '');
89 $('#openai_compatible_tts_key').toggleClass('success', !!secret_state[SECRET_KEYS.CUSTOM_OPENAI_TTS]);90 $('#openai_compatible_tts_key').toggleClass('success', !!secret_state[SECRET_KEYS.CUSTOM_OPENAI_TTS]);
90 toastr.success('API Key removed');91 [event_types.SECRET_WRITTEN, event_types.SECRET_DELETED, event_types.SECRET_ROTATED].forEach(event => {
91 await this.onRefreshClick();92 eventSource.on(event, this.handler);
92 },
93 }],
94 });
95
96 if (!key) {
97 return;
98 }
99
100 await writeSecret(SECRET_KEYS.CUSTOM_OPENAI_TTS, String(key));
101
102 toastr.success('API Key saved');
103 $('#openai_compatible_tts_key').toggleClass('success', secret_state[SECRET_KEYS.CUSTOM_OPENAI_TTS]);
104 await this.onRefreshClick();
105 });93 });
10694
107 await this.checkReady();95 await this.checkReady();
public/scripts/extensions/vectors/index.js+7 -28
@@ -22,7 +22,7 @@ import {
22 openThirdPartyExtensionMenu,22 openThirdPartyExtensionMenu,
23} from '../../extensions.js';23} from '../../extensions.js';
24import { collapseNewlines, registerDebugFunction } from '../../power-user.js';24import { collapseNewlines, registerDebugFunction } from '../../power-user.js';
25import { SECRET_KEYS, secret_state, writeSecret } from '../../secrets.js';25import { SECRET_KEYS, secret_state } from '../../secrets.js';
26import { getDataBankAttachments, getDataBankAttachmentsForSource, getFileAttachment } from '../../chats.js';26import { getDataBankAttachments, getDataBankAttachmentsForSource, getFileAttachment } from '../../chats.js';
27import { debounce, getStringHash as calculateHash, waitUntilCondition, onlyUnique, splitRecursive, trimToStartSentence, trimToEndSentence, escapeHtml } from '../../utils.js';27import { debounce, getStringHash as calculateHash, waitUntilCondition, onlyUnique, splitRecursive, trimToStartSentence, trimToEndSentence, escapeHtml } from '../../utils.js';
28import { debounce_timeout } from '../../constants.js';28import { debounce_timeout } from '../../constants.js';
@@ -33,7 +33,6 @@ import { SlashCommand } from '../../slash-commands/SlashCommand.js';
33import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';33import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
34import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';34import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';
35import { slashCommandReturnHelper } from '../../slash-commands/SlashCommandReturnHelper.js';35import { slashCommandReturnHelper } from '../../slash-commands/SlashCommandReturnHelper.js';
36import { callGenericPopup, POPUP_RESULT, POPUP_TYPE } from '../../popup.js';
37import { generateWebLlmChatPrompt, isWebLlmSupported } from '../shared.js';36import { generateWebLlmChatPrompt, isWebLlmSupported } from '../shared.js';
38import { WebLlmVectorProvider } from './webllm.js';37import { WebLlmVectorProvider } from './webllm.js';
39import { removeReasoningFromString } from '../../reasoning.js';38import { removeReasoningFromString } from '../../reasoning.js';
@@ -1494,32 +1493,6 @@ jQuery(async () => {
1494 Object.assign(extension_settings.vectors, settings);1493 Object.assign(extension_settings.vectors, settings);
1495 saveSettingsDebounced();1494 saveSettingsDebounced();
1496 });1495 });
1497 $('#api_key_nomicai').on('click', async () => {
1498 const popupText = 'NomicAI API Key:';
1499 const key = await callGenericPopup(popupText, POPUP_TYPE.INPUT, '', {
1500 customButtons: [{
1501 text: 'Remove Key',
1502 appendAtEnd: true,
1503 result: POPUP_RESULT.NEGATIVE,
1504 action: async () => {
1505 await writeSecret(SECRET_KEYS.NOMICAI, '');
1506 toastr.success('API Key removed');
1507 $('#api_key_nomicai').toggleClass('success', !!secret_state[SECRET_KEYS.NOMICAI]);
1508 saveSettingsDebounced();
1509 },
1510 }],
1511 });
1512
1513 if (!key) {
1514 return;
1515 }
1516
1517 await writeSecret(SECRET_KEYS.NOMICAI, String(key));
1518 $('#api_key_nomicai').toggleClass('success', !!secret_state[SECRET_KEYS.NOMICAI]);
1519
1520 toastr.success('API Key saved');
1521 saveSettingsDebounced();
1522 });
1523 $('#vectors_togetherai_model').val(settings.togetherai_model).on('change', () => {1496 $('#vectors_togetherai_model').val(settings.togetherai_model).on('change', () => {
1524 settings.togetherai_model = String($('#vectors_togetherai_model').val());1497 settings.togetherai_model = String($('#vectors_togetherai_model').val());
1525 Object.assign(extension_settings.vectors, settings);1498 Object.assign(extension_settings.vectors, settings);
@@ -1777,6 +1750,12 @@ jQuery(async () => {
1777 });1750 });
17781751
1779 $('#api_key_nomicai').toggleClass('success', !!secret_state[SECRET_KEYS.NOMICAI]);1752 $('#api_key_nomicai').toggleClass('success', !!secret_state[SECRET_KEYS.NOMICAI]);
1753 [event_types.SECRET_WRITTEN, event_types.SECRET_DELETED, event_types.SECRET_ROTATED].forEach(event => {
1754 eventSource.on(event, (/** @type {string} */ key)=> {
1755 if (key !== SECRET_KEYS.NOMICAI) return;
1756 $('#api_key_nomicai').toggleClass('success', !!secret_state[SECRET_KEYS.NOMICAI]);
1757 });
1758 });
17801759
1781 toggleSettings();1760 toggleSettings();
1782 eventSource.on(event_types.MESSAGE_DELETED, onChatEvent);1761 eventSource.on(event_types.MESSAGE_DELETED, onChatEvent);
public/scripts/extensions/vectors/settings.html+1 -1
@@ -145,7 +145,7 @@
145 <label for="api_key_nomicai" class="flex1">145 <label for="api_key_nomicai" class="flex1">
146 <span data-i18n="NomicAI API Key">NomicAI API Key</span>146 <span data-i18n="NomicAI API Key">NomicAI API Key</span>
147 </label>147 </label>
148 <div id="api_key_nomicai" class="menu_button menu_button_icon">148 <div id="api_key_nomicai" class="menu_button menu_button_icon manage-api-keys" data-key="api_key_nomicai">
149 <i class="fa-solid fa-key"></i>149 <i class="fa-solid fa-key"></i>
150 <span data-i18n="Click to set">Click to set</span>150 <span data-i18n="Click to set">Click to set</span>
151 </div>151 </div>