DeutschLernen/GermanApp/Application/Models/MistralRequest.cs
Lasse Rune Hansen aa3db295ce fix(backend): Fix Mistral story generation with proper chat completion format
- Update MistralChatRequest to remove unused properties (User, Stop, FrequencyPenalty, PresencePenalty) causing 422 errors
- Add explicit JsonPropertyName attributes to ensure correct JSON serialization
- Update MistralService to send minimal requests matching Mistral API expectations
- Pass SegmentCount and CustomPrompt through StoryGenerationService to build proper prompts
- Add request logging in MistralConnector to debug API calls
- Update default model to mistral-small-latest
- Enhance error handling to log raw JSON responses

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-18 15:21:04 +02:00

206 lines
6.1 KiB
C#

using System.Text.Json.Serialization;
namespace GermanApp.Application.Models;
/// <summary>
/// Request model for Mistral completion API.
/// Used for text generation (stories, feedback, etc.).
/// </summary>
/// <remarks>
/// See: https://docs.mistral.ai/api/#operation/createCompletion
/// </remarks>
public record MistralRequest
{
/// <summary>
/// ID of the model to use.
/// </summary>
public string Model { get; init; } = "mistral-medium";
/// <summary>
/// The prompt(s) to generate completions for.
/// </summary>
public string Prompt { get; init; } = string.Empty;
/// <summary>
/// The maximum number of tokens to generate in the completion.
/// Default: 256, Max: 2048 for mistral-medium
/// </summary>
public int? MaxTokens { get; init; } = 512;
/// <summary>
/// What sampling temperature to use.
/// Higher values means the model will take more risks. Try 0.9 for more creative applications, and 0 for ones with a well-defined answer.
/// Default: 0.7
/// </summary>
public double? Temperature { get; init; } = 0.7;
/// <summary>
/// Nucleus sampling, where the model considers the results of the tokens with top_p probability mass.
/// So 0.1 means only the tokens comprising the top 10% probability mass are considered.
/// Default: 1.0
/// </summary>
public double? TopP { get; init; } = 1.0;
/// <summary>
/// How many completions to generate for each prompt.
/// Default: 1
/// </summary>
public int? N { get; init; } = 1;
/// <summary>
/// Whether to stream partial responses.
/// Not supported by this connector (use streaming endpoint separately if needed).
/// </summary>
public bool? Stream { get; init; } = false;
/// <summary>
/// Whether to echo the prompt in the response.
/// Default: false
/// </summary>
public bool? Echo { get; init; } = false;
/// <summary>
/// Up to 4 sequences where the API will stop generating further tokens.
/// </summary>
public IReadOnlyList<string>? Stop { get; init; }
/// <summary>
/// Number between -2.0 and 2.0. Positive values penalize new tokens based on their frequency in the text so far.
/// </summary>
public double? FrequencyPenalty { get; init; }
/// <summary>
/// Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far.
/// </summary>
public double? PresencePenalty { get; init; }
/// <summary>
/// User identifier for tracking usage.
/// </summary>
public string? User { get; init; }
/// <summary>
/// Factory method to create a completion request with default settings.
/// </summary>
public static MistralRequest CreateCompletion(string prompt, string model = "mistral-medium", int maxTokens = 512)
{
return new MistralRequest
{
Model = model,
Prompt = prompt,
MaxTokens = maxTokens,
Temperature = 0.7,
TopP = 1.0,
N = 1,
Stream = false,
Echo = false
};
}
}
/// <summary>
/// Request model for Mistral chat completion API.
/// Used for conversational text generation.
/// </summary>
/// <remarks>
/// See: https://docs.mistral.ai/api/#operation/createChatCompletion
/// </remarks>
public record MistralChatRequest
{
/// <summary>
/// ID of the model to use.
/// </summary>
[JsonPropertyName("model")]
public string Model { get; init; } = "mistral-small-latest";
/// <summary>
/// A list of messages comprising the conversation so far.
/// </summary>
[JsonPropertyName("messages")]
public IReadOnlyList<MistralMessage> Messages { get; init; } = new List<MistralMessage>();
/// <summary>
/// The maximum number of tokens to generate in the completion.
/// </summary>
[JsonPropertyName("max_tokens")]
public int? MaxTokens { get; init; }
/// <summary>
/// What sampling temperature to use.
/// </summary>
[JsonPropertyName("temperature")]
public double? Temperature { get; init; }
/// <summary>
/// Factory method to create a chat request.
/// </summary>
public static MistralChatRequest CreateChat(IReadOnlyList<MistralMessage> messages, string model = "mistral-small-latest", int maxTokens = 512)
{
return new MistralChatRequest
{
Model = model,
Messages = messages,
MaxTokens = maxTokens,
Temperature = 0.7
};
}
}
/// <summary>
/// Represents a message in a Mistral chat conversation.
/// </summary>
public record MistralMessage
{
/// <summary>
/// The role of the message author.
/// </summary>
[JsonPropertyName("role")]
public string Role { get; init; } = string.Empty;
/// <summary>
/// The content of the message.
/// </summary>
[JsonPropertyName("content")]
public string Content { get; init; } = string.Empty;
/// <summary>
/// Factory method to create a user message.
/// </summary>
public static MistralMessage User(string content) => new() { Role = "user", Content = content };
/// <summary>
/// Factory method to create an assistant message.
/// </summary>
public static MistralMessage Assistant(string content) => new() { Role = "assistant", Content = content };
/// <summary>
/// Factory method to create a system message.
/// </summary>
public static MistralMessage System(string content) => new() { Role = "system", Content = content };
}
/// <summary>
/// Model information from Mistral API.
/// </summary>
public record MistralModel
{
/// <summary>
/// The model identifier.
/// </summary>
public string Id { get; init; } = string.Empty;
/// <summary>
/// The model object type.
/// </summary>
public string Object { get; init; } = string.Empty;
/// <summary>
/// When the model was created.
/// </summary>
public long Created { get; init; }
/// <summary>
/// The model's description.
/// </summary>
public string Description { get; init; } = string.Empty;
}