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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-4 12:57 编辑
( l! X! ?) u: G( l3 i9 Q2 \* u9 i6 e+ x- k; ]; X7 b! i% j: j' y
本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,
) l6 G& ~8 d& y- n0 R/ M 使用时需要輸入语言,源文件路径和目标文件路径
- H# E9 k5 N+ V1 H1 s; ~最后是输出srt文件
2 q2 z. B6 x+ T$ l3 h/ L( y! n+ ^/ }5 X# m
代码如下2 n" x8 a6 h) G) d
以下这句用多线程可以增速,否则很慢: B/ _0 m3 C9 e7 J  n7 r" H* }
以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。! _, h/ r2 Y' I* Y5 }5 X1 V

8 U- {4 r; T: h% M, }/ f3 `
0 k8 n  Y8 o4 Q. L8 |! U
  1. var builder = factory.CreateBuilder()5 W- B/ U# R% r! a6 ^
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码
; C1 B% g3 v" u* x& F/ g

: b* E$ J2 @; G  M5 }( k
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT2 N) M) X, v! J0 [: S/ n) L7 D

  2. 6 |" z( P' P9 C  e: Q
  3. using System;. i/ t  w8 J, }8 R
  4. using System.Diagnostics;/ F9 O/ K0 ]4 B
  5. using System.IO;
      k; m3 ?* h/ z. z7 E4 M9 N/ Y
  6. using System.Threading;, O4 E/ a% G5 {( n# i4 G6 H
  7. using System.Threading.Tasks;+ r% M" B. [4 T9 z) q0 T* W
  8. using CommandLine;9 N4 D0 i" _- w- m
  9. using Whisper.net;5 L. A0 s: }" p
  10. using Whisper.net.Ggml;: b! k7 M5 z1 ?- S6 @
  11. using Whisper.net.Wave;+ X- Z7 k1 u8 ?  m; @

  12. + }; u6 d9 G# D! c, l
  13. await Parser.Default.ParseArguments<Options>(args)
    0 p& {0 j4 U& n7 y: e( v) L5 N
  14.     .WithParsedAsync(Demo);5 D- q) T. x8 c# u. i

  15. 9 g, F6 b. F3 a- S
  16. async Task Demo(Options opt)
    2 K3 `! `+ O8 _6 b0 d

  17. ) F# V. L8 L1 h4 G$ n9 Q
  18. {% O& f; u0 Y: y
  19.     if (!File.Exists(opt.ModelName))5 f* N2 t- K/ [: M) s( A7 |9 s
  20.     {# H- j7 o) d- O7 U" J2 S, Y1 E
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");5 |1 t3 M: ~; l
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);
      P9 q$ a7 f; b( K! T
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);6 H# V. j9 W) K9 o  Y; m6 Z
  24.         await modelStream.CopyToAsync(fileWriter);
    + s4 Z* z. v0 z6 x+ i4 L
  25.     }
    8 ^8 s5 z& k1 Q% h* I

  26. 4 Z. H2 @2 T# B5 F" Z
  27.     switch (opt.Command)
    ; s! ?$ l- J! v' P7 l  W7 A
  28.     {
    * @( A) B: O' H
  29.         case "lang-detect":; m( ~" l9 I3 {* S4 @& l
  30.             LanguageIdentification(opt);; T/ z# B0 C* B9 a2 r  j7 ^& O
  31.             break;! X: b9 g' ?3 V: J( j4 {  S  Y
  32.         case "transcribe":
    ( m- @7 [9 I$ A  j& d
  33.         case "translate":
    ( X( ^: [# z; Y7 u' X) g1 r
  34.             await FullDetection(opt);. y* r) _0 x& k8 a" {( s
  35.             break;4 ]: Q6 [2 ^! s0 a9 U! K6 ]) b& c
  36.         default:; q3 q; n. L$ y7 D# u( I8 L4 \
  37.             Console.WriteLine("Unknown command");
    + j9 a+ n; }) \# L
  38.             break;
    ! B% m1 h% Y, q4 W
  39.     }: t" |- v% w4 F" k* F6 O
  40. }6 X0 D) o* M& X& b
  41. ; O8 {; l% M( f7 t
  42. void LanguageIdentification(Options opt)! \# W* m  G' R( {& h
  43. {; m7 _6 o; m( e
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);8 V/ }* p: A6 _' \

  45. 0 X+ e. X9 I8 M
  46.     // Same factory can be used by multiple task to create processors.2 Y, y2 ]+ I0 j' L4 H! p
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);3 B8 d; m) ?+ r( A

  48. . E# W- c5 k& W# D& n3 E% ]
  49. /*    var builder = factory.CreateBuilder()
    ' h! _) j1 d+ N& u' _
  50.        .WithLanguage(opt.Language);*/  m& m' `6 j. ]9 K' q! h5 i7 e
  51.     var builder = factory.CreateBuilder()
    3 U1 h, g5 I' g$ h0 G
  52.    .WithLanguage("english");
    2 p2 j" @# k. A6 |% p
  53.     using var processor = builder.Build();' h$ c8 ~9 H, }# |: X: ]

  54. - q/ a$ ?) a0 \
  55.     using var fileStream = File.OpenRead(opt.FileName);
    3 j6 L2 y6 j6 v9 Z8 `' ^" L

  56. ( I) t" G+ ^/ g" N
  57.     var wave = new WaveParser(fileStream);
    5 p; {: n& C. i" [8 e6 [4 x; o
  58. $ R  W8 ^0 Q5 j* t
  59.     var samples = wave.GetAvgSamples();
    # R; ]3 s% Y: f0 O, M% i6 I. b- h

  60. ' a. N" O, u9 \5 O
  61.     var language = processor.DetectLanguage(samples, speedUp: true);6 x  O' @' Y' q: v0 Z( O. @
  62.     Console.WriteLine("Language is " + language);  u4 l% r; r0 n& k" {. r
  63. }
    - o+ C4 M  G* t& c6 x3 |  f2 q& Q2 k

  64. + I1 A8 v4 o4 E2 J/ n" Y
  65. async Task FullDetection(Options opt). z: s; {6 f1 e8 g) ^2 ?- r* h+ j
  66. {/ d$ i8 t/ F% V0 H# c
  67.     // Same factory can be used by multiple task to create processors.
    $ k9 s; c  L$ X) U: K; Z1 X
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);7 @7 C3 K4 |9 W" e) t
  69. ( s. H: P( r$ L! _" `* Q& Y! Y& n
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);# o3 w* R% D& S
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");
    : X6 e) N% c# F. w
  72.     string languageOption = Console.ReadLine();
    8 ^; m: K# C. d4 O
  73.     var builder = factory.CreateBuilder(), c% W& j# W$ e
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);0 [3 \! Y3 \0 y
  75. ! m* K( e6 M3 d6 P: x
  76.     if (opt.Command == "translate")$ Q! b+ ^, {! l' Q& ~" J2 M- F
  77.     {" e! A$ W5 r2 H, U3 ]$ I
  78.         builder.WithTranslate();
    + }. a1 E7 W$ F1 |
  79.     }
    * i% ^) L4 z" _8 {
  80. 3 w4 v- k8 s7 f5 W
  81.     WhisperProcessor processor = builder.Build();5 w' ^  k' z9 o& u+ J0 r$ Z: p+ e/ c4 `6 h
  82.     & u1 J" m7 J! Z% q
  83.     Console.WriteLine("请输入wave源文件目录:");
    ( g6 M* Y# W9 n2 G" `
  84.     string sourceDirectory = Console.ReadLine();2 p  H6 U! C, A; n, V

  85. 7 _) a. V/ }* E0 A, H
  86.     Console.WriteLine("请输入目标文件目录:");4 C0 g9 s, r7 F) q2 c/ I
  87.     string targetDirectory = Console.ReadLine();
    * _# G; f/ q- Q! c' x1 r

  88. 6 n3 I( [- f! b6 v- ?
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))
    ; ?( `7 ?& a- e. C
  90.     {8 l, g; J! Q4 }# N: z1 K
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");
    3 j3 f) q6 X6 r3 K$ b
  92.         return;& I* T% A. N, b, |7 O
  93.     }5 Q2 R  U/ S' ^/ O# x3 `) E
  94. " p% q6 z  C2 U! u5 _, j8 }
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);
    6 [* B. y* q9 S* e; n

  96. ' H- b$ T* f0 ?9 B
  97.     Console.WriteLine("处理完成!");& @" W/ w  C! w
  98. ) r9 g9 c8 B! \) h! W- d
  99. }& I3 G; J! q$ g' w, E
  100. static async Task ProcessFilesAsync(WhisperProcessor processor,
    % I4 ~# e6 |7 \/ h$ s/ `
  101.     string sourceDirectory, string targetDirectory)
    - s# E; m  ~" J+ X
  102. {  n( o. ^8 G" {4 t* B1 z
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);
    5 z- c5 \6 I9 e, L9 j4 M. o1 R& c
  104. 2 g2 S4 Z# i8 a+ J
  105.     foreach (var sourceFilePath in files)& v9 B* L7 {& C* @6 p% I
  106.     {8 F1 ^/ z0 O; Z7 E4 Q
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);: z8 t8 q7 z, \% C3 T
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);) G/ ?/ ]8 D/ D. W
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");
    , ~! o8 F5 r' x: j9 E- J# r
  110.   w$ {& O/ k1 W: s+ p8 J/ L
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));6 ^! w& s$ W& i( p7 @) x0 Q

  112.   C. U. c8 e* h! i& j2 e$ {
  113. 1 G, |3 [6 f; f- h& u& n
  114.         if (!File.Exists(destinationFilePath))0 n7 s" X0 ~+ s; a0 Q; w8 X4 E/ W3 F
  115.         {' z, S# L! e7 U& j8 M( t, \6 S5 v
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");, Q0 T, G" O& |9 q
  117. * _" y9 y& B6 u2 J5 o* d
  118.             using var fileStream = File.OpenRead(sourceFilePath);! l6 s1 W* E: d! l) z7 ^
  119.             var segmentIndex = 1;
    1 }5 \, c9 r+ y6 f5 [0 w& F
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter
    ! u, w4 @* F' J& c% x$ p
  121.             var startTime = DateTime.Now; // 记录开始时间: A, {: R7 B2 I% O# @1 l7 o" q" f
  122. 8 s; }. p: o7 R
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))
    ) L1 t7 V' ~8 ^$ g
  124.             {8 i9 [* C* N) M/ |: v4 o
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");% O) v. Y3 _9 J7 M6 U0 V
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    2 b0 V4 {' J7 |& C3 Y/ s' q* `7 [
  127.                 Console.WriteLine(segment.Text);
    0 q7 ^6 L; I" E" y& o$ m; _  C
  128.                 Console.WriteLine();1 X3 a7 K5 k/ q
  129. , v0 a) x2 V0 f3 T" @; A
  130.                 // 将srt内容写入文件
    : O1 J" S$ W' z2 f5 Q& Q/ ^$ }- c
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");
    * h. L: m% W5 H$ y0 d. J
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    3 w# |( V4 u- |$ k
  133.                 await writer.WriteLineAsync(segment.Text);8 p: }9 e$ b' r7 U0 ?( U+ b
  134.                 await writer.WriteLineAsync();
    0 k$ n/ f7 b' G0 E/ i
  135. % Q  X4 |& [; a4 s
  136.                 writer.Flush(); // 立即保存srt文件! W& A$ \8 K, q; j' h& b$ o

  137. 3 R+ \/ J0 k0 G* `( k
  138.                 segmentIndex++;
    . L( m& d# Y; N6 ^6 z" E3 n% y
  139.             }
    + n9 _$ X- I7 Y& S7 K

  140. 6 h4 U3 L( H( j
  141.             var endTime = DateTime.Now; // 记录结束时间) m+ S. a/ M3 I, P4 T3 _
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;3 Y- }7 C$ i, u( A
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");( Q: W. U3 f2 E/ v8 u: X6 F
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");+ V& a% U- a4 ]5 C& G
  145.         }
    , R8 S0 ]3 u8 x# [' V6 T
  146.         else {2 M" s6 N8 {; J- i9 N" G& R
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");* k; `2 X2 D, L# v
  148.         }( {" Y" Y# M, b: e6 B
  149.     }) \# N, {; ^5 h
  150. }
    7 E; q* g2 ~2 `- m" N
  151. public class Options
    1 t; D8 o* i4 u* y/ i
  152. {6 b8 A. c! |) l$ ?( Q5 N
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]
    ' ]. S8 F$ S8 w
  154.     public string Command { get; set; }( w6 j* V1 o  g6 r, q8 {" V
  155. . Y. y( {$ l# w' n& o- J1 m
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]9 ^, W3 s+ ]$ L3 C+ K* b  C
  157.     public string FileName { get; set; }% v4 E: @4 s' m1 Z4 E! ?

  158. , T$ h# c8 I! w" f! W
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]
    9 a. d1 J  M7 C6 g9 }$ ~# }8 |2 B
  160.     public string Language { get; set; }
    . }# A5 y  A0 r; Y

  161. 1 X6 d4 E6 X* c9 |% Z
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]2 E  z, B* c2 Y1 Q* l6 s% P: z/ l
  163.     public string ModelName { get; set; }
    0 ~' ^- I( O3 s* O
  164.   ?( M. d2 V8 {6 P$ V; p/ a' u
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]
    8 ?) p7 b% H% O( I- j9 J
  166.     public GgmlType ModelType { get; set; }% n" r0 ]  @/ H
  167. }6 i$ \9 I" ^$ D2 H: i8 e. Q
复制代码
: {# f' r& F! W9 b& z3 Z
/ \1 E/ Y' H5 L- J: R# R3 Q
5 H; T( n5 q- s7 x" y! ^8 h& q
% B9 y3 m, z8 K- K- X- ^% R6 ?) V
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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