using System.Net.Http.Json; using System.Text.Json; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using UniVerse.Application.Interfaces; using UniVerse.Application.Prompts; namespace UniVerse.Infrastructure.ExternalServices; public class LlmClient : ILlmClient { private readonly HttpClient _http; private readonly IConfiguration _config; private readonly IReviewPromptService _reviewPrompts; private readonly ILogger _logger; public LlmClient( HttpClient http, IConfiguration config, IReviewPromptService reviewPrompts, ILogger logger) { _http = http; _config = config; _reviewPrompts = reviewPrompts; _logger = logger; } public async Task AnalyzeReviewAsync(string reviewText, string lectureContext) { var promptSetting = await _reviewPrompts.GetAsync(); var prompt = ReviewPromptTemplate.Render(promptSetting.Prompt, reviewText, lectureContext); var request = new { model = _config["Llm:Model"] ?? "gpt-4o-mini", messages = new[] { new { role = "user", content = prompt } }, temperature = 0.3, response_format = new { type = "json_object" } }; var apiKey = _config["Llm:ApiKey"] ?? ""; _http.DefaultRequestHeaders.Clear(); if (!string.IsNullOrEmpty(apiKey)) _http.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}"); var response = await _http.PostAsJsonAsync("chat/completions", request); response.EnsureSuccessStatusCode(); var json = await response.Content.ReadFromJsonAsync(); var content = json.GetProperty("choices")[0].GetProperty("message").GetProperty("content").GetString()!; var analysis = JsonSerializer.Deserialize(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true })!; return new LlmReviewAnalysis(analysis.QualityScore, analysis.Sentiment, analysis.Tags, analysis.IsInformative); } private record LlmRawResponse(double QualityScore, string Sentiment, string[] Tags, bool IsInformative); }