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);
|
||||
}
|
||||
|
||||
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 = '';
|
||||
const maxPri = Math.max(0, ...providersForAlias(aliasId).map((p) => p.priority));
|
||||
try {
|
||||
|
|
@ -320,8 +356,8 @@
|
|||
body: JSON.stringify({
|
||||
alias_id: aliasId,
|
||||
priority: maxPri + 1,
|
||||
litellm_model: `openrouter/${model.id}`,
|
||||
api_key_env: 'OPENROUTER_API_KEY'
|
||||
litellm_model: modelForKey(model, keyEnv),
|
||||
api_key_env: keyEnv
|
||||
})
|
||||
});
|
||||
if (!res.ok) throw new Error('Feil ved opprettelse');
|
||||
|
|
@ -329,14 +365,14 @@
|
|||
providers = [...providers, row];
|
||||
addingFromCatalog = null;
|
||||
catalogAddAlias = '';
|
||||
catalogAddKey = '';
|
||||
} catch {
|
||||
errorMsg = 'Kunne ikke legge til provider fra katalog';
|
||||
}
|
||||
}
|
||||
|
||||
function selectFromPicker(model: CatalogModel) {
|
||||
newProvider.litellm_model = `openrouter/${model.id}`;
|
||||
newProvider.api_key_env = 'OPENROUTER_API_KEY';
|
||||
newProvider.litellm_model = modelForKey(model, newProvider.api_key_env);
|
||||
showCatalogPicker = false;
|
||||
catalogPickerSearch = '';
|
||||
}
|
||||
|
|
@ -830,21 +866,31 @@
|
|||
<span class="cat-col-price">{formatPrice(model.completion_price_per_m)}</span>
|
||||
<span class="cat-col-add">
|
||||
{#if addingFromCatalog === model.id}
|
||||
<select
|
||||
bind:value={catalogAddAlias}
|
||||
onchange={() => {
|
||||
if (catalogAddAlias) addFromCatalog(model, catalogAddAlias);
|
||||
}}
|
||||
>
|
||||
<option value="">Velg alias...</option>
|
||||
{@const modelKeys = availableKeysForModel(model)}
|
||||
<div class="catalog-add-form">
|
||||
<select bind:value={catalogAddAlias}>
|
||||
<option value="">Alias...</option>
|
||||
{#each aliases as a}
|
||||
<option value={a.id}>{a.alias}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<select bind:value={catalogAddKey}>
|
||||
<option value="">Nøkkel...</option>
|
||||
{#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}
|
||||
<button
|
||||
class="toggle-btn"
|
||||
onclick={() => { addingFromCatalog = model.id; catalogAddAlias = ''; }}
|
||||
onclick={() => { addingFromCatalog = model.id; catalogAddAlias = ''; catalogAddKey = ''; }}
|
||||
>Legg til →</button>
|
||||
{/if}
|
||||
</span>
|
||||
|
|
@ -1500,6 +1546,17 @@
|
|||
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 */
|
||||
.table-list {
|
||||
display: flex;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue