冒险解谜游戏中文网 ChinaAVG

标题: 【汉化工具系列 #2】指定wave格式转换为srt格式字幕(CPU版本) [打印本页]

作者: shane007    时间: 2023-9-4 11:03
标题: 【汉化工具系列 #2】指定wave格式转换为srt格式字幕(CPU版本)
本帖最后由 shane007 于 2023-9-4 12:57 编辑 ; O$ X; q% ]+ p! _+ y5 C
2 J+ f  n+ e1 [9 w/ k" j: E8 e
本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,+ O/ `: l# T2 E7 [' n- E; v6 o
使用时需要輸入语言,源文件路径和目标文件路径
) P0 T# X8 P' N7 b0 A最后是输出srt文件
6 H0 {+ m4 @2 M8 N4 ], H8 x" X6 e/ o1 S/ g  k3 H7 X: S
代码如下
, D* t5 R8 u5 y以下这句用多线程可以增速,否则很慢
( `& U5 P: L) d以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。
+ T9 y9 n. c/ Y# ]- I5 }1 I
; ]6 `6 Y+ z6 D& H8 {: `' U" r7 C0 `3 E- p  R% U
  1. var builder = factory.CreateBuilder()
    ; P( c/ `0 z. s0 q& S6 w  a- A
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码
) X8 B7 o  Q4 W3 L

9 g( i: Q; o4 w& ]' Z; H5 t. @
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT
    / I' j- m  U7 G, q- H$ I" k; x1 t" D
  2. ( u6 l6 A2 m  ]5 r  M. J9 K
  3. using System;
    * A% M! m$ s3 `, _% s2 z: L8 `1 ]
  4. using System.Diagnostics;
    ! i4 n# O- K& P3 C3 v: j
  5. using System.IO;
    7 }, C" t( F: D; D2 y4 }
  6. using System.Threading;: W5 @/ A/ B' l" P2 T5 w: Y& Z
  7. using System.Threading.Tasks;- q4 g( a+ d( o/ W
  8. using CommandLine;: \/ Y9 M4 K; \4 t
  9. using Whisper.net;
    # S' k$ @8 E) s; U
  10. using Whisper.net.Ggml;- U+ b5 \6 ?- ?' L
  11. using Whisper.net.Wave;4 {3 f2 {8 l8 X1 A* f0 e: z% e5 E

  12. 9 }2 b) r) t) a
  13. await Parser.Default.ParseArguments<Options>(args)
    + t2 ?: D+ J8 \+ f! I+ N9 G1 }5 f
  14.     .WithParsedAsync(Demo);! l% E" M( x8 s& d2 N9 A) n
  15. ; }% @# n, v3 v
  16. async Task Demo(Options opt)
    * @& b6 @* `, h8 o  v  a# n$ T

  17. . F: Q1 Q/ P% a! j
  18. {; A3 x* k4 \. @' y1 [2 n' }, x
  19.     if (!File.Exists(opt.ModelName))
    % M" Z% P5 L' P. ?% c
  20.     {
    & _1 b) Y1 E0 t: `1 `1 ]" Y8 l
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");
    . Y3 ^( L, o) L" f
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);
    : P3 q4 Z9 @0 C$ [3 u1 }6 ?
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);
    5 d$ v( \* s8 o3 l6 c/ a
  24.         await modelStream.CopyToAsync(fileWriter);
    8 Q2 x% g# b* N$ Q. u8 n% e7 ]
  25.     }8 N! q; I, N) V2 ?$ G2 `

  26. " I3 Z) N% \% W$ Y. P/ J
  27.     switch (opt.Command)
    " o+ f! W6 W9 L: B, r
  28.     {
    - U2 ?7 L+ _' F% }4 Q. Q3 O
  29.         case "lang-detect":& q9 j! R/ [6 d, t
  30.             LanguageIdentification(opt);+ r/ g" z& `- y+ y# |+ s7 p
  31.             break;
    $ m* \- ]/ _0 C# X9 f. j! r7 `2 Z
  32.         case "transcribe":" X/ B+ ~9 A% X+ ^/ t* f
  33.         case "translate":
    ! j5 y  G$ d7 L* v/ Q
  34.             await FullDetection(opt);
    / P' }. w* B. g
  35.             break;
    + _0 Q/ o0 c1 u6 C
  36.         default:2 ]3 @1 r) a' O7 r0 u* q) w
  37.             Console.WriteLine("Unknown command");8 V- x" ?8 f* O+ E' Z3 [( ~+ Y
  38.             break;
    6 n" N' M4 g6 [) P% h2 Z: r6 V
  39.     }  g( x8 k1 U/ K6 M, Y2 G3 x
  40. }
    1 q1 [! H* A2 k. G- _& k

  41. . Q: x6 q1 L, ]
  42. void LanguageIdentification(Options opt)6 {  {4 w& j2 @$ p8 g1 i$ N) W6 N
  43. {! @! Z) i. l; R% I$ c
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);4 r/ w. y5 ^2 V# L& }9 X
  45. + a8 d% W7 n3 o7 f$ z( l( y
  46.     // Same factory can be used by multiple task to create processors.. m7 G! ]3 A9 T" h" e+ f
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);  y' d0 g$ p% ?

  48. 3 Z+ p1 Y) d$ W7 C+ ], Z& f3 p
  49. /*    var builder = factory.CreateBuilder()& k; Y$ z1 Z  I6 j( _4 _! a
  50.        .WithLanguage(opt.Language);*/
    - a  Y4 x3 d. i# E8 A5 l& h
  51.     var builder = factory.CreateBuilder()4 v. l& {% Z( v4 ?$ y) Q
  52.    .WithLanguage("english");
    3 E6 l7 ]! C9 e" n/ V5 Y8 m! C: S
  53.     using var processor = builder.Build();6 b& X9 L! b: w
  54. , M& L; F; J& w4 w6 ]
  55.     using var fileStream = File.OpenRead(opt.FileName);: r& f& m( i1 p( g! |% {

  56. 7 W8 Y: ^- {4 B5 z0 G
  57.     var wave = new WaveParser(fileStream);
    - }$ r' C7 a! R# |, Z: z5 L
  58. ; Z* J) f( e: o7 Z* E9 K
  59.     var samples = wave.GetAvgSamples();
    - u' G7 Q: g9 ~$ `% p
  60. & u9 s, H% I$ T9 v; b7 y0 G% b
  61.     var language = processor.DetectLanguage(samples, speedUp: true);
    , m) z. Q8 ~- X/ |% z1 q8 L
  62.     Console.WriteLine("Language is " + language);
    1 |0 X2 P9 ?5 x) t. ~- h3 X, T
  63. }' q7 V6 r% Y+ a) G7 i

  64. ' z: e" e3 ?, @7 s. h/ S
  65. async Task FullDetection(Options opt)
    ( X, y2 S7 @, Z1 T9 I& [; i
  66. {. \. N+ W) W  f1 C
  67.     // Same factory can be used by multiple task to create processors.! C8 e" P5 Y8 u, L) ]  }! g0 \
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);
    + p/ r. Y5 K$ Y6 |( \/ [9 P' y2 }* c5 d
  69.   X, f! Z& n- o" h  `" ]
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);
    ! g  Y, j  Z/ @2 [2 r8 L
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");/ x& c) X& U6 g- i% \# C
  72.     string languageOption = Console.ReadLine();7 M7 X' ?, T9 J7 F( J3 h, J
  73.     var builder = factory.CreateBuilder()
    6 R2 x& Z- C; Z2 Z7 P6 y+ E0 [
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);6 J. r2 H6 J- Q4 ?5 Y

  75. + p8 n$ p' r4 S7 B( Z( F
  76.     if (opt.Command == "translate")4 z5 @9 z* `& O: j5 P0 C6 `; c
  77.     {
    7 _. g0 ?4 u6 F- m/ w5 W! S: i
  78.         builder.WithTranslate();' l) [: |7 s+ }4 l. T
  79.     }( f$ x* Y: o0 B5 h

  80. / u; C8 A- A0 O
  81.     WhisperProcessor processor = builder.Build();6 A6 h, R- q% Q6 i+ E
  82.    
    : e' c) B& i( f4 [  ?
  83.     Console.WriteLine("请输入wave源文件目录:");& a: {& l; k) Y$ B
  84.     string sourceDirectory = Console.ReadLine();
    0 p5 ?7 z* D" N6 ~6 e

  85. 0 |. \! s3 t( _2 q3 x3 b; I% r
  86.     Console.WriteLine("请输入目标文件目录:");' P' Z0 o) B* {0 b0 c
  87.     string targetDirectory = Console.ReadLine();
    2 b, b" M# U3 R: U; f) _6 r/ X) c# ]
  88. & ]3 H0 t% \6 e" C  j/ b
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))
    ' \! h- `- P& _- Z, m; S
  90.     {+ z6 Q( Y# d) Q+ m6 C  w5 W
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");
    0 p1 B2 k) h3 Z$ ?' a5 W# s5 `
  92.         return;0 \" L0 N$ I. ?3 W
  93.     }( }8 c& a' P: W) k$ p5 n
  94. 1 ~6 Z3 q1 B0 U' B1 A# {. S" \$ N7 a
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);
    2 v) d8 q5 J, b+ j+ e* D' l
  96. & t2 h" z% l& r" {- d
  97.     Console.WriteLine("处理完成!");8 S4 x3 k; G. q7 w6 q
  98.   f" [# p4 z# o+ z
  99. }0 l( [8 {, D& l# \3 b- I
  100. static async Task ProcessFilesAsync(WhisperProcessor processor,
    9 w& p0 g* {- T, \4 v; B2 N1 K9 j3 d
  101.     string sourceDirectory, string targetDirectory)
    6 K6 a" A* `2 S- y8 c
  102. {- W+ E3 n! I! v
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);
    - ]1 ?' y  X' c* t- O
  104. $ E$ U& M3 ]+ O* B4 K) R, Z1 P( N
  105.     foreach (var sourceFilePath in files)2 m! w" E$ h0 |- E6 P$ B
  106.     {
    . W: x6 C4 m. W/ B" k. N
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);
    / K  L+ j1 ?, \
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);# e7 z" R- x$ n9 Q5 S
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");$ k2 x( p$ z) B7 m- O
  110. # T5 ?$ w: ?" H' G- f# b& N5 g" H  t
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));4 l& V) ^) @# K0 v) {
  112. " o. g# o7 X5 M0 q
  113. # C. B; }5 M- o# g
  114.         if (!File.Exists(destinationFilePath))
    . ]) c* \5 C; P9 `; b7 q: p
  115.         {3 Y. a# U, q: ?
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");. Q* p! z( A5 e. o5 d

  117. 3 k8 e8 U7 ]6 t
  118.             using var fileStream = File.OpenRead(sourceFilePath);
    9 M2 \9 s" {# J( d: z) k
  119.             var segmentIndex = 1;( Z2 E% M+ o2 P4 {4 K  @4 e$ M
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter
    # k7 `0 q4 ?: v6 v! i" R" \
  121.             var startTime = DateTime.Now; // 记录开始时间
    " a/ a- E8 e9 z" E3 o+ ]
  122. 4 a7 o) Y, H! \" H
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))
    / R. I# Y8 b; _, `5 q" Z! V
  124.             {( n( z5 @; V4 k7 L6 |% R1 \$ y
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");
    & B; r% ?* g  P$ X, t# y
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");& f  L# Y9 N! R- ?
  127.                 Console.WriteLine(segment.Text);9 F0 B: e0 E- |+ [" m
  128.                 Console.WriteLine();6 ]7 s0 X& h3 _$ \- A7 O/ n  }
  129. . ^- M" q  b: S  q9 k) p9 ~
  130.                 // 将srt内容写入文件/ @  D2 |8 O3 U) e1 a. }& Q
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");( A0 n; o7 G: H/ b* D! n7 Q
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    7 v" X, f2 f* O/ u
  133.                 await writer.WriteLineAsync(segment.Text);0 Y' r# J2 A, W# t1 [9 G$ e
  134.                 await writer.WriteLineAsync();: C- S( y6 Z+ g2 |3 u3 T/ L

  135. , s% D. F/ k; [, X0 o
  136.                 writer.Flush(); // 立即保存srt文件
    5 X. b) f5 q$ o3 ?: ~
  137. & P4 [: h# P, b: t
  138.                 segmentIndex++;7 W3 D+ O8 y4 L5 v7 r
  139.             }
    2 W# u' ?& G7 B/ Y

  140. ) m' l' d3 k# B1 w
  141.             var endTime = DateTime.Now; // 记录结束时间0 j1 [$ h& G1 c9 b2 L  |/ _/ r
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;
      ~& d- n( D0 l0 y
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");
    7 N( B- K. w6 C3 a9 z
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");
    1 K- e- ?0 g$ W0 s+ g' Y( f
  145.         }
    % u* _% q8 \" f7 D
  146.         else {" U7 w8 o+ Z, v, q8 f$ g# t$ [
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");5 i% o' b9 y" q) l: q, A/ a+ ]
  148.         }
    9 W8 x8 D- ^3 J
  149.     }& x  J( g$ W& ~1 u  n+ ~
  150. }
    " ?# S! d) @- s1 v: z% H
  151. public class Options0 z$ M- O; V) W
  152. {
    7 g2 J1 Z7 E: k' W8 l1 u" q
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]
    0 U: T: T$ L, i0 \/ m0 m
  154.     public string Command { get; set; }
    5 L9 M& q1 F+ W& H! p" ~/ F
  155. , ]& d* J# h  m2 u; S
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]" N/ G6 S+ k0 U
  157.     public string FileName { get; set; }
    ; C+ D8 S) j" w: l( Z
  158. 8 K, x) z6 P% K0 L
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]
      c/ ?- o3 p3 M
  160.     public string Language { get; set; }5 ?8 r1 X2 i; i0 h, m9 Z
  161. ; |, i" W& ~- ]6 j
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]
    6 a: I# W4 i' L3 P
  163.     public string ModelName { get; set; }; Z, ?5 O1 G/ D+ _! T7 s

  164. 7 ~. @8 R3 e+ Y6 |
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]
    ( _/ J( L! U9 O6 x: v- F9 }8 A
  166.     public GgmlType ModelType { get; set; }# y; Q3 ?0 @( {/ R" \
  167. }" t6 v" v! a$ z# ?
复制代码
/ R/ B  }2 N0 V6 B+ E

6 G) [3 W; ]5 g1 V, n' n, l' ?% o% I* `
% E% {2 R1 P4 }6 E8 c  u9 E  Z6 o





欢迎光临 冒险解谜游戏中文网 ChinaAVG (https://chinaavg.com/) Powered by Discuz! X3.2