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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-4 12:57 编辑 0 |5 n0 X% _2 V' P' {
# _5 O! o$ J( ]' q" P; R+ P
本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,
9 K- z5 f" a' I, [( t; t' M* K 使用时需要輸入语言,源文件路径和目标文件路径, b. F4 N& [+ Q- _* [
最后是输出srt文件
+ a1 x- z8 h, Y& A  ]* q7 a4 \2 G' l$ R) |% e
代码如下
8 y/ m; |) _3 h" d以下这句用多线程可以增速,否则很慢" g4 k. p$ X4 B# J* G. C6 D6 g
以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。
1 S. s4 ?* J. _! V$ w9 E6 V* p* e# H5 p& G2 O6 B( w1 ~% r
6 `. N$ R5 P+ H/ s- ?: `& w$ w
  1. var builder = factory.CreateBuilder()
    9 s8 B3 B& d( ~- d/ b- U6 n) Q- M
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码

7 P) z# Z) z. c5 Q2 h  q+ R) Y7 [; e9 O" v
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT  }$ s0 ?" M5 O6 H
  2. $ @: P' U) y/ W0 l* M  s+ U
  3. using System;
    8 _9 }, ?# d- Y( ~1 z
  4. using System.Diagnostics;+ |1 i/ _0 [4 m9 p6 m) |; C
  5. using System.IO;" e$ p. U/ c7 [7 {. e2 C9 n
  6. using System.Threading;/ g4 N% j! N: h+ C
  7. using System.Threading.Tasks;
    # l1 V1 E8 |9 `3 Y' [, }
  8. using CommandLine;0 R9 e. j  `8 c( |
  9. using Whisper.net;. V2 i- X7 ^8 u
  10. using Whisper.net.Ggml;1 ~; A4 P( ]3 V4 a2 K- g
  11. using Whisper.net.Wave;
    " R9 ]8 k$ M% C' t" z
  12. * h7 b% k1 R5 W( p+ E4 c+ @
  13. await Parser.Default.ParseArguments<Options>(args)
    - V+ R$ q% R- z* _5 a
  14.     .WithParsedAsync(Demo);
    " z3 ?7 h5 q  s5 d, P

  15. & c! Q' @) F1 p9 ]
  16. async Task Demo(Options opt). C8 g9 F( G. U' |: q4 z3 l
  17. % I7 L% }  F. H; h- R& W2 z0 D! ~
  18. {
    % u* K1 F5 a) O/ s+ |( {
  19.     if (!File.Exists(opt.ModelName)): m% k8 c2 o1 E
  20.     {
    " h: h. m3 H# F  J4 y4 d6 [: W
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");
    % c" U4 a' t7 N0 d: r
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);
    ' d$ m0 J! c6 u  i% a
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);2 f: `! E9 _# H( ]4 \" [
  24.         await modelStream.CopyToAsync(fileWriter);& N4 Z7 S( V. L1 ~5 V4 F2 o' K0 `
  25.     }
    ! @" R2 \7 |; l. i: b; J6 C
  26. % t4 ?* U3 f! l" P* R$ E
  27.     switch (opt.Command)
    / \1 [. a7 g8 F  y$ `
  28.     {
    ; S# g: U: K; w3 h' P
  29.         case "lang-detect":
    ( O/ ~! t1 s% W9 U& A
  30.             LanguageIdentification(opt);0 ^6 Q1 c: I. j  L, H) u( K
  31.             break;% P/ R$ n  X) Q2 p2 Q7 ?
  32.         case "transcribe":2 a) A, _- a" P, L& N  j; A7 [9 @
  33.         case "translate":
    4 A: e+ z8 [/ S8 ~3 y4 c; E1 v
  34.             await FullDetection(opt);6 G% S: W0 D" P& L- H& [" x. t7 ]
  35.             break;
    3 Z1 r# a: w% V" G& W6 }
  36.         default:
    + i( P6 m& s9 V$ @: M7 A5 B7 d% v
  37.             Console.WriteLine("Unknown command");
    * ]5 G% x7 O0 e: t& C- f
  38.             break;& t) f0 I/ s% N% X5 m/ N$ o
  39.     }7 c# e' ?& H  L
  40. }
    - b4 V4 f- Z& ~/ |# V
  41. 7 P* [7 J* @, a, g
  42. void LanguageIdentification(Options opt)% J& y" ^- L- |( ^# N  q
  43. {
    : K8 S8 h7 t# C: r" D
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);4 h/ l7 @  m; H9 _5 C0 X
  45. # L1 O$ Q3 F- t. a7 Y1 `/ Z6 \
  46.     // Same factory can be used by multiple task to create processors.
    : P( Y: c( W* B% o. H" Q& S* ^
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);0 d1 p" H% z# F/ c- i' a5 Y
  48. 7 ]+ y% L  ]' n8 n: [
  49. /*    var builder = factory.CreateBuilder()
    # g9 k% i; y5 O" A% l- W% x. M( a
  50.        .WithLanguage(opt.Language);*/
    4 `, p: F7 Q, e5 ~% E
  51.     var builder = factory.CreateBuilder()
    6 z3 U4 `3 f, g2 n- s8 z
  52.    .WithLanguage("english");
    / z# a  W* O$ |
  53.     using var processor = builder.Build();
    + o; n0 q2 H8 y( |3 P# A. i

  54. 2 T9 F0 I+ w9 s7 ^/ x9 U( g
  55.     using var fileStream = File.OpenRead(opt.FileName);/ c) s" g# @0 H1 d
  56. " \( o5 P- n1 x: j& P& X
  57.     var wave = new WaveParser(fileStream);  a1 Y- }0 Z1 ?- A$ Y% u2 T# ~; t" b
  58. + }- w/ S2 v4 p+ \0 l2 X+ d( s
  59.     var samples = wave.GetAvgSamples();# U' w3 `8 a6 E7 p
  60. 2 g. `) G' ^( Q4 D5 O% `* E' u1 _) c9 ]
  61.     var language = processor.DetectLanguage(samples, speedUp: true);
    2 w4 j" ~) A2 P# J$ P
  62.     Console.WriteLine("Language is " + language);
    , b0 g: H' r1 r+ U1 r
  63. }: _' X9 h% {7 V

  64. # }/ R4 k, \4 o3 S- @
  65. async Task FullDetection(Options opt), d, ^$ v+ B9 @
  66. {4 q6 }. D5 K4 G) w
  67.     // Same factory can be used by multiple task to create processors.
    ' P9 F' a% K8 X; B5 Z
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);( A& ~- A/ P) i' ^3 G  V

  69. ! z# Z! E) o, G
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);
    * c: m/ }" h' g$ D4 j; A4 |1 N8 z
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");
    2 j. ~  w9 S* x3 ]5 }+ S  Q
  72.     string languageOption = Console.ReadLine();
    8 O  t- H  p- _7 `) W0 i, t
  73.     var builder = factory.CreateBuilder()
    " J: s" ]' J+ ]4 P# b
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);) E0 s2 Z6 n7 K
  75. ) u8 B1 h" C/ W
  76.     if (opt.Command == "translate")
    / O$ U  c1 ]$ _2 |$ ~8 \* m
  77.     {
    - U2 \+ Q/ X& l' ]! g
  78.         builder.WithTranslate();
    ! d4 b5 q# H4 L  {
  79.     }
    % h  J$ J% P) W
  80. : q" p4 U) I$ w, ^
  81.     WhisperProcessor processor = builder.Build();+ \; \7 f& L- _, Z
  82.     & w0 b: m, j* h( Q
  83.     Console.WriteLine("请输入wave源文件目录:");
    * }$ G* G- x2 f0 w4 f* C* h4 \
  84.     string sourceDirectory = Console.ReadLine();+ q* B) g! Q, H
  85. 2 O; {+ u) Z3 |+ N& J
  86.     Console.WriteLine("请输入目标文件目录:");
    & B  @% N: I, S! V* h
  87.     string targetDirectory = Console.ReadLine();2 L0 y7 N( R! ]/ j& h. A+ q! U
  88. 9 K0 ~* p3 H, @" V9 E" Z: @
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))
    & m2 L" G6 Z4 o! p" I" f
  90.     {
      J0 a- R2 R+ r; G
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");
    . z' I% v5 y4 [. ?6 V0 d' k
  92.         return;
    ; ~- ?/ H' }( r" R$ F( t  X
  93.     }
    . e) b! [5 }2 t2 c
  94. 6 a4 `- t$ p; Z
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);3 [* w# c* i  _0 d( ~- H

  96. $ o# h8 B. R: {) }" O
  97.     Console.WriteLine("处理完成!");
    8 T7 c5 _; c5 o  R; b' F# [

  98. 0 c* F8 E9 J! h) w1 A; E. m
  99. }* T5 n# r) }; a& _) A
  100. static async Task ProcessFilesAsync(WhisperProcessor processor, : S, }& H$ B/ L3 B2 J0 a6 V
  101.     string sourceDirectory, string targetDirectory)! i) N' G5 K) P( V* c1 P$ [
  102. {
    3 }8 j; ]! d( t# p2 D
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);# `" C2 _) @7 @0 ?" g( j
  104. " W" K4 ?/ c- m  A1 E7 g
  105.     foreach (var sourceFilePath in files)
    9 _& v2 u2 b) ]8 C
  106.     {. w4 y# H0 f0 R$ D  m' Q* X
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);
    $ v- P4 p  z9 F% D+ @
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);
    " X# I. P8 l# ]
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");- l$ B  `0 a, G8 P$ ?/ O
  110. " j- C7 u- e- `( |. U; p7 J- y2 H/ C
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));( E) r! `& g! ^

  112. 6 S; x' M/ g/ i# f

  113. . I! r* p, {# y7 K% K
  114.         if (!File.Exists(destinationFilePath))1 e$ i2 ~) p/ H0 y% x; e
  115.         {
    6 Z6 R3 N5 V- v0 s* o( Y
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");
    # j- W6 J/ G+ w4 K( O
  117. & ?' }2 V. t5 |3 R1 ~
  118.             using var fileStream = File.OpenRead(sourceFilePath);' f' n# l/ I. b6 P$ ~
  119.             var segmentIndex = 1;% V3 R) n" t7 s" D
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter
    9 B( E" I: S' l$ S3 G8 o; v
  121.             var startTime = DateTime.Now; // 记录开始时间( V, @7 I+ U1 n: b, r* s
  122. 9 z$ y+ F5 y$ _+ b
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))7 \- L) E* T- m+ U8 [9 e3 h
  124.             {
    5 z# _: n2 u* l% W* y
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");
      W, ?8 ]5 R( g  j5 e5 p1 u* \: P) F
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");1 f* M7 m/ T* @! H& y6 W. C1 ?
  127.                 Console.WriteLine(segment.Text);6 E- l+ Q9 b5 \* U2 x9 T  w
  128.                 Console.WriteLine();+ {$ u4 t8 E% N

  129. . O& y( ]- [0 `' Y, }- G& p
  130.                 // 将srt内容写入文件
    4 P4 f$ \  e9 e' e+ _1 _& C- h
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");
    1 x4 y9 X* |! v; ]* z0 S- H( |& C. S
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");( Q) k$ Y: J/ m  C7 K3 K: x
  133.                 await writer.WriteLineAsync(segment.Text);" w7 s, k3 N, i0 R+ V$ v9 l! j
  134.                 await writer.WriteLineAsync();
    , a  J$ R; ]& R# _0 ^0 F+ i6 x" Z

  135. 8 Z. ]2 L" K0 j" v1 H
  136.                 writer.Flush(); // 立即保存srt文件
    ( N1 z& \8 N2 t& i6 _- Z. @2 S/ |
  137. 5 c% A& Z# J, D0 N2 [( ]
  138.                 segmentIndex++;) |1 e, D+ L6 K" g" e
  139.             }
    7 L' W7 }+ @! I- P+ j1 i
  140. - r& l4 i% w; E4 r! O8 E
  141.             var endTime = DateTime.Now; // 记录结束时间) m: a" k) q  h8 P: I! p
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;
    % d% i. V$ R* ]3 O
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");6 r% \. E1 b& j! @+ ?
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");
    % W8 K$ {5 b+ o8 v+ V4 a
  145.         }2 T  }/ G4 f, d) c& E0 V
  146.         else {+ m  u; _9 x2 q9 {' m0 ^
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");
    9 n* r5 J1 f- I7 \
  148.         }; K4 F8 w* v- r8 V
  149.     }
    : a4 A0 P8 }( B
  150. }
    1 R2 D4 X1 i. ?; D6 a
  151. public class Options! u: N! r) ^% @9 k( {& t
  152. {
    ! s. i/ B( X- r
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]
    # f( L1 F- n( x; ^8 f
  154.     public string Command { get; set; }  S: m# S8 k& \' D! @

  155. 3 R  H7 g4 [7 x- N+ f
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]# _8 Z- \7 j- _2 j- C7 i+ i
  157.     public string FileName { get; set; }
    ! K8 U0 S1 N* c/ @* j
  158. : y/ f* |7 L& F1 R& _  f
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]
      {+ h0 ?. L% k: u0 h
  160.     public string Language { get; set; }  T& X; S5 g- _) {3 J  c9 t8 \  r

  161. . p7 V7 q  @  f) o
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]. b' Y* G, l$ ]9 R
  163.     public string ModelName { get; set; }
    + b+ T% f2 O  [* l! }& c2 Q6 u' S

  164. 5 G* i0 y' n- m- g6 T
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]5 y8 y0 g+ k/ L. }1 h5 N
  166.     public GgmlType ModelType { get; set; }
    & Q. x# R! ?$ e% b( @. G
  167. }" \* d1 S4 [1 D5 N6 ]
复制代码
' }6 X' h  _0 `5 I9 _
# h( T, L2 m! p) m2 h# c( ]
0 p/ ^/ u6 ^- f4 @" @) N% A
! _1 c( Q1 B$ Y( H5 o
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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