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:
1 parent
7972ca6a3a
commit
5ed910edcd
5 files changed
+127
-3
No files matched your search
@@ -0,0 +1,32 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Gott.Services;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
|
||||||
|
namespace Gott.Endpoints;
|
||||||
|
|
||||||
|
public static class ModelsEndpoint
|
||||||
|
{
|
||||||
|
public static void MapModelsEndpoint(this IEndpointRouteBuilder app)
|
||||||
|
{
|
||||||
|
app.MapGet("/api/models/nvidia", HandleNvidiaModels);
|
||||||
|
app.MapGet("/api/models/pollinations", HandlePollinationsModels);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IResult HandleNvidiaModels(OpenAiService openAiService)
|
||||||
|
{
|
||||||
|
var models = openAiService.GetNvidiaModels()
|
||||||
|
.Select(m => new { id = m.Id, displayName = m.DisplayName })
|
||||||
|
.ToList();
|
||||||
|
return Results.Json(new { models });
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IResult HandlePollinationsModels(OpenAiService openAiService)
|
||||||
|
{
|
||||||
|
var models = openAiService.GetPollinationsModels()
|
||||||
|
.Select(m => new { id = m.Id, displayName = m.DisplayName })
|
||||||
|
.ToList();
|
||||||
|
return Results.Json(new { models });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -92,6 +92,7 @@ builder.Services.AddHostedService<CronjobService>(sp => sp.GetRequiredService<Cr
|
|||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
app.Services.GetRequiredService<AnthropicService>().SetTelegramService(app.Services.GetRequiredService<TelegramService>());
|
app.Services.GetRequiredService<AnthropicService>().SetTelegramService(app.Services.GetRequiredService<TelegramService>());
|
||||||
|
await app.Services.GetRequiredService<OpenAiService>().LoadModelsAsync();
|
||||||
app.UseWebSockets();
|
app.UseWebSockets();
|
||||||
app.UseDefaultFiles();
|
app.UseDefaultFiles();
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
@@ -104,6 +105,7 @@ app.MapSessionEndpoints();
|
|||||||
app.MapAgentEndpoints();
|
app.MapAgentEndpoints();
|
||||||
app.MapWorkspaceEndpoint();
|
app.MapWorkspaceEndpoint();
|
||||||
app.MapInfoEndpoint();
|
app.MapInfoEndpoint();
|
||||||
|
app.MapModelsEndpoint();
|
||||||
app.MapBackupEndpoint();
|
app.MapBackupEndpoint();
|
||||||
app.MapSkillEndpoints();
|
app.MapSkillEndpoints();
|
||||||
app.MapProfileEndpoints();
|
app.MapProfileEndpoints();
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ public class OpenAiService
|
|||||||
// Provider-Definitionen
|
// Provider-Definitionen
|
||||||
private static readonly Dictionary<string, (string BaseUrl, string ApiKey)> Providers = new()
|
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
|
// 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)
|
public OpenAiService(IHttpClientFactory httpFactory, DatabaseService db, ToolService toolService)
|
||||||
{
|
{
|
||||||
_httpFactory = httpFactory;
|
_httpFactory = httpFactory;
|
||||||
@@ -153,6 +159,61 @@ public class OpenAiService
|
|||||||
_toolService = toolService;
|
_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>
|
/// <summary>
|
||||||
/// Gibt den Provider und das eigentliche Modell-ID aus einem kombinierten Model-String zurück.
|
/// 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")
|
/// Format: "nvidia:moonshotai/kimi-k2.5" → ("nvidia", "moonshotai/kimi-k2.5")
|
||||||
|
|||||||
+5
-2
@@ -191,8 +191,11 @@
|
|||||||
<option value="opus-4-5">Opus 4.5</option>
|
<option value="opus-4-5">Opus 4.5</option>
|
||||||
<option value="opus-4-6" selected>Opus 4.6</option>
|
<option value="opus-4-6" selected>Opus 4.6</option>
|
||||||
<option value="haiku-4-5">Haiku 4.5</option>
|
<option value="haiku-4-5">Haiku 4.5</option>
|
||||||
<optgroup label="Nvidia (via g4f.space)">
|
<optgroup label="Pollinations (via g4f.space)" id="pollinationsOptgroup">
|
||||||
<option value="nvidia:moonshotai/kimi-k2.5">Kimi K2.5 (Moonshot)</option>
|
<option value="" disabled>Wird geladen...</option>
|
||||||
|
</optgroup>
|
||||||
|
<optgroup label="Nvidia (via g4f.space)" id="nvidiaOptgroup">
|
||||||
|
<option value="" disabled>Wird geladen...</option>
|
||||||
</optgroup>
|
</optgroup>
|
||||||
</select>
|
</select>
|
||||||
<div class="more">
|
<div class="more">
|
||||||
|
|||||||
@@ -18,6 +18,32 @@ registerPage('agent', {
|
|||||||
const nameEl = document.getElementById('agentName');
|
const nameEl = document.getElementById('agentName');
|
||||||
const descEl = document.getElementById('agentDescription');
|
const descEl = document.getElementById('agentDescription');
|
||||||
const modelEl = document.getElementById('agentModel');
|
const modelEl = document.getElementById('agentModel');
|
||||||
|
const nvidiaOptgroup = document.getElementById('nvidiaOptgroup');
|
||||||
|
const pollinationsOptgroup = document.getElementById('pollinationsOptgroup');
|
||||||
|
|
||||||
|
// Modelle dynamisch laden
|
||||||
|
const loadProviderModels = async (url, prefix, optgroup) => {
|
||||||
|
try {
|
||||||
|
const resp = await fetch(url);
|
||||||
|
const data = await resp.json();
|
||||||
|
if (optgroup && data.models && data.models.length > 0) {
|
||||||
|
optgroup.innerHTML = '';
|
||||||
|
for (const m of data.models) {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = prefix + ':' + m.id;
|
||||||
|
opt.textContent = m.displayName;
|
||||||
|
optgroup.appendChild(opt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (optgroup) optgroup.innerHTML = '<option value="" disabled>Fehler beim Laden</option>';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
loadProviderModels('/api/models/nvidia', 'nvidia', nvidiaOptgroup),
|
||||||
|
loadProviderModels('/api/models/pollinations', 'pollinations', pollinationsOptgroup)
|
||||||
|
]);
|
||||||
const allowUserChoiceEl = document.getElementById('agentAllowUserChoice');
|
const allowUserChoiceEl = document.getElementById('agentAllowUserChoice');
|
||||||
const autoCommitEl = document.getElementById('agentAutoCommit');
|
const autoCommitEl = document.getElementById('agentAutoCommit');
|
||||||
const useSoulEl = document.getElementById('agentUseSoul');
|
const useSoulEl = document.getElementById('agentUseSoul');
|
||||||
|
|||||||
Reference in new issue
Block a user