设为首页收藏本站官方微博

建议 【汉化工具系列 #2】指定wave格式转换为srt格式字幕(CPU版本)

[复制链接]
查看: 457|回复: 0
打印 上一主题 下一主题

[建议] 【汉化工具系列 #2】指定wave格式转换为srt格式字幕(CPU版本)

跳转到指定楼层
楼主
发表于 2023-9-4 11:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

【汉化工具系列 #2】指定wave格式转换为srt格式字幕(CPU版本)

本帖最后由 shane007 于 2023-9-4 12:57 编辑
# v; C  Q/ i1 R. \' l; X
$ ^  c( Z8 E) z  U0 s$ n* E4 a2 ? 本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,
9 D# u9 l% F* Q% W 使用时需要輸入语言,源文件路径和目标文件路径, t/ w5 U4 @+ Y4 V5 V# C% Z7 @; o+ _5 v
最后是输出srt文件; H" H7 e7 A$ k- z' M
3 V6 I, b4 L$ s* G, }% o+ j7 n
代码如下
7 F4 ^( \! K; t6 u  ]以下这句用多线程可以增速,否则很慢
: C0 p7 I3 c& u以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。
" [4 ?" \/ {- Q, C8 O+ e
3 D" V3 o& r* U: q1 k7 l) w) }8 K
  1. var builder = factory.CreateBuilder()
    4 C- y6 \1 E" O+ }; [2 w8 Q1 I
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码

' z, m1 R: C  o. W2 H/ z
1 Z# p0 f1 f' e
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT9 F- w) j% y* E! E/ ?: N
  2. ( x4 C+ U. @4 ^4 J& A7 S; A
  3. using System;$ i5 x& V$ A+ s; B5 z  y
  4. using System.Diagnostics;: c) J" ^5 w2 F( ^" C7 A
  5. using System.IO;2 y; d& ^, X$ H; Z9 b
  6. using System.Threading;' }4 S/ e- V' m3 F/ ]5 m# t  ^
  7. using System.Threading.Tasks;; U7 e, n5 c; [: l" E4 I! i. G
  8. using CommandLine;# }, x7 \' ]" s0 b9 o/ e
  9. using Whisper.net;; i+ b1 {3 O! w! }# w" V
  10. using Whisper.net.Ggml;9 ?/ }7 a! [2 v2 k$ H  ?; g
  11. using Whisper.net.Wave;' \3 ^9 D8 ]  u: Y) ^
  12. / s. }! e0 x( j0 X4 n
  13. await Parser.Default.ParseArguments<Options>(args)
    * Z  H) A8 U  R  o- J
  14.     .WithParsedAsync(Demo);
    5 ~9 N; g' m' G/ z- f0 j
  15. ( }5 C/ X$ Y. T% c) e' k
  16. async Task Demo(Options opt)  A* r+ k( _& s1 @

  17. ; Z8 j) r' J+ R. D4 Q  x9 x/ Y4 J
  18. {1 |$ {5 A: D" Y- J2 O2 P2 I/ m; @
  19.     if (!File.Exists(opt.ModelName)), B: T- K% X0 j8 U9 z4 T
  20.     {. B& k: b# O0 Q3 F) u$ A
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");
    + [) K' ]7 @, @# k: Y5 w7 u3 E
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);" K" s6 S6 Q' b3 C8 N) ?1 U
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);/ e, F: n1 c7 i' p5 K7 N) p
  24.         await modelStream.CopyToAsync(fileWriter);
      w# a0 h1 B) F: c% G9 T
  25.     }
    - t) ~5 F& y9 S; X
  26. $ O* `9 T" B- e$ L( J' L
  27.     switch (opt.Command)
    ( F. L# P3 e( p7 Q3 r% U
  28.     {7 s! V$ I, Q0 X+ B" n
  29.         case "lang-detect":
    - k& z6 e* [# l1 a
  30.             LanguageIdentification(opt);
    & a5 @% t) [4 A2 M0 a5 }, d
  31.             break;  g$ f+ }  v  y' u* [+ x" T
  32.         case "transcribe":
    * \' g2 i2 Z: h
  33.         case "translate":* g! T' R6 X7 |7 |8 U" G
  34.             await FullDetection(opt);7 ?* S' x  X6 X, ?" M8 B( ~' O1 J0 d
  35.             break;
      ]$ e8 w& ~" F( a6 r" C; h
  36.         default:
    / p3 z6 g  g7 y0 p
  37.             Console.WriteLine("Unknown command");9 G" s2 ~2 _) e
  38.             break;
    2 I% B) {3 z% T- C. ^
  39.     }, q! S( ?/ R% e9 a5 a4 T
  40. }
    $ m( [% [, J$ z; {" G; m+ c! H" d

  41.   {; M' r$ ?3 u% B* ?, R; c' Z
  42. void LanguageIdentification(Options opt), Z  N: l0 W2 r( w
  43. {$ d2 ^( T, ^$ _3 ~
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);% c7 N( p, M0 e2 @4 t7 ^- l% M

  45. 8 E6 t$ l7 k' Z# h9 ]+ |0 J
  46.     // Same factory can be used by multiple task to create processors.. U) L5 w  t7 g* m, p  w
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);
    * f5 |& q# C; u; [

  48. 8 L! B! Y: h' t3 h: {
  49. /*    var builder = factory.CreateBuilder()
    ! ^/ p6 j* l' o
  50.        .WithLanguage(opt.Language);*/6 c2 ?, Y+ m9 N% }, E
  51.     var builder = factory.CreateBuilder()
    " S6 I, w$ i/ Y6 Q6 \$ e
  52.    .WithLanguage("english");
    2 L% L% ]8 h2 p# ?% l
  53.     using var processor = builder.Build();
    0 T% g4 t+ N$ d4 G( N! U

  54. 4 S' B9 ]8 N% |# f! k! W. N6 p
  55.     using var fileStream = File.OpenRead(opt.FileName);
    + T! [- ~. O/ l& X# d3 B, j3 @4 H
  56. 5 v- V5 v% j7 \% f0 `3 Q# f
  57.     var wave = new WaveParser(fileStream);' J/ T3 k6 r. }# U& U6 `) V

  58. . L- s% y* }. ~, |. |% ~, r
  59.     var samples = wave.GetAvgSamples();1 B! L$ |# L6 R( F* _( h

  60. . o% N# X2 p7 m" k
  61.     var language = processor.DetectLanguage(samples, speedUp: true);
    ) F4 D& Q3 n! x4 j  H
  62.     Console.WriteLine("Language is " + language);
    " d+ @% o4 P* b2 c! g; B
  63. }* `9 p( G" f2 A1 d

  64. ( \5 I3 R& G% h7 y- n% U6 U! }
  65. async Task FullDetection(Options opt), T2 m+ ^; z$ ~1 D1 d+ s3 c
  66. {
    / R6 G, w+ v* p/ I: R2 r* W2 i0 h
  67.     // Same factory can be used by multiple task to create processors.; w; W7 g: ]- f0 G/ Y3 V! _& ]  x2 \
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);
    " x/ k. G) a$ s0 Z5 t( c

  69. . m2 o! T' I5 y1 t5 z
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);8 ]( z8 k2 V, T7 D" w7 C( @
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");
    8 \/ L. i: k2 G! g
  72.     string languageOption = Console.ReadLine();
    ' M7 I) T- }* x. Z& m9 X
  73.     var builder = factory.CreateBuilder()  p. s; v* Z$ m" F
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
    ( t4 r/ ~4 H; M9 N
  75. 6 s- ?9 Z1 m, P! M2 `
  76.     if (opt.Command == "translate")
    * J* ?7 ]4 U9 d" d7 |% ]
  77.     {. A% ^- c# |! O' Z+ G
  78.         builder.WithTranslate();! I: Z$ T$ F  Z+ {
  79.     }
    5 Y/ K0 k: [" [5 S. z+ \  A

  80. ; ~. m! c; s3 I/ F! `
  81.     WhisperProcessor processor = builder.Build();' U, r* `0 m! s" n$ [
  82.    
    / Y! f, R8 w* x" j
  83.     Console.WriteLine("请输入wave源文件目录:");/ _4 w% N+ R9 D8 r( U2 V: n9 m
  84.     string sourceDirectory = Console.ReadLine();
    $ |3 E2 q3 _# L# X7 t; Y

  85. 5 i" Y- q$ k4 L7 X
  86.     Console.WriteLine("请输入目标文件目录:");
    - L) O: Q: p# k* g9 q0 j2 N
  87.     string targetDirectory = Console.ReadLine();
    / _' D4 I  k$ V- Z9 F, L1 C; D
  88. 3 ~* [2 k) }$ F& z2 ^1 h
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))
    ; I$ G- a- T4 Z5 o, Y4 L9 U9 u% O. L
  90.     {
    6 k  g) s9 b, b' f6 P
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");
    ! Q8 ^1 N& B/ `+ J
  92.         return;; H0 O+ ?. v4 L: R  u
  93.     }
    " y$ ]& }) X. R1 q

  94. 7 x1 ?7 y8 c( g
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);) G. n, U' s0 Y, u2 I
  96. 1 i& q  e4 H& b; Q! A2 r- l
  97.     Console.WriteLine("处理完成!");
    , x/ p6 M1 a& P; A# r# Y: D

  98. & f9 z1 V5 Q1 V  M1 {  {% e. l$ i
  99. }
    " L( m3 _+ C1 |0 C2 k  Z
  100. static async Task ProcessFilesAsync(WhisperProcessor processor,
    - f- e& [5 t* A
  101.     string sourceDirectory, string targetDirectory)$ M9 z( N- l3 n: P
  102. {
    + d) x8 o" w5 w" t8 m
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);
    8 d3 }3 X, B* J( N1 T9 H5 N

  104. ! S; J: E+ p6 L
  105.     foreach (var sourceFilePath in files)
    - B* c- a) M( L" X7 o$ t
  106.     {1 H% g7 r% w+ m' U0 _
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);  ^) Y# K' r, E5 w; h& `7 ~
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);/ T# j2 H1 [0 `8 f: J7 d& X6 y( ^& w
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");( d7 A1 L( D7 ^; u

  110. 3 e9 I2 W/ @6 {$ k; j
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));* y; Q$ d* f  M8 m; ^( [
  112. % ]6 P+ Z9 K$ V) A, a6 P

  113. ( z* y$ n) E, z2 [% O7 p
  114.         if (!File.Exists(destinationFilePath))
    ! I  w* U: P3 b4 R+ Z' H" n
  115.         {
    ' ?% B: ^. I" i* Z# W
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");
    / b0 F- ^# {+ S0 A4 T! t& x2 C
  117. , b, F; x& N& a" T
  118.             using var fileStream = File.OpenRead(sourceFilePath);
    ; E% n0 U) _4 t4 I) w
  119.             var segmentIndex = 1;
    , Q$ G, C7 ?) o/ A) h
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter/ s0 l1 }' N. P6 P7 M2 ]
  121.             var startTime = DateTime.Now; // 记录开始时间
    3 t, y& H& R% G5 p$ F3 i6 J: e& D

  122. $ T& G6 V5 y' q2 S4 I
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))4 D3 |* E6 w; a+ U4 C2 S
  124.             {) y2 Q3 M2 L2 L( ~( z0 s; U7 m) {8 A
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");5 H9 Z4 m! b+ w
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    7 q0 k6 R/ v+ |; |2 Y
  127.                 Console.WriteLine(segment.Text);5 h# o/ F/ I0 t6 p5 L% r
  128.                 Console.WriteLine();
    & j  U$ u% W5 \! c

  129. ! z: u) ^  M, Z- v  G
  130.                 // 将srt内容写入文件
    & Y; v4 T2 P, S3 I6 C& Y
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");" a$ A4 F' ^- ^- N2 E
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");1 Y  X2 m2 R% E# I. w  N& |$ ]* x: \
  133.                 await writer.WriteLineAsync(segment.Text);6 F2 S9 A0 R$ B2 a' e' P6 p0 g
  134.                 await writer.WriteLineAsync();+ c( d7 K+ i  A% F+ M3 O9 K

  135. 3 ]/ }5 W, h, G' B
  136.                 writer.Flush(); // 立即保存srt文件' R* c( a& b5 O2 Q! x" B4 ?8 |

  137. 9 Q8 ^. }" Q; U- y/ w; J
  138.                 segmentIndex++;, L) F2 b  J- p1 T9 E
  139.             }
    ! t# P: J8 {( ?* u8 j3 T

  140. 9 v3 m2 ^5 _0 [
  141.             var endTime = DateTime.Now; // 记录结束时间
    # }5 s* D8 J: o" |
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;
    ( X9 s  q) q  ^! C: J: M$ X! b
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");2 W5 `' c) n2 a8 k
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");! X5 u& l' D/ J; p5 L/ f
  145.         }
    2 c& ]% s! a& _$ n& k
  146.         else {
    - Q: O+ P( ]5 t8 [% h0 B$ R
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");
    ! l5 Y8 v" J& }4 w( j4 t0 H& o
  148.         }7 k, k% I. |9 V' Y" K
  149.     }
    1 Y6 b, p/ o3 G0 `% \) O& M2 U
  150. }  J' F: X" ~7 d% @4 S$ }
  151. public class Options6 a+ k/ B: G& C+ G' w
  152. {! e  \/ _( _# Y$ G# n& a+ o; M: [
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]
    7 G+ d0 j1 G. ^, o
  154.     public string Command { get; set; }
    7 H. p) d; ~+ k; B) P
  155. / ^$ D0 j2 k" r. }: h$ u& T
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]
    - N6 }# Z% F! J+ Z
  157.     public string FileName { get; set; }: p9 }! g; d- z  z# \
  158. 4 `, d9 L; A- o* W, y% Q
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]
    + f0 o4 S7 J4 P3 f( s
  160.     public string Language { get; set; }6 y0 h! a* i" \
  161. 3 w. G3 _9 U6 L( `+ G) N: `8 _9 ~
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]. F  a4 N; o, Q" r/ F# V2 B# R4 k
  163.     public string ModelName { get; set; }
    0 o* ~. e5 l5 M0 L) b! X6 `

  164. 2 p# e/ l% `8 F, g5 h! l) R9 R) \8 [8 n
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]
    6 ^; S! Y4 Z0 [) e4 L) e
  166.     public GgmlType ModelType { get; set; }& C2 Y8 T% \) R$ V& m. k& m& n
  167. }" P% O3 ^; x5 x- T1 K7 i
复制代码
" m. t( ~5 s/ J; o4 W8 _7 k

7 C9 s+ U* M' U, v
. e" r5 K! K* M9 O. ^
  q* W: H- _3 D6 ]. I. h2 g8 M# A! Z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 很美好很美好 很差劲很差劲
回复

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies

本版积分规则

冒险解谜游戏中文网 ChinaAVG

官方微博官方微信号小黑屋 微信玩家群  

(C) ChinaAVG 2004 - 2019 All Right Reserved. Powered by Discuz! X3.2
辽ICP备11008827号 | 桂公网安备 45010702000051号

冒险,与你同在。 冒险解谜游戏中文网ChinaAVG诞生于2004年9月9日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

快速回复 返回顶部 返回列表