From e87455ffe9a660d4229767d6fc60ce9d86127417 Mon Sep 17 00:00:00 2001 From: Meleki Date: Wed, 11 Mar 2026 18:41:47 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20Gemini=20als=20Provider=20hinzugef?= =?UTF-8?q?=C3=BCgt=20(Free-Tier-Modelle=20hardcodiert)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - OpenAiService: Gemini-Provider mit Base-URL generativelanguage.googleapis.com/v1beta/openai - GeminiApiKey aus IConfiguration (appsettings.json / appsettings.Production.json) - Gemini Free-Tier-Modelle hardcodiert: 2.5 Pro, 2.5 Flash, 2.5 Flash Lite - ModelsEndpoint: /api/models/gemini Endpoint - Frontend: geminiOptgroup dynamisch befüllt - ProviderKeys als static HashSet (für ChatService.ResolveModelId) --- Endpoints/ModelsEndpoint.cs | 9 ++++++++ Program.cs | 2 +- Services/OpenAiService.cs | 39 +++++++++++++++++++++++----------- appsettings.json | 3 ++- wwwroot/index.html | 3 +++ wwwroot/js/pages/agent-page.js | 4 +++- 6 files changed, 45 insertions(+), 15 deletions(-) diff --git a/Endpoints/ModelsEndpoint.cs b/Endpoints/ModelsEndpoint.cs index 7f4d7a3..ce6ba86 100644 --- a/Endpoints/ModelsEndpoint.cs +++ b/Endpoints/ModelsEndpoint.cs @@ -12,6 +12,7 @@ public static class ModelsEndpoint { app.MapGet("/api/models/nvidia", HandleNvidiaModels); app.MapGet("/api/models/pollinations", HandlePollinationsModels); + app.MapGet("/api/models/gemini", HandleGeminiModels); } private static IResult HandleNvidiaModels(OpenAiService openAiService) @@ -29,4 +30,12 @@ public static class ModelsEndpoint .ToList(); return Results.Json(new { models }); } + + private static IResult HandleGeminiModels(OpenAiService openAiService) + { + var models = openAiService.GetGeminiModels() + .Select(m => new { id = m.Id, displayName = m.DisplayName }) + .ToList(); + return Results.Json(new { models }); + } } diff --git a/Program.cs b/Program.cs index 318e7f1..159fcf2 100644 --- a/Program.cs +++ b/Program.cs @@ -70,7 +70,7 @@ builder.Services.AddSingleton(sp => // OpenAI-kompatibler Service (Nvidia etc.) builder.Services.AddSingleton(sp => - new OpenAiService(sp.GetRequiredService(), dbService, sp.GetRequiredService())); + new OpenAiService(sp.GetRequiredService(), dbService, sp.GetRequiredService(), builder.Configuration)); // Telegram Bot (pro Session – Token aus Session-Config) var maxIterations = builder.Configuration.GetValue("MaxIterations", 100); diff --git a/Services/OpenAiService.cs b/Services/OpenAiService.cs index b82be79..b2c33a0 100644 --- a/Services/OpenAiService.cs +++ b/Services/OpenAiService.cs @@ -22,12 +22,11 @@ public class OpenAiService private readonly DatabaseService _db; private readonly ToolService _toolService; - // Provider-Definitionen - private static readonly Dictionary Providers = new() - { - ["nvidia"] = ("https://g4f.space/api/nvidia/v1", ""), - ["pollinations"] = ("https://text.pollinations.ai/openai", "") - }; + // Provider-Keys (statisch für ChatService.ResolveModelId) + public static readonly HashSet ProviderKeys = new() { "nvidia", "pollinations", "gemini" }; + + // Provider-Definitionen (inkl. API-Keys, instanzgebunden) + private readonly Dictionary Providers; // Tools die für OpenAI-kompatible Provider verfügbar sind private static readonly List OpenAiTools = new() @@ -151,12 +150,19 @@ public class OpenAiService private List _nvidiaModels = new List(); private List _pollinationsModels = new List(); + private List _geminiModels = new List(); - public OpenAiService(IHttpClientFactory httpFactory, DatabaseService db, ToolService toolService) + public OpenAiService(IHttpClientFactory httpFactory, DatabaseService db, ToolService toolService, Microsoft.Extensions.Configuration.IConfiguration configuration) { _httpFactory = httpFactory; _db = db; _toolService = toolService; + Providers = new Dictionary + { + ["nvidia"] = ("https://g4f.space/api/nvidia/v1", ""), + ["pollinations"] = ("https://text.pollinations.ai/openai", ""), + ["gemini"] = ("https://generativelanguage.googleapis.com/v1beta/openai", configuration["GeminiApiKey"] ?? "") + }; } /// @@ -164,15 +170,23 @@ public class OpenAiService /// public async Task LoadModelsAsync() { - _nvidiaModels = await FetchModels("https://g4f.space/api/nvidia/models", "Nvidia"); + _nvidiaModels = await FetchModels("https://g4f.space/api/nvidia/models", "Nvidia"); _pollinationsModels = await FetchModels("https://text.pollinations.ai/models", "Pollinations"); + + // Gemini: nur kostenlose Free-Tier-Modelle (hardcodiert) + _geminiModels = new List + { + new ProviderModel("gemini-2.5-pro", "Gemini 2.5 Pro"), + new ProviderModel("gemini-2.5-flash", "Gemini 2.5 Flash"), + new ProviderModel("gemini-2.5-flash-lite", "Gemini 2.5 Flash Lite"), + }; } - private async Task> FetchModels(string url, string providerName) + private async Task> FetchModels(string url, string providerName, string apiKey = "") { try { - var client = CreateClient(""); + var client = CreateClient(apiKey); var resp = await client.GetAsync(url); if (!resp.IsSuccessStatusCode) return new List(); @@ -211,8 +225,9 @@ public class OpenAiService } } - public List GetNvidiaModels() => _nvidiaModels; + public List GetNvidiaModels() => _nvidiaModels; public List GetPollinationsModels() => _pollinationsModels; + public List GetGeminiModels() => _geminiModels; /// /// Gibt den Provider und das eigentliche Modell-ID aus einem kombinierten Model-String zurück. @@ -232,7 +247,7 @@ public class OpenAiService public static bool IsOpenAiProvider(string model) { var (provider, _) = ParseModelString(model); - return Providers.ContainsKey(provider); + return ProviderKeys.Contains(provider); } public async Task StreamChat( diff --git a/appsettings.json b/appsettings.json index b8f5b68..9a11bb8 100755 --- a/appsettings.json +++ b/appsettings.json @@ -14,5 +14,6 @@ "PayloadLogging": false, "PayloadLoggingGzip": false, "KreaToken": "", - "KreaApiKey": "" + "KreaApiKey": "", + "GeminiApiKey": "" } diff --git a/wwwroot/index.html b/wwwroot/index.html index bf70e4f..b5ef6a3 100644 --- a/wwwroot/index.html +++ b/wwwroot/index.html @@ -191,6 +191,9 @@ + + + diff --git a/wwwroot/js/pages/agent-page.js b/wwwroot/js/pages/agent-page.js index 917f4a1..0ecbec9 100644 --- a/wwwroot/js/pages/agent-page.js +++ b/wwwroot/js/pages/agent-page.js @@ -20,6 +20,7 @@ registerPage('agent', { const modelEl = document.getElementById('agentModel'); const nvidiaOptgroup = document.getElementById('nvidiaOptgroup'); const pollinationsOptgroup = document.getElementById('pollinationsOptgroup'); + const geminiOptgroup = document.getElementById('geminiOptgroup'); // Modelle dynamisch laden const loadProviderModels = async (url, prefix, optgroup) => { @@ -42,7 +43,8 @@ registerPage('agent', { await Promise.all([ loadProviderModels('/api/models/nvidia', 'nvidia', nvidiaOptgroup), - loadProviderModels('/api/models/pollinations', 'pollinations', pollinationsOptgroup) + loadProviderModels('/api/models/pollinations', 'pollinations', pollinationsOptgroup), + loadProviderModels('/api/models/gemini', 'gemini', geminiOptgroup) ]); const allowUserChoiceEl = document.getElementById('agentAllowUserChoice'); const autoCommitEl = document.getElementById('agentAutoCommit');