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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-4 12:57 编辑
* b/ ~3 N) b5 Z& _" s7 Z
# x8 A# o# u- x  H: t& c; c8 \ 本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,
4 _2 O  q* {# L$ }4 Q 使用时需要輸入语言,源文件路径和目标文件路径) n) j* i% U; ?1 n/ k! @$ T
最后是输出srt文件
* I+ G5 W, Y# g$ z5 Z% e$ d
! ^0 L, \5 \" q, d! ]" P代码如下) j. Q+ i! P) Z  P1 z% S
以下这句用多线程可以增速,否则很慢
  n3 E" A0 c; c  o8 i4 y1 u  F. f以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。
( [$ v: B3 [6 O. l/ N6 `5 F3 T6 w# N1 F* m% s/ A$ c0 V
2 V' s7 S3 D8 l0 j
  1. var builder = factory.CreateBuilder()
    9 P% X: j- `) T! [
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码

) W# |# O+ O" j1 X: u. f3 {% m- I- j$ j$ j) B( T
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT
    7 d1 s' l" ]* X9 k' |

  2. 3 O9 O+ Z) B& N
  3. using System;
    1 ~3 Q' u+ ?2 ?  Z3 l
  4. using System.Diagnostics;/ @4 N3 G5 S$ h. [' I! B# J/ O
  5. using System.IO;
    ! ^2 Y$ o! o+ b5 w0 t7 y. f
  6. using System.Threading;: H; ?$ t# X* R( c
  7. using System.Threading.Tasks;" ~: I9 N1 ^5 ^/ F4 P
  8. using CommandLine;) U, y, {9 m8 j  Q' s5 h& E; a; [
  9. using Whisper.net;4 P% w' g- i5 e2 n
  10. using Whisper.net.Ggml;$ a3 v, M5 `) f& Z- x7 v) w
  11. using Whisper.net.Wave;$ G0 w# I$ ?% P  E6 {& [
  12. , Y6 k+ }* z. _; y6 w
  13. await Parser.Default.ParseArguments<Options>(args)5 B* f, _) L+ p6 t+ X8 r4 M
  14.     .WithParsedAsync(Demo);
    0 Y. k3 L+ a% D$ t7 n( A

  15. ) B  R; L. |  C. `$ A7 c8 L8 C" m
  16. async Task Demo(Options opt)
    9 V, [0 ^  P8 b! X

  17. " Q. p' D5 M' v- J
  18. {
    7 s+ Y/ J3 ]+ ]+ d2 z
  19.     if (!File.Exists(opt.ModelName))
    ' S1 Q4 G3 k7 P. R: l) O
  20.     {
    - b& D& G  Z7 t0 Y- z
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");+ d; i& x0 g' ~
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);4 M2 O- n) i; d  L
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);0 }. t; L* ~! i+ K
  24.         await modelStream.CopyToAsync(fileWriter);2 U% b4 Q5 C! b( n, L/ Q
  25.     }
    7 q" m/ _, ^2 n: ^

  26. " v2 m# ]1 }' Z
  27.     switch (opt.Command)
    ' @7 W+ F$ x' A8 G6 s
  28.     {; Z0 ~; i$ c7 F( C1 }4 L
  29.         case "lang-detect":3 e& f7 v7 f) q2 s! P/ m
  30.             LanguageIdentification(opt);- k2 y; A) m* F. F( b
  31.             break;
    1 g( B- }3 S% }3 c& X# F/ [; }% p
  32.         case "transcribe":
    2 f+ D' U; K! P1 U3 ]4 R
  33.         case "translate":
    ' @  n/ V2 E7 L! s$ |3 I
  34.             await FullDetection(opt);
    $ J! o% G8 i8 D+ E: ^3 s
  35.             break;
    1 p; z- U! h  I) X1 V" w# r; `
  36.         default:& r# n1 [7 H: T9 T& u) ?
  37.             Console.WriteLine("Unknown command");* G( e/ q% d5 e- S* X* u! I/ B
  38.             break;; C# }  w/ G& l9 L( F9 K' [# f
  39.     }4 s6 n4 Z: b" f6 `! E! f6 j: `' V
  40. }
    ! w0 L$ i$ D; M  \: @
  41. , u. ?$ [3 E8 j1 ?; ~: O
  42. void LanguageIdentification(Options opt)0 f1 k( Z) c6 @* a8 `0 |
  43. {
    $ z$ h9 x. m+ f" N
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);. z6 Q! S1 x) V1 p8 c( \
  45. , y- D* L/ q" \; Z0 ^0 C
  46.     // Same factory can be used by multiple task to create processors.9 G2 g9 V' R6 m3 ~
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);
    9 _, |. j  M( u7 w

  48. 2 G3 F  W+ g: {- M
  49. /*    var builder = factory.CreateBuilder(), S& {7 d% U3 K5 Q- V5 z
  50.        .WithLanguage(opt.Language);*/$ k5 Q" t8 a( _+ y' c: E. n  k
  51.     var builder = factory.CreateBuilder()
    - i' w- H- `  c2 _+ X& B
  52.    .WithLanguage("english");6 R) R' q+ z) Y; A, d5 m5 F" z
  53.     using var processor = builder.Build();
    , q% L: v: o7 C+ C$ d  q- A  ?( u

  54. ; j4 S7 R* N5 y, t- W
  55.     using var fileStream = File.OpenRead(opt.FileName);
    2 k1 D& a, c. M. v& U
  56. ! M# j6 ?0 p3 H1 P
  57.     var wave = new WaveParser(fileStream);
    7 k* O' J+ A  Z# Y5 g

  58. : G9 P& S4 T8 v
  59.     var samples = wave.GetAvgSamples();
    3 m  J$ z7 e1 u; T
  60. 4 P& X7 q, Q9 n# e5 f
  61.     var language = processor.DetectLanguage(samples, speedUp: true);
    . Y, y6 v+ ]4 }5 u/ F
  62.     Console.WriteLine("Language is " + language);% w. j2 E9 M) Z5 J2 c
  63. }
    ; }7 E4 m3 H8 m, p
  64. & s2 r+ e1 L' K3 x( F8 g
  65. async Task FullDetection(Options opt)$ b* Y. M: _" e
  66. {
    . _- [+ s$ Z$ S4 g7 F+ g# }, s6 {
  67.     // Same factory can be used by multiple task to create processors.1 Q3 f- E, k+ m3 ]
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);
    ; C6 J: ~6 p- U7 T( d8 n) k

  69. / \& S  H7 K2 R6 n7 }* I* N
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);9 u2 U, k+ f9 t& `
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");" P, L# N3 h* q1 w  p; W( z
  72.     string languageOption = Console.ReadLine();+ t6 Q6 p0 ^' j  B
  73.     var builder = factory.CreateBuilder(): }- l, d9 f& @1 _/ {
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
    4 a& q& ^- u! G+ D6 }* V! X* E0 `
  75. $ x7 {( y0 e! u% m. y9 ^
  76.     if (opt.Command == "translate")6 K% e/ [% O% C; T. s
  77.     {
    3 T9 e# V3 n2 a# U
  78.         builder.WithTranslate();
    / Q0 ?( @- j1 t( B
  79.     }
    6 ^6 ~! y( h5 W

  80. . V. M! T/ V- H+ o( s
  81.     WhisperProcessor processor = builder.Build();
    ( r& H# w: I8 C, z. L
  82.    
    6 y' b8 u" }" k7 p' O1 Q
  83.     Console.WriteLine("请输入wave源文件目录:");! ?, R5 C: c* i& T
  84.     string sourceDirectory = Console.ReadLine();) [! t2 Y2 a, \6 V( P
  85. 5 ?6 v/ E$ O) A" l8 E
  86.     Console.WriteLine("请输入目标文件目录:");  {* u0 [, q! {1 i- e( _  ?% s
  87.     string targetDirectory = Console.ReadLine();
      `: o4 ]) [; U# F8 b

  88. 5 M# l6 `5 N- o3 N3 W" `
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))
    : z: M+ S) N. `- e3 X" D
  90.     {, B3 l: T8 J! n* `  ~9 X
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");
    , r" u9 g' E/ z& {2 G# _
  92.         return;
    ) x/ k! I! V. V: w* ~
  93.     }- q: i* k; l6 }* E' j8 l6 N* Y

  94. 0 w. ?! ]3 {/ j$ y8 z9 g3 B
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);' X0 b) p" M  o) p6 k9 e. I/ U1 B

  96. 7 L5 x- r' s7 w6 Y
  97.     Console.WriteLine("处理完成!");' a0 m5 N5 u$ ]/ ^
  98. , O: u* ]( n6 m: m# j' V; B# Z
  99. }7 f( X% {' L; j+ G1 B* ]+ B7 |- w
  100. static async Task ProcessFilesAsync(WhisperProcessor processor,
    " P/ @8 t$ E; a! D, ^* d: g
  101.     string sourceDirectory, string targetDirectory)
    $ _0 l; a, F0 X) N: ?
  102. {5 @' w1 e5 G0 `5 ~
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);  Z% m* ?* d- o( A

  104. 5 y( Y/ \% w7 p% ^! @
  105.     foreach (var sourceFilePath in files)# c8 M3 t- e; S' {  e
  106.     {
    ! @, m* j' N$ E/ S+ H
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);
    - D4 ?: N" U" u
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);, a: E9 k! Y( I; ]) p; U+ W7 y
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");$ f- G1 x  q4 n5 U6 o2 _7 @
  110. - j# t% }! w7 k0 s$ m$ W
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));6 S- s3 }7 G) @! ?( s5 T- }# b
  112. $ T, p: k9 J/ w" g

  113. , s# u" f4 ~2 o% z$ ]
  114.         if (!File.Exists(destinationFilePath))* ]8 z) q7 ?' W
  115.         {0 C' ?% E( r& _2 |7 n7 l! j/ \7 P
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");: J6 j4 M8 J+ D# W$ ?

  117. 6 c+ H$ ?7 X! a' r& x
  118.             using var fileStream = File.OpenRead(sourceFilePath);, d- g8 n. W, b+ r! D
  119.             var segmentIndex = 1;& @7 n+ _7 J( D! ~6 S( A/ ?
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter4 N* T  Z, d1 C/ A4 [2 \
  121.             var startTime = DateTime.Now; // 记录开始时间7 }& z$ p  r/ S3 @( `
  122. 1 V" N+ t# P0 @8 A( `& o& v
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))
    ' h" V2 B! g: g) [
  124.             {
    ' `% l8 z& O( n- n0 O
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");. t4 y$ G! U2 x4 r3 N
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    * x4 P/ N$ K* B
  127.                 Console.WriteLine(segment.Text);
    # h1 l7 h0 a* n$ g# X) T# C3 f
  128.                 Console.WriteLine();
    ( y% e' ~; i) s
  129. 6 p% o8 K/ z* q) p( `. }
  130.                 // 将srt内容写入文件
    - W/ a* S% t- E6 ~
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");
    & @9 d4 I. j; r
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");+ @$ ^. U9 @- Y3 z  y
  133.                 await writer.WriteLineAsync(segment.Text);/ n+ J* s0 [; U' C3 Z+ ?
  134.                 await writer.WriteLineAsync();% g8 Q7 h9 ~% M
  135. # g6 D' v4 s% {4 N
  136.                 writer.Flush(); // 立即保存srt文件9 n( G/ p5 J9 W
  137. " o* X6 I2 h7 y6 p
  138.                 segmentIndex++;
    & r8 E- s( N% |* C, x3 W
  139.             }# {3 O: h6 q7 ~- D
  140. ; B# W  l, D/ }7 \- d6 E
  141.             var endTime = DateTime.Now; // 记录结束时间7 @$ G# J  `  D) d* a& j/ s
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;0 j, p8 a9 z0 f# |
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");
    7 [, z; l, s9 y; S3 u* }
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");8 n1 v# H1 l6 P) B" X: X/ H. _
  145.         }
    3 l4 M8 J2 }+ i) T
  146.         else {
    8 k% z3 U8 U9 h$ \
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");6 r( i, Y/ H/ f' z8 r8 s. N; ~6 N
  148.         }
    ' ~0 s; V. W8 s& Z; R
  149.     }
    : l* _$ {9 W: P6 i2 B
  150. }# w' y( R. F9 S2 O8 L) ^
  151. public class Options$ h- [/ N8 G/ s" c) N
  152. {
    ! g# o* Y" p4 Q7 m2 [( r+ `
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]) f7 O* Y% [1 z) l, L6 }  X
  154.     public string Command { get; set; }
      @" p( {8 s- g4 u+ V& V2 H3 c
  155. $ ]. l/ |6 u0 l# @
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]8 T5 s9 Q" Y- A, y& Z; T
  157.     public string FileName { get; set; }& F# w' x2 W! p2 L9 W

  158.   R7 U' B! A- k1 G& i
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]
    3 g; v( b; ~& ^  W
  160.     public string Language { get; set; }
    2 y; z4 U% `3 O. G9 q1 {* U- J5 l

  161. ' T# p+ F+ J$ O2 |1 e# V6 K' Y
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]; C7 ]" o: [) T6 g9 P8 ~: \$ b" M
  163.     public string ModelName { get; set; }
    4 S6 \5 J8 N3 Q4 i

  164. 1 W* k' m) @/ u# p5 N
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]
    ( b) f2 N2 L2 C4 H  v
  166.     public GgmlType ModelType { get; set; }
    / `1 ?7 j* Z& `0 Q, q' Y% A4 Z
  167. }
    : Y: O. E, M7 a* M% N/ p
复制代码
$ @5 {1 O! V4 Q: [" _

- e# R) O' w/ [: L% A  w* Q. X+ g. f$ E

6 {( {( f' \9 T9 ]8 b4 n  y- [4 y
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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