generated from fahricansecer/boilerplate-be
@@ -128,8 +128,9 @@ public class FFmpegService
|
|||||||
var concatenatedPath = Path.Combine(outputDirectory, "concatenated.mp4");
|
var concatenatedPath = Path.Combine(outputDirectory, "concatenated.mp4");
|
||||||
var concatArgs = new StringBuilder();
|
var concatArgs = new StringBuilder();
|
||||||
concatArgs.Append($"-y -f concat -safe 0 -i \"{concatListPath}\" ");
|
concatArgs.Append($"-y -f concat -safe 0 -i \"{concatListPath}\" ");
|
||||||
concatArgs.Append("-c:v libx264 -preset fast -crf 22 ");
|
// OPTIMIZASYON: libx264 yerine Stream Copy (Hardware Acceleration'a gerek kalmadan saniyeler sürer)
|
||||||
concatArgs.Append("-c:a aac -b:a 128k ");
|
concatArgs.Append("-c:v copy ");
|
||||||
|
concatArgs.Append("-c:a copy ");
|
||||||
concatArgs.Append("-movflags +faststart ");
|
concatArgs.Append("-movflags +faststart ");
|
||||||
concatArgs.Append($"\"{concatenatedPath}\"");
|
concatArgs.Append($"\"{concatenatedPath}\"");
|
||||||
|
|
||||||
|
|||||||
@@ -93,21 +93,25 @@ public class VideoRenderPipeline
|
|||||||
_logger.LogInformation("🎙️ Adım 2/5: TTS narration üretimi");
|
_logger.LogInformation("🎙️ Adım 2/5: TTS narration üretimi");
|
||||||
|
|
||||||
var voiceStyle = job.ScriptJson?.VoiceStyle ?? "Deep authoritative male voice";
|
var voiceStyle = job.ScriptJson?.VoiceStyle ?? "Deep authoritative male voice";
|
||||||
var ttsTasks = new List<Task<GeneratedMediaFile>>();
|
var ttsResults = new List<GeneratedMediaFile>();
|
||||||
|
|
||||||
foreach (var scene in scenes)
|
foreach (var scene in scenes)
|
||||||
{
|
{
|
||||||
ttsTasks.Add(GenerateTtsWithProgress(
|
var result = await GenerateTtsWithProgress(
|
||||||
scene, projectDir, voiceStyle,
|
scene, projectDir, voiceStyle,
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
completedSteps++;
|
completedSteps++;
|
||||||
var progress = (int)(completedSteps / (double)totalSteps * 40); // TTS %0-40
|
var progress = (int)(completedSteps / (double)totalSteps * 40); // TTS %0-40
|
||||||
return progressCallback(progress, "TTS_GENERATION");
|
return progressCallback(progress, "TTS_GENERATION");
|
||||||
}, ct));
|
}, ct);
|
||||||
|
|
||||||
|
ttsResults.Add(result);
|
||||||
|
|
||||||
|
// Rate limit (429 Too Many Requests) yememek için sahneler arası 1 saniye bekle
|
||||||
|
await Task.Delay(1000, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
var ttsResults = await Task.WhenAll(ttsTasks);
|
|
||||||
allMediaFiles.AddRange(ttsResults);
|
allMediaFiles.AddRange(ttsResults);
|
||||||
|
|
||||||
// ═══════════════════════════════════════
|
// ═══════════════════════════════════════
|
||||||
@@ -273,7 +277,15 @@ public class VideoRenderPipeline
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(scene.TtsProvider) && scene.TtsProvider.Equals("openai", StringComparison.OrdinalIgnoreCase))
|
if (!string.IsNullOrEmpty(scene.TtsProvider) && scene.TtsProvider.Equals("openai", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
result = await _openAiTts.GenerateNarrationAsync(scene, outputDir, voiceStyle, ct);
|
try
|
||||||
|
{
|
||||||
|
result = await _openAiTts.GenerateNarrationAsync(scene, outputDir, voiceStyle, ct);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "OpenAI TTS başarısız (Muhtemelen 429 Rate Limit/Quota). Voicebox'a fallback yapılıyor.");
|
||||||
|
result = await _voiceboxTts.GenerateNarrationAsync(scene, outputDir, voiceStyle, ct);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrEmpty(scene.TtsProvider) && scene.TtsProvider.Equals("minimax", StringComparison.OrdinalIgnoreCase))
|
else if (!string.IsNullOrEmpty(scene.TtsProvider) && scene.TtsProvider.Equals("minimax", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,15 +46,52 @@ public class VoiceboxTtsService
|
|||||||
scene.Order,
|
scene.Order,
|
||||||
scene.NarrationText[..Math.Min(60, scene.NarrationText.Length)]);
|
scene.NarrationText[..Math.Min(60, scene.NarrationText.Length)]);
|
||||||
|
|
||||||
// VoiceBox'ta varsayılan bir profil (Örn: Kokoro default)
|
// 1. Voicebox profillerini çek ve uygun bir profil ID bul
|
||||||
var profileId = string.IsNullOrWhiteSpace(voiceStyle) ? "b6a8a474-0fc0-4a8f-b9f1-a1e4c84a8649" : voiceStyle;
|
string profileId = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var profilesResponse = await _httpClient.GetAsync("profiles", ct);
|
||||||
|
if (profilesResponse.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var profilesStr = await profilesResponse.Content.ReadAsStringAsync(ct);
|
||||||
|
using var profilesDoc = JsonDocument.Parse(profilesStr);
|
||||||
|
if (profilesDoc.RootElement.ValueKind == JsonValueKind.Array)
|
||||||
|
{
|
||||||
|
foreach (var profile in profilesDoc.RootElement.EnumerateArray())
|
||||||
|
{
|
||||||
|
var lang = profile.GetProperty("language").GetString();
|
||||||
|
var id = profile.GetProperty("id").GetString();
|
||||||
|
// Türkçe profil öncelikli
|
||||||
|
if (lang != null && lang.StartsWith("tr") && !string.IsNullOrEmpty(id))
|
||||||
|
{
|
||||||
|
profileId = id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (string.IsNullOrEmpty(profileId) && !string.IsNullOrEmpty(id))
|
||||||
|
{
|
||||||
|
profileId = id; // İlk bulduğunu yedek olarak tut
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Voicebox profilleri çekilirken hata oluştu.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eğer hiçbir profil bulamazsak, hardcoded bir fallback (Voicebox'un ilk kurulumunda eklediği rastgele GUID değildir umarım)
|
||||||
|
if (string.IsNullOrEmpty(profileId))
|
||||||
|
{
|
||||||
|
profileId = "b6a8a474-0fc0-4a8f-b9f1-a1e4c84a8649";
|
||||||
|
}
|
||||||
|
|
||||||
var requestBody = new
|
var requestBody = new
|
||||||
{
|
{
|
||||||
text = scene.NarrationText,
|
text = scene.NarrationText,
|
||||||
profile_id = profileId,
|
profile_id = profileId,
|
||||||
language = "tr",
|
language = "tr",
|
||||||
engine = "kokoro"
|
engine = "edge_tts" // Türkçe için en stabil olan edge_tts
|
||||||
};
|
};
|
||||||
|
|
||||||
var content = new StringContent(
|
var content = new StringContent(
|
||||||
|
|||||||
Reference in New Issue
Block a user