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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-4 12:57 编辑 , q* f2 j+ T4 {
4 L7 Q: |$ ?( F- y* r, O7 Q6 A
本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,
9 K  J, ~- b& [& u0 X 使用时需要輸入语言,源文件路径和目标文件路径  @7 P  D1 [- R
最后是输出srt文件" P* [4 J1 E& p# r6 l7 M4 G, s
9 J* s* U- p' D7 D
代码如下
" L+ S% ?# V% w5 O- a& R/ {! `' {以下这句用多线程可以增速,否则很慢
2 S; ]( M  x* e' G' a5 G以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。
/ I, R9 S( f9 x& o( T4 m
: I" e' }, H$ a# Q( D" k
/ G( Q: ], {! H7 W. M
  1. var builder = factory.CreateBuilder()
    ' Y& ^* b# h8 G( i' u- {( `0 E
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码
" y  h4 M& Y: b
, O; e7 b" d& ~, j8 E/ y
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT- U4 U0 k  j3 {6 h; k8 Y4 M

  2. ) ~1 S7 F7 p5 ~! t( x
  3. using System;
    / O" N+ b7 U3 g& ?, b
  4. using System.Diagnostics;
    ' Q: d# a: e0 }0 ?( ?$ a6 c6 n
  5. using System.IO;
    ' \& ]) a. l5 R7 f
  6. using System.Threading;8 P$ S) p0 |/ T" }1 B8 p
  7. using System.Threading.Tasks;7 P, h! X8 e4 C! I6 ?2 f
  8. using CommandLine;
    2 Z. W& G  P5 T, M
  9. using Whisper.net;
    & {+ n; y# Q  n5 I9 Y9 x3 c
  10. using Whisper.net.Ggml;
    3 K% X; v# l5 d0 l9 F
  11. using Whisper.net.Wave;- E1 Y* g* {) @$ N+ C

  12. ( @2 @% f) e+ Q/ B; q: I& }+ l6 L1 l
  13. await Parser.Default.ParseArguments<Options>(args)
    ( F, A- ?9 o. r! L8 z( F  [
  14.     .WithParsedAsync(Demo);0 A( D* c/ e% Q( D
  15. % K6 c2 s% s% I/ [4 n9 X7 M
  16. async Task Demo(Options opt)
    0 n: t( ~4 c0 o. ~. ?0 I
  17. 9 w; M' G4 T2 V3 @
  18. {
      `/ x, Z3 |7 G
  19.     if (!File.Exists(opt.ModelName))/ W2 ^, F% m6 b7 p; z" m
  20.     {
    4 X3 v% G# C0 U) E) o. q' A
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");, C5 A2 W) \* R& c( i# d
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);& v8 ~! h9 d4 h; j, {: p6 M+ g4 _
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);
    % l8 f3 J1 j) _8 K) B$ ^% k
  24.         await modelStream.CopyToAsync(fileWriter);3 m) H: r$ Q. V$ t; k7 y
  25.     }9 g. Y4 I7 G1 B5 N
  26. : F' v. _  O% ?" y6 i* {# Z
  27.     switch (opt.Command)5 c2 \" _2 j4 d+ x$ \1 K2 c
  28.     {& h% O* K, U4 r' E* b# j8 x1 _+ @
  29.         case "lang-detect":4 @  j7 k4 U" u2 n
  30.             LanguageIdentification(opt);
    ! i8 ^" S- G' t7 |
  31.             break;
    * ~! m( N& L6 y' Q
  32.         case "transcribe":% D  N1 W* [  J5 O: E5 H8 K
  33.         case "translate":
    : d0 O5 N) p" ]2 H- z; P
  34.             await FullDetection(opt);
    % L% L3 D2 E- q) |% X
  35.             break;$ b: h' D, K8 Z! s0 S
  36.         default:
    5 ^+ R5 ?, l6 V3 Y8 D! e, M9 K
  37.             Console.WriteLine("Unknown command");
    , K- V8 c9 ^( N$ U
  38.             break;
    9 o& q( {; C6 I$ l+ [: V
  39.     }
    * T; t$ B* [0 Z% c3 j
  40. }
    ' H' R- G7 f4 Z
  41. , H/ }& _& J- V+ j$ T, h; D
  42. void LanguageIdentification(Options opt)+ ?4 Q7 n8 U4 N. _7 D, g
  43. {5 d2 [$ H, x6 T3 b
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);. \5 `6 A; l& v) N

  45.   t$ i! w. r# ~9 P9 ~
  46.     // Same factory can be used by multiple task to create processors.0 }* K- W& ?. N8 ]9 l
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);
    0 u6 b$ T+ A7 }5 R3 _

  48. 3 Q) t% N9 y/ X" @) F1 f: S
  49. /*    var builder = factory.CreateBuilder()
    " b0 h- g$ A% H
  50.        .WithLanguage(opt.Language);*/
    . U+ x  L# x6 x0 H% T. e/ [
  51.     var builder = factory.CreateBuilder()
    9 a6 e, h  l; |) R5 D# r
  52.    .WithLanguage("english");
    * t/ N6 u. P) o  u' @
  53.     using var processor = builder.Build();
    6 K8 W; P' D; n% _2 Y2 W) P

  54. : g9 A* W8 D- y+ R* s
  55.     using var fileStream = File.OpenRead(opt.FileName);  R0 i2 C6 R5 Z* {6 J9 S6 E; f
  56. 0 w& |# z5 O" f! y  y
  57.     var wave = new WaveParser(fileStream);: K  y+ K" e8 t  b$ s! |

  58. ; b3 v% L1 I# h% S) Y- m6 T
  59.     var samples = wave.GetAvgSamples();
      ^: Y" Z" Y: i
  60. 7 p" A5 ~, |& `1 H0 c/ }' G$ h
  61.     var language = processor.DetectLanguage(samples, speedUp: true);
    5 C) J2 X  k* i5 a3 Q1 T
  62.     Console.WriteLine("Language is " + language);
    6 k. l1 l( q3 v* h3 n$ l% |
  63. }
    2 ^" [+ s, ]' b% h0 A% ~
  64. , o/ B& O- j; g% |  Z* E! T
  65. async Task FullDetection(Options opt)
    * M, j5 I3 @! s9 O8 l9 ]
  66. {, u& J2 e( K* \% _3 ?
  67.     // Same factory can be used by multiple task to create processors." d' Z7 m' K# Q% J8 K5 D' ]
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);( ~! l+ B4 _9 I9 m8 c; H4 ^, h

  69. 0 Q* v) J0 m0 S
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);  J) K& T- |# j; }, p" a
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");  Q) Z; b) q5 ^( O
  72.     string languageOption = Console.ReadLine();3 ]8 V8 ^- D3 o6 S. |. c/ M2 j! ?
  73.     var builder = factory.CreateBuilder()
    0 T4 j1 U. {5 |% ?6 w& {4 [% F* P
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);, H4 n( D+ x. G: a! k
  75. ' c; d3 M) }% R, X0 n
  76.     if (opt.Command == "translate")$ q7 \" B6 [! h' t1 S" }. R1 q. g; ^
  77.     {8 G; \5 B* f' G1 \0 h$ O. v8 v6 k3 Q* [5 {
  78.         builder.WithTranslate();1 H# I" A4 k1 C8 @8 S
  79.     }1 k$ h6 q4 M, ?$ }. R% t8 q7 P
  80. 4 @1 M* E/ t& s# U3 z+ J
  81.     WhisperProcessor processor = builder.Build();% i+ D  A* P+ ^; h) k( {: a; m
  82.     7 a6 z3 I5 n/ Y
  83.     Console.WriteLine("请输入wave源文件目录:");
    : {2 {/ I$ d% ?. A# V# O
  84.     string sourceDirectory = Console.ReadLine();/ b5 X+ c5 n$ Y
  85. % R( }4 R( ]) M
  86.     Console.WriteLine("请输入目标文件目录:");
    . O( ]: N  Z1 {% S5 t
  87.     string targetDirectory = Console.ReadLine();& [) @# i" J/ v6 q& t% F

  88. 3 A8 a6 \, Y% w" k) t: G
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))- l; P* n  M3 ^' [; {2 t
  90.     {' O9 i  ~* g. k& h
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");4 M% k* I$ P$ c/ O8 L4 Q8 u
  92.         return;6 m0 T9 _3 f* C% \+ u5 d; @  F
  93.     }3 C5 k& E: w" b

  94. * D# p# e; w$ A( a( |  H' p" ?( p4 K
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);, Z3 P6 {0 E$ M2 K. V" |4 W

  96. ! ]" U( |  L. X; G9 r
  97.     Console.WriteLine("处理完成!");/ V' g) v1 O) F; e

  98. 1 e0 s8 ~/ h4 S1 S$ f4 J
  99. }# f  O, T) u) N2 y( x( q- j
  100. static async Task ProcessFilesAsync(WhisperProcessor processor, % E# x+ j3 B, `
  101.     string sourceDirectory, string targetDirectory)1 t$ u- d% ~( k5 w
  102. {4 Q% }/ K# T4 n$ z" o% H
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);
    ) ?9 z5 w2 |6 ]# a3 r8 n* n# E, L
  104. ( J, u* Q+ f$ b
  105.     foreach (var sourceFilePath in files), {8 N% V3 `' f2 t% l8 J/ |- X. U
  106.     {2 V/ y" o' H; e- _/ d
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);
    4 |' v6 _) s: \& A* m/ E7 t
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);6 `  b* I; A! L% I# z2 P, I
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");
    + I) ?1 [: [! o: l8 s& W3 p' H

  110. " ~# z+ }$ i2 y1 m- R
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));
    6 F, z( g+ _8 d8 v% K
  112. ' F! Y! e- B/ i) R. b* w

  113. ; [" m% Z8 S9 h( I4 K) v0 g, ~) u
  114.         if (!File.Exists(destinationFilePath))$ r) ^0 @" B, W
  115.         {
    * z' U& U9 o0 [: g
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");
    ! e' ], W) d* B( w3 Y, {5 [
  117. , D7 {( e, J+ r" i, y) L. X
  118.             using var fileStream = File.OpenRead(sourceFilePath);7 X$ ~' ?- t0 g1 g6 r
  119.             var segmentIndex = 1;% x2 q% n; }, T1 _
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter
    1 {- O/ n0 b5 ]" m+ R; X
  121.             var startTime = DateTime.Now; // 记录开始时间6 N- v5 B2 |  A4 B  _( t

  122. : i5 _4 V; j# R5 q# E0 w
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))
    5 G7 A6 T/ v+ `7 C; W* u
  124.             {( \2 S! c$ I7 l' @" V3 X& Y9 d
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");. I# r* E: a  f$ {+ h; j5 {
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");. M' T) e/ \$ I3 b( V
  127.                 Console.WriteLine(segment.Text);
    8 G0 O$ ]1 n6 G7 D; O3 I- @' c" d
  128.                 Console.WriteLine();  v2 N8 I/ \! b4 M( N9 M
  129. 3 J9 I! G+ V' X/ _# L& n9 l; N
  130.                 // 将srt内容写入文件
    - _' p' t2 e: v$ F
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");
    5 g- x1 Z; R7 {+ i- o  q
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    ) e1 z! o2 W0 q/ D5 d8 @
  133.                 await writer.WriteLineAsync(segment.Text);* C; N( s+ N2 t! o9 N0 j
  134.                 await writer.WriteLineAsync();% ?/ {! Q" l( {. E( y" M
  135. 5 F) J6 c: P' g5 L' E: D/ c* L
  136.                 writer.Flush(); // 立即保存srt文件6 E$ _& L$ k' h8 V" O# n# u

  137. * Q% z4 e9 y9 @; P9 Q6 u* w/ p4 f( I! O
  138.                 segmentIndex++;# Q+ b8 [/ s: V
  139.             }6 @2 g1 \( p. ?3 x

  140. ) M3 C9 s6 P) f0 c1 v
  141.             var endTime = DateTime.Now; // 记录结束时间
    ; b9 R- m# }! d1 _2 g9 B, A
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;) Y/ F* h9 X1 c: d% L; I& ]  V
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");
    . v( T$ W: z2 E3 F4 k" R- h# u
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");; q* _1 n) k. v& x" ?/ k
  145.         }
    - m7 M( a$ H) e! t; z% C
  146.         else {
    , _4 L. ?, t+ N1 S# M
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");
      g$ i% D+ `# c1 K4 A
  148.         }
    , C! X0 I6 g1 m, c9 X$ p% B* u
  149.     }
    ) Z2 ^' q" h. d% m4 _. J. [
  150. }
    8 X5 f, Y+ }5 Q
  151. public class Options( w3 Z* K. j2 {3 Y6 T2 r2 D, i( r
  152. {$ E0 I. z" n) y. K2 }
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]
    # U" f% n* N/ ?6 @/ m; {; F
  154.     public string Command { get; set; }+ ~+ J* s1 X( t) J5 B

  155. 2 X9 _' Z9 L0 r
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]. z8 \* T- a; ?# x3 W
  157.     public string FileName { get; set; }7 B) h; v" C1 O9 b1 k3 N- T3 L
  158. / d- H" _% E% y6 a
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]
    3 [; T$ L6 Z9 M' n6 i
  160.     public string Language { get; set; }
    ; q. M) B0 W' g
  161. 0 b2 j+ F4 o/ A2 \% [! g
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]% ]# r$ y: j$ ~% Z! }
  163.     public string ModelName { get; set; }
      F( D! x  [; `$ p$ _0 R! E9 C

  164. 0 w  @) j; W3 q- C3 ^5 |
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]
    # r. O( Z) b$ A9 P( h
  166.     public GgmlType ModelType { get; set; }: c5 p1 i: d; ?1 L* y, g& {
  167. }
    * n& \- ~2 ~3 D9 S
复制代码
8 \4 H9 O  s4 p- Y& ^" v9 s+ ^

/ {: }7 _: ~3 f! q9 ~7 T& l
( x* t. R4 H2 |7 ]" E% v
4 K4 z$ P, |3 X5 F  n+ ]8 \3 [
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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