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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-4 12:57 编辑 1 t! R; h7 M! D5 q* r
; ]$ d- W, W( c8 u+ M' q! M
本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,- ?6 x& d$ K9 V, l  ]) V
使用时需要輸入语言,源文件路径和目标文件路径
3 k! i  {$ ~& N/ B% u% o最后是输出srt文件* W/ w: m% X, s; U8 G# s' B
7 O5 h' G4 S6 w1 f/ Y3 ^. X
代码如下$ [  T- x! v$ ?6 O! @7 l
以下这句用多线程可以增速,否则很慢! {0 ?, A) C5 _
以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。
7 T3 x! v3 t) U: |6 D9 o3 E
2 W* Y4 @0 P/ Y* T; N! b3 B! P# c: g/ V2 @. ^
  1. var builder = factory.CreateBuilder()
    ! v% U* C+ y" f* |
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码
: D% Z1 Y& p# c& H8 X

! j1 z# @+ E: ^: Y, y$ V% x
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT/ \9 R: @+ I" c) A

  2. # ^6 `# `. ], F  c7 w, ]
  3. using System;$ u6 f1 |6 G, E3 S; M
  4. using System.Diagnostics;/ A6 L, _: I! q
  5. using System.IO;8 N3 d/ w: @# ?* Q+ B# z) n
  6. using System.Threading;5 }6 O$ `7 U+ D7 G" t
  7. using System.Threading.Tasks;6 M0 {( g/ @8 a( e  E- @1 R
  8. using CommandLine;2 m" ?# g$ P$ m) V! M& u
  9. using Whisper.net;
    8 j, ~! x% \/ e- r% v7 \
  10. using Whisper.net.Ggml;
    1 O* S/ T% J$ G* ^3 K3 l
  11. using Whisper.net.Wave;
    6 h* o/ T" ~. a% r/ Y0 x
  12. ' Y/ G, y' A7 q; Z
  13. await Parser.Default.ParseArguments<Options>(args)
    : p5 W$ f  s9 x5 \' R* v$ i
  14.     .WithParsedAsync(Demo);2 `' b, n) t5 J  w' p3 k; ^" \4 z# [' s0 }
  15. & y* l4 j; i) V1 P: u
  16. async Task Demo(Options opt)
    % E( q5 b/ ^5 ~% w/ n, _

  17. 7 L: X; H4 |; A9 e5 V4 b. o
  18. {  s4 c2 l9 _, a2 l! X+ z+ s
  19.     if (!File.Exists(opt.ModelName))
    * D: F( w) }0 y4 V* m; e
  20.     {
    7 y7 W3 r2 z; a7 y5 J, Z/ F2 L. X
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");9 {  N' f7 a+ K0 t
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);
    8 A; U" y1 w2 `+ d" o+ H
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);
    , H! y) n9 x% q% b- |
  24.         await modelStream.CopyToAsync(fileWriter);$ L: @3 T2 D6 W! q
  25.     }- w; r& a* h7 d' [8 z, r8 z
  26. # u! s8 l# U- w- g( Q9 ~$ o8 L$ p
  27.     switch (opt.Command)2 `+ d& o& F6 q6 g- G
  28.     {' k) }2 B/ H: ?2 t7 P
  29.         case "lang-detect":( b( G7 E7 O0 _4 }- c
  30.             LanguageIdentification(opt);4 n! Z7 `( y& p) W
  31.             break;) f3 y- e1 x& @) ~! O3 ~4 ^: X
  32.         case "transcribe":: w3 W9 S  e1 M* P7 `# H
  33.         case "translate":# H3 D& F( {3 U% E* |% ^
  34.             await FullDetection(opt);) d4 a' K; c& p% q3 }, u9 L
  35.             break;6 C4 f9 u9 z# L* k
  36.         default:- u/ W& R" Y  C# d% j  x
  37.             Console.WriteLine("Unknown command");
    ; d+ _' S4 H' }: T7 M! w$ k
  38.             break;
    8 w$ G' w2 i/ {& f$ S
  39.     }: x) N7 j* Z, I) u4 l+ c
  40. }
    & J# V3 X6 Q+ r4 T

  41. 7 V! T/ |- Q) e8 i' \8 [4 Y! B, V8 Z
  42. void LanguageIdentification(Options opt)
    5 [0 b# p: P2 m! E
  43. {0 ], ?. z0 v2 x2 d* {, D
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);2 G' ~/ A! J' V( ?7 S! _

  45. " C2 ?' C, `: Y! H; Z5 P/ k/ }  W
  46.     // Same factory can be used by multiple task to create processors.
    9 `' Q$ p$ O& D+ }
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);
    1 z) M9 K- a! N, A" n& p1 v0 F

  48. 2 M% n1 u8 }6 A; k& c3 V
  49. /*    var builder = factory.CreateBuilder()  ?% M% L& _/ ?/ x' V; {" k/ E
  50.        .WithLanguage(opt.Language);*/
    # k$ d0 L" Z* d  p. [
  51.     var builder = factory.CreateBuilder()# T5 N! {: l! J& _9 g; K4 `
  52.    .WithLanguage("english");$ }7 G% f! b8 T; p: \* i- K
  53.     using var processor = builder.Build();3 M1 B2 a' L9 z0 _) d
  54. / N& ~; y. }7 O) K0 r: M
  55.     using var fileStream = File.OpenRead(opt.FileName);
    3 h# r: t0 I5 ?! T6 q1 V

  56. ; y4 g3 q( Q/ _& V
  57.     var wave = new WaveParser(fileStream);
    8 @- A% s- @9 M0 y* Y

  58. $ _* J9 P' H8 [7 }  H9 I
  59.     var samples = wave.GetAvgSamples();' M+ P  q8 [% R' w: o& A

  60. + |& q8 `/ m4 R- S
  61.     var language = processor.DetectLanguage(samples, speedUp: true);
    + z- c* |2 \8 A- s$ B9 J# h9 ]$ v
  62.     Console.WriteLine("Language is " + language);
    $ E+ [1 w" C/ a* Q
  63. }
    1 e) v# a, N# \4 t- S% c1 K
  64. 2 ?, R, z; B" [- f1 a; B
  65. async Task FullDetection(Options opt)
    * w' f' A% P+ q; f- |; t
  66. {  k9 A0 B( D6 f( k; O7 Z
  67.     // Same factory can be used by multiple task to create processors.; M" ^7 c+ }) K0 Z0 x2 `1 w
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);
    : y  ~% w; k0 M; W1 K$ d3 e: p
  69. ; G/ u+ `+ @' d. J# W: J' H# K
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);
    3 C* r; ?( Q4 `$ f, g6 a
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");
      }) o+ S" I& T- b
  72.     string languageOption = Console.ReadLine();5 O( u. ~' {& V! _
  73.     var builder = factory.CreateBuilder()" ?1 o4 J  _0 ]  u/ K" a9 W3 f  z7 R
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
    + l7 c( U/ ~% b2 C
  75. 9 r( z6 @/ V' T3 Y$ t& u" f1 U' R
  76.     if (opt.Command == "translate")
    . m; f4 A( W% t/ ]" M! q. T/ f
  77.     {
    ' d: ^8 O# O( Z; L) v( }9 e
  78.         builder.WithTranslate();
    + L& }$ k3 b4 s# W2 {  D
  79.     }# C! Y" T& {+ m+ `

  80. / _" w! h* `! ^
  81.     WhisperProcessor processor = builder.Build();% P7 Y7 \9 ^" y- b  R) [
  82.    
    / s/ J8 m7 e) `# v1 q4 P
  83.     Console.WriteLine("请输入wave源文件目录:");
    9 |8 I  d' `/ \! ]; @9 E
  84.     string sourceDirectory = Console.ReadLine();& N* G& J" U. x- }6 D# d6 s

  85. 5 h3 h6 K6 p" I3 p' e# @) w( @
  86.     Console.WriteLine("请输入目标文件目录:");2 W: k! |! k) w7 u- r1 F! Q
  87.     string targetDirectory = Console.ReadLine();5 e# L6 w) F6 g% `5 [5 X7 P

  88. ; F$ \$ E/ @- @) H# x: W# Y0 ?
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))/ [) r9 b  T( t) I, t4 K/ Q8 B
  90.     {
    ' \: Q1 p( _- r8 G
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");7 L0 @" h2 x* F
  92.         return;
    ! y0 Q) j% j5 ?
  93.     }
    4 R) W5 i. M/ L/ X
  94. ( E) o9 @; f, ?: w9 a
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);
    ! {7 N: U4 i: D- S- z
  96. 4 H+ F' Q) r% s8 `- {: G
  97.     Console.WriteLine("处理完成!");
    2 `% P3 y- F7 V/ B

  98. 3 [9 @& u4 ?8 h( c4 R  k7 J
  99. }; }# ]2 l% }" X% T1 Q$ B. b
  100. static async Task ProcessFilesAsync(WhisperProcessor processor,
    8 M8 Y8 S0 f2 h
  101.     string sourceDirectory, string targetDirectory)
    4 s7 P" T! K, J5 n( n
  102. {
    ' g+ P1 o" N! ~8 b& u/ G
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);
    ' X0 ~. b: [2 h* m  k8 B

  104. 8 \, z* `8 C: Q% A
  105.     foreach (var sourceFilePath in files)
    # E; p6 v) n1 }. H2 M" ^
  106.     {. N) T% @; }. N! ?
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);7 m0 l8 r& J2 ]& y: ]
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);7 ~4 @' _# Z. A" B! Q" G% F
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");
    & x5 _5 L1 x* E' U- M; G
  110. / D; o3 n) P! y+ n' \
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));! k3 ]/ v' n1 `% Y2 d
  112. 7 ^8 z) d, h5 d+ F% A" M# [# r
  113. 5 G1 j5 _) ~8 M' m. A
  114.         if (!File.Exists(destinationFilePath))
    ! N& B5 Y9 S5 f8 f  C( {
  115.         {1 _8 T, M4 B6 M1 @
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");. E* @8 z3 q/ L) r: R; ^+ |

  117. 6 w: i" E- k% D. c5 T
  118.             using var fileStream = File.OpenRead(sourceFilePath);
    0 ]! T& R+ o& Z; K# M# |
  119.             var segmentIndex = 1;3 R. X6 c+ f9 S+ f
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter
    ; f& ]# e# T$ z+ _6 D  `; r, o
  121.             var startTime = DateTime.Now; // 记录开始时间* X! O2 X4 n" [( t& t  y

  122. 1 b, a: j2 A" l2 ~" \
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))0 B, q4 r( \5 F. u6 u/ y+ m) Q
  124.             {8 s* q( v% H2 c
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");& Y' b/ _7 U; _6 K4 }% M3 `
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    6 }2 o9 T' x4 t* k; q1 A3 u
  127.                 Console.WriteLine(segment.Text);' T3 a& j; T+ B" j# ~& T
  128.                 Console.WriteLine();: b' S# s& J6 `: ~1 `) ]) P* z, G
  129. 1 p! B& \' S2 w" n; k
  130.                 // 将srt内容写入文件
    - j; q  C. S+ t9 ~
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");
    6 U1 y/ [3 A/ O9 k  Q" u
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    - F- D7 e  z* q9 h
  133.                 await writer.WriteLineAsync(segment.Text);
    1 j: ?" E1 @' V3 q0 R3 @& q
  134.                 await writer.WriteLineAsync();. T: `3 V# |$ u! S
  135. $ j) F; S- V. o
  136.                 writer.Flush(); // 立即保存srt文件
    : u/ s0 N0 z2 P$ H4 y
  137. , l  e7 E5 a9 u" v- j9 \
  138.                 segmentIndex++;
    7 T4 p5 W) p6 H+ m4 B
  139.             }
    # w/ C3 w6 D" L+ W
  140. ; b8 x; U, q4 e1 x' P' l8 a
  141.             var endTime = DateTime.Now; // 记录结束时间5 e* o0 m8 |: v: r
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;
    6 e% J8 C. A9 q  D0 z
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");3 Z8 K2 c4 W9 U( _
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");
    6 c$ h( @! O) u
  145.         }- L$ V1 d5 k# t1 E( P5 ~' f4 c
  146.         else {" d# W% {* ~8 M6 U% Q, H0 b% p9 U
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");+ u4 o: \& z  c* [; W- K
  148.         }8 ]% O% s% K4 U1 ^7 r
  149.     }" y# G6 C+ F8 U1 Y# x. Y6 `0 {
  150. }
    ; l" V$ \3 {% n& O
  151. public class Options
    6 Z" p& z& K. X9 v  r  b9 v3 W
  152. {
    1 \2 i0 U% L; G! i) R6 W+ L& {5 J. [
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]
    , z( t, Y: s& P: W; l2 ^, p
  154.     public string Command { get; set; }$ G9 P; ^: f8 P  p+ r
  155. : n4 _' ]4 {/ e- h! @" `, h
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]
    - ]! t4 R5 V; m# U) e/ C
  157.     public string FileName { get; set; }# i, q) {. T' _5 E9 u4 S6 n& n. h. r
  158. 8 d' o7 Y- B! r$ l2 B) @
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]/ e* F4 a7 ~+ u; D
  160.     public string Language { get; set; }
    " `5 S! h8 m  `: h, O2 C: \% l

  161. : {  Y7 v# E& Y' g: W" k0 ^
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]
      q# `4 a& f* }& v6 }; I
  163.     public string ModelName { get; set; }7 ?, I& l0 H. ]- [

  164. " f" ^, V- c* m# E' @
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]
    5 Y+ A4 }& s3 _" `9 H3 f# z- j
  166.     public GgmlType ModelType { get; set; }2 I5 f! F6 Q5 S& S
  167. }+ r8 O) y, n; S2 X
复制代码

; \7 t* @& m( P/ v  ?/ ?: c* e" o
0 L9 M6 n2 S2 r  y: p# N
2 _0 i0 ?' e4 b! t
- z2 e9 J/ C' e. c
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 很美好很美好1 很差劲很差劲
回复

使用道具 举报

沙发
发表于 2025-4-4 01:06 | 只看该作者
学习学习一下
回复 支持 反对

使用道具 举报

高级模式
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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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