feat: Dynamisches Modell-Laden für Nvidia & Pollinations Provider

- OpenAiService: FetchModels() generisch für beide Provider (OpenAI-Format & Pollinations-Array-Format)
- Pollinations Base-URL direkt auf text.pollinations.ai/openai (kein g4f.space Proxy → kein 402)
- Pollinations Modelle-URL: text.pollinations.ai/models
- ModelsEndpoint: /api/models/nvidia + /api/models/pollinations
- agent-page.js: loadProviderModels() generisch, Promise.all für beide Provider parallel
- index.html: statische Nvidia-Option entfernt, beide Optgroups mit 'Wird geladen...'
This commit is contained in:
Meleki committed 2026-03-11 16:43:08 +01:00
1 parent 7972ca6a3a
commit 5ed910edcd
5 files changed
+127 -3

No files matched your search

+62 -1
View File
@@ -25,7 +25,8 @@ public class OpenAiService
// Provider-Definitionen
private static readonly Dictionary<string, (string BaseUrl, string ApiKey)> Providers = new()
{
["nvidia"] = ("https://g4f.space/api/nvidia/v1", "")
["nvidia"] = ("https://g4f.space/api/nvidia/v1", ""),
["pollinations"] = ("https://text.pollinations.ai/openai", "")
};
// Tools die für OpenAI-kompatible Provider verfügbar sind
@@ -146,6 +147,11 @@ public class OpenAiService
}
};
public record ProviderModel(string Id, string DisplayName);
private List<ProviderModel> _nvidiaModels = new List<ProviderModel>();
private List<ProviderModel> _pollinationsModels = new List<ProviderModel>();
public OpenAiService(IHttpClientFactory httpFactory, DatabaseService db, ToolService toolService)
{
_httpFactory = httpFactory;
@@ -153,6 +159,61 @@ public class OpenAiService
_toolService = toolService;
}
/// <summary>
/// Lädt verfügbare Modelle aller Provider beim Server-Start und cached sie.
/// </summary>
public async Task LoadModelsAsync()
{
_nvidiaModels = await FetchModels("https://g4f.space/api/nvidia/models", "Nvidia");
_pollinationsModels = await FetchModels("https://text.pollinations.ai/models", "Pollinations");
}
private async Task<List<ProviderModel>> FetchModels(string url, string providerName)
{
try
{
var client = CreateClient("");
var resp = await client.GetAsync(url);
if (!resp.IsSuccessStatusCode) return new List<ProviderModel>();
var json = await resp.Content.ReadAsStringAsync();
var root = JsonSerializer.Deserialize<JsonElement>(json);
// Pollinations: root is array [{ name, ... }]
// Nvidia/OpenAI: root is { data: [{ id, ... }] }
JsonElement arr;
if (root.ValueKind == JsonValueKind.Array)
arr = root;
else if (root.TryGetProperty("data", out var data))
arr = data;
else
return new List<ProviderModel>();
var models = new List<ProviderModel>();
foreach (var item in arr.EnumerateArray())
{
// try "id" first (Nvidia), fallback to "name" (Pollinations)
string id = null;
if (item.TryGetProperty("id", out var idProp) && idProp.ValueKind == JsonValueKind.String) id = idProp.GetString();
if (id == null && item.TryGetProperty("name", out var nameProp) && nameProp.ValueKind == JsonValueKind.String) id = nameProp.GetString();
if (string.IsNullOrEmpty(id)) continue;
var display = id.Contains('/') ? id[(id.LastIndexOf('/') + 1)..] : id;
models.Add(new ProviderModel(id, display));
}
Console.WriteLine($"[OpenAiService] {models.Count} {providerName}-Modelle geladen.");
return models;
}
catch (Exception ex)
{
Console.WriteLine($"[OpenAiService] Fehler beim Laden der {providerName}-Modelle: {ex.Message}");
return new List<ProviderModel>();
}
}
public List<ProviderModel> GetNvidiaModels() => _nvidiaModels;
public List<ProviderModel> GetPollinationsModels() => _pollinationsModels;
/// <summary>
/// Gibt den Provider und das eigentliche Modell-ID aus einem kombinierten Model-String zurück.
/// Format: "nvidia:moonshotai/kimi-k2.5" → ("nvidia", "moonshotai/kimi-k2.5")