DeutschLernen/GermanApp/Presentation/Controllers/MistralController.cs
Lasse Rune Hansen 769c63b005
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
feat(backend/ai-services): Complete AI Services Phase 0-4 implementation
- Add Domain interfaces: IMistralService, IVoskService, ITtsService
- Add Configuration classes: VoskConfig, CoquiConfig
- Add Application service: MistralService (text generation with Mistral)
- Add Infrastructure services: VoskService (speech recognition), TtsService (TTS)
- Add Presentation controllers: MistralController, SpeechController, TtsController
- Fix MistralService to use correct IMistralConnector methods (CompleteAsync, ChatAsync)
- Fix TtsController to use record constructor syntax
- Fix TtsService Task.FromResult type specification
- Fix Program.cs service registration and remove merge conflict markers
- Update docs/features/ai-services.md with progress (Phases 0-4 complete)
- Update docs/ROADMAP.md with AI Services status and test metrics (296 tests)

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-13 10:09:19 +02:00

216 lines
6.3 KiB
C#

using GermanApp.Domain.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace GermanApp.Presentation.Controllers;
/// <summary>
/// API controller for Mistral AI text generation.
/// This is part of the Presentation layer.
/// </summary>
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class MistralController : ControllerBase
{
private readonly IMistralService _mistralService;
public MistralController(IMistralService mistralService)
{
_mistralService = mistralService;
}
/// <summary>
/// Generates text from a prompt.
/// </summary>
/// <param name="request">Text generation request</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>Generated text</returns>
[HttpPost("generate")]
public async Task<IActionResult> GenerateText(
[FromBody] TextGenerationRequest request,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(request.Prompt))
return BadRequest("Prompt is required");
try
{
var result = await _mistralService.GenerateTextAsync(
request.Prompt,
request.Model,
request.Temperature,
request.MaxTokens,
cancellationToken);
return Ok(new TextGenerationResponse(result));
}
catch (Exception ex)
{
return StatusCode(500, new { Error = ex.Message });
}
}
/// <summary>
/// Generates text from chat messages.
/// </summary>
/// <param name="request">Chat generation request</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>Generated text</returns>
[HttpPost("chat")]
public async Task<IActionResult> GenerateChat(
[FromBody] ChatGenerationRequest request,
CancellationToken cancellationToken = default)
{
if (request.Messages == null || request.Messages.Count == 0)
return BadRequest("Messages are required");
try
{
var result = await _mistralService.GenerateChatAsync(
request.Messages,
request.Model,
request.Temperature,
request.MaxTokens,
cancellationToken);
return Ok(new TextGenerationResponse(result));
}
catch (Exception ex)
{
return StatusCode(500, new { Error = ex.Message });
}
}
/// <summary>
/// Generates a story based on lesson context.
/// </summary>
/// <param name="request">Story generation request</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>Generated story</returns>
[HttpPost("story")]
public async Task<IActionResult> GenerateStory(
[FromBody] StoryGenerationRequest request,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(request.Level))
return BadRequest("Level is required");
try
{
var result = await _mistralService.GenerateStoryAsync(
request.Level,
request.Topic ?? string.Empty,
request.VocabularyWords ?? new List<string>(),
request.Length,
cancellationToken);
return Ok(new StoryGenerationResponse(result));
}
catch (Exception ex)
{
return StatusCode(500, new { Error = ex.Message });
}
}
/// <summary>
/// Provides feedback on user writing.
/// </summary>
/// <param name="request">Writing feedback request</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>Generated feedback</returns>
[HttpPost("writing-feedback")]
public async Task<IActionResult> GenerateWritingFeedback(
[FromBody] WritingFeedbackRequest request,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(request.UserText))
return BadRequest("User text is required");
if (string.IsNullOrWhiteSpace(request.Level))
return BadRequest("Level is required");
try
{
var result = await _mistralService.GenerateWritingFeedbackAsync(
request.UserText,
request.Level,
request.Prompt,
cancellationToken);
return Ok(new WritingFeedbackResponse(result));
}
catch (Exception ex)
{
return StatusCode(500, new { Error = ex.Message });
}
}
/// <summary>
/// Tests the Mistral API connection.
/// </summary>
/// <returns>Health check result</returns>
[HttpGet("health")]
[AllowAnonymous]
public async Task<IActionResult> HealthCheck(CancellationToken cancellationToken = default)
{
try
{
var isHealthy = await _mistralService.TestConnectionAsync(cancellationToken);
return Ok(new { Healthy = isHealthy });
}
catch (Exception ex)
{
return StatusCode(500, new { Error = ex.Message });
}
}
}
/// <summary>
/// Request DTO for text generation.
/// </summary>
public record TextGenerationRequest(
string Prompt,
string? Model = null,
float Temperature = 0.7f,
int? MaxTokens = null);
/// <summary>
/// Request DTO for chat generation.
/// </summary>
public record ChatGenerationRequest(
IReadOnlyList<(string Role, string Content)> Messages,
string? Model = null,
float Temperature = 0.7f,
int? MaxTokens = null);
/// <summary>
/// Request DTO for story generation.
/// </summary>
public record StoryGenerationRequest(
string Level,
string? Topic = null,
IReadOnlyList<string>? VocabularyWords = null,
int Length = 200);
/// <summary>
/// Request DTO for writing feedback.
/// </summary>
public record WritingFeedbackRequest(
string UserText,
string Level,
string? Prompt = null);
/// <summary>
/// Response DTO for text generation.
/// </summary>
public record TextGenerationResponse(string Text);
/// <summary>
/// Response DTO for story generation.
/// </summary>
public record StoryGenerationResponse(string Story);
/// <summary>
/// Response DTO for writing feedback.
/// </summary>
public record WritingFeedbackResponse(string Feedback);