using System.Net.Http.Headers; using System.Text; using System.Text.Json; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using SaasMediaWorker.Configuration; using SaasMediaWorker.Models; namespace SaasMediaWorker.Services; /// /// ElevenLabs TTS API Client — Metin → Ses dönüşümü. /// Her sahnenin narrationText'ini sese çevirir. /// public class TtsService { private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly ApiSettings _settings; public TtsService( HttpClient httpClient, ILogger logger, IOptions settings) { _httpClient = httpClient; _logger = logger; _settings = settings.Value; _httpClient.BaseAddress = new Uri(_settings.TtsBaseUrl); _httpClient.DefaultRequestHeaders.Add("xi-api-key", _settings.TtsApiKey); _httpClient.Timeout = TimeSpan.FromMinutes(2); } /// /// Bir sahnenin narration metnini sese çevirir ve dosyaya kaydeder. /// public async Task GenerateNarrationAsync( ScenePayload scene, string outputDirectory, string voiceStyle, CancellationToken ct) { _logger.LogInformation( "🎙️ TTS üretimi — Sahne {Order}: \"{Text}\"", scene.Order, scene.NarrationText[..Math.Min(60, scene.NarrationText.Length)]); var voiceId = _settings.TtsVoiceId; var requestBody = new { text = scene.NarrationText, model_id = "eleven_multilingual_v2", voice_settings = new { stability = 0.5, similarity_boost = 0.75, style = 0.3, use_speaker_boost = true } }; var content = new StringContent( JsonSerializer.Serialize(requestBody), Encoding.UTF8, "application/json"); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var response = await _httpClient.PostAsync( $"/text-to-speech/{voiceId}", content, ct); response.EnsureSuccessStatusCode(); // Ses dosyasını kaydet var outputPath = Path.Combine(outputDirectory, $"scene_{scene.Order:D2}_narration.mp3"); await using var fileStream = File.Create(outputPath); await response.Content.CopyToAsync(fileStream, ct); var fileInfo = new FileInfo(outputPath); _logger.LogInformation( "TTS tamamlandı — Sahne {Order}: {Size} bytes", scene.Order, fileInfo.Length); return new GeneratedMediaFile { SceneId = scene.Id, SceneOrder = scene.Order, Type = MediaFileType.AudioNarration, LocalPath = outputPath, FileSizeBytes = fileInfo.Length, DurationSeconds = scene.Duration, MimeType = "audio/mpeg", AiProvider = "elevenlabs" }; } }