diff --git a/web/src/routes/api/admin/ai/generate-config/+server.ts b/web/src/routes/api/admin/ai/generate-config/+server.ts index 6625d57..f64644a 100644 --- a/web/src/routes/api/admin/ai/generate-config/+server.ts +++ b/web/src/routes/api/admin/ai/generate-config/+server.ts @@ -3,11 +3,13 @@ import type { RequestHandler } from './$types'; import { sql } from '$lib/server/db'; import { writeFileSync } from 'node:fs'; import { join } from 'node:path'; +import { execSync } from 'node:child_process'; /** * POST /api/admin/ai/generate-config — Generer LiteLLM config.yaml fra PG. + * Query: ?restart=true — restart ai-gateway etter generering. */ -export const POST: RequestHandler = async ({ locals }) => { +export const POST: RequestHandler = async ({ locals, url }) => { if (!locals.workspace || !locals.user) error(401); // Hent aktive aliaser med aktive providers @@ -46,9 +48,38 @@ export const POST: RequestHandler = async ({ locals }) => { const configPath = join(process.cwd(), 'config', 'litellm', 'config.yaml'); writeFileSync(configPath, yaml, 'utf-8'); + // Restart ai-gateway container hvis forespurt + const shouldRestart = url.searchParams.get('restart') === 'true'; + let restarted = false; + let restartError = ''; + + if (shouldRestart) { + try { + // Finn container med "ai-gateway" i navnet + const name = execSync('docker ps --format "{{.Names}}" | grep ai-gateway', { + encoding: 'utf-8', + timeout: 5000 + }).trim(); + + if (name) { + execSync(`docker restart ${name}`, { timeout: 30000 }); + restarted = true; + } else { + restartError = 'ai-gateway container ikke funnet'; + } + } catch (e: any) { + restartError = e.message || 'Kunne ikke restarte ai-gateway'; + } + } + return json({ ok: true, - message: 'Config generert. Restart ai-gateway for å aktivere.', - model_count: rows.length + message: restarted + ? 'Config generert og ai-gateway restartet.' + : restartError + ? `Config generert, men restart feilet: ${restartError}` + : 'Config generert. Restart ai-gateway for å aktivere.', + model_count: rows.length, + restarted }); }; diff --git a/web/src/routes/server-admin/ai/+page.svelte b/web/src/routes/server-admin/ai/+page.svelte index d0f1680..5a73665 100644 --- a/web/src/routes/server-admin/ai/+page.svelte +++ b/web/src/routes/server-admin/ai/+page.svelte @@ -395,16 +395,24 @@ } } - async function generateConfig() { + let configLoading = $state(false); + + async function generateConfig(restart = false) { configMsg = ''; errorMsg = ''; + configLoading = true; try { - const res = await fetch('/api/admin/ai/generate-config', { method: 'POST' }); + const url = restart + ? '/api/admin/ai/generate-config?restart=true' + : '/api/admin/ai/generate-config'; + const res = await fetch(url, { method: 'POST' }); const data = await res.json(); if (!res.ok) throw new Error(data.message ?? 'Feil'); configMsg = `${data.message} (${data.model_count} modeller)`; } catch (e: any) { errorMsg = e.message || 'Feil ved config-generering'; + } finally { + configLoading = false; } } @@ -761,11 +769,16 @@

Konfigurasjon

- + + {#if configMsg} {configMsg} {/if} -

Genererer LiteLLM config.yaml fra databasen. AI Gateway (LiteLLM) må restartes for å lese ny config.

+

Genererer LiteLLM config.yaml fra databasen. «Generer + restart» aktiverer endringene umiddelbart.

@@ -1216,10 +1229,24 @@ cursor: pointer; } - .generate-btn:hover { + .generate-btn:hover:not(:disabled) { background: #264b7a; } + .generate-btn:disabled { + opacity: 0.5; + cursor: not-allowed; + } + + .generate-btn--restart { + background: #1e4f3a; + border-color: #22c55e; + } + + .generate-btn--restart:hover:not(:disabled) { + background: #276b4f; + } + /* Forms */ .add-form { display: flex;