using System.Text.Json.Serialization;
using GermanApp.Domain.Interfaces;
namespace GermanApp.Application.Models;
///
/// Response model for Mistral completion and chat completion APIs.
///
///
/// See: https://docs.mistral.ai/api/#operation/createCompletion
/// See: https://docs.mistral.ai/api/#operation/createChatCompletion
///
public record MistralResponse
{
///
/// Unique identifier for the completion.
///
[JsonPropertyName("id")]
public string Id { get; init; } = string.Empty;
///
/// The object type (always "text_completion" or "chat.completion").
///
[JsonPropertyName("object")]
public string Object { get; init; } = string.Empty;
///
/// The Unix timestamp (in seconds) of when the completion was created.
///
[JsonPropertyName("created")]
public long Created { get; init; }
///
/// The model used for the completion.
///
[JsonPropertyName("model")]
public string Model { get; init; } = string.Empty;
///
/// The list of completion choices generated by the model.
///
[JsonPropertyName("choices")]
public IReadOnlyList Choices { get; init; } = new List();
///
/// Usage statistics for the completion.
///
[JsonPropertyName("usage")]
public MistralUsage Usage { get; init; } = new();
///
/// Gets the first choice's text content.
/// Convenience property for single-completion requests.
///
[JsonIgnore]
public string FirstChoiceText => Choices.Count > 0 ? Choices[0].Text : string.Empty;
///
/// Gets the first choice's message content (for chat completions).
///
[JsonIgnore]
public string FirstChoiceMessageContent =>
Choices.Count > 0 && Choices[0].Message != null
? Choices[0].Message.Content
: string.Empty;
///
/// Gets all generated texts from all choices.
///
[JsonIgnore]
public IReadOnlyList AllChoiceTexts => Choices.Select(c => c.Text).ToList();
///
/// Checks if the response contains any valid completions.
///
[JsonIgnore]
public bool HasValidChoices => Choices != null && Choices.Count > 0 &&
Choices.Any(c => !string.IsNullOrWhiteSpace(c.Text) || c.Message != null);
}
///
/// A single completion choice returned by Mistral API.
///
public record MistralChoice
{
///
/// The generated text for this choice.
///
[JsonPropertyName("text")]
public string Text { get; init; } = string.Empty;
///
/// For chat completions, this contains the message object.
///
[JsonPropertyName("message")]
public MistralChatMessage? Message { get; init; }
///
/// The reason the model stopped generating tokens (e.g., "stop", "length", "error").
///
[JsonPropertyName("finish_reason")]
public string FinishReason { get; init; } = string.Empty;
///
/// The index of this choice in the list of choices.
///
[JsonPropertyName("index")]
public int Index { get; init; }
///
/// Log probability information for the generated tokens.
///
[JsonPropertyName("logprobs")]
public object? LogProbs { get; init; }
}
///
/// Message object returned in chat completion choices.
///
public record MistralChatMessage
{
///
/// The role of the message author.
///
[JsonPropertyName("role")]
public string Role { get; init; } = string.Empty;
///
/// The content of the message.
///
[JsonPropertyName("content")]
public string Content { get; init; } = string.Empty;
}
///
/// Token usage statistics from Mistral API.
///
public record MistralUsage
{
///
/// Number of tokens in the prompt.
///
[JsonPropertyName("prompt_tokens")]
public int PromptTokens { get; init; }
///
/// Number of tokens generated in the completion.
///
[JsonPropertyName("completion_tokens")]
public int CompletionTokens { get; init; }
///
/// Total number of tokens used (prompt + completion).
///
[JsonPropertyName("total_tokens")]
public int TotalTokens { get; init; }
///
/// Gets the total cost estimate based on token usage.
/// Note: Actual pricing may vary based on Mistral's pricing model.
///
[JsonIgnore]
public decimal EstimatedCost => TotalTokens * 0.0000025m; // Approx $0.0000025 per token for mistral-medium
}
///
/// Error response from Mistral API.
///
public record MistralErrorResponse
{
///
/// The object type (always "error").
///
[JsonPropertyName("object")]
public string Object { get; init; } = string.Empty;
///
/// The error message.
///
[JsonPropertyName("message")]
public string Message { get; init; } = string.Empty;
///
/// The type of error that occurred.
///
[JsonPropertyName("type")]
public string Type { get; init; } = string.Empty;
///
/// The HTTP status code associated with the error.
///
[JsonIgnore]
public int? StatusCode { get; init; }
///
/// Additional error details.
///
[JsonPropertyName("details")]
public object? Details { get; init; }
///
/// Maps the error type to an AiErrorCode.
///
[JsonIgnore]
public AiErrorCode ErrorCode => Type switch
{
"rate_limit_exceeded" or "rate_limit" => AiErrorCode.RateLimited,
"invalid_request_error" => AiErrorCode.InvalidRequest,
"authentication_error" or "invalid_api_key" => AiErrorCode.AuthenticationError,
"server_error" or "internal_server_error" => AiErrorCode.Temporary,
"timeout" => AiErrorCode.Timeout,
_ => AiErrorCode.Unknown
};
}
///
/// Response wrapper for listing Mistral models.
///
public record MistralListModelsResponse
{
///
/// The object type (always "list").
///
[JsonPropertyName("object")]
public string Object { get; init; } = string.Empty;
///
/// List of available models.
///
[JsonPropertyName("data")]
public IReadOnlyList Data { get; init; } = new List();
}