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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-4 12:57 编辑 4 _; W/ _& R! f; V6 k& ^' @7 ~

9 |. Y+ u! n5 v7 k& ~7 d/ x 本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,3 ?9 B9 q  r  l( ?1 a% ]
使用时需要輸入语言,源文件路径和目标文件路径+ @; Q# k0 W4 ?7 M7 ?
最后是输出srt文件
* G) |- Z$ ]( J: E2 J, G  F& Q
" k" G$ C$ p0 q4 E- N代码如下
. Z3 e" s0 P1 t% v/ t以下这句用多线程可以增速,否则很慢# e5 h# ^4 F. o& L) h# f1 o
以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。
4 g; {) a& E+ n' S$ z6 w$ l
. o/ S! j& w) q+ D3 ]9 L4 i6 n2 H1 [% Z5 w
  1. var builder = factory.CreateBuilder()
    6 Q6 o. \9 u6 B& X4 K
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码
8 j6 z4 \6 @8 x; \. e
0 C( @5 `; a& ]* t9 y# j: [  L$ \
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT# [, d- z7 M9 S+ ^% b. x! I: Q
  2. 6 H. K5 G# K" f$ a: S& t# T
  3. using System;" P9 v6 V8 T/ a( P! ]/ a& B
  4. using System.Diagnostics;
    . [. [1 H5 r$ k6 a
  5. using System.IO;
    ' z. ~* b: }  w: R2 Y: |
  6. using System.Threading;! i7 c( R6 N- \: `% g# Y$ @
  7. using System.Threading.Tasks;
    $ Z' _" |) ]2 ?& p, R+ z
  8. using CommandLine;- J! ^* l7 l& t6 P$ f5 x! M8 s+ V) ^
  9. using Whisper.net;0 y6 `% P. d6 A3 H, D# R
  10. using Whisper.net.Ggml;
    . T( T  P7 @& o5 @! A1 K# ]
  11. using Whisper.net.Wave;
    , y) Z2 k; z# B
  12. 0 s8 e( E' Y. N( c" y
  13. await Parser.Default.ParseArguments<Options>(args)- Q8 Y0 m! L. B4 N) D2 |
  14.     .WithParsedAsync(Demo);, `- b5 Q) j( J+ r; L

  15. 5 @. g1 K& @/ {$ S
  16. async Task Demo(Options opt)
    & ]* B, [& b/ w$ @+ }
  17. 5 M& I1 a1 H0 \: K. y$ ?  a9 x; A  v
  18. {% Z2 l, a% h4 }+ q4 ?
  19.     if (!File.Exists(opt.ModelName))/ E* I9 ]( u8 f' U) s5 x7 n4 Z, S
  20.     {
    0 N4 R# p8 ?5 B' V2 @
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");
    ' I& r, b1 S' W. o; A6 ]# |
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);3 m* t: c/ q$ j# Y. ~  |9 N; V
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);
    . v& R/ @* z  U; u* Z
  24.         await modelStream.CopyToAsync(fileWriter);
    " b. e: l1 V0 m) v
  25.     }0 Z& o0 E( Q( X( v7 A1 O5 M7 w0 D; ~

  26. ( |9 y; Q, O# Z/ _8 ?
  27.     switch (opt.Command)3 R0 u# ?6 V+ b! G) a
  28.     {8 r' A8 _) |# V* K! a. H& l  Y
  29.         case "lang-detect":6 q( W3 y5 H3 ]" _% e: ^
  30.             LanguageIdentification(opt);
    $ c. ]9 U' W; F+ y  s4 s
  31.             break;4 ]# ^2 h+ L$ {0 \2 F
  32.         case "transcribe":
    9 E; \/ M0 K3 P  t
  33.         case "translate":7 O' U& z9 y( }6 Y$ E% d9 }- g. ^
  34.             await FullDetection(opt);9 x2 M, w3 a2 ^1 `! a
  35.             break;
    & Z0 k# r! ?* @' X# y/ ?( j
  36.         default:
    $ s+ [' P3 d# C; L
  37.             Console.WriteLine("Unknown command");
    * u1 u1 ]1 J: t6 t1 ~8 |* j8 N7 n
  38.             break;
    ( C7 F7 W5 b+ \* I8 A; `
  39.     }9 j/ _# L- r: t& e4 F
  40. }
    # L! l% T0 o9 \6 d, S
  41. , q% |0 s  }) x. h0 }2 M4 `9 \8 o
  42. void LanguageIdentification(Options opt)
    - R2 B. |( X) I9 `
  43. {
    , h: E$ u& n) S1 x
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);: K' S- P; h, G* a) k. r
  45. % M( d5 c( G" g- x
  46.     // Same factory can be used by multiple task to create processors.1 Z8 e- P: Z" m
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);
    9 d, Q3 K$ u$ k9 `1 u( ^

  48. # N- f9 s) u: d7 @& {* w2 \% A
  49. /*    var builder = factory.CreateBuilder(); F# y6 }% o! o* B- L: P; i
  50.        .WithLanguage(opt.Language);*/' W# [# d% g& `3 N" B
  51.     var builder = factory.CreateBuilder()
    9 u8 f% |3 f0 P" m  t
  52.    .WithLanguage("english");- ]) n3 Z8 \7 t2 o! h
  53.     using var processor = builder.Build();# \$ M! h/ N- j% F& U8 {) S$ T' y

  54. ' x+ c! o9 t- z. s3 V; G
  55.     using var fileStream = File.OpenRead(opt.FileName);
    ! ]/ Z5 h) k, W4 p& S( `! o1 z% a- p4 _

  56. + A. k5 n* h: l' l1 D1 w
  57.     var wave = new WaveParser(fileStream);; R6 H* |1 k3 n6 d
  58. . q1 f  W7 }* h) |# C6 @
  59.     var samples = wave.GetAvgSamples();
    ( f8 g' ~' ]5 q1 v$ D8 f/ y2 A

  60. ( p2 t- H0 `+ D5 r
  61.     var language = processor.DetectLanguage(samples, speedUp: true);
    $ [# {; P. g+ o1 [; g
  62.     Console.WriteLine("Language is " + language);
    : T* P6 A! k7 k9 e
  63. }
      s5 O: C! F4 m+ h( u$ z

  64. 1 i! n" X$ s3 {+ i6 Q$ y& v
  65. async Task FullDetection(Options opt)
    0 \( m7 A; h0 |$ x0 R1 Y. v# s
  66. {
    # J6 v3 L  g5 Y& }( ^
  67.     // Same factory can be used by multiple task to create processors.
    2 B! ?4 G2 e$ a. V: @- ~5 s
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);% N3 y+ _2 d- ]: c1 a- Z9 a- A5 N

  69. 0 r8 H3 Y( P8 W0 N7 ]
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);% A' y, y: O8 Q' {: H
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");8 a7 `6 i) p% P- x# G7 Y/ q) [  j
  72.     string languageOption = Console.ReadLine();
    : D: c5 D& a+ I' }
  73.     var builder = factory.CreateBuilder()0 F. H9 k4 h0 A6 y
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);2 d* w5 p! Y5 _# @( b
  75. 1 h) D( k. S1 h# L$ @, k8 U: k
  76.     if (opt.Command == "translate")1 V  ~3 W% W- @
  77.     {
    ! d9 t# d  ]% ^7 c: L
  78.         builder.WithTranslate();
    ( j  F+ q# D" X& W
  79.     }
    ' s1 d9 x5 X2 H2 ~" E, r8 F
  80. ' e$ _' m& P# y- R8 ~
  81.     WhisperProcessor processor = builder.Build();
    2 B. n8 a1 G  P6 q% d
  82.    
    / a- g/ [8 G' f% g& L+ m
  83.     Console.WriteLine("请输入wave源文件目录:");
    % b1 e/ A! l& y0 \# D. P: N0 F
  84.     string sourceDirectory = Console.ReadLine();& K. _" d% \* j2 x) V- V
  85. % K: u0 l% p$ w/ G1 c  C0 V. l/ }
  86.     Console.WriteLine("请输入目标文件目录:");
    ( W$ z% W" B4 M7 p4 {+ H6 R
  87.     string targetDirectory = Console.ReadLine();8 E% @5 n4 D/ N9 _) r: I+ l9 f

  88. : W, y/ k. T2 C7 H
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))4 J$ l/ f4 X4 F  k& p+ o
  90.     {# q$ |/ a5 i6 u7 v, S' B( s& x6 w' u
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");
    5 I" U9 Y/ q2 u
  92.         return;) [8 K% v4 _% y  U
  93.     }
    & X, {; B5 d4 j

  94. 3 }0 h# R- y0 M8 d" Z+ I  Y
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);
    ( l; W% N  R) a' K5 d

  96. # b" s9 D5 y% m: Q3 p0 A" ?; F
  97.     Console.WriteLine("处理完成!");
    # t9 b9 {6 r4 N* s: `1 `

  98. 0 g7 q& g% W/ m6 V
  99. }0 x, m: N# O) Y
  100. static async Task ProcessFilesAsync(WhisperProcessor processor,
    6 J/ |4 z) J- z& S$ h( j
  101.     string sourceDirectory, string targetDirectory)
    ! D: t( `- k2 e
  102. {
    6 K/ {' C; S0 W" l
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);0 i  l0 e7 ^; P; }7 N

  104. 6 p+ ]7 M+ f* r/ p0 J. O
  105.     foreach (var sourceFilePath in files)6 v& ]  A& y, h: U9 l
  106.     {
    # s+ m* ]0 i) n2 P5 A6 y9 [' O0 R
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);
    " N; F4 i6 Y+ R  M+ n
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);" |& o0 I+ E) J8 c
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");
    . b; v, h; E+ ?
  110. 3 ?7 o0 m& y+ m* C/ K$ L
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));2 ?2 H+ o* o7 W% U
  112. & P, E7 j0 b! O2 _
  113. ' \. i1 v# D, |- v" n8 p* F# R: {* @
  114.         if (!File.Exists(destinationFilePath))
      j% j+ c& M# Y$ t1 Q
  115.         {
    - F; l/ _) w4 f1 K5 t
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");0 ^! A2 G0 _7 q: ?! v8 x0 ]

  117. ( _7 m1 Q: J0 N/ e6 G5 I- C" q, e
  118.             using var fileStream = File.OpenRead(sourceFilePath);
    2 u- u, @& e; K" ]
  119.             var segmentIndex = 1;
    , B; N& h- l" G4 {7 m  O
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter( K. d7 `4 a+ U8 s- J; l1 d
  121.             var startTime = DateTime.Now; // 记录开始时间8 e: n: `: W/ g2 B, _% E5 l+ X0 q
  122.   i  t$ k4 r5 C9 V$ D' c
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))$ n6 s0 S8 V# d( H
  124.             {+ c% l2 z% a  F  U0 ]! O
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");
    ! k: z% z  k/ E+ A* o
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    ! D  L! d# p8 y
  127.                 Console.WriteLine(segment.Text);
    ( C* p' E' `) S7 w6 v# z- }' `% m
  128.                 Console.WriteLine();
    5 F, @/ [( i6 c5 R1 w
  129. / |' Y& q. L, _8 u
  130.                 // 将srt内容写入文件
    1 k% H( ]3 s1 X9 b
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");1 m$ ]' M* ~2 A- N
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");' m5 T3 K& ^$ m' a& q1 S% @. ]
  133.                 await writer.WriteLineAsync(segment.Text);
    & R# P; f4 c6 Y& G  W
  134.                 await writer.WriteLineAsync();0 L0 r6 W2 {$ R
  135. ' T3 W  I& v2 U* U4 A; o
  136.                 writer.Flush(); // 立即保存srt文件
    9 }3 w, \! g  ]% c& S
  137. : J' @2 i9 P& y
  138.                 segmentIndex++;
    % H6 E( b8 x" D* Z
  139.             }
      t* q6 D0 t3 h' w

  140. 2 ]) ~6 T; h! Y0 {3 |' l  E% p# Q, z
  141.             var endTime = DateTime.Now; // 记录结束时间
    - V+ J$ B4 S) T2 c# k4 h
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;' M( j% E! e- u0 z! C  }
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");
    / }6 e; n. E3 ~, s/ T4 v
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");% T% e' h9 E3 m- l
  145.         }
    5 j( Q. v0 @& B8 G0 Q* N: o
  146.         else {
    3 Z5 R/ M  q" d, y/ `& |/ L: J
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");
    - q, W. e* x/ `* J$ `
  148.         }9 B  }6 R( w  T" p
  149.     }
    ; ?) t6 m# A+ D; o  B# [
  150. }
    7 ]+ R5 \( p2 C& h; Z
  151. public class Options
    4 L$ v" Z1 [# w- q* U
  152. {4 {6 s& I4 K$ L4 i
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]
    9 P6 i2 a; r( b  W  ?
  154.     public string Command { get; set; }
    6 U+ v4 \7 E4 D
  155. 7 U8 A+ z# v, x5 J- X
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]
    ' X8 E' w! K* i9 _" U/ ]
  157.     public string FileName { get; set; }* b5 }  Z  C' c! z6 t

  158. 3 n6 M* H" q8 M6 p
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]
    4 ~6 v, g( a, A9 i
  160.     public string Language { get; set; }8 I6 e% K$ a! A7 c$ @  H

  161. ) V8 |! Y& \4 T. U  q
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]! T- S6 B9 ]  u$ T, b, ?* E' h
  163.     public string ModelName { get; set; }
    5 K' M- a' H' b( \) g# \

  164. 6 c3 O8 N. L! p, N. G2 Q$ r* ^
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]5 ^8 P' U0 u: @9 Z( |3 P  u, p4 O" g
  166.     public GgmlType ModelType { get; set; }
    7 k' x* u- r$ M' X: d
  167. }- x/ Q2 l' X6 i
复制代码
( \) D9 L! I: X6 H6 {9 e

) T5 w5 a6 v8 S3 x  a1 W
. j$ ]  [/ u4 e" Y3 I, `- ?2 I9 w' D
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 很美好很美好1 很差劲很差劲
回复

使用道具 举报

沙发
发表于 2025-4-4 01:06 | 只看该作者
学习学习一下
回复 支持 反对

使用道具 举报

高级模式
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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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