feat(ui): redesign AI Provider settings with provider presets and model catalog

- Replace hardcoded provider list with PROVIDER_PRESETS (OpenAI, Ollama,
  DeepSeek, Groq, OpenRouter, OpenCode Go, Custom)
- Load model lists from models.dev/api.json catalog at startup
- Add Combobox vanilla JS component for model/base-URL selection
- Fetch local Ollama models via live API instead of catalog
- Hide API key values from frontend (boolean-only llm_api_key_set)
- Add i18n translations for all 9+ locales
- Update snapshot tests for new response fields
This commit is contained in:
Will Miao
2026-07-03 16:08:51 +08:00
parent f06c60bd47
commit 4ed9169646
22 changed files with 916 additions and 50 deletions

View File

@@ -662,7 +662,15 @@
"title": "KI-Anbieter",
"provider": "Anbieter",
"providerHelp": "Wählen Sie Ihren LLM-Anbieter. OpenAI und Ollama verwenden voreingestellte API-Endpunkte. Mit \"Benutzerdefiniert\" können Sie jeden OpenAI-kompatiblen Endpunkt angeben.",
"custom": "Benutzerdefiniert (OpenAI-kompatibel)",
"providerOptions": {
"openai": "OpenAI",
"ollama": "Ollama (lokal)",
"deepseek": "DeepSeek",
"groq": "Groq",
"openrouter": "OpenRouter",
"opencode-go": "OpenCode Go",
"custom": "Benutzerdefiniert (OpenAI-kompatibel)"
},
"apiBase": "API-Basis-URL",
"apiBaseHelp": "Die Basis-URL für die LLM-API (z.B. https://api.openai.com/v1). Leer lassen, um die Anbietervoreinstellung zu verwenden.",
"apiBasePlaceholder": "https://api.openai.com/v1",
@@ -673,7 +681,8 @@
"apiKeyConfigured": "Konfiguriert",
"apiKeySet": "Einrichten",
"model": "Modell",
"modelHelp": "Der zu verwendende Modellname (z.B. deepseek-v4-flash, gemini-2.5-flash, gemma4:12b). Prüfen Sie Ihren Anbieter auf verfügbare Modelle."
"modelHelp": "Der zu verwendende Modellname (z.B. deepseek-v4-flash, gemini-2.5-flash, gemma4:12b). Prüfen Sie Ihren Anbieter auf verfügbare Modelle.",
"modelPlaceholder": "Modell auswählen..."
}
},
"loras": {

View File

@@ -661,10 +661,18 @@
"aiProvider": {
"title": "AI Provider",
"provider": "Provider",
"providerHelp": "Choose your LLM provider. OpenAI and Ollama use preset API endpoints. Custom lets you specify any OpenAI-compatible endpoint.",
"custom": "Custom (OpenAI-compatible)",
"providerHelp": "Choose your LLM provider. Preset providers set the API base URL automatically. Custom lets you specify any OpenAI-compatible endpoint.",
"providerOptions": {
"openai": "OpenAI",
"ollama": "Ollama (local)",
"deepseek": "DeepSeek",
"groq": "Groq",
"openrouter": "OpenRouter",
"opencode-go": "OpenCode Go",
"custom": "Custom (OpenAI-compatible)"
},
"apiBase": "API Base URL",
"apiBaseHelp": "The base URL for the LLM API (e.g. https://api.openai.com/v1). Leave empty to use the provider default.",
"apiBaseHelp": "The base URL for the LLM API. Select a preset or enter a custom URL. The dropdown shows presets for all supported providers.",
"apiBasePlaceholder": "https://api.openai.com/v1",
"apiKey": "API Key",
"apiKeyHelp": "Your LLM provider API key. Stored locally, never sent to any server except your chosen LLM provider.",
@@ -673,7 +681,8 @@
"apiKeyConfigured": "Configured",
"apiKeySet": "Set up",
"model": "Model",
"modelHelp": "The model name to use (e.g. deepseek-v4-flash, gemini-2.5-flash, gemma4:12b). Check your provider for available models."
"modelHelp": "The model to use. Select from the dropdown (fetched from your provider) or type a custom model name.",
"modelPlaceholder": "Select a model..."
}
},
"loras": {

View File

@@ -662,7 +662,15 @@
"title": "Proveedor de IA",
"provider": "Proveedor",
"providerHelp": "Elija su proveedor de LLM. OpenAI y Ollama usan endpoints predefinidos. Personalizado le permite especificar cualquier endpoint compatible con OpenAI.",
"custom": "Personalizado (compatible con OpenAI)",
"providerOptions": {
"openai": "OpenAI",
"ollama": "Ollama (local)",
"deepseek": "DeepSeek",
"groq": "Groq",
"openrouter": "OpenRouter",
"opencode-go": "OpenCode Go",
"custom": "Personalizado (compatible con OpenAI)"
},
"apiBase": "URL base de la API",
"apiBaseHelp": "La URL base para la API LLM (p.ej. https://api.openai.com/v1). Déjelo vacío para usar el valor predeterminado del proveedor.",
"apiBasePlaceholder": "https://api.openai.com/v1",
@@ -673,7 +681,8 @@
"apiKeyConfigured": "Configurada",
"apiKeySet": "Configurar",
"model": "Modelo",
"modelHelp": "El nombre del modelo a usar (p.ej. deepseek-v4-flash, gemini-2.5-flash, gemma4:12b). Consulte a su proveedor para ver los modelos disponibles."
"modelHelp": "El nombre del modelo a usar (p.ej. deepseek-v4-flash, gemini-2.5-flash, gemma4:12b). Consulte a su proveedor para ver los modelos disponibles.",
"modelPlaceholder": "Seleccionar un modelo..."
}
},
"loras": {

View File

@@ -662,7 +662,15 @@
"title": "Fournisseur d'IA",
"provider": "Fournisseur",
"providerHelp": "Choisissez votre fournisseur LLM. OpenAI et Ollama utilisent des endpoints prédéfinis. Personnalisé vous permet de spécifier n'importe quel endpoint compatible OpenAI.",
"custom": "Personnalisé (compatible OpenAI)",
"providerOptions": {
"openai": "OpenAI",
"ollama": "Ollama (local)",
"deepseek": "DeepSeek",
"groq": "Groq",
"openrouter": "OpenRouter",
"opencode-go": "OpenCode Go",
"custom": "Personnalisé (compatible OpenAI)"
},
"apiBase": "URL de base de l'API",
"apiBaseHelp": "L'URL de base pour l'API LLM (ex. https://api.openai.com/v1). Laissez vide pour utiliser le fournisseur par défaut.",
"apiBasePlaceholder": "https://api.openai.com/v1",
@@ -673,7 +681,8 @@
"apiKeyConfigured": "Configurée",
"apiKeySet": "Configurer",
"model": "Modèle",
"modelHelp": "Le nom du modèle à utiliser (ex. deepseek-v4-flash, gemini-2.5-flash, gemma4:12b). Consultez votre fournisseur pour les modèles disponibles."
"modelHelp": "Le nom du modèle à utiliser (ex. deepseek-v4-flash, gemini-2.5-flash, gemma4:12b). Consultez votre fournisseur pour les modèles disponibles.",
"modelPlaceholder": "Sélectionner un modèle..."
}
},
"loras": {

View File

@@ -662,7 +662,15 @@
"title": "ספק AI",
"provider": "ספק",
"providerHelp": "בחר את ספק ה-LLM שלך. OpenAI ו-Ollama משתמשים בנקודות קצה מוגדרות מראש. מותאם אישית מאפשר לך לציין כל נקודת קצה תואמת OpenAI.",
"custom": "מותאם אישית (תואם OpenAI)",
"providerOptions": {
"openai": "OpenAI",
"ollama": "Ollama (מקומי)",
"deepseek": "DeepSeek",
"groq": "Groq",
"openrouter": "OpenRouter",
"opencode-go": "OpenCode Go",
"custom": "מותאם אישית (תואם OpenAI)"
},
"apiBase": "כתובת בסיס API",
"apiBaseHelp": "כתובת ה-URL הבסיסית ל-API של LLM (לדוגמה https://api.openai.com/v1). השאר ריק לשימוש בברירת המחדל של הספק.",
"apiBasePlaceholder": "https://api.openai.com/v1",
@@ -673,7 +681,8 @@
"apiKeyConfigured": "הוגדר",
"apiKeySet": "הגדר",
"model": "מודל",
"modelHelp": "שם המודל לשימוש (לדוגמה deepseek-v4-flash, gemini-2.5-flash, gemma4:12b). בדוק אצל הספק שלך אילו מודלים זמינים."
"modelHelp": "שם המודל לשימוש (לדוגמה deepseek-v4-flash, gemini-2.5-flash, gemma4:12b). בדוק אצל הספק שלך אילו מודלים זמינים.",
"modelPlaceholder": "בחר מודל..."
}
},
"loras": {

View File

@@ -662,7 +662,15 @@
"title": "AIプロバイダー",
"provider": "プロバイダー",
"providerHelp": "LLMプロバイダーを選択してください。OpenAIとOllamaはプリセットのAPIエンドポイントを使用します。カスタムでは任意のOpenAI互換エンドポイントを指定できます。",
"custom": "カスタムOpenAI互換",
"providerOptions": {
"openai": "OpenAI",
"ollama": "Ollamaローカル",
"deepseek": "DeepSeek",
"groq": "Groq",
"openrouter": "OpenRouter",
"opencode-go": "OpenCode Go",
"custom": "カスタムOpenAI 互換)"
},
"apiBase": "APIベースURL",
"apiBaseHelp": "LLM APIのベースURLhttps://api.openai.com/v1。空の場合はプロバイダーのデフォルトが使用されます。",
"apiBasePlaceholder": "https://api.openai.com/v1",
@@ -673,7 +681,8 @@
"apiKeyConfigured": "設定済み",
"apiKeySet": "設定",
"model": "モデル",
"modelHelp": "使用するモデル名deepseek-v4-flash, gemini-2.5-flash, gemma4:12b。プロバイダーで利用可能なモデルをご確認ください。"
"modelHelp": "使用するモデル名deepseek-v4-flash, gemini-2.5-flash, gemma4:12b。プロバイダーで利用可能なモデルをご確認ください。",
"modelPlaceholder": "モデルを選択..."
}
},
"loras": {

View File

@@ -662,7 +662,15 @@
"title": "AI 제공자",
"provider": "제공자",
"providerHelp": "LLM 제공자를 선택하세요. OpenAI와 Ollama는 사전 설정된 API 엔드포인트를 사용합니다. 사용자 정의를 선택하면 모든 OpenAI 호환 엔드포인트를 지정할 수 있습니다.",
"custom": "사용자 정의 (OpenAI 호환)",
"providerOptions": {
"openai": "OpenAI",
"ollama": "Ollama (로컬)",
"deepseek": "DeepSeek",
"groq": "Groq",
"openrouter": "OpenRouter",
"opencode-go": "OpenCode Go",
"custom": "사용자 정의 (OpenAI 호환)"
},
"apiBase": "API 기본 URL",
"apiBaseHelp": "LLM API의 기본 URL입니다 (예: https://api.openai.com/v1). 비워두면 제공자 기본값이 사용됩니다.",
"apiBasePlaceholder": "https://api.openai.com/v1",
@@ -673,7 +681,8 @@
"apiKeyConfigured": "설정됨",
"apiKeySet": "설정",
"model": "모델",
"modelHelp": "사용할 모델 이름 (예: deepseek-v4-flash, gemini-2.5-flash, gemma4:12b). 제공자에서 사용 가능한 모델을 확인하세요."
"modelHelp": "사용할 모델 이름 (예: deepseek-v4-flash, gemini-2.5-flash, gemma4:12b). 제공자에서 사용 가능한 모델을 확인하세요.",
"modelPlaceholder": "모델 선택..."
}
},
"loras": {

View File

@@ -662,7 +662,15 @@
"title": "Поставщик ИИ",
"provider": "Поставщик",
"providerHelp": "Выберите поставщика LLM. OpenAI и Ollama используют предустановленные API-эндпоинты. Пользовательский позволяет указать любой совместимый с OpenAI эндпоинт.",
"custom": "Пользовательский (совместимый с OpenAI)",
"providerOptions": {
"openai": "OpenAI",
"ollama": "Ollama (локальный)",
"deepseek": "DeepSeek",
"groq": "Groq",
"openrouter": "OpenRouter",
"opencode-go": "OpenCode Go",
"custom": "Пользовательский (совместимый с OpenAI)"
},
"apiBase": "Базовый URL API",
"apiBaseHelp": "Базовый URL для LLM API (например, https://api.openai.com/v1). Оставьте пустым, чтобы использовать значение по умолчанию.",
"apiBasePlaceholder": "https://api.openai.com/v1",
@@ -673,7 +681,8 @@
"apiKeyConfigured": "Настроен",
"apiKeySet": "Настроить",
"model": "Модель",
"modelHelp": "Имя модели для использования (например, deepseek-v4-flash, gemini-2.5-flash, gemma4:12b). Проверьте доступные модели у вашего поставщика."
"modelHelp": "Имя модели для использования (например, deepseek-v4-flash, gemini-2.5-flash, gemma4:12b). Проверьте доступные модели у вашего поставщика.",
"modelPlaceholder": "Выберите модель..."
}
},
"loras": {

View File

@@ -662,18 +662,27 @@
"title": "AI 提供商",
"provider": "提供商",
"providerHelp": "选择您的 LLM 提供商。OpenAI 和 Ollama 使用预设的 API 端点。自定义允许您指定任何兼容 OpenAI 的端点。",
"custom": "自定义(兼容 OpenAI",
"providerOptions": {
"openai": "OpenAI",
"ollama": "Ollama本地",
"deepseek": "DeepSeek",
"groq": "Groq",
"openrouter": "OpenRouter",
"opencode-go": "OpenCode Go",
"custom": "自定义OpenAI 兼容)"
},
"apiBase": "API 基础地址",
"apiBaseHelp": "LLM API 的基础 URL例如 https://api.openai.com/v1。留空则使用提供商默认地址。",
"apiBaseHelp": "LLM API 的基础地址。选择预设或输入自定义地址,下拉框显示所有支持的提供商预设。",
"apiBasePlaceholder": "https://api.openai.com/v1",
"apiKey": "API 密钥",
"apiKeyHelp": "您的 LLM 提供商 API 密钥。本地存储,不会发送到您选择的 LLM 提供商之外的任何服务器。",
"apiKeyHelp": "LLM 提供商 API 密钥。本地存储,您选择的 LLM 提供商外不会发送到任何服务器。",
"apiKeyPlaceholder": "sk-...",
"apiKeyNotSet": "未设置",
"apiKeyConfigured": "已配置",
"apiKeySet": "设置",
"model": "模型",
"modelHelp": "要使用的模型名称(例如 deepseek-v4-flash, gemini-2.5-flash, gemma4:12b。请查看您的提供商支持的可用模型列表。"
"modelHelp": "要使用的模型。从下拉框选择(从提供商获取)或输入自定义模型名称。",
"modelPlaceholder": "选择一个模型..."
}
},
"loras": {

View File

@@ -662,18 +662,27 @@
"title": "AI 提供者",
"provider": "提供者",
"providerHelp": "選擇您的 LLM 提供者。OpenAI 和 Ollama 使用預設 API 端點。自訂允許您指定任何相容 OpenAI 的端點。",
"custom": "自訂(相容 OpenAI",
"apiBase": "API 基礎位址",
"apiBaseHelp": "LLM API 的基礎 URL例如 https://api.openai.com/v1。留空則使用提供者預設位址。",
"providerOptions": {
"openai": "OpenAI",
"ollama": "Ollama本地",
"deepseek": "DeepSeek",
"groq": "Groq",
"openrouter": "OpenRouter",
"opencode-go": "OpenCode Go",
"custom": "自訂OpenAI 相容)"
},
"apiBase": "API 基礎網址",
"apiBaseHelp": "LLM API 的基礎網址。選擇預設或輸入自訂網址,下拉選單顯示所有支援的提供者預設。",
"apiBasePlaceholder": "https://api.openai.com/v1",
"apiKey": "API 金鑰",
"apiKeyHelp": "您的 LLM 提供者 API 金鑰。儲存在本地,除您選擇的 LLM 提供者外不會送到任何伺服器。",
"apiKeyPlaceholder": "sk-...",
"apiKeyHelp": "LLM 提供者 API 金鑰。儲存在本地,除您選擇的 LLM 提供者外不會送到任何伺服器。",
"apiKeyPlaceholder": "[TODO: Translate] sk-...",
"apiKeyNotSet": "未設定",
"apiKeyConfigured": "已設定",
"apiKeySet": "設定",
"model": "模型",
"modelHelp": "要使用的模型名稱(例如 deepseek-v4-flash, gemini-2.5-flash, gemma4:12b。請查看您的提供者支援的可用模型列表。"
"modelHelp": "要使用的模型。從下拉選單選擇(從提供者取得)或輸入自訂模型名稱。",
"modelPlaceholder": "選擇一個模型..."
}
},
"loras": {