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(); }