generated from fahricansecer/boilerplate-be
This commit is contained in:
99
media-worker/Services/TtsService.cs
Normal file
99
media-worker/Services/TtsService.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// ElevenLabs TTS API Client — Metin → Ses dönüşümü.
|
||||
/// Her sahnenin narrationText'ini sese çevirir.
|
||||
/// </summary>
|
||||
public class TtsService
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ILogger<TtsService> _logger;
|
||||
private readonly ApiSettings _settings;
|
||||
|
||||
public TtsService(
|
||||
HttpClient httpClient,
|
||||
ILogger<TtsService> logger,
|
||||
IOptions<ApiSettings> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bir sahnenin narration metnini sese çevirir ve dosyaya kaydeder.
|
||||
/// </summary>
|
||||
public async Task<GeneratedMediaFile> 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"
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user