From a71094cbf59d56bd0744991ca0f8f02fac184535 Mon Sep 17 00:00:00 2001 From: owenchen Date: Tue, 2 Jun 2026 11:15:49 +0800 Subject: [PATCH] ow --- Task/TTS/TtsTask.cs | 28 ++++++---------- Utility/ConsoleHelper.cs | 68 ++++++++++++++++++++++++++++++++++++++ Utility/SherpaLogFilter.cs | 56 +++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 18 deletions(-) create mode 100644 Utility/ConsoleHelper.cs create mode 100644 Utility/SherpaLogFilter.cs diff --git a/Task/TTS/TtsTask.cs b/Task/TTS/TtsTask.cs index eff26db..d8a54a7 100644 --- a/Task/TTS/TtsTask.cs +++ b/Task/TTS/TtsTask.cs @@ -30,6 +30,8 @@ namespace CloudBuilder.Topshelf.Task.TTS public void Run(Dictionary bodyDict) { + ConsoleOutput.HideStdError(); + IRepository repository = service.GetRepository>(); string bookId = string.Empty; @@ -64,13 +66,12 @@ namespace CloudBuilder.Topshelf.Task.TTS .GroupBy(ent => new { ent.BookId, ent.ChapterId }) .ToList(); - int totalLines = chapterGroups.Count(); + int totalLines = ents.Count(); int processedLines = 0; // 已处理行数计数器 + UpdateProgress(processedLines, totalLines); foreach (var chapter in chapterGroups) { - processedLines++; - string bookId = chapter.Key.BookId; int chapterId = chapter.Key.ChapterId; List tempMp3List = new List(); // 本章所有碎片音频 @@ -78,6 +79,8 @@ namespace CloudBuilder.Topshelf.Task.TTS // 2. 生成本章所有句子音频 foreach (AiSentenceViewEntity ent in chapter) { + processedLines++; + string voice = ChineseTtsVoice.Sherpa2.ToString(); if (ent.DialogueIndc == YesNoPolicy.YES) { @@ -102,6 +105,8 @@ namespace CloudBuilder.Topshelf.Task.TTS SaveAudioToFileHelper.AudioToFile(EnumHelper.ToEnum(voice), ent.Content, filePath); tempMp3List.Add(filePath); // 加入合并列表 + + UpdateProgress(processedLines, totalLines); } Thread.Sleep(100); @@ -118,8 +123,6 @@ namespace CloudBuilder.Topshelf.Task.TTS try { File.Delete(chunk); } catch { } } - Console.WriteLine($"章节合并完成:{outputFileName}"); - UpdateProgress(processedLines, totalLines); } } @@ -166,22 +169,11 @@ namespace CloudBuilder.Topshelf.Task.TTS } } - Console.WriteLine($"✅ 合并成功:{outputFilePath},大小:{new FileInfo(outputFilePath).Length} 字节"); + //Console.WriteLine($"✅ 合并成功:{outputFilePath},大小:{new FileInfo(outputFilePath).Length} 字节"); } catch (Exception ex) { - Console.WriteLine($"❌ 合并失败:{ex.Message}"); - } - } - - // 辅助方法:WAV 转 MP3 - private void WaveFileToMp3(byte[] wavData, string mp3Path) - { - using (var ms = new MemoryStream(wavData)) - using (var waveReader = new WaveFileReader(ms)) - using (var mp3Writer = new LameMP3FileWriter(mp3Path, waveReader.WaveFormat, 128)) - { - waveReader.CopyTo(mp3Writer); + //Console.WriteLine($"❌ 合并失败:{ex.Message}"); } } diff --git a/Utility/ConsoleHelper.cs b/Utility/ConsoleHelper.cs new file mode 100644 index 0000000..2b01adf --- /dev/null +++ b/Utility/ConsoleHelper.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Topshelf.Utility +{ + // 先把这个类放到你的代码文件里 + public static class ConsoleHelper + { + [DllImport("kernel32.dll")] + static extern IntPtr GetStdHandle(int nStdHandle); + + [DllImport("kernel32.dll")] + static extern int SetStdHandle(int nStdHandle, IntPtr hHandle); + + const int STD_OUTPUT_HANDLE = -11; + const int STD_ERROR_HANDLE = -12; + + /// + /// 屏蔽所有底层C++输出(彻底隐藏 SherpaOnnx 日志) + /// + public static void DisableConsoleOutput() + { + var nullHandle = IntPtr.Zero; + SetStdHandle(STD_OUTPUT_HANDLE, nullHandle); + SetStdHandle(STD_ERROR_HANDLE, nullHandle); + } + + /// + /// 恢复输出(如果你需要) + /// + public static void EnableConsoleOutput() + { + var outHandle = GetStdHandle(STD_OUTPUT_HANDLE); + var errHandle = GetStdHandle(STD_ERROR_HANDLE); + SetStdHandle(STD_OUTPUT_HANDLE, outHandle); + SetStdHandle(STD_ERROR_HANDLE, errHandle); + } + } + + public static class ConsoleOutput + { + private const int STD_ERROR_HANDLE = -12; + private static IntPtr _originalErrorHandle; + + [DllImport("kernel32.dll")] + private static extern IntPtr GetStdHandle(int nStdHandle); + + [DllImport("kernel32.dll")] + private static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle); + + /// + /// 只关闭 标准错误输出(stderr) + /// 作用:屏蔽 sherpa-onnx 所有垃圾日志 + /// 保留:你的进度条、控制台输出(stdout) + /// + public static void HideStdError() + { + _originalErrorHandle = GetStdHandle(STD_ERROR_HANDLE); + SetStdHandle(STD_ERROR_HANDLE, IntPtr.Zero); + } + } +} + + diff --git a/Utility/SherpaLogFilter.cs b/Utility/SherpaLogFilter.cs new file mode 100644 index 0000000..4da03f4 --- /dev/null +++ b/Utility/SherpaLogFilter.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Topshelf.Utility +{ + public static class SherpaLogFilter + { + /// + /// 只屏蔽 sherpa-onnx 输出的日志,不影响你的进度条 + /// + public static void HideSherpaOnnxLogs() + { + // 过滤 stdout + var originalOut = Console.Out; + Console.SetOut(new FilterWriter(originalOut)); + + // 过滤 stderr + var originalError = Console.Error; + Console.SetError(new FilterWriter(originalError)); + } + + private class FilterWriter : TextWriter + { + private readonly TextWriter _inner; + public FilterWriter(TextWriter inner) => _inner = inner; + public override Encoding Encoding => Encoding.UTF8; + + public override void WriteLine(string value) + { + // 屏蔽包含这些关键词的日志 + if (!ShouldFilter(value)) + _inner.WriteLine(value); + } + + public override void Write(string value) + { + // 关键:不屏蔽 Write(...) → 你的进度条就是用 Write 输出的,会保留! + if (!ShouldFilter(value)) + _inner.Write(value); + } + + private bool ShouldFilter(string s) + { + if (s == null) return false; + return + s.Contains("sherpa-onnx") || + s.Contains("character-lexicon.cc") || + s.Contains("Ignore OOV") || + s.Contains("ConvertTextToTokenIds"); + } + } + } +}