AI-admin: katalog lar deg velge nøkkel — direkte API eller OpenRouter
- Ny mapping fra OpenRouter-provider til LiteLLM direkte-prefiks (google→gemini/, anthropic→anthropic/, openai→openai/, x-ai→xai/) - «Legg til»-knappen i katalogen viser nå to dropdowns: alias + nøkkel - Velger du Google-nøkkel → gemini/modellnavn, OpenRouter → openrouter/google/modellnavn - Inline picker respekterer også valgt nøkkel i provider-skjemaet Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8652f0969f
commit
2d17a632cd
1 changed files with 74 additions and 17 deletions
|
|
@ -310,7 +310,43 @@
|
||||||
expandedProviders = new Set(expandedProviders);
|
expandedProviders = new Set(expandedProviders);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addFromCatalog(model: CatalogModel, aliasId: string) {
|
// Mapping fra OpenRouter-provider til LiteLLM direkte-prefiks + nøkkel
|
||||||
|
const directKeyMap: Record<string, { prefix: string; key: string }> = {
|
||||||
|
google: { prefix: 'gemini/', key: 'GEMINI_API_KEY' },
|
||||||
|
anthropic: { prefix: 'anthropic/', key: 'ANTHROPIC_API_KEY' },
|
||||||
|
openai: { prefix: 'openai/', key: 'OPENAI_API_KEY' },
|
||||||
|
'x-ai': { prefix: 'xai/', key: 'XAI_API_KEY' },
|
||||||
|
};
|
||||||
|
|
||||||
|
function modelForKey(model: CatalogModel, keyEnv: string): string {
|
||||||
|
if (keyEnv === 'OPENROUTER_API_KEY') return `openrouter/${model.id}`;
|
||||||
|
// Direkte: strip provider-prefix fra model.id, legg til LiteLLM-prefiks
|
||||||
|
const mapping = directKeyMap[model.provider];
|
||||||
|
if (mapping) {
|
||||||
|
const modelName = model.id.replace(`${model.provider}/`, '');
|
||||||
|
return `${mapping.prefix}${modelName}`;
|
||||||
|
}
|
||||||
|
return `openrouter/${model.id}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function availableKeysForModel(model: CatalogModel): ApiKey[] {
|
||||||
|
const keys: ApiKey[] = [];
|
||||||
|
// Direkte nøkkel for denne leverandøren
|
||||||
|
const mapping = directKeyMap[model.provider];
|
||||||
|
if (mapping) {
|
||||||
|
const directKey = apiKeys.find(k => k.name === mapping.key);
|
||||||
|
if (directKey) keys.push(directKey);
|
||||||
|
}
|
||||||
|
// OpenRouter alltid tilgjengelig
|
||||||
|
const orKey = apiKeys.find(k => k.name === 'OPENROUTER_API_KEY');
|
||||||
|
if (orKey) keys.push(orKey);
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catalog add — steg 1: velg alias, steg 2: velg nøkkel
|
||||||
|
let catalogAddKey = $state('');
|
||||||
|
|
||||||
|
async function addFromCatalog(model: CatalogModel, aliasId: string, keyEnv: string) {
|
||||||
errorMsg = '';
|
errorMsg = '';
|
||||||
const maxPri = Math.max(0, ...providersForAlias(aliasId).map((p) => p.priority));
|
const maxPri = Math.max(0, ...providersForAlias(aliasId).map((p) => p.priority));
|
||||||
try {
|
try {
|
||||||
|
|
@ -320,8 +356,8 @@
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
alias_id: aliasId,
|
alias_id: aliasId,
|
||||||
priority: maxPri + 1,
|
priority: maxPri + 1,
|
||||||
litellm_model: `openrouter/${model.id}`,
|
litellm_model: modelForKey(model, keyEnv),
|
||||||
api_key_env: 'OPENROUTER_API_KEY'
|
api_key_env: keyEnv
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
if (!res.ok) throw new Error('Feil ved opprettelse');
|
if (!res.ok) throw new Error('Feil ved opprettelse');
|
||||||
|
|
@ -329,14 +365,14 @@
|
||||||
providers = [...providers, row];
|
providers = [...providers, row];
|
||||||
addingFromCatalog = null;
|
addingFromCatalog = null;
|
||||||
catalogAddAlias = '';
|
catalogAddAlias = '';
|
||||||
|
catalogAddKey = '';
|
||||||
} catch {
|
} catch {
|
||||||
errorMsg = 'Kunne ikke legge til provider fra katalog';
|
errorMsg = 'Kunne ikke legge til provider fra katalog';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectFromPicker(model: CatalogModel) {
|
function selectFromPicker(model: CatalogModel) {
|
||||||
newProvider.litellm_model = `openrouter/${model.id}`;
|
newProvider.litellm_model = modelForKey(model, newProvider.api_key_env);
|
||||||
newProvider.api_key_env = 'OPENROUTER_API_KEY';
|
|
||||||
showCatalogPicker = false;
|
showCatalogPicker = false;
|
||||||
catalogPickerSearch = '';
|
catalogPickerSearch = '';
|
||||||
}
|
}
|
||||||
|
|
@ -830,21 +866,31 @@
|
||||||
<span class="cat-col-price">{formatPrice(model.completion_price_per_m)}</span>
|
<span class="cat-col-price">{formatPrice(model.completion_price_per_m)}</span>
|
||||||
<span class="cat-col-add">
|
<span class="cat-col-add">
|
||||||
{#if addingFromCatalog === model.id}
|
{#if addingFromCatalog === model.id}
|
||||||
<select
|
{@const modelKeys = availableKeysForModel(model)}
|
||||||
bind:value={catalogAddAlias}
|
<div class="catalog-add-form">
|
||||||
onchange={() => {
|
<select bind:value={catalogAddAlias}>
|
||||||
if (catalogAddAlias) addFromCatalog(model, catalogAddAlias);
|
<option value="">Alias...</option>
|
||||||
}}
|
{#each aliases as a}
|
||||||
>
|
<option value={a.id}>{a.alias}</option>
|
||||||
<option value="">Velg alias...</option>
|
{/each}
|
||||||
{#each aliases as a}
|
</select>
|
||||||
<option value={a.id}>{a.alias}</option>
|
<select bind:value={catalogAddKey}>
|
||||||
{/each}
|
<option value="">Nøkkel...</option>
|
||||||
</select>
|
{#each modelKeys as k}
|
||||||
|
<option value={k.name}>{k.label}</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
<button
|
||||||
|
class="add-btn"
|
||||||
|
disabled={!catalogAddAlias || !catalogAddKey}
|
||||||
|
onclick={() => addFromCatalog(model, catalogAddAlias, catalogAddKey)}
|
||||||
|
>OK</button>
|
||||||
|
<button class="toggle-btn" onclick={() => { addingFromCatalog = null; }}>✗</button>
|
||||||
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<button
|
<button
|
||||||
class="toggle-btn"
|
class="toggle-btn"
|
||||||
onclick={() => { addingFromCatalog = model.id; catalogAddAlias = ''; }}
|
onclick={() => { addingFromCatalog = model.id; catalogAddAlias = ''; catalogAddKey = ''; }}
|
||||||
>Legg til →</button>
|
>Legg til →</button>
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -1500,6 +1546,17 @@
|
||||||
padding: 0.15rem 0.25rem;
|
padding: 0.15rem 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.catalog-add-form {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalog-add-form select {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
padding: 0.15rem 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
/* Alias table */
|
/* Alias table */
|
||||||
.table-list {
|
.table-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue