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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-4 12:57 编辑
+ Q  U  k  w- ]: ?$ Y$ O) n
! l' e/ J5 e4 w: Y+ r 本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,9 ]4 [- k8 J1 L
使用时需要輸入语言,源文件路径和目标文件路径# T8 O2 X0 Q5 Q7 e% w
最后是输出srt文件
' m6 p6 _1 ]+ C1 j
  c1 j* A/ b  i2 o代码如下  m8 K; ~% h* f3 {* ]2 `/ E
以下这句用多线程可以增速,否则很慢
' `& k+ d& [2 r4 t- Z1 A; y以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。
7 _7 r) a; ~, v# A0 \6 z7 ~0 \/ M4 |8 d! i4 H
7 C  f4 F; p9 h, ]/ v2 R5 V6 s/ A4 B' }
  1. var builder = factory.CreateBuilder()/ ^' Y' m$ g; G8 v
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码
$ y9 `6 `6 K( J$ f2 H

* F8 X4 p$ q' u; k( Z0 G* C: j1 a
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT5 b; W  U2 h6 k& h5 }: b6 a: H1 q

  2. - V% ?! B- l6 B- r% ?6 R
  3. using System;
    9 _  Y, m  x7 r2 \- M+ C$ m  b
  4. using System.Diagnostics;
    ; F1 d' z: D& l7 e
  5. using System.IO;$ I" n+ `5 a9 K( \
  6. using System.Threading;8 m$ X, b1 K6 e0 t* G( t9 X5 J3 w
  7. using System.Threading.Tasks;
    6 v- v9 E0 i9 V
  8. using CommandLine;- d5 @0 v% Q' Y8 V$ q
  9. using Whisper.net;3 S/ v! |6 G  a3 c: |7 a
  10. using Whisper.net.Ggml;1 m1 Y* K# v4 V1 @! O" d
  11. using Whisper.net.Wave;
    2 m2 ?8 n' F6 K, N9 M- b1 x

  12. " }' o% c- {5 T
  13. await Parser.Default.ParseArguments<Options>(args)$ t4 k9 ~# C$ q$ w6 q1 K
  14.     .WithParsedAsync(Demo);
    - n/ A2 T1 s' I) }' u
  15. 6 J/ V9 K( G" [/ w0 K0 p: W( F# z
  16. async Task Demo(Options opt)
    0 y" [3 D1 q* P9 z

  17. ' v7 o- ]9 |% ?3 U7 z, w
  18. {) u1 J8 w5 b* s. Z! p# w7 o, r
  19.     if (!File.Exists(opt.ModelName))& i/ z4 Y- t3 A" h7 u0 o, m
  20.     {0 d$ B1 [" y; }; N. G' ?' V$ c5 b. k. U
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");) ^0 h6 v: I6 _2 a$ E+ F+ x
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);  Z; T  ?/ q! D0 R! [
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);& H9 d6 l) J( R
  24.         await modelStream.CopyToAsync(fileWriter);& B/ s# J4 _; r) D0 Y' e, {" e
  25.     }' _. W6 g/ C) x- {& @7 |6 O/ u
  26. " ?6 K: ?; }& G7 r
  27.     switch (opt.Command)- u' c: `+ P# v3 X
  28.     {( P; E3 i1 A/ R& D1 |2 T$ D5 [
  29.         case "lang-detect":
    4 _. S& z: E0 [
  30.             LanguageIdentification(opt);' w- @, O. d5 H- w
  31.             break;
    . D6 G& `- w5 l2 {$ W1 x2 F. k( ^
  32.         case "transcribe":
    ; Y1 {) p" ^! X# e
  33.         case "translate":; N/ j+ F0 z; O
  34.             await FullDetection(opt);
    & E5 g8 l  h9 D& c4 I; z
  35.             break;
    " C/ r: [( [0 E
  36.         default:
    1 B( `2 Y% X- x. }
  37.             Console.WriteLine("Unknown command");
    5 A0 d3 N  ^( S6 [6 V; Q* E
  38.             break;
    1 B, g1 }3 p% T6 x8 p
  39.     }
    0 S3 v  j" p0 H4 t' M
  40. }
    , a% X1 U  J1 o  [* y  P

  41. 5 I+ r0 R. b+ f# D: f$ O" W- U
  42. void LanguageIdentification(Options opt)
    2 |/ v# q1 a9 R) ^1 d+ O( n, X
  43. {
    - i; V- X2 B, T! A' ]8 }
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);
    - W  M; L8 f) b. H! D( ]' p

  45. / F+ i8 C+ p/ ?2 L/ R' i! G" o) S
  46.     // Same factory can be used by multiple task to create processors.
    0 Y, b% v4 {7 g) S: ^4 p0 R- e
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);
    % `3 c, k% n. y$ a' {

  48. % k! M/ U, J5 o" s/ f3 u
  49. /*    var builder = factory.CreateBuilder()
    0 v* j* }3 L0 t; c& a' M, y
  50.        .WithLanguage(opt.Language);*/
    $ O( M' V; Y1 Z, N( t. p" @
  51.     var builder = factory.CreateBuilder()( b3 d7 C/ q# c- k$ H6 D4 q
  52.    .WithLanguage("english");
    3 l, ?5 h1 Z3 Z# X) |
  53.     using var processor = builder.Build();7 y) C/ E! ~- z2 X2 E4 E4 w( b
  54. 6 W# l' H, \  b+ a- P7 f! f
  55.     using var fileStream = File.OpenRead(opt.FileName);
    - x6 p: M5 o  s/ P
  56. ' o; M  z, N3 K+ s
  57.     var wave = new WaveParser(fileStream);5 d; q# L0 W( ]% f9 }

  58. , |$ }8 o3 G! g
  59.     var samples = wave.GetAvgSamples();
    6 C7 j' p6 N9 G) \& ]7 `0 I$ \" H" ?( t

  60. % p% ?, r4 v; j0 V- @, N
  61.     var language = processor.DetectLanguage(samples, speedUp: true);( b& C- k) c5 `  T. z- ?& f9 c! ?
  62.     Console.WriteLine("Language is " + language);" n9 Q7 g3 A, {) E
  63. }; f& M& @; ?9 |+ N8 l, S1 N

  64. - J. A$ y0 h6 [) C* }. H& W
  65. async Task FullDetection(Options opt)
    / J$ P% b5 Q+ O$ U( S. j
  66. {4 W9 x6 L( m9 q. d( _" G
  67.     // Same factory can be used by multiple task to create processors.
    ! Q( ~* z5 @. l; j2 R
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);( ^1 J6 i0 t# W& s

  69. 5 Q0 P/ Z: D3 t
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);# _/ b. u# T, g9 @$ B
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");
    0 G( A+ S# d: u: y3 c- v# i
  72.     string languageOption = Console.ReadLine();. G& T9 i  B2 n& J3 V% P) l8 }; B
  73.     var builder = factory.CreateBuilder()* L4 z" x4 D+ V' i: b- x1 Y
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
    7 m* A- h- |( i1 P# x( O4 ]
  75. " p  b  v0 {9 Y# z* b
  76.     if (opt.Command == "translate")
    8 c1 U, M) G7 t! V! u& J/ ^
  77.     {4 p. x/ v& t* e8 k
  78.         builder.WithTranslate();) E' D& {% W1 {1 B
  79.     }
    # K& b. k7 w+ H& g' N

  80. : a0 f$ b6 s1 ]8 Z! L
  81.     WhisperProcessor processor = builder.Build();
    4 \% d: Y, l( G6 m6 v2 r
  82.     ' g; L7 Z9 O4 m; t
  83.     Console.WriteLine("请输入wave源文件目录:");
    % Q5 N& G- y0 k
  84.     string sourceDirectory = Console.ReadLine();
    ) b8 a/ D/ b$ {- N% j4 [! P7 h
  85. ; t) A* c- |5 G* K( @1 u; k9 S1 W2 w
  86.     Console.WriteLine("请输入目标文件目录:");5 S7 e6 E  u' j& t: c7 t$ D2 Q8 Y
  87.     string targetDirectory = Console.ReadLine();
    ) S) U: S( o* ?6 L% e4 |% @

  88. ( J( r6 {% F0 L, i$ I% G
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))
    # x" x. B+ x* }6 P2 S
  90.     {
      b) ~  x: d* o6 u6 ^
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");& A' Y* B# G: F4 [3 b# K
  92.         return;8 ~1 f9 u$ d- M8 p
  93.     }
      g1 l. ~" ^- d- C7 e

  94. 4 v# d9 Q1 k, R+ Y
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);
    1 P4 _* T! q7 u+ }  d
  96. 1 Y) G6 j& _# P' a
  97.     Console.WriteLine("处理完成!");, S& q+ @( c  t- n, u+ s* ]! A
  98. 8 E% i8 H# x2 W7 i' z
  99. }( E% U, Z- w' O6 E
  100. static async Task ProcessFilesAsync(WhisperProcessor processor, 3 y. g3 A* _& L# L" g+ ^9 p" v
  101.     string sourceDirectory, string targetDirectory)5 G1 F* K  H+ W9 A; W' @7 P7 g- p
  102. {
    " o% h8 ^' s, {' F+ p* B
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);/ M9 Z$ \3 m3 k+ V( U; E2 B

  104. * I7 Y2 k# S) e0 O* K" b, p- y/ y) P
  105.     foreach (var sourceFilePath in files)
    - f& Q; N0 Y" S; o# X7 ]* B
  106.     {9 D) n5 f. R+ R4 v% n
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);# r) G/ K3 b8 L" `! N
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);5 `3 [! z' k4 A1 H. x
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");7 ]' B/ `/ S/ }& [9 g. |$ Y
  110.   A6 J2 Y1 F7 J; M
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));
    4 E0 U! I; Z/ K0 Z$ \
  112. ( z: B: q. Q' P! f
  113. ' t3 u* d( [0 R- I3 \  U
  114.         if (!File.Exists(destinationFilePath))
    / s& \3 c4 T( [" J+ J4 d
  115.         {) U- c! T6 s8 }
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");
      m% @5 s% ^; k

  117. 8 P$ T' J8 w. g: L' T8 F# w" }
  118.             using var fileStream = File.OpenRead(sourceFilePath);
    6 ^* ?% X9 R5 v# j
  119.             var segmentIndex = 1;1 L1 x2 p8 K& G' k2 Q4 D  k. x
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter
    , m$ b" [! d8 J7 _" Z8 X* J
  121.             var startTime = DateTime.Now; // 记录开始时间
    ' j, [2 X7 M* V& Y

  122. 2 t& U+ m3 N: h2 J; ^
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))
    % R' y9 ~4 @  Z/ ?' p; F; j
  124.             {( T9 ^3 @8 O9 ]' d# `. `+ D
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");3 z9 k' `0 v( H, W5 V# O. g
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");. E" W" n, `! e! ]
  127.                 Console.WriteLine(segment.Text);- V* n  F  B/ O9 ^, Z+ o
  128.                 Console.WriteLine();1 g8 o; Y1 B0 F

  129. 0 d0 z* e& j5 `3 G. q* R# D
  130.                 // 将srt内容写入文件2 x5 F4 ?* }, K8 s' C% p
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");' o2 u* @4 w! p
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    3 s, n" v0 s. Z% I5 @0 }
  133.                 await writer.WriteLineAsync(segment.Text);
    3 |4 t, ]- H& s1 v, {- C& h  t. a1 {
  134.                 await writer.WriteLineAsync();
    - e/ Y8 B, a* E$ ]4 t
  135. * \( l( ?) |* F- Y
  136.                 writer.Flush(); // 立即保存srt文件. T, N9 ~' f. N/ r2 I. z$ o* |

  137. , N( [  }! h% v) w/ P
  138.                 segmentIndex++;" z, n9 \$ L& C  z) A
  139.             }
    8 m. y: D% P! U8 h; i$ ]
  140. " c0 l' _! G, m4 Y
  141.             var endTime = DateTime.Now; // 记录结束时间
    $ d( i- \! W) U! c
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;, @0 d. Z7 C0 P) R
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");
    ( `% H& d3 Q4 R7 J
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");* {  ^- `, a- k1 d/ E
  145.         }* E, [" b: X# B9 Q: C
  146.         else {
    # w: s) E6 }9 o
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");2 I7 H0 v  c4 W$ b6 b% b
  148.         }1 L. g* j4 s8 a) v1 ~
  149.     }
    : V+ p5 L# P/ T- ?
  150. }
    ) p: b7 C: H/ ?6 u1 J1 X7 C
  151. public class Options
    2 x- w, F! W* L1 a+ [
  152. {
    2 C$ o8 Z( j% O6 I9 `/ s, P
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]
    4 O4 R9 Z" W' h# @% F2 D. D
  154.     public string Command { get; set; }
    0 X. v. d+ H( g6 Q1 Y7 y3 t2 v
  155. 4 T* d! a, J' p4 v  _  I4 S
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]
    3 V6 C3 J( q3 A( w- Y
  157.     public string FileName { get; set; }5 N# A5 q9 c# \" M
  158. 1 H  I# t- l- F& Q( G7 y- {4 i
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]
    - U9 ~- f  C$ Z* _
  160.     public string Language { get; set; }
    5 i4 d1 a# n& [( e: K

  161. % w% ~3 V. @/ V) E
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]
    " `# j+ U$ E0 q' L
  163.     public string ModelName { get; set; }
    / j1 H0 ~  B0 @4 U1 P( [

  164. 3 E' f9 W1 u3 E3 J( l
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]
      h  ~6 D% s' V/ m: N6 \
  166.     public GgmlType ModelType { get; set; }. v8 y5 f# P4 ~% [9 m9 P5 u" {
  167. }& N3 d8 t- y- M6 l
复制代码
0 _* j# ^0 d  I  Z: U* E% M! z

! s, i, Q2 P, C5 O, h8 H) K# E
$ `$ B! q; L# M$ H1 j) o: y/ C3 z( s9 S. \0 f( Z/ t
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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