diff --git a/artifacts/skillguard/src/i18n/locales/de/admin.ts b/artifacts/skillguard/src/i18n/locales/de/admin.ts index 265dbdd..3b4509c 100644 --- a/artifacts/skillguard/src/i18n/locales/de/admin.ts +++ b/artifacts/skillguard/src/i18n/locales/de/admin.ts @@ -32,6 +32,8 @@ export default { fields: { name: "Name", apiType: "API-Typ", + endpointPreset: "Anbieter-Voreinstellung", + endpointPresetPlaceholder: "Anbieter wählen …", baseUrl: "API-Endpunkt (Base URL)", baseUrlPlaceholder: "z.B. https://api.openai.com/v1", baseUrlHintOpenai: "OpenAI-kompatibel: https://api.openai.com/v1", diff --git a/artifacts/skillguard/src/i18n/locales/en/admin.ts b/artifacts/skillguard/src/i18n/locales/en/admin.ts index 3652111..ba2edb3 100644 --- a/artifacts/skillguard/src/i18n/locales/en/admin.ts +++ b/artifacts/skillguard/src/i18n/locales/en/admin.ts @@ -32,6 +32,8 @@ export default { fields: { name: "Name", apiType: "API type", + endpointPreset: "Provider preset", + endpointPresetPlaceholder: "Choose provider …", baseUrl: "API endpoint (base URL)", baseUrlPlaceholder: "e.g. https://api.openai.com/v1", baseUrlHintOpenai: "OpenAI-compatible: https://api.openai.com/v1", diff --git a/artifacts/skillguard/src/i18n/locales/es/admin.ts b/artifacts/skillguard/src/i18n/locales/es/admin.ts index ffb3e00..3dbc7c0 100644 --- a/artifacts/skillguard/src/i18n/locales/es/admin.ts +++ b/artifacts/skillguard/src/i18n/locales/es/admin.ts @@ -32,6 +32,8 @@ export default { fields: { name: "Nombre", apiType: "Tipo de API", + endpointPreset: "Configuración de proveedor", + endpointPresetPlaceholder: "Elegir proveedor …", baseUrl: "Endpoint de API (URL base)", baseUrlPlaceholder: "p. ej. https://api.openai.com/v1", baseUrlHintOpenai: "Compatible con OpenAI: https://api.openai.com/v1", diff --git a/artifacts/skillguard/src/pages/admin.tsx b/artifacts/skillguard/src/pages/admin.tsx index bcffebd..a955611 100644 --- a/artifacts/skillguard/src/pages/admin.tsx +++ b/artifacts/skillguard/src/pages/admin.tsx @@ -23,6 +23,25 @@ import { useToast } from "@/hooks/use-toast"; import { Loader2, Plus, Trash2, CheckCircle2, XCircle, BrainCircuit, ShieldAlert, KeyRound, Server, Activity } from "lucide-react"; import { AxisBadge, SeverityBadge } from "@/components/ui-helpers"; +type ProviderPreset = { label: string; baseUrl: string; chatCompletion: string }; + +const PROVIDER_PRESETS: Partial> = { + [AiProviderApiType.openai]: [ + { label: "OpenAI", baseUrl: "https://api.openai.com/v1", chatCompletion: "https://api.openai.com/v1/chat/completions" }, + { label: "Groq", baseUrl: "https://api.groq.com/openai/v1", chatCompletion: "https://api.groq.com/openai/v1/chat/completions" }, + { label: "OpenRouter", baseUrl: "https://openrouter.ai/api/v1", chatCompletion: "https://openrouter.ai/api/v1/chat/completions" }, + { label: "Mistral AI", baseUrl: "https://api.mistral.ai/v1", chatCompletion: "https://api.mistral.ai/v1/chat/completions" }, + { label: "DeepSeek", baseUrl: "https://api.deepseek.com/v1", chatCompletion: "https://api.deepseek.com/v1/chat/completions" }, + { label: "Together AI", baseUrl: "https://api.together.xyz/v1", chatCompletion: "https://api.together.xyz/v1/chat/completions" }, + { label: "Perplexity AI", baseUrl: "https://api.perplexity.ai", chatCompletion: "https://api.perplexity.ai/chat/completions" }, + { label: "Ollama (lokal)", baseUrl: "http://localhost:11434/v1", chatCompletion: "http://localhost:11434/v1/chat/completions" }, + { label: "LM Studio (lokal)", baseUrl: "http://localhost:1234/v1", chatCompletion: "http://localhost:1234/v1/chat/completions" }, + ], + [AiProviderApiType.anthropic]: [ + { label: "Anthropic", baseUrl: "https://api.anthropic.com", chatCompletion: "https://api.anthropic.com/v1/messages" }, + ], +}; + function ModelField({ models, loading, tried, value, onChange }: { models: string[]; loading: boolean; @@ -98,6 +117,11 @@ function ProviderTab() { const [editModelsTried, setEditModelsTried] = useState(false); const [testingId, setTestingId] = useState(null); + const [addPreset, setAddPreset] = useState(""); + const [editPreset, setEditPreset] = useState(""); + + const addSelectedPreset = PROVIDER_PRESETS[addForm.apiType]?.find(p => p.label === addPreset) ?? null; + const editSelectedPreset = PROVIDER_PRESETS[editForm.apiType]?.find(p => p.label === editPreset) ?? null; const resetAddDiscovery = () => { setAddTestResult(null); @@ -124,6 +148,7 @@ function ProviderTab() { toast({ title: t("admin.providers.toasts.added") }); setIsAddOpen(false); setAddForm({ name: "", apiType: AiProviderApiType.openai as AiProviderApiType, baseUrl: "", model: "", apiToken: "", enabled: true }); + setAddPreset(""); resetAddDiscovery(); invalidate(); }, @@ -262,6 +287,7 @@ function ProviderTab() { apiToken: "", enabled: provider.enabled }); + setEditPreset(""); resetEditDiscovery(); setEditingId(provider.id); }; @@ -294,19 +320,45 @@ function ProviderTab() {
- { + setAddForm({ ...addForm, apiType: v, baseUrl: "" }); + setAddPreset(""); + resetAddDiscovery(); + }}> - OpenAI + OpenAI-kompatibel Anthropic Custom
+ {(PROVIDER_PRESETS[addForm.apiType]?.length ?? 0) > 0 && ( +
+ + + {addSelectedPreset && ( +
+
Base URL: {addSelectedPreset.baseUrl}
+
Chat Completions: {addSelectedPreset.chatCompletion}
+
+ )} +
+ )}
{ setAddForm({...addForm, baseUrl: e.target.value}); resetAddDiscovery(); }} required placeholder={t("admin.providers.fields.baseUrlPlaceholder")} /> -

{t("admin.providers.fields.baseUrlHintOpenai")}
{t("admin.providers.fields.baseUrlHintAnthropic")}

@@ -399,15 +451,41 @@ function ProviderTab() {
- { + setEditForm({ ...editForm, apiType: v }); + setEditPreset(""); + }}> - OpenAI + OpenAI-kompatibel Anthropic Custom
+ {(PROVIDER_PRESETS[editForm.apiType]?.length ?? 0) > 0 && ( +
+ + + {editSelectedPreset && ( +
+
Base URL: {editSelectedPreset.baseUrl}
+
Chat Completions: {editSelectedPreset.chatCompletion}
+
+ )} +
+ )}
{ setEditForm({...editForm, baseUrl: e.target.value}); resetEditDiscovery(); }} required /> diff --git a/attached_assets/image_1781631809853.png b/attached_assets/image_1781631809853.png new file mode 100644 index 0000000..3fb2ca9 Binary files /dev/null and b/attached_assets/image_1781631809853.png differ