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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-4 12:57 编辑 # h, R" ^* `. j& t& `/ u3 w% d$ F
1 I- D/ Q4 a& r" b: r+ G  S6 s" W
本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,
6 s  z' s) u+ v; t 使用时需要輸入语言,源文件路径和目标文件路径! k. r& M$ d# G! K
最后是输出srt文件
) u0 |2 e& |+ g/ A5 R8 Q" r
9 t4 v1 ?  q7 o0 W代码如下+ o$ q7 T$ ]9 {3 @( w7 G7 l7 T
以下这句用多线程可以增速,否则很慢3 v, w% z8 j& I& O% a4 R
以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。3 D% A$ B1 q+ S4 b3 C: s

; r; Q! `  H' r" c6 S3 K) T5 _8 x6 M! U5 [
  1. var builder = factory.CreateBuilder()
    $ G- F9 ^: |4 S& F% h" e; H3 q! L
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码

/ y; r" w. l) g$ {- I2 ?3 J! z
/ Z( P: a" x; v
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT) q  @# v8 `& o2 N' |* f$ X

  2. 9 M% k. o) C/ ]# l4 K
  3. using System;+ E- A* ]4 J4 u, i& t- J7 x' w
  4. using System.Diagnostics;
    8 C9 d& t, y0 r4 z) P
  5. using System.IO;( w' N* H  U  X
  6. using System.Threading;: h3 |: J8 x, o$ I( r
  7. using System.Threading.Tasks;
    # }! N9 H6 |8 M1 s
  8. using CommandLine;# V- o; c' r$ j  M8 n
  9. using Whisper.net;7 N' t: D" j8 q) _- a. ]% R
  10. using Whisper.net.Ggml;
    & y' N- G& x; K
  11. using Whisper.net.Wave;
    ' J7 ]& B/ V' O' i' U6 D% z
  12. ) q3 m" a% `# F- [- a4 w
  13. await Parser.Default.ParseArguments<Options>(args)
    ) h. }4 t2 w% }9 q4 ?
  14.     .WithParsedAsync(Demo);
    $ Q; X( T) y" h+ B% N! f0 t
  15. ' Z( n' l- G: W
  16. async Task Demo(Options opt)
    . b0 c( u" R" H" }; h1 P! F
  17. 9 E0 |+ L) a' T# P
  18. {
    1 X& |( w( j, g" x4 {' p" b4 F! J
  19.     if (!File.Exists(opt.ModelName)); f. n0 \0 [" P: W) L% c
  20.     {3 K- a5 \6 h1 E5 x) V2 [1 T
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");  n( N6 C4 c( q% U4 n$ D
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);; z; Z" g0 y: w, Z& x! D6 s+ }& L
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);1 y/ n- T) I% |' @& K8 Q: S. Y
  24.         await modelStream.CopyToAsync(fileWriter);
    0 V, u' r0 b9 W4 v0 R, {) M
  25.     }7 {& l' B" c$ {7 h3 H2 z

  26. / U% {$ A4 o6 l
  27.     switch (opt.Command)  h9 J& d8 F3 G) a3 R
  28.     {% H' Y/ a' ~5 e
  29.         case "lang-detect":
    1 D" l; X* X8 n( Q6 @! M3 T3 d1 U
  30.             LanguageIdentification(opt);
    2 g6 U; f/ n( ~$ h6 @, n
  31.             break;
    7 D8 X3 w3 B: w+ D8 T. ^5 d% F
  32.         case "transcribe":
    $ I& b) g- O' s# p# n
  33.         case "translate":! y. B% h  S* ^  Y9 o4 \# s
  34.             await FullDetection(opt);
    3 |8 R! u* m* ~
  35.             break;# C+ o  ]% t0 K$ T, u$ g$ l! a' m" c/ ^
  36.         default:5 D: ]! |5 z1 r3 z& j
  37.             Console.WriteLine("Unknown command");9 n% O" b5 N# s, d
  38.             break;8 t. T9 L0 }3 g% Z! i4 Z9 C
  39.     }+ i; i- q* o; I4 g4 g
  40. }
    7 b: H; Q' |0 d

  41. # M+ a; }/ o$ N5 u' o4 s
  42. void LanguageIdentification(Options opt)& v# ]" t! w4 T% b  f
  43. {
    $ I) B" J+ b5 v! c8 P
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);
    : ~- b; |! s7 N. u. ^8 `! ~; F$ i

  45. % ]$ a) O1 Y' H6 f
  46.     // Same factory can be used by multiple task to create processors.2 W0 G9 ^1 q. X; {! w& q
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);
    . \- w* z: r0 s) z  T* R* D! V
  48. # P0 e$ n9 S5 j8 Z' @  B6 H
  49. /*    var builder = factory.CreateBuilder()9 E; p5 a) m1 J6 J) P# d
  50.        .WithLanguage(opt.Language);*/
    / @8 h6 B1 E7 Q7 o6 r! ^
  51.     var builder = factory.CreateBuilder()
    8 J7 E0 ^  J4 N7 y, ^6 w
  52.    .WithLanguage("english");
    , r' O9 R1 F) j5 i0 l
  53.     using var processor = builder.Build();# e& [  ^: |4 G6 k+ h6 Z

  54. 8 w  L, u" Z% S3 _4 U
  55.     using var fileStream = File.OpenRead(opt.FileName);
    4 Z# o( d* T9 r$ T* b& e
  56. - E; b6 J# i# ^  y* _  W
  57.     var wave = new WaveParser(fileStream);! P% U6 |3 p. t2 Q4 n; n- N

  58. + b. U7 g9 Q8 v. N1 S: j
  59.     var samples = wave.GetAvgSamples();2 D5 r& [( e# x. x! U
  60. : J1 e( ?: q9 M' Z* S  `5 N+ y( [
  61.     var language = processor.DetectLanguage(samples, speedUp: true);
    # z  ^# s* V, ]! ?6 ?4 L
  62.     Console.WriteLine("Language is " + language);) n  z" b' R0 x/ h( Q1 _
  63. }; @# j( j4 o7 E* s, K
  64. 0 W% d" w4 }6 J2 b+ b' w& ?# l
  65. async Task FullDetection(Options opt)+ U& I. l, h- I2 P
  66. {  Y! m" y0 z9 e- S
  67.     // Same factory can be used by multiple task to create processors.4 k3 T1 A2 y1 ]5 g9 c( x0 E' R
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);9 \7 V! ^/ M$ r( P* o5 j% f7 V
  69. " S' {; _. r" U* l# c+ F2 v
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);8 @1 s3 L; C; x: S; B
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");
    9 f8 v# A5 v" K  h
  72.     string languageOption = Console.ReadLine();
    , m+ D/ L! Y% {6 {7 x7 C
  73.     var builder = factory.CreateBuilder()
    % e/ s4 |+ ?) i
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);& [+ c" F( U$ ]3 K( x

  75. 8 h! s6 K# b/ X8 q0 C" T
  76.     if (opt.Command == "translate")
    8 [! r) Q( B) P, b- q( a; ~
  77.     {% c5 o1 U; U- }% n/ S0 z( I& x
  78.         builder.WithTranslate();
    ' T& G: }8 E$ h1 G0 `+ R9 j
  79.     }
    , |* u6 o9 Z. O& ~9 b

  80. , O4 c8 n2 @0 v! i9 Q( @
  81.     WhisperProcessor processor = builder.Build();
    ! X0 X! U) L- f4 `
  82.     ) u! ?' w& t7 s$ c: D) ~; m
  83.     Console.WriteLine("请输入wave源文件目录:");
    9 `! g1 [( ^- c& g  ]5 e  J
  84.     string sourceDirectory = Console.ReadLine();; T. k8 s: s" y% \/ M$ M, ^+ D

  85. # A0 P8 C/ ?5 ]# V! B
  86.     Console.WriteLine("请输入目标文件目录:");
    " _5 C: e- T0 d- u
  87.     string targetDirectory = Console.ReadLine();: s' K9 V8 ?+ ^. F8 B3 u

  88. # _2 [6 u1 ^: \$ U4 x
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))
    - j8 O- W3 o( _+ p, A
  90.     {. t/ |7 L) v% g7 J. @* G
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");
    8 h- L2 u3 m' O3 ^+ v
  92.         return;
    8 g1 O9 g; v- d" L4 _; A" {
  93.     }1 h5 K$ ?; n' b& ^. B

  94. ! t' g: n+ \( X3 z3 v; M0 H/ O
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);
    % L. G- p, A6 C! E- d: q

  96. : {! ], A4 W' Q
  97.     Console.WriteLine("处理完成!");
    ( K7 Q+ Q5 ~3 C6 [+ p& d4 U

  98. * i2 E. f/ C/ V- R  Q. w
  99. }
    7 F& Q9 Q/ a5 c) m
  100. static async Task ProcessFilesAsync(WhisperProcessor processor, ; R; H: \3 X1 W) _7 F
  101.     string sourceDirectory, string targetDirectory)
      O, W& C9 _: v' `
  102. {8 m" M$ V! Z, j4 l4 F
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);
    4 o& g5 j$ x% E! E

  104. " ]% n/ F7 l3 b
  105.     foreach (var sourceFilePath in files)
    4 B( J' L7 l- s: R1 R
  106.     {$ U! N! Z* J: V" d
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);% K  x7 G3 z5 p
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);
    6 _( D# o" q# \8 z& m- I
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");
    , p$ w' B# q" F' e/ G' }' x

  110. 3 ~1 a! Y+ @, m* x! Q* g
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));
    : G* j. P/ L7 ~' k+ ]! F8 I/ G8 m  m
  112. : S# W+ I) c8 V; o& a* m' f' ]3 {

  113. 9 ^6 f7 |6 ~& _) P5 T4 J% y9 B: p! E: F
  114.         if (!File.Exists(destinationFilePath)). f8 G9 l( [- G2 D1 K  Q
  115.         {5 Q, N' t" P* e- m# f( i8 Q, r
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");
    1 w& g* Z6 K8 e, u
  117. - p9 X. {* c9 K* b' P1 B: Q# I+ ^
  118.             using var fileStream = File.OpenRead(sourceFilePath);* C' f( n/ W; U9 A  V: s- ~8 `0 G
  119.             var segmentIndex = 1;9 p, L) z. [. W1 c7 w2 H
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter5 m+ q  |! V' `( P, V
  121.             var startTime = DateTime.Now; // 记录开始时间! t6 k7 G6 a4 J% X+ n: h
  122. 2 t2 g) ?) }3 h7 d5 x& Y3 V
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))/ _( \- E$ Q) ]* B7 D2 @6 n& N
  124.             {% s/ X( r! [6 B8 D+ x6 J
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");
    ( L. Z  p$ n1 l- @
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");5 X$ P9 j+ G- c; H# \: L% ~! ~9 n
  127.                 Console.WriteLine(segment.Text);& s$ e8 W0 }! N+ Y* u6 H7 O, i6 @2 l
  128.                 Console.WriteLine();1 u3 E0 d' T0 N% Z
  129. 6 F+ ]8 X& P: X/ G1 m/ T* q
  130.                 // 将srt内容写入文件) P% a" N. R$ V) a( q1 T
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");( O! f, O3 O/ w5 ]
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    # m' K1 u! M% u6 R
  133.                 await writer.WriteLineAsync(segment.Text);
    : u4 w! I, G. Y( y
  134.                 await writer.WriteLineAsync();
    . k$ b* v! e+ r* q: ]/ |0 e
  135. 1 [& V' B/ \! t+ p; J6 [
  136.                 writer.Flush(); // 立即保存srt文件
    # g( j, ?6 S' ]1 E' V

  137. ! e) v- d' r: T& w& i9 p
  138.                 segmentIndex++;: ?: s- M2 Q" y" F6 u3 o7 G' m
  139.             }4 V8 k& X* D5 s7 w
  140. ; C0 W0 F. X/ A7 ?
  141.             var endTime = DateTime.Now; // 记录结束时间! v  t( Q4 W. B  [* \, D
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;2 J; t! @( ?' _& f& {! C3 p
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");" }! o2 O; H' L; f3 _
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");
    & \7 ?* K  m0 h+ [2 T% j
  145.         }
    * E" I0 |& ?3 K
  146.         else {0 ~) x8 `9 g: V9 y: W1 O
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");
    ( E+ H* G! Q1 X1 H" E  F
  148.         }
    " \2 g! ^  Y3 K7 _
  149.     }# j5 X' O5 [2 l; A2 a* k
  150. }1 Y2 @5 V1 h1 R2 C7 r
  151. public class Options9 w; N4 u- J9 ^; ^5 q1 b% s
  152. {
    4 G& w2 h7 B! D$ E
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]
    $ s+ u& B/ L& A8 Y% y5 ]
  154.     public string Command { get; set; }
    * G# V3 I1 Y+ ?" q  E; w. h* q
  155. ( C+ A0 Q8 c/ ]* b
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]
    4 E1 a8 Z+ O. ~. R. v/ ~* n
  157.     public string FileName { get; set; }  e& w0 d3 Z' `0 f) o/ U, K: k4 n* U

  158. 4 g, y. M( k/ G& U0 n! y- Q
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]
    , m9 w6 c' m# C( Q4 U4 w
  160.     public string Language { get; set; }
    2 W' o8 E( K- G# E' T* H

  161. 8 ^7 i, s' A6 z/ @4 f
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]
    ) h/ l4 k1 l4 P9 H/ Q2 x
  163.     public string ModelName { get; set; }
    2 Q' r, _2 A% i/ ^5 I& J, L. Y5 m% T

  164. * S* n% H! R) Q9 |
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]
    # L: {! P0 d/ S6 Y# S
  166.     public GgmlType ModelType { get; set; }
    2 r/ O- o0 a6 _3 u  {+ {
  167. }
    / C( t3 K" S. ~9 s
复制代码
% S' [; M1 I: Z
# K/ B% q% ]$ R0 h/ o6 r
% f6 ]) Z: E- w. D) ~2 v

9 `4 C4 N5 Q; A# M! f% }8 f" ?
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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