using BLAIzor.Models; using Newtonsoft.Json; using System.Net.Http; using System.Text.Json; using System.Text; namespace BLAIzor.Services { public class DeepSeekApiService { private readonly IConfiguration _configuration; private readonly HttpClient _httpClient; public DeepSeekApiService(IConfiguration configuration, HttpClient httpClient) { _configuration = configuration; _httpClient = httpClient; } private const string DeepSeekEndpoint = "https://api.deepseek.com/chat/completions"; public string _apiKey; private Action _callback; public string GetApiKey() { if (_configuration == null) { return string.Empty; } if (_configuration.GetSection("DeepSeek") == null) { return string.Empty; } return _configuration.GetSection("DeepSeek").GetValue("ApiKey")!; } public void RegisterCallback(Action callback) { _callback = callback; } public async Task GetSimpleChatGPTResponse(string systemMessage, string userMessage, string? assistantMessage = null) { _apiKey = GetApiKey(); var requestBody = new ChatGPTRequest(); if (assistantMessage == null) { requestBody = new ChatGPTRequest { Model = "deepseek-chat", Temperature = 0.2, Messages = new[] { new Message { Role = "system", Content = systemMessage }, new Message { Role = "user", Content = userMessage } }, Stream = false }; } else { requestBody = new ChatGPTRequest { Model = "deepseek-chat", Temperature = 0.2, Messages = new[] { new Message { Role = "system", Content = systemMessage }, new Message {Role = "assistant", Content = assistantMessage }, new Message { Role = "user", Content = userMessage } }, Stream = false }; } string requestJson = System.Text.Json.JsonSerializer.Serialize(requestBody, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = false } ); var requestContent = new StringContent(requestJson, Encoding.UTF8, "application/json"); _httpClient.DefaultRequestHeaders.Clear(); _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}"); var response = await _httpClient.PostAsync(DeepSeekEndpoint, requestContent); response.EnsureSuccessStatusCode(); Console.Write(response.Content.ReadAsStringAsync()); var responseBody = await response.Content.ReadFromJsonAsync(); Console.Write(responseBody.GetRawText()); var result = responseBody.GetProperty("choices")[0].GetProperty("message").GetProperty("content").GetString() ?? "No response"; Console.Write("Answer: " + result); return result; } public async Task GetChatGPTStreamedResponse(string sessionId, string systemMessage, string userMessage, string? assistanMessage = null) { _apiKey = GetApiKey(); ChatGPTRequest finalRequestBody; if (assistanMessage == null) { finalRequestBody = new ChatGPTRequest { Model = "deepseek-chat", Temperature = 0.2, Messages = new[] { new Message { Role = "system", Content = systemMessage }, new Message { Role = "user", Content = userMessage } }, Stream = true }; } else { finalRequestBody = new ChatGPTRequest { Model = "deepseek-chat", Temperature = 0.2, Messages = new[] { new Message { Role = "system", Content = systemMessage }, new Message {Role = "assistant", Content= assistanMessage}, new Message { Role = "user", Content = userMessage } }, Stream = true }; } string requestJson = System.Text.Json.JsonSerializer.Serialize(finalRequestBody, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true } ); var finalRequestContent = new StringContent(requestJson, Encoding.UTF8, "application/json"); Console.Write(finalRequestContent); var httpRequest = new HttpRequestMessage(HttpMethod.Post, DeepSeekEndpoint) { Content = finalRequestContent }; _httpClient.DefaultRequestHeaders.Clear(); _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}"); // Use SendAsync with streamed response var sResponse = await _httpClient.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead); sResponse.EnsureSuccessStatusCode(); using var responseStream = await sResponse.Content.ReadAsStreamAsync(); using var reader = new StreamReader(responseStream); //Console.Write("Streamed response:"); string streamedHtmlContent = string.Empty; while (!reader.EndOfStream) { var line = await reader.ReadLineAsync(); //Console.WriteLine($"Raw Stream Line: {line}"); // Log each line if (!string.IsNullOrWhiteSpace(line) && line.StartsWith("data: ")) { var jsonResponse = line.Substring(6); // Remove "data: " prefix if (jsonResponse == "[DONE]") { Console.WriteLine("Stream ended."); break; // End of stream } try { //Console.WriteLine($"JSON Response: {jsonResponse}"); // Debug JSON response //TODO: do we really have to += the content, or should we just invoke with the delta? var chunk = JsonConvert.DeserializeObject(jsonResponse); if (chunk?.Choices != null && chunk.Choices.Count > 0 && chunk.Choices[0].Delta?.Content != null) { streamedHtmlContent += chunk.Choices[0].Delta.Content; // Append the streamed content if (!string.IsNullOrEmpty(streamedHtmlContent) && _callback != null) { _callback?.Invoke(streamedHtmlContent); } //Console.WriteLine($"Appended Text: {chunk.Choices[0].Delta.Content}"); // Debug appended text } else { Console.WriteLine("No content in this chunk."); } } catch (JsonSerializationException ex) { Console.WriteLine($"Deserialization error: {ex.Message}"); } } } Console.WriteLine("Final streamed content:"); Console.WriteLine(streamedHtmlContent); return streamedHtmlContent; } } }