Enhance UI, add AI integration, improve logging and database stats

This commit is contained in:
Richard
2026-07-04 21:11:31 +02:00
parent 7a44914d9d
commit d102af2965
57 changed files with 4025 additions and 229 deletions
@@ -0,0 +1,88 @@
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Predictalytics.Application.Interfaces;
namespace Predictalytics.Infrastructure.Providers.OpenRouter;
public class OpenRouterApiClient : IOpenRouterApiClient
{
private readonly HttpClient _httpClient;
private readonly IConfiguration _config;
private readonly ILogger<OpenRouterApiClient> _logger;
public OpenRouterApiClient(HttpClient httpClient, IConfiguration config, ILogger<OpenRouterApiClient> logger)
{
_httpClient = httpClient;
_config = config;
_logger = logger;
var baseUrl = _config["OpenRouter:BaseUrl"] ?? "https://openrouter.ai/api/v1";
var apiKey = _config["OpenRouter:ApiKey"];
_httpClient.BaseAddress = new Uri(baseUrl.EndsWith("/") ? baseUrl : baseUrl + "/");
if (!string.IsNullOrEmpty(apiKey))
{
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
}
// OpenRouter recommends adding a referer and title for ranking
_httpClient.DefaultRequestHeaders.Add("HTTP-Referer", "http://localhost");
_httpClient.DefaultRequestHeaders.Add("X-Title", "Predictalytics");
}
public async Task<string> GenerateChatCompletionAsync(string prompt, bool useManualModel = false, CancellationToken ct = default)
{
var model = useManualModel
? _config["OpenRouter:ManualAnalysisModel"] ?? "anthropic/claude-3-opus"
: _config["OpenRouter:DefaultModel"] ?? "google/gemini-flash-1.5";
var requestBody = new
{
model = model,
messages = new[]
{
new { role = "system", content = "You are an expert crypto and prediction market analyst. You analyze a trader's history and deduce their strategy, strengths, and weaknesses." },
new { role = "user", content = prompt }
}
};
try
{
var response = await _httpClient.PostAsJsonAsync("chat/completions", requestBody, ct);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<OpenRouterResponse>(cancellationToken: ct);
return result?.Choices?[0]?.Message?.Content ?? "No response generated.";
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to generate chat completion from OpenRouter using model {Model}", model);
return $"Error: {ex.Message}";
}
}
private class OpenRouterResponse
{
[JsonPropertyName("choices")]
public Choice[]? Choices { get; set; }
}
private class Choice
{
[JsonPropertyName("message")]
public Message? Message { get; set; }
}
private class Message
{
[JsonPropertyName("content")]
public string? Content { get; set; }
}
}