using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace AiAgent.Core.Infrastructure
{
///
/// A client for interacting with the x.ai (Grok) API.
///
public class GrokClient
{
private readonly HttpClient _httpClient;
private const string ApiUrl = "https://api.x.ai/v1/chat/completions";
///
/// Initializes a new instance of the GrokClient.
///
/// Your x.ai API key.
public GrokClient(string apiKey)
{
_httpClient = new HttpClient();
_httpClient.Timeout = TimeSpan.FromMinutes(60);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
_httpClient.DefaultRequestHeaders.Add("User-Agent", "NewAI/1.0"); // Optional, but helps
}
public static async Task Query(string prompt)
{
var apiKey = "xai-AR8626vr2xOffBhsnhs3vKXGPePi9h4JDRhOshRUGYOU2lEuuyXAtGO5iiHINVUf96qODKZlaX9FSxJW";
var client = new GrokClient(apiKey);
return await client.GetChatCompletionAsync(prompt);
}
///
/// Sends a prompt to the Grok API and gets a response.
///
/// The user's question or prompt.
/// The content of the AI's response, or an error message.
public async Task GetChatCompletionAsync(string prompt)
{
var requestBody = new GrokRequest
{
messages = new List
{
new GrokMessage { role = "user", content = prompt }
},
model = "grok-4-fast-reasoning", // "grok-4-0709", //
stream = false,
temperature = 0.0
};
//try
//{
var jsonRequest = JsonSerializer.Serialize(requestBody).Replace("\\r", "");
var grokRequestLogFile = Path.Combine("Archive", "grok_request.json");
File.WriteAllText(grokRequestLogFile, jsonRequest + Environment.NewLine);
var content = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
try
{
var response = await _httpClient.PostAsync(ApiUrl, content);
if (response.IsSuccessStatusCode)
{
var jsonResponse = await response.Content.ReadAsStringAsync();
var grokResponse = JsonSerializer.Deserialize(jsonResponse);
File.WriteAllText(grokRequestLogFile, jsonResponse + Environment.NewLine);
string metadataLogFile = grokRequestLogFile + ".csv";
if (!File.Exists(metadataLogFile))
File.WriteAllText(metadataLogFile, "Timestamp,Model,PromptTokens,CompletionTokens,TotalTokens,ReasoningTokens,SystemFingerprint" + Environment.NewLine);
File.AppendAllText(metadataLogFile,
$"{DateTime.Now}," +
$"{grokResponse.Model}," +
$"{grokResponse.Usage.PromptTokens}," +
$"{grokResponse.Usage.CompletionTokens}," +
$"{grokResponse.Usage.TotalTokens}," +
$"{grokResponse.Usage.CompletionTokensDetails.ReasoningTokens}," +
$"{grokResponse.SystemFingerprint}{Environment.NewLine}");
return grokResponse?.Choices?.FirstOrDefault()?.Message?.Content ?? "No content received.";
}
else
{
var errorContent = await response.Content.ReadAsStringAsync();
return $"Error: {response.StatusCode} - {errorContent}";
}
// Rest of your logic
}
catch (HttpRequestException ex)
{
Console.WriteLine($"HttpRequestException: {ex.Message}");
if (ex.InnerException != null)
{
Console.WriteLine($"Inner Exception: {ex.InnerException.GetType().Name} - {ex.InnerException.Message}");
}
throw; // Re-throw to see if it crashes your app
}
//}
//catch (Exception ex)
//{
// return $"An exception occurred: {ex.Message}";
//}
}
}
public class GrokMessage
{
public string role { get; set; }
public string content { get; set; }
}
public class GrokRequest
{
public List messages { get; set; }
public string model { get; set; }
public bool stream { get; set; }
public double temperature { get; set; }
}
public class GrokChoice
{
public GrokMessage message { get; set; }
}
public class GrokResponse
{
[JsonPropertyName("id")]
public string Id { get; set; }
[JsonPropertyName("object")] // "object" is a C# keyword, so the attribute is required
public string ObjectType { get; set; }
[JsonPropertyName("created")]
public long Created { get; set; } // Unix timestamp
[JsonPropertyName("model")]
public string Model { get; set; }
[JsonPropertyName("choices")]
public List Choices { get; set; }
[JsonPropertyName("usage")]
public Usage Usage { get; set; }
[JsonPropertyName("system_fingerprint")]
public string SystemFingerprint { get; set; }
}
public class Choice
{
[JsonPropertyName("index")]
public int Index { get; set; }
[JsonPropertyName("message")]
public Message Message { get; set; }
[JsonPropertyName("finish_reason")]
public string FinishReason { get; set; }
}
public class Message
{
[JsonPropertyName("role")]
public string Role { get; set; }
[JsonPropertyName("content")]
public string Content { get; set; }
}
public class Usage
{
[JsonPropertyName("prompt_tokens")]
public int PromptTokens { get; set; }
[JsonPropertyName("completion_tokens")]
public int CompletionTokens { get; set; }
[JsonPropertyName("total_tokens")]
public int TotalTokens { get; set; }
// Add this property
[JsonPropertyName("prompt_tokens_details")]
public PromptTokensDetails PromptTokensDetails { get; set; }
// And add this property
[JsonPropertyName("completion_tokens_details")]
public CompletionTokensDetails CompletionTokensDetails { get; set; }
[JsonPropertyName("num_sources_used")]
public int NumSourcesUsed { get; set; }
}
public class PromptTokensDetails
{
[JsonPropertyName("text_tokens")]
public int TextTokens { get; set; }
[JsonPropertyName("cached_tokens")]
public int CachedTokens { get; set; }
}
public class CompletionTokensDetails
{
[JsonPropertyName("reasoning_tokens")]
public int ReasoningTokens { get; set; }
}
}