From 518d1c8f2727f91bc915d8bdca74d4d3bea4dfee Mon Sep 17 00:00:00 2001 From: Mistral Vibe Date: Sat, 13 Jun 2026 14:47:32 +0200 Subject: [PATCH] feat(backend/story-integration): Phase 5 - Audio Generation - Fixed audio file path generation in StoryGenerationService.GenerateAudioAsync - Audio files now stored at wwwroot/audio/story/level{id}-segment{order}.wav - Added static file serving in Program.cs (app.UseStaticFiles) - Added wwwroot/audio/story directory creation on startup - Updated StoryController.GetSegmentAudioAsync to return audio URL - Static file middleware serves audio files automatically - All 324 tests still pass Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe --- .../Services/StoryGenerationService.cs | 22 ++++++++++++------- .../Controllers/StoryController.cs | 5 +++-- GermanApp/Program.cs | 7 ++++++ docs/features/story-integration.md | 17 +++++++------- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/GermanApp/Application/Services/StoryGenerationService.cs b/GermanApp/Application/Services/StoryGenerationService.cs index 09234b9..d20f065 100644 --- a/GermanApp/Application/Services/StoryGenerationService.cs +++ b/GermanApp/Application/Services/StoryGenerationService.cs @@ -227,25 +227,31 @@ public class StoryGenerationService return StorySegmentDto.FromEntity(segment); } - // Generate audio file path - var audioPath = $"/audio/story/level{segment.LevelId}-segment{segment.Order}.wav"; + // Generate file system path for audio file (relative to current directory) + var audioDirectory = Path.Combine("wwwroot", "audio", "story"); + var filename = $"level{segment.LevelId}-segment{segment.Order}.wav"; + var audioFilePath = Path.Combine(audioDirectory, filename); try { - // Generate audio using the TTS service directly + // Ensure directory exists + Directory.CreateDirectory(audioDirectory); + + // Generate audio using the TTS service await _ttsService.GenerateAudioToFileAsync( segment.Content, - audioPath, + audioFilePath, null, "de", cancellationToken); - // Update segment with audio URL - segment.UpdateAudioUrl(audioPath); + // Convert to URL path for storage + var audioUrl = $"/audio/story/{filename}"; + segment.UpdateAudioUrl(audioUrl); await _storyRepository.UpdateAsync(segment, cancellationToken); - _logger.LogInformation("Generated audio for segment {SegmentId}: {AudioPath}", - segmentId, audioPath); + _logger.LogInformation("Generated audio for segment {SegmentId}: {AudioUrl}", + segmentId, audioUrl); return StorySegmentDto.FromEntity(segment); } diff --git a/GermanApp/Presentation/Controllers/StoryController.cs b/GermanApp/Presentation/Controllers/StoryController.cs index bda01d4..8c6d4b8 100644 --- a/GermanApp/Presentation/Controllers/StoryController.cs +++ b/GermanApp/Presentation/Controllers/StoryController.cs @@ -411,8 +411,9 @@ public class StoryController : ControllerBase return NotFound(); } - // In a real implementation, return the actual file - // For now, return the URL + // Static files are served from wwwroot, and audio files are stored at wwwroot/audio/story/ + // The segment.AudioUrl is already in the format "/audio/story/levelN-segmentM.wav" + // The static file middleware will serve it automatically return Ok(new { AudioUrl = segment.AudioUrl }); } diff --git a/GermanApp/Program.cs b/GermanApp/Program.cs index 0346908..a6b2ef2 100644 --- a/GermanApp/Program.cs +++ b/GermanApp/Program.cs @@ -22,6 +22,7 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Serilog; +using System.IO; using System.Text; // Configure Serilog @@ -218,11 +219,17 @@ try var app = builder.Build(); + // Create static file directories + Directory.CreateDirectory(Path.Combine("wwwroot", "audio", "story")); + // Configure the HTTP request pipeline. // Use exception middleware first (to catch all exceptions) app.UseExceptionMiddleware(); + // Serve static files (audio, etc.) + app.UseStaticFiles(); + if (app.Environment.IsDevelopment()) { app.MapOpenApi(); diff --git a/docs/features/story-integration.md b/docs/features/story-integration.md index b9bdd38..f7e8426 100644 --- a/docs/features/story-integration.md +++ b/docs/features/story-integration.md @@ -1,7 +1,7 @@ # Feature: Story Integration > **Status**: 🚀 In Progress -> **📊 Current Progress**: Phase 1-4 ✅ Complete (Database & Models, Backend Services, Unit Tests, AI Integration), Phase 5 Next (Audio Generation) +> **📊 Current Progress**: Phase 1-5 ✅ Complete (Database & Models, Backend Services, Unit Tests, AI Integration, Audio Generation), Phase 6 Next (Frontend Integration) > **Priority**: High > **Complexity**: High > **Estimate**: 8-12 hours @@ -165,12 +165,12 @@ Order: 1 - [x] Handle AI API errors gracefully (AiServiceException with error codes) - [x] Add retry logic for failed generations (ExecuteWithRetryAsync with exponential backoff) -### Phase 5: Audio Generation (2 hours) -- [ ] Integrate with Coqui TTS service -- [ ] Generate audio for each story segment -- [ ] Store audio files with consistent naming -- [ ] Update StorySegment.AudioUrl after generation -- [ ] Add audio file serving endpoint +### Phase 5: Audio Generation (2 hours) - COMPLETE +- [x] Integrate with Coqui TTS service (ITtsService, TtsService with CoquiConfig) +- [x] Generate audio for each story segment (GenerateAudioAsync in StoryGenerationService) +- [x] Store audio files with consistent naming (wwwroot/audio/story/level{id}-segment{order}.wav) +- [x] Update StorySegment.AudioUrl after generation (segment.UpdateAudioUrl) +- [x] Add audio file serving endpoint (UseStaticFiles + GET segments/{id}/audio) ### Phase 5: Frontend Integration (2-3 hours) - [ ] Create StoryPage component @@ -194,7 +194,7 @@ Order: 1 | Backend Services | June 13, 2025 | ✅ | | Unit Tests | June 13, 2025 | ✅ | | AI Integration | June 13, 2025 | ✅ | -| Audio Generation | - | ⏳ | +| Audio Generation | June 13, 2025 | ✅ | | Frontend Integration | - | ⏳ | | User Progress | - | ⏳ | @@ -417,6 +417,7 @@ Make the story engaging and suitable for adult learners. | June 13, 2025 | Phase 1-2 Complete | Database & Models, Backend Services implemented | | June 13, 2025 | Phase 3 Complete | All unit tests written and passing (324 tests) | | June 13, 2025 | Phase 4 Complete | Enhanced prompts with CEFR-level-specific requirements for story generation | +| June 13, 2025 | Phase 5 Complete | Audio generation with Coqui TTS, static file serving, and endpoints | ---