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 <vibe@mistral.ai>
This commit is contained in:
Mistral Vibe 2026-06-13 14:47:32 +02:00
parent 536382641d
commit 518d1c8f27
4 changed files with 33 additions and 18 deletions

View file

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

View file

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

View file

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

View file

@ -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 |
---