Merge pull request #79 from munimunigamer/external-mode

feature: Add External API Generation Mode with Secure Key Storage
This commit is contained in:
Spicy Marinara
2025-12-29 10:29:35 +01:00
committed by GitHub
8 changed files with 571 additions and 116 deletions
+108 -1
View File
@@ -51,7 +51,7 @@ import {
generateSeparateUpdatePrompt
} from './src/systems/generation/promptBuilder.js';
import { parseResponse, parseUserStats } from './src/systems/generation/parser.js';
import { updateRPGData } from './src/systems/generation/apiClient.js';
import { updateRPGData, testExternalAPIConnection } from './src/systems/generation/apiClient.js';
import { onGenerationStarted } from './src/systems/generation/injector.js';
// Rendering modules
@@ -624,6 +624,99 @@ async function initUI() {
}
});
// External API settings event handlers
$('#rpg-external-base-url').on('change', function() {
if (!extensionSettings.externalApiSettings) {
extensionSettings.externalApiSettings = {
baseUrl: '', apiKey: '', model: '', maxTokens: 8192, temperature: 0.7
};
}
extensionSettings.externalApiSettings.baseUrl = String($(this).val()).trim();
saveSettings();
});
$('#rpg-external-api-key').on('change', function() {
// Securely store API key in localStorage instead of shared extension settings
const apiKey = String($(this).val()).trim();
localStorage.setItem('rpg_companion_external_api_key', apiKey);
// Ensure the externalApiSettings object exists, but don't store the key in it
if (!extensionSettings.externalApiSettings) {
extensionSettings.externalApiSettings = {
baseUrl: '', model: '', maxTokens: 8192, temperature: 0.7
};
saveSettings();
}
});
$('#rpg-external-model').on('change', function() {
if (!extensionSettings.externalApiSettings) {
extensionSettings.externalApiSettings = {
baseUrl: '', apiKey: '', model: '', maxTokens: 8192, temperature: 0.7
};
}
extensionSettings.externalApiSettings.model = String($(this).val()).trim();
saveSettings();
});
$('#rpg-external-max-tokens').on('change', function() {
if (!extensionSettings.externalApiSettings) {
extensionSettings.externalApiSettings = {
baseUrl: '', apiKey: '', model: '', maxTokens: 8192, temperature: 0.7
};
}
extensionSettings.externalApiSettings.maxTokens = parseInt(String($(this).val()));
saveSettings();
});
$('#rpg-external-temperature').on('change', function() {
if (!extensionSettings.externalApiSettings) {
extensionSettings.externalApiSettings = {
baseUrl: '', apiKey: '', model: '', maxTokens: 8192, temperature: 0.7
};
}
extensionSettings.externalApiSettings.temperature = parseFloat(String($(this).val()));
saveSettings();
});
$('#rpg-toggle-api-key-visibility').on('click', function() {
const $input = $('#rpg-external-api-key');
const type = $input.attr('type') === 'password' ? 'text' : 'password';
$input.attr('type', type);
$(this).find('i').toggleClass('fa-eye fa-eye-slash');
});
$('#rpg-test-external-api').on('click', async function() {
const $result = $('#rpg-external-api-test-result');
const $btn = $(this);
const originalText = $btn.html();
$btn.html('<i class="fa-solid fa-spinner fa-spin"></i> Testing...').prop('disabled', true);
$result.hide().removeClass('rpg-success-message rpg-error-message');
try {
const result = await testExternalAPIConnection();
if (result.success) {
$result.addClass('rpg-success-message')
.html(`<i class="fa-solid fa-check-circle"></i> ${result.message}`)
.slideDown();
toastr.success(result.message);
} else {
$result.addClass('rpg-error-message')
.html(`<i class="fa-solid fa-exclamation-circle"></i> ${result.message}`)
.slideDown();
toastr.error(result.message);
}
} catch (error) {
$result.addClass('rpg-error-message')
.html(`<i class="fa-solid fa-exclamation-circle"></i> Error: ${error.message}`)
.slideDown();
} finally {
$btn.html(originalText).prop('disabled', false);
}
});
// Initialize UI state (enable/disable is in Extensions tab)
$('#rpg-toggle-auto-update').prop('checked', extensionSettings.autoUpdate);
$('#rpg-position-select').val(extensionSettings.panelPosition);
@@ -681,6 +774,20 @@ async function initUI() {
$('#rpg-custom-accent').val(extensionSettings.customColors.accent);
$('#rpg-custom-text').val(extensionSettings.customColors.text);
$('#rpg-custom-highlight').val(extensionSettings.customColors.highlight);
// Initialize External API settings values
if (extensionSettings.externalApiSettings) {
$('#rpg-external-base-url').val(extensionSettings.externalApiSettings.baseUrl || '');
// Load API Key from secure localStorage
const storedApiKey = localStorage.getItem('rpg_companion_external_api_key') || '';
$('#rpg-external-api-key').val(storedApiKey);
$('#rpg-external-model').val(extensionSettings.externalApiSettings.model || '');
$('#rpg-external-max-tokens').val(extensionSettings.externalApiSettings.maxTokens || 8192);
$('#rpg-external-temperature').val(extensionSettings.externalApiSettings.temperature ?? 0.7);
}
$('#rpg-generation-mode').val(extensionSettings.generationMode);
$('#rpg-skip-guided-mode').val(extensionSettings.skipInjectionsForGuided);
$('#rpg-save-tracker-history').prop('checked', extensionSettings.saveTrackerHistory);