Add per-operation AI provider routing
Each operation (inpaint, txt2img, img2img, outpaint) can now use a different provider. Resolution order: per-op override → global AI_PROVIDER default. Example: txt2img→openai, inpaint→invokeai, everything else→invokeai default. Backend: - config.py: add AI_PROVIDER_INPAINT / TXT2IMG / IMG2IMG / OUTPAINT settings - remote_provider.py: get_remote_provider(operation) resolves override then default; _build_provider() extracted as shared factory; _OP_FIELD maps op→setting name - ai_tools.py: each endpoint passes its operation to _require_remote(); GET /api/config runs per-op health checks concurrently, returns operations map and overrides; POST /api/config accepts and applies per-op override fields Frontend: - ai_provider_settings.js: four new selects (inpaint/txt2img/img2img/outpaint); persists to localStorage and sends per-op fields to POST /api/config - provider-badge.js: shows override summary (e.g. "invokeai · txt2img→openai") and per-op health in tooltip - .env.example: document per-op override env vars with examples https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
This commit is contained in:
@@ -34,8 +34,19 @@ export async function mountProviderBadge(container) {
|
||||
dot.style.background = '#44cc44';
|
||||
badge.style.background = '#1a2a1a';
|
||||
badge.style.color = '#aaffaa';
|
||||
label.textContent = remote.provider + (local.gpu_detected ? ' · GPU' : ' · CPU');
|
||||
badge.title = 'Remote provider: ' + remote.provider + '\nCapabilities: ' + (remote.capabilities || []).join(', ');
|
||||
|
||||
// Show override summary if any operations use different providers
|
||||
var overrides = remote.overrides || {};
|
||||
var overrideEntries = Object.entries(overrides).filter(([, v]) => v);
|
||||
var overrideStr = overrideEntries.length
|
||||
? ' · ' + overrideEntries.map(([k, v]) => `${k}→${v}`).join(', ')
|
||||
: '';
|
||||
label.textContent = remote.provider + overrideStr + (local.gpu_detected ? ' · GPU' : '');
|
||||
|
||||
var opLines = Object.entries(remote.operations || {})
|
||||
.map(([op, s]) => `${op}: ${s.provider || remote.provider} ${s.healthy ? '✓' : '✗'}`)
|
||||
.join('\n');
|
||||
badge.title = opLines || ('Provider: ' + remote.provider);
|
||||
} else if (remote.provider && !remote.healthy) {
|
||||
dot.style.background = '#ffaa00';
|
||||
badge.style.background = '#2a2000';
|
||||
|
||||
@@ -47,11 +47,44 @@ class Tools_ai_provider_settings_class {
|
||||
},
|
||||
{
|
||||
name: 'provider',
|
||||
title: 'Remote provider:',
|
||||
title: 'Default provider (used unless overridden below):',
|
||||
value: ls_get('provider', remote.provider || ''),
|
||||
values: ['', 'openai', 'invokeai', 'comfyui', 'replicate'],
|
||||
type: 'select',
|
||||
},
|
||||
// ── Per-operation overrides ───────────────────────────────
|
||||
{
|
||||
title: '',
|
||||
html: '<div style="font-size:11px;color:#888;margin:2px 0 6px;">Per-operation overrides — blank = use default above</div>',
|
||||
},
|
||||
{
|
||||
name: 'provider_inpaint',
|
||||
title: 'Inpaint / Replace Selection:',
|
||||
value: ls_get('provider_inpaint', remote.overrides?.inpaint || ''),
|
||||
values: ['', 'openai', 'invokeai', 'comfyui', 'replicate'],
|
||||
type: 'select',
|
||||
},
|
||||
{
|
||||
name: 'provider_txt2img',
|
||||
title: 'Text → Image:',
|
||||
value: ls_get('provider_txt2img', remote.overrides?.txt2img || ''),
|
||||
values: ['', 'openai', 'invokeai', 'comfyui', 'replicate'],
|
||||
type: 'select',
|
||||
},
|
||||
{
|
||||
name: 'provider_img2img',
|
||||
title: 'Image → Image:',
|
||||
value: ls_get('provider_img2img', remote.overrides?.img2img || ''),
|
||||
values: ['', 'openai', 'invokeai', 'comfyui', 'replicate'],
|
||||
type: 'select',
|
||||
},
|
||||
{
|
||||
name: 'provider_outpaint',
|
||||
title: 'Expand Canvas (Outpaint):',
|
||||
value: ls_get('provider_outpaint', remote.overrides?.outpaint || ''),
|
||||
values: ['', 'openai', 'invokeai', 'comfyui', 'replicate'],
|
||||
type: 'select',
|
||||
},
|
||||
// ── OpenAI ────────────────────────────────────────────────
|
||||
{
|
||||
name: 'openai_key',
|
||||
@@ -108,7 +141,11 @@ class Tools_ai_provider_settings_class {
|
||||
|
||||
async _save(params) {
|
||||
// Persist to localStorage
|
||||
ls_set('provider', params.provider || '');
|
||||
ls_set('provider', params.provider || '');
|
||||
ls_set('provider_inpaint', params.provider_inpaint || '');
|
||||
ls_set('provider_txt2img', params.provider_txt2img || '');
|
||||
ls_set('provider_img2img', params.provider_img2img || '');
|
||||
ls_set('provider_outpaint', params.provider_outpaint || '');
|
||||
ls_set('openai_key', params.openai_key || '');
|
||||
ls_set('openai_model', params.openai_model || 'dall-e-3');
|
||||
ls_set('invokeai_url', params.invokeai_url || '');
|
||||
@@ -117,17 +154,21 @@ class Tools_ai_provider_settings_class {
|
||||
ls_set('comfyui_model', params.comfyui_model || 'v1-5-pruned-emaonly.ckpt');
|
||||
ls_set('replicate_key', params.replicate_key || '');
|
||||
|
||||
// Push to backend (requires a running server that accepts runtime config)
|
||||
// Push to backend
|
||||
try {
|
||||
var payload = {
|
||||
ai_provider: params.provider || '',
|
||||
openai_api_key: params.openai_key || '',
|
||||
openai_model: params.openai_model || 'dall-e-3',
|
||||
invokeai_url: params.invokeai_url || '',
|
||||
invokeai_default_model: params.invokeai_model || 'flux-dev',
|
||||
comfyui_url: params.comfyui_url || '',
|
||||
comfyui_default_model: params.comfyui_model || '',
|
||||
replicate_api_key: params.replicate_key || '',
|
||||
ai_provider: params.provider || '',
|
||||
ai_provider_inpaint: params.provider_inpaint || '',
|
||||
ai_provider_txt2img: params.provider_txt2img || '',
|
||||
ai_provider_img2img: params.provider_img2img || '',
|
||||
ai_provider_outpaint: params.provider_outpaint || '',
|
||||
openai_api_key: params.openai_key || '',
|
||||
openai_model: params.openai_model || 'dall-e-3',
|
||||
invokeai_url: params.invokeai_url || '',
|
||||
invokeai_default_model: params.invokeai_model || 'flux-dev',
|
||||
comfyui_url: params.comfyui_url || '',
|
||||
comfyui_default_model: params.comfyui_model || '',
|
||||
replicate_api_key: params.replicate_key || '',
|
||||
};
|
||||
var base = window.API_BASE_URL || '';
|
||||
var r = await fetch(`${base}/api/config`, {
|
||||
|
||||
Reference in New Issue
Block a user