Chat Completion: Streamline settings and API key handling (#4687) * refactor: streamline CC settings and API key handling * Add types for API settings * Allow keyless custom source connection

55969bc96efc75beb95ac2e9c269d61fd8a0e74c

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

Signed
2 files changed, +42 -362Showing whitespace changes
public/global.d.ts+4 -0
@@ -2,12 +2,16 @@ import libs from './lib';
2import getContext from './scripts/st-context';2import getContext from './scripts/st-context';
3import { power_user } from './scripts/power-user';3import { power_user } from './scripts/power-user';
4import { QuickReplyApi } from './scripts/extensions/quick-reply/api/QuickReplyApi';4import { QuickReplyApi } from './scripts/extensions/quick-reply/api/QuickReplyApi';
5import { oai_settings } from './scripts/openai';
6import { textgenerationwebui_settings } from './scripts/textgen-settings';
57
6declare global {8declare global {
7 // Custom types9 // Custom types
8 type InstructSettings = typeof power_user.instruct;10 type InstructSettings = typeof power_user.instruct;
9 type ContextSettings = typeof power_user.context;11 type ContextSettings = typeof power_user.context;
10 type ReasoningSettings = typeof power_user.reasoning;12 type ReasoningSettings = typeof power_user.reasoning;
13 type ChatCompletionSettings = typeof oai_settings;
14 type TextCompletionSettings = typeof textgenerationwebui_settings;
1115
12 // Global namespace modules16 // Global namespace modules
13 interface Window {17 interface Window {
public/scripts/openai.js+38 -362
@@ -387,7 +387,7 @@ const default_settings = {
387 electronhub_group_models: false,387 electronhub_group_models: false,
388 nanogpt_model: 'gpt-4o-mini',388 nanogpt_model: 'gpt-4o-mini',
389 deepseek_model: 'deepseek-chat',389 deepseek_model: 'deepseek-chat',
390 aimlapi_model: 'gpt-4o-mini-2024-07-18',390 aimlapi_model: 'chatgpt-4o-latest',
391 xai_model: 'grok-3-beta',391 xai_model: 'grok-3-beta',
392 pollinations_model: 'openai',392 pollinations_model: 'openai',
393 cometapi_model: 'gpt-4o',393 cometapi_model: 'gpt-4o',
@@ -442,102 +442,7 @@ const default_settings = {
442 extensions: {},442 extensions: {},
443};443};
444444
445const oai_settings = {445const oai_settings = structuredClone(default_settings);
446 preset_settings_openai: 'Default',
447 temp_openai: 1.0,
448 freq_pen_openai: 0,
449 pres_pen_openai: 0,
450 top_p_openai: 1.0,
451 top_k_openai: 0,
452 min_p_openai: 0,
453 top_a_openai: 0,
454 repetition_penalty_openai: 1,
455 stream_openai: false,
456 openai_max_context: max_4k,
457 openai_max_tokens: 300,
458 wrap_in_quotes: false,
459 ...chatCompletionDefaultPrompts,
460 ...promptManagerDefaultPromptOrders,
461 send_if_empty: '',
462 impersonation_prompt: default_impersonation_prompt,
463 new_chat_prompt: default_new_chat_prompt,
464 new_group_chat_prompt: default_new_group_chat_prompt,
465 new_example_chat_prompt: default_new_example_chat_prompt,
466 continue_nudge_prompt: default_continue_nudge_prompt,
467 bias_preset_selected: default_bias,
468 bias_presets: default_bias_presets,
469 wi_format: default_wi_format,
470 group_nudge_prompt: default_group_nudge_prompt,
471 scenario_format: default_scenario_format,
472 personality_format: default_personality_format,
473 openai_model: 'gpt-4-turbo',
474 claude_model: 'claude-sonnet-4-5',
475 google_model: 'gemini-2.5-pro',
476 vertexai_model: 'gemini-2.5-pro',
477 ai21_model: 'jamba-large',
478 mistralai_model: 'mistral-large-latest',
479 cohere_model: 'command-r-plus',
480 perplexity_model: 'sonar-pro',
481 groq_model: 'llama-3.1-70b-versatile',
482 electronhub_model: 'gpt-4o-mini',
483 electronhub_sort_models: 'alphabetically',
484 electronhub_group_models: false,
485 nanogpt_model: 'gpt-4o-mini',
486 deepseek_model: 'deepseek-chat',
487 aimlapi_model: 'gpt-4-turbo',
488 xai_model: 'grok-3-beta',
489 pollinations_model: 'openai',
490 cometapi_model: 'gpt-4o',
491 moonshot_model: 'kimi-latest',
492 fireworks_model: 'accounts/fireworks/models/kimi-k2-instruct',
493 zai_model: 'glm-4.6',
494 azure_base_url: '',
495 azure_deployment_name: '',
496 azure_api_version: '2024-02-15-preview',
497 azure_openai_model: '',
498 custom_model: '',
499 custom_url: '',
500 custom_include_body: '',
501 custom_exclude_body: '',
502 custom_include_headers: '',
503 openrouter_model: openrouter_website_model,
504 openrouter_use_fallback: false,
505 openrouter_group_models: false,
506 openrouter_sort_models: 'alphabetically',
507 openrouter_providers: [],
508 openrouter_allow_fallbacks: true,
509 openrouter_middleout: openrouter_middleout_types.ON,
510 reverse_proxy: '',
511 chat_completion_source: chat_completion_sources.OPENAI,
512 max_context_unlocked: false,
513 show_external_models: false,
514 proxy_password: '',
515 assistant_prefill: '',
516 assistant_impersonation: '',
517 claude_use_sysprompt: false,
518 use_makersuite_sysprompt: true,
519 vertexai_auth_mode: 'express',
520 vertexai_region: 'us-central1',
521 vertexai_express_project_id: '',
522 squash_system_messages: false,
523 image_inlining: false,
524 inline_image_quality: 'low',
525 video_inlining: false,
526 bypass_status_check: false,
527 continue_prefill: false,
528 function_calling: false,
529 names_behavior: character_names_behavior.DEFAULT,
530 continue_postfix: continue_postfix_types.SPACE,
531 custom_prompt_post_processing: custom_prompt_post_processing_types.NONE,
532 show_thoughts: true,
533 reasoning_effort: reasoning_effort_types.auto,
534 enable_web_search: false,
535 request_images: false,
536 seed: -1,
537 n: 1,
538 bind_preset_to_connection: true,
539 extensions: {},
540};
541446
542export let proxies = [447export let proxies = [
543 {448 {
@@ -5373,282 +5278,53 @@ function onReverseProxyInput() {
5373async function onConnectButtonClick(e) {5278async function onConnectButtonClick(e) {
5374 e.stopPropagation();5279 e.stopPropagation();
53755280
5376 if (oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER) {5281 /** @type {Object.<string, {key: string, selector: string, proxy?: boolean, keyless?: boolean}>} */
5377 const api_key_openrouter = String($('#api_key_openrouter').val()).trim();5282 const apiSourceConfig = {
53785283 [chat_completion_sources.OPENROUTER]: { key: SECRET_KEYS.OPENROUTER, selector: '#api_key_openrouter', proxy: false },
5379 if (api_key_openrouter.length) {5284 [chat_completion_sources.MAKERSUITE]: { key: SECRET_KEYS.MAKERSUITE, selector: '#api_key_makersuite', proxy: true },
5380 await writeSecret(SECRET_KEYS.OPENROUTER, api_key_openrouter);5285 [chat_completion_sources.CLAUDE]: { key: SECRET_KEYS.CLAUDE, selector: '#api_key_claude', proxy: true },
5381 }5286 [chat_completion_sources.OPENAI]: { key: SECRET_KEYS.OPENAI, selector: '#api_key_openai', proxy: true },
53825287 [chat_completion_sources.AI21]: { key: SECRET_KEYS.AI21, selector: '#api_key_ai21', proxy: false },
5383 if (!secret_state[SECRET_KEYS.OPENROUTER]) {5288 [chat_completion_sources.MISTRALAI]: { key: SECRET_KEYS.MISTRALAI, selector: '#api_key_mistralai', proxy: true },
5384 console.log('No secret key saved for OpenRouter');5289 [chat_completion_sources.CUSTOM]: { key: SECRET_KEYS.CUSTOM, selector: '#api_key_custom', proxy: false, keyless: true },
5385 return;5290 [chat_completion_sources.COHERE]: { key: SECRET_KEYS.COHERE, selector: '#api_key_cohere', proxy: false },
5386 }5291 [chat_completion_sources.PERPLEXITY]: { key: SECRET_KEYS.PERPLEXITY, selector: '#api_key_perplexity', proxy: false },
5387 }5292 [chat_completion_sources.GROQ]: { key: SECRET_KEYS.GROQ, selector: '#api_key_groq', proxy: false },
53885293 [chat_completion_sources.ELECTRONHUB]: { key: SECRET_KEYS.ELECTRONHUB, selector: '#api_key_electronhub', proxy: false },
5389 if (oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE) {5294 [chat_completion_sources.NANOGPT]: { key: SECRET_KEYS.NANOGPT, selector: '#api_key_nanogpt', proxy: false },
5390 const api_key_makersuite = String($('#api_key_makersuite').val()).trim();5295 [chat_completion_sources.DEEPSEEK]: { key: SECRET_KEYS.DEEPSEEK, selector: '#api_key_deepseek', proxy: true },
53915296 [chat_completion_sources.XAI]: { key: SECRET_KEYS.XAI, selector: '#api_key_xai', proxy: true },
5392 if (api_key_makersuite.length) {5297 [chat_completion_sources.AIMLAPI]: { key: SECRET_KEYS.AIMLAPI, selector: '#api_key_aimlapi', proxy: false },
5393 await writeSecret(SECRET_KEYS.MAKERSUITE, api_key_makersuite);5298 [chat_completion_sources.MOONSHOT]: { key: SECRET_KEYS.MOONSHOT, selector: '#api_key_moonshot', proxy: false },
5394 }5299 [chat_completion_sources.FIREWORKS]: { key: SECRET_KEYS.FIREWORKS, selector: '#api_key_fireworks', proxy: false },
53955300 [chat_completion_sources.COMETAPI]: { key: SECRET_KEYS.COMETAPI, selector: '#api_key_cometapi', proxy: false },
5396 if (!secret_state[SECRET_KEYS.MAKERSUITE] && !oai_settings.reverse_proxy) {5301 [chat_completion_sources.AZURE_OPENAI]: { key: SECRET_KEYS.AZURE_OPENAI, selector: '#api_key_azure_openai', proxy: false },
5397 console.log('No secret key saved for Google AI Studio');5302 [chat_completion_sources.ZAI]: { key: SECRET_KEYS.ZAI, selector: '#api_key_zai', proxy: false },
5398 return;5303 };
5399 }
5400 }
54015304
5402 if (oai_settings.chat_completion_source == chat_completion_sources.VERTEXAI) {5305 // Vertex AI Express version - use API key
5403 if (oai_settings.vertexai_auth_mode === 'express') {5306 if (oai_settings.vertexai_auth_mode === 'express') {
5404 // Express mode - use API key5307 apiSourceConfig[chat_completion_sources.VERTEXAI] = { key: SECRET_KEYS.VERTEXAI, selector: '#api_key_vertexai', proxy: true };
5405 const api_key_vertexai = String($('#api_key_vertexai').val()).trim();
5406
5407 if (api_key_vertexai.length) {
5408 await writeSecret(SECRET_KEYS.VERTEXAI, api_key_vertexai);
5409 }
5410
5411 if (!secret_state[SECRET_KEYS.VERTEXAI] && !oai_settings.reverse_proxy) {
5412 console.log('No secret key saved for Vertex AI Express mode');
5413 return;
5414 }5308 }
5415 } else {
5416 // Full version - use service account
5417 // Project ID will be extracted from the Service Account JSON
54185309
5419 // Check if service account JSON is saved in backend5310 // Vertex AI Full version - use service account
5311 if (oai_settings.chat_completion_source === chat_completion_sources.VERTEXAI && oai_settings.vertexai_auth_mode === 'full') {
5420 if (!secret_state[SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT]) {5312 if (!secret_state[SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT]) {
5421 toastr.error('Service Account JSON is required for Vertex AI full version. Please validate and save your Service Account JSON.');5313 toastr.error(t`Service Account JSON is required for Vertex AI full version. Please validate and save your Service Account JSON.`);
5422 return;
5423 }
5424 }
5425 }
5426
5427 if (oai_settings.chat_completion_source == chat_completion_sources.CLAUDE) {
5428 const api_key_claude = String($('#api_key_claude').val()).trim();
5429
5430 if (api_key_claude.length) {
5431 await writeSecret(SECRET_KEYS.CLAUDE, api_key_claude);
5432 }
5433
5434 if (!secret_state[SECRET_KEYS.CLAUDE] && !oai_settings.reverse_proxy) {
5435 console.log('No secret key saved for Claude');
5436 return;5314 return;
5437 }5315 }
5438 }5316 }
54395317
5440 if (oai_settings.chat_completion_source == chat_completion_sources.OPENAI) {5318 // Other generic configs
5441 const api_key_openai = String($('#api_key_openai').val()).trim();5319 const config = apiSourceConfig[oai_settings.chat_completion_source];
54425320 if (config) {
5443 if (api_key_openai.length) {5321 const apiKey = String($(config.selector).val()).trim();
5444 await writeSecret(SECRET_KEYS.OPENAI, api_key_openai);5322 if (apiKey.length) {
5445 }5323 await writeSecret(config.key, apiKey);
5446
5447 if (!secret_state[SECRET_KEYS.OPENAI] && !oai_settings.reverse_proxy) {
5448 console.log('No secret key saved for OpenAI');
5449 return;
5450 }
5451 }
5452
5453 if (oai_settings.chat_completion_source == chat_completion_sources.AI21) {
5454 const api_key_ai21 = String($('#api_key_ai21').val()).trim();
5455
5456 if (api_key_ai21.length) {
5457 await writeSecret(SECRET_KEYS.AI21, api_key_ai21);
5458 }
5459
5460 if (!secret_state[SECRET_KEYS.AI21]) {
5461 console.log('No secret key saved for AI21');
5462 return;
5463 }
5464 }
5465
5466 if (oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI) {
5467 const api_key_mistralai = String($('#api_key_mistralai').val()).trim();
5468
5469 if (api_key_mistralai.length) {
5470 await writeSecret(SECRET_KEYS.MISTRALAI, api_key_mistralai);
5471 }
5472
5473 if (!secret_state[SECRET_KEYS.MISTRALAI] && !oai_settings.reverse_proxy) {
5474 console.log('No secret key saved for MistralAI');
5475 return;
5476 }
5477 }
5478
5479 if (oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) {
5480 const api_key_custom = String($('#api_key_custom').val()).trim();
5481
5482 if (api_key_custom.length) {
5483 await writeSecret(SECRET_KEYS.CUSTOM, api_key_custom);
5484 }
5485 }
5486
5487 if (oai_settings.chat_completion_source == chat_completion_sources.COHERE) {
5488 const api_key_cohere = String($('#api_key_cohere').val()).trim();
5489
5490 if (api_key_cohere.length) {
5491 await writeSecret(SECRET_KEYS.COHERE, api_key_cohere);
5492 }
5493
5494 if (!secret_state[SECRET_KEYS.COHERE]) {
5495 console.log('No secret key saved for Cohere');
5496 return;
5497 }
5498 }
5499
5500 if (oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY) {
5501 const api_key_perplexity = String($('#api_key_perplexity').val()).trim();
5502
5503 if (api_key_perplexity.length) {
5504 await writeSecret(SECRET_KEYS.PERPLEXITY, api_key_perplexity);
5505 }
5506
5507 if (!secret_state[SECRET_KEYS.PERPLEXITY]) {
5508 console.log('No secret key saved for Perplexity');
5509 return;
5510 }
5511 }
5512
5513 if (oai_settings.chat_completion_source == chat_completion_sources.GROQ) {
5514 const api_key_groq = String($('#api_key_groq').val()).trim();
5515
5516 if (api_key_groq.length) {
5517 await writeSecret(SECRET_KEYS.GROQ, api_key_groq);
5518 }
5519
5520 if (!secret_state[SECRET_KEYS.GROQ]) {
5521 console.log('No secret key saved for Groq');
5522 return;
5523 }
5524 }
5525
5526 if (oai_settings.chat_completion_source == chat_completion_sources.ELECTRONHUB) {
5527 const api_key_electronhub = String($('#api_key_electronhub').val()).trim();
5528
5529 if (api_key_electronhub.length) {
5530 await writeSecret(SECRET_KEYS.ELECTRONHUB, api_key_electronhub);
5531 }
5532
5533 if (!secret_state[SECRET_KEYS.ELECTRONHUB]) {
5534 console.log('No secret key saved for Electron Hub');
5535 return;
5536 }
5537 }
5538
5539 if (oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) {
5540 const api_key_nanogpt = String($('#api_key_nanogpt').val()).trim();
5541
5542 if (api_key_nanogpt.length) {
5543 await writeSecret(SECRET_KEYS.NANOGPT, api_key_nanogpt);
5544 }
5545
5546 if (!secret_state[SECRET_KEYS.NANOGPT]) {
5547 console.log('No secret key saved for NanoGPT');
5548 return;
5549 }
5550 }
5551
5552 if (oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) {
5553 const api_key_deepseek = String($('#api_key_deepseek').val()).trim();
5554
5555 if (api_key_deepseek.length) {
5556 await writeSecret(SECRET_KEYS.DEEPSEEK, api_key_deepseek);
5557 }
5558
5559 if (!secret_state[SECRET_KEYS.DEEPSEEK] && !oai_settings.reverse_proxy) {
5560 console.log('No secret key saved for DeepSeek');
5561 return;
5562 }
5563 }
5564
5565 if (oai_settings.chat_completion_source === chat_completion_sources.XAI) {
5566 const api_key_xai = String($('#api_key_xai').val()).trim();
5567
5568 if (api_key_xai.length) {
5569 await writeSecret(SECRET_KEYS.XAI, api_key_xai);
5570 }
5571
5572 if (!secret_state[SECRET_KEYS.XAI] && !oai_settings.reverse_proxy) {
5573 console.log('No secret key saved for XAI');
5574 return;
5575 }
5576 }
5577
5578 if (oai_settings.chat_completion_source === chat_completion_sources.AIMLAPI) {
5579 const api_key_aimlapi = String($('#api_key_aimlapi').val()).trim();
5580
5581 if (api_key_aimlapi.length) {
5582 await writeSecret(SECRET_KEYS.AIMLAPI, api_key_aimlapi);
5583 }
5584
5585 if (!secret_state[SECRET_KEYS.AIMLAPI]) {
5586 console.log('No secret key saved for AI/ML API');
5587 return;
5588 }
5589 }
5590
5591 if (oai_settings.chat_completion_source == chat_completion_sources.MOONSHOT) {
5592 const api_key_moonshot = String($('#api_key_moonshot').val()).trim();
5593
5594 if (api_key_moonshot.length) {
5595 await writeSecret(SECRET_KEYS.MOONSHOT, api_key_moonshot);
5596 }
5597
5598 if (!secret_state[SECRET_KEYS.MOONSHOT]) {
5599 console.log('No secret key saved for Moonshot');
5600 return;
5601 }
5602 }
5603
5604 if (oai_settings.chat_completion_source == chat_completion_sources.FIREWORKS) {
5605 const api_key_fireworks = String($('#api_key_fireworks').val()).trim();
5606
5607 if (api_key_fireworks.length) {
5608 await writeSecret(SECRET_KEYS.FIREWORKS, api_key_fireworks);
5609 }
5610
5611 if (!secret_state[SECRET_KEYS.FIREWORKS]) {
5612 console.log('No secret key saved for Fireworks');
5613 return;
5614 }
5615 }
5616
5617 if (oai_settings.chat_completion_source == chat_completion_sources.COMETAPI) {
5618 const api_key_cometapi = String($('#api_key_cometapi').val()).trim();
5619
5620 if (api_key_cometapi.length) {
5621 await writeSecret(SECRET_KEYS.COMETAPI, api_key_cometapi);
5622 }
5623
5624 if (!api_key_cometapi && !secret_state[SECRET_KEYS.COMETAPI]) {
5625 console.log('No secret key saved for CometAPI');
5626 return;
5627 }
5628 }
5629
5630 if (oai_settings.chat_completion_source == chat_completion_sources.AZURE_OPENAI) {
5631 const api_key_azure_openai = String($('#api_key_azure_openai').val()).trim();
5632
5633 if (api_key_azure_openai.length) {
5634 await writeSecret(SECRET_KEYS.AZURE_OPENAI, api_key_azure_openai);
5635 }
5636
5637 if (!api_key_azure_openai && !secret_state[SECRET_KEYS.AZURE_OPENAI]) {
5638 console.log('No secret key saved for Azure OpenAI');
5639 return;
5640 }
5641 }
5642
5643 if (oai_settings.chat_completion_source == chat_completion_sources.ZAI) {
5644 const api_key_zai = String($('#api_key_zai').val()).trim();
5645
5646 if (api_key_zai.length) {
5647 await writeSecret(SECRET_KEYS.ZAI, api_key_zai);
5648 }5324 }
56495325
5650 if (!api_key_zai && !secret_state[SECRET_KEYS.ZAI]) {5326 if (!secret_state[config.key] && (!config.proxy || !oai_settings.reverse_proxy) && !config.keyless) {
5651 console.log('No secret key saved for ZAI');5327 console.log(`No secret key saved for ${oai_settings.chat_completion_source}`);
5652 return;5328 return;
5653 }5329 }
5654 }5330 }