feat: OpenAI Provider, Key-Checker Quota-Erkennung, persistierte Scanner-Logs
- OpenAI als vollwertiger Chat-Provider (Modell-Auswahl, Key-Routing, StreamChat) - Hardcoded OpenAI-Modelle im Cache (gpt-5.x, gpt-4.1, o3, o4-mini etc.) - /api/models/openai Endpoint, OpenAI-Optgroup im Agent-Dropdown - Key-Routing: OpenAI-Key aus api_keys-Tabelle, Fallback via GetFirstActiveKeyByProvider - OpenAI-Checker: 2-Schritt-Check (Models + chat/completions mit max_tokens=1) - Google-Checker: 2-Schritt-Check (Models + generateContent mit maxOutputTokens=1) - 429 insufficient_quota und billing_not_active korrekt als quota_exceeded erkannt - Provider-Erkennung beim Adopt via KeyPatterns.DetectType() statt hardcoded anthropic - HandleCheck/HandleCheckAll unterstützt jetzt Anthropic, OpenAI und Google - Neue scanner_logs-Tabelle mit details-Spalte (JSON) für strukturierte Auswertung - GitHubEventScannerService: AddLog persistiert in DB, detaillierte Key-Fund-Logs - KeyScannerService: AddLog-Methode mit DB-Persistierung, detaillierte Logs - Frontend: Ungeprüfte-prüfen-Button (sequenziell, stoppt bei valid) - Frontend: Provider-Indicator im Key-Switch-Modal (Anthropic/OpenAI/Google) - Frontend: Check-Button für alle Provider (nicht nur Anthropic)
This commit is contained in:
1 parent
c8859a89d0
commit
542a031172
15 files changed
+614
-90
No files matched your search
@@ -519,4 +519,48 @@ public partial class DatabaseService
|
||||
await conn.ExecuteAsync("UPDATE scanned_keys SET deleted = 1 WHERE scanned_key_id = @scannedKeyId", new { scannedKeyId });
|
||||
}
|
||||
|
||||
// ── Scanner Logs ──
|
||||
|
||||
public async Task CreateScannerLog(string type, string message, string scanner = "event", string details = null)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
// Sicherstellen dass die details-Spalte existiert (Migration)
|
||||
try
|
||||
{
|
||||
await conn.ExecuteAsync(@"ALTER TABLE scanner_logs ADD COLUMN details TEXT");
|
||||
}
|
||||
catch { /* Spalte existiert bereits */ }
|
||||
|
||||
await conn.ExecuteAsync(@"
|
||||
INSERT INTO scanner_logs (timestamp, type, message, scanner, details)
|
||||
VALUES (@timestamp, @type, @message, @scanner, @details)",
|
||||
new { timestamp = DateTime.UtcNow.ToString("o"), type, message, scanner, details });
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<dynamic>> GetScannerLogs(int limit = 200, int offset = 0, string type = null, string scanner = null)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
var where = "WHERE 1=1";
|
||||
if (!string.IsNullOrEmpty(type)) where += " AND type = @type";
|
||||
if (!string.IsNullOrEmpty(scanner)) where += " AND scanner = @scanner";
|
||||
|
||||
return await conn.QueryAsync($@"
|
||||
SELECT id, timestamp, type, message, scanner, details
|
||||
FROM scanner_logs {where}
|
||||
ORDER BY id DESC
|
||||
LIMIT @limit OFFSET @offset",
|
||||
new { limit, offset, type, scanner });
|
||||
}
|
||||
|
||||
public async Task<int> GetScannerLogCount(string type = null, string scanner = null)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
var where = "WHERE 1=1";
|
||||
if (!string.IsNullOrEmpty(type)) where += " AND type = @type";
|
||||
if (!string.IsNullOrEmpty(scanner)) where += " AND scanner = @scanner";
|
||||
|
||||
return await conn.ExecuteScalarAsync<int>(
|
||||
$"SELECT COUNT(*) FROM scanner_logs {where}",
|
||||
new { type, scanner });
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user