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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-4 12:57 编辑 0 x8 Y% }6 u. _( |/ h, B8 o% I6 g
' M$ i- ^/ h' t- `# N# M
本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,
" E# v: I/ N  p. o2 D( G! T 使用时需要輸入语言,源文件路径和目标文件路径: f" B3 R% b0 _
最后是输出srt文件
2 ~3 C8 G* X7 N% L" O
" [( ?! c: \+ j) m* J( _- m代码如下
$ t; C: Y8 B5 B$ N5 F) o以下这句用多线程可以增速,否则很慢
1 x, A- r, B: w" V4 R3 e: m. g  J以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。
. ^' P  l4 @+ S! l  p0 ?
5 _* R% }8 i% {0 u0 S8 Q5 V" A& u; ^3 z3 E* o% B
  1. var builder = factory.CreateBuilder()
    + V- D/ W. Z% q4 z+ T6 x% X( J
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码

& B7 Y( g6 ?1 y' ~; y  ?( g7 b
/ j& E4 d" P+ x5 S0 m
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT( P6 Q+ z& z/ R0 q2 A, C4 o# m9 h
  2. 1 W% ]5 ^( Z/ f* T/ ]- P( J
  3. using System;
    ( r* T) N: d+ [1 l( N9 f/ I+ e
  4. using System.Diagnostics;
    1 R! y+ W' V8 T5 ^$ n
  5. using System.IO;2 L, ?9 u; X  }3 E; a! I
  6. using System.Threading;& a# u, k( R! G$ y  a( `5 c; X
  7. using System.Threading.Tasks;
    . \% O  p: z8 Z# g% V7 f
  8. using CommandLine;/ L% y  v$ j: n0 ]/ h
  9. using Whisper.net;$ o9 ^- K0 G* I: y, r) y4 R
  10. using Whisper.net.Ggml;
    7 E: G' I1 p3 J
  11. using Whisper.net.Wave;: `% s, y* c5 @3 m: A5 J# f

  12. # n' b4 R& F" a) W9 R& E4 B/ A
  13. await Parser.Default.ParseArguments<Options>(args)7 b  C2 b3 e. B  k0 G# W
  14.     .WithParsedAsync(Demo);
    / S8 i. A* Y6 k0 D8 z

  15. % p6 F! ^7 {0 K! g
  16. async Task Demo(Options opt)) M! Y- R) ~" A& \; a. X! {
  17. " O# Z. \0 b2 d, {1 B0 \. K
  18. {" C+ i3 ^0 m; p: M; S
  19.     if (!File.Exists(opt.ModelName))
    - }- B! v) [* K7 ^* U+ {+ Z
  20.     {
    ; Z7 R' t! ], t" K
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");) `- @6 |& F5 y# [' F
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);
    ) g9 K+ X* J: e# A. |
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);; ~' \" n) S; k1 c9 L$ _+ L  ^2 f
  24.         await modelStream.CopyToAsync(fileWriter);
    - f9 I% r# Q) u3 n& m7 \
  25.     }
    - n7 M! l" K+ n5 f; z% n
  26. # o/ i) j" N. B2 F4 J
  27.     switch (opt.Command)
    # v4 z+ r+ z: @' ]  F
  28.     {+ v) {3 ~: y" E3 R+ t; K" }6 I+ w
  29.         case "lang-detect":- V8 J8 q6 t/ R
  30.             LanguageIdentification(opt);' @9 q; f4 O8 B
  31.             break;, q  W# Q+ q' I, F" x2 a2 B7 T
  32.         case "transcribe":
    ! D( Y, v- }+ I8 v) K) s- D
  33.         case "translate":+ o/ {+ C# g4 i
  34.             await FullDetection(opt);1 `8 z1 \3 K  q& k, T  H5 _
  35.             break;$ d( M/ @) h% R# m( w. _7 J4 Y0 ~* N
  36.         default:
    8 ?# o. V# m3 J: E2 d" h; u
  37.             Console.WriteLine("Unknown command");
    + ~3 V2 H5 [: U% S; X, Q
  38.             break;
    $ x) J5 n( G" s- J! O$ r
  39.     }
    . k! ^) D; Z# _, ?0 u& N0 M0 D
  40. }
    3 U9 C8 Z+ J& n4 I# C

  41. 0 z- z% [1 P4 G) a0 y
  42. void LanguageIdentification(Options opt)
    + v( L' B/ U5 B6 ^2 w# e- I; ~
  43. {
    # m9 m6 f& S% V" b0 ^/ y2 S# \2 o
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);
    4 Q7 f; O% J- E. r& O, N

  45. 5 f" \0 m# f( y8 k6 ~8 h( V( u6 i
  46.     // Same factory can be used by multiple task to create processors.! Y" C3 h/ k  h7 m1 Q$ V2 m- S+ _3 ?
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);1 |# n% Z# y- @; |( `; I
  48. & u/ T( W; m' K! w3 F$ B( @
  49. /*    var builder = factory.CreateBuilder()
    8 c" M, _" I9 Q7 J* `* ]" R
  50.        .WithLanguage(opt.Language);*/
    ; x1 d1 V$ w% B5 Q' L3 ?) x
  51.     var builder = factory.CreateBuilder()6 e) i: T- c" `4 w. v
  52.    .WithLanguage("english");
    ( C$ ]% V; `/ d0 ]" C& P: `
  53.     using var processor = builder.Build();
    9 k1 L# W3 l* r6 M' K% k

  54. # k( `& R- b9 Y* g: K# k
  55.     using var fileStream = File.OpenRead(opt.FileName);
    ' a3 b) a  j3 \/ [; x
  56. , b1 k6 C( v: z! o  J/ q6 q5 W4 Y
  57.     var wave = new WaveParser(fileStream);
    / d0 L- ^% Z  _! O; I5 O$ t5 Z

  58. 1 |8 ^0 \# l# v5 W4 l$ m8 d7 F+ z
  59.     var samples = wave.GetAvgSamples();5 G7 P4 m  l- i# ~' a4 C

  60. " N7 D0 t( G1 ]! ^/ z. T6 E
  61.     var language = processor.DetectLanguage(samples, speedUp: true);6 c$ @, X$ p: `6 {
  62.     Console.WriteLine("Language is " + language);
    , t+ Z+ q  f" h( E- e% @
  63. }# r2 c6 J* z, Y1 ]2 n6 P/ h0 [' V8 P
  64. ( b3 V, Y3 G* h! d5 f
  65. async Task FullDetection(Options opt)
    % b" a1 k) d* S* a* I7 x
  66. {
    / X, d9 W& y: z' a2 \# }
  67.     // Same factory can be used by multiple task to create processors.
    5 D7 i5 t8 U. U8 J8 w9 W4 l$ K
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);
    % U6 J  i4 \; q7 Z
  69. . I7 J7 K$ V  P7 o1 ^
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);
    / Q& w5 _: V: f9 C) h4 H/ b
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");
    / C* f* K* w2 U8 k9 @  Y
  72.     string languageOption = Console.ReadLine();) Y( i# x# }  \, i/ w3 v
  73.     var builder = factory.CreateBuilder()
    : `0 Z% ^: G6 Y( W) |
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);, S/ c  g+ x# s  t0 O; _+ a1 t5 B  D# J2 I

  75. ( d2 f7 p# x% M+ Q
  76.     if (opt.Command == "translate")7 ~0 E* Z7 S  h( R
  77.     {) t% t6 y* N3 L4 I
  78.         builder.WithTranslate();
    5 V0 e" _" x6 u2 H
  79.     }
    2 m$ u4 N( c7 n7 r$ b( o4 Y& v

  80. 7 i. g' o+ N9 A$ ~
  81.     WhisperProcessor processor = builder.Build();1 J: }4 b4 ?+ i) I; c
  82.     ( {2 {. L& [3 f# X2 b
  83.     Console.WriteLine("请输入wave源文件目录:");( c8 ?+ S+ z6 ^8 p' B2 U4 w% z1 `$ p
  84.     string sourceDirectory = Console.ReadLine();
    9 ~9 a  c6 j7 N* \" U+ d
  85. , O3 e# z7 N; Q* L7 h" \$ ~
  86.     Console.WriteLine("请输入目标文件目录:");
    5 Q* Q3 U1 q" k7 N3 H
  87.     string targetDirectory = Console.ReadLine();0 V# y. n! J! E0 K" P

  88. 5 [- Z1 o7 v) {( Q- w; z" h$ S, V
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))+ d- E- D  B2 P7 k% L# z
  90.     {
    7 t1 [0 v% `) ?* J4 ?. U, h
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");5 O4 [4 Q; F( G8 d% W
  92.         return;
    * L) w: J% q7 y2 M8 ]# _
  93.     }
      d2 a  B) ?2 e
  94. 5 L5 F) q: A( \; ?, U
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);: U5 l: r! R- Z% J9 L# s% |2 M
  96. 5 k0 K- H% U4 J' g5 Q
  97.     Console.WriteLine("处理完成!");
    0 {' u( r+ D, k' h1 O- ^

  98. ! O/ m7 Y4 n) E1 P8 A8 d1 u7 H
  99. }
    ! j6 _/ n- ?/ H" C
  100. static async Task ProcessFilesAsync(WhisperProcessor processor,
    , y# K# X3 k6 q2 C6 N0 E
  101.     string sourceDirectory, string targetDirectory)
    3 G  j- b0 ?; e
  102. {8 }$ }, H, _: s$ a& E6 _
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);& r2 P) J) f# S3 c& M

  104. % u: |, E" ^7 ]; K+ c
  105.     foreach (var sourceFilePath in files)4 v' w% T; p. @+ s
  106.     {1 f( h5 H1 H' ?% r( B. g, ~1 u; _
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);) {; Y! T0 a% N1 f$ {1 G
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);* W0 [& Q& @8 ]1 h  F& p1 I. c5 N" }
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");
      t1 l; r. f/ X1 u
  110. , \6 @; r/ f0 u4 C- d- @6 h
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));  ?- U2 p% m: e- J
  112. 0 R/ W& p3 U# I" J  ?( i; Z) g

  113. 2 A- E8 l& r5 |: I- O
  114.         if (!File.Exists(destinationFilePath)): \6 ?2 r5 T4 L. {, V9 \+ u
  115.         {
    ! e( B+ V8 I0 B3 s
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");0 ~4 o9 C) I* K

  117. ' _: J4 ]2 m/ L1 y
  118.             using var fileStream = File.OpenRead(sourceFilePath);* ^# l9 ^6 O" t. A- ^  Q
  119.             var segmentIndex = 1;1 |5 |+ R7 @: K1 \6 s! |/ q
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter
    " x. I( _* B9 A. o& o
  121.             var startTime = DateTime.Now; // 记录开始时间3 |3 J0 w1 h& o. H- V

  122. " r! J  I! d0 h) B" C* ^* y0 j
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))
    + ^3 W3 X: P- k( B5 h& q3 f8 M
  124.             {6 ^% L% g7 d8 S1 d0 J/ c
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");' [' W8 t& c. y8 ^% {3 p+ T9 V) x! O
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    , ?) Q. }, o& L. n. D2 F
  127.                 Console.WriteLine(segment.Text);$ s4 X& X; i  R
  128.                 Console.WriteLine();( E+ @/ p) U0 v- b9 ^$ R

  129. 9 M# ~( y/ d* ~8 f: L6 t& t
  130.                 // 将srt内容写入文件
      s' N2 l( Z/ S) a
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");5 T1 Z( R7 M6 Y: k3 ?7 n8 M
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    + i7 k: q1 i1 k% f4 [: K
  133.                 await writer.WriteLineAsync(segment.Text);
    - B5 d  U6 G- \. t! L% [+ w
  134.                 await writer.WriteLineAsync();$ B) ^5 `3 N0 j  b% ~
  135. ( {. x$ \* q, @8 c! k
  136.                 writer.Flush(); // 立即保存srt文件
    & p, f$ d2 }& U7 c( T- ?4 s5 w& d

  137. 2 T+ x( o  w, \
  138.                 segmentIndex++;
      S0 v; @& n' x. Z* d
  139.             }: l/ j$ |: d5 F5 L4 M

  140. 9 b7 w8 r5 D: ~9 k! t
  141.             var endTime = DateTime.Now; // 记录结束时间
    ; K6 g* o- v& I
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;9 d4 c5 h+ K7 ^, F
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");% H. y# |; o0 w) O9 q$ I9 N
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");
    ' I1 d: o2 S! N5 y( o
  145.         }
    * _" M3 [1 d' n3 Q% G: Q
  146.         else {
    / `7 t  o; v1 T+ O
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");
    8 P& Q+ U2 e  m
  148.         }6 T8 H8 A% x" x/ f" V" K
  149.     }
    % N# i, X$ T/ M1 s
  150. }; _+ Y$ F6 }( v8 t7 a/ N3 ^
  151. public class Options
    ' j8 z9 J7 }1 ]3 N
  152. {
    + h* }/ U9 m7 m8 I9 Z+ H
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]* G% U$ h! J$ h/ W' F5 s
  154.     public string Command { get; set; }( g1 }6 d; u5 J; W' b
  155. ( r5 D7 |2 y7 B" ]8 t
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]! ]/ @4 f& ^6 c
  157.     public string FileName { get; set; }  L8 d/ C2 _% A) s8 P

  158. % s$ A, I' e) g5 }2 m
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]. e( k8 L0 |- H
  160.     public string Language { get; set; }
    ; H8 S0 x$ H6 W2 Q1 m7 f
  161. 2 k) {4 p% v3 s5 s5 [& \- H: t: u
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]
    ) Z# s% m+ X% }5 d9 @
  163.     public string ModelName { get; set; }8 G5 Q1 W+ v) F9 N; e! g
  164. 6 W0 @' o! o* S4 N4 R" R
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]
    3 l8 K+ o" m( S! @8 X
  166.     public GgmlType ModelType { get; set; }
    # n- c8 x% h9 l: U- i8 C3 V* Q
  167. }. k6 L, ~7 U. E* ]
复制代码

; K' ^0 B7 h9 x$ e4 ?. O# L2 Q
2 q! k: c+ t5 s; p2 ~7 r' i- q' t) W+ S( y3 P$ B
8 |$ G6 E6 @2 N5 ]
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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