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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-4 12:57 编辑
: Q% H/ D( ]+ X! R0 [3 L! y) |/ i2 f4 l
本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,! a, d" ^/ x' b5 U, p( j# O
使用时需要輸入语言,源文件路径和目标文件路径
: ~1 U) Y2 W) \' Y0 W' p最后是输出srt文件
4 _1 w3 ^2 }# [
" J. N5 X6 \* b, @  \1 T7 e& H6 c代码如下) w3 d* @5 B9 k* t
以下这句用多线程可以增速,否则很慢8 d+ g+ g6 h$ T  z$ ~3 U8 }- g
以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。! P" Q( m' {, R& T* N* }7 h! @
/ K& p+ G) s: q2 C
& [& h* r3 C8 e% B7 D* a
  1. var builder = factory.CreateBuilder()
    $ y+ F" n: p' m% C& C% u7 k0 v
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码
1 w0 I  o. A7 {! d+ Y3 p
- _9 I. Z7 }: h8 b% f! p4 Q
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT9 K, t0 I6 x  c2 {
  2. 8 e- F  @5 j; a' y! ]5 O) W) t4 s2 \
  3. using System;
    ) B7 ]2 ]) w& }% o
  4. using System.Diagnostics;
    $ Z. ^* D, t! m! X' L$ b
  5. using System.IO;
    - k; S' ~, i0 v' U; b2 \
  6. using System.Threading;
    : q& I; B9 Y! r" Y; l. l% B* h; q
  7. using System.Threading.Tasks;
    $ X$ k# L8 j& x0 R2 J
  8. using CommandLine;
    5 o7 E; T" e) e: p! b" S) o% k
  9. using Whisper.net;2 H: w/ I4 {( C" C& }
  10. using Whisper.net.Ggml;4 A5 W% n  I4 P1 m% a
  11. using Whisper.net.Wave;* \3 D1 ^' {/ k- j  N* b& F  a

  12. ! j9 |% _( f: }8 e) [3 b3 T
  13. await Parser.Default.ParseArguments<Options>(args)
    * z" K. S% o  V% l8 V
  14.     .WithParsedAsync(Demo);" b7 W2 ?  f% n
  15. / V0 u8 Y# N3 m7 S3 o4 d& ~- I
  16. async Task Demo(Options opt)% t* J+ G; w& C( M! p1 }. c
  17. & B9 e4 [5 g; V, U! U5 U
  18. {
    0 ]6 B, X* s& Q$ Z6 @
  19.     if (!File.Exists(opt.ModelName))" x0 u, ~4 S7 z, K
  20.     {- r2 d5 P2 N  O
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");/ ?- V2 ?) m% u8 h" B- b
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);9 p" b2 @, u8 \1 F+ U
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);
    " {% P; {2 X4 t; L& O
  24.         await modelStream.CopyToAsync(fileWriter);. b7 I1 c3 Q; i& o: V
  25.     }; @) R8 N9 K" g
  26. 9 e, {3 `, e  q' `1 O; W) h6 r2 @
  27.     switch (opt.Command)( P$ F. b, ]0 L6 {; g& a
  28.     {
    0 e& g0 f9 G+ b0 Z4 |& w
  29.         case "lang-detect":
    0 F$ `1 a# n( }4 S6 \; o* B9 [
  30.             LanguageIdentification(opt);' z" K" [% ]9 ]$ L6 k$ x- T
  31.             break;7 U1 o' ^3 o- @7 n9 p
  32.         case "transcribe":
    / s8 b( K4 a- d$ x
  33.         case "translate":; h0 B/ t% g4 n" e7 }, `& O
  34.             await FullDetection(opt);
    5 M5 W+ @. r( }+ e6 q
  35.             break;% q; }' H* s! l. Z* N2 t
  36.         default:
    5 b" o0 S/ m; A( ~: n7 U$ r6 x4 }/ C- s
  37.             Console.WriteLine("Unknown command");
    6 [$ s% A+ C2 A! M1 F
  38.             break;
    + G; ?( j' A! x( o
  39.     }: i* }% u5 W2 |4 d8 l
  40. }. B" q* I" R/ Z  B5 N

  41. ! J8 @1 ?' [/ H' }( a  }4 i
  42. void LanguageIdentification(Options opt)2 D' p2 P0 W1 @+ }4 c* {
  43. {# r0 n. c- W" h3 q% m1 [
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);' ], s7 p% W! V& E7 B

  45. $ s& R: }4 M! U+ n0 Y7 V/ S$ }
  46.     // Same factory can be used by multiple task to create processors.
    5 n* C1 i( B9 |6 \; c* Y
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);" i" P" ^1 j, y* E

  48. : s/ r: n" c$ L4 Y! g6 O9 O
  49. /*    var builder = factory.CreateBuilder(). h7 i+ i: t8 D3 n' @0 }+ n
  50.        .WithLanguage(opt.Language);*/, Z3 K6 }1 K! \* r3 T$ |! E/ _
  51.     var builder = factory.CreateBuilder()' \. Z5 J) V$ ^! }
  52.    .WithLanguage("english");
    " k* y+ ?# e4 @: e: c5 ]
  53.     using var processor = builder.Build();' R$ y' ^2 t, A6 C$ ~3 i( D

  54. 7 Q# K" X/ H3 @1 U. u8 B" c( f
  55.     using var fileStream = File.OpenRead(opt.FileName);
    ' Q, f7 h8 V* g0 U3 e; d* b6 @
  56. 7 }' Y3 F# f0 h6 _7 @0 [
  57.     var wave = new WaveParser(fileStream);. E4 Y: T- ~' {+ y5 o( t4 \; G
  58. 4 O" ~" I, x' Q- t) W* v
  59.     var samples = wave.GetAvgSamples();
    - [! j/ V; q$ ^5 a; y

  60. 1 g2 G9 K' W/ |7 q7 i) X& [
  61.     var language = processor.DetectLanguage(samples, speedUp: true);
    2 X( }( e# p6 d
  62.     Console.WriteLine("Language is " + language);
    5 i9 f, a4 I$ |& L' }; Z9 d
  63. }4 g/ i, I0 o% l1 C

  64. ; ?3 T2 e2 q0 @! i  }: l3 g/ F8 u
  65. async Task FullDetection(Options opt)
    ! f; w: B+ S% ?5 S3 O. G5 A
  66. {% M1 N$ o0 ~' K( r. y
  67.     // Same factory can be used by multiple task to create processors.& B& i" D8 _! Y+ C; u, p
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);
    : k- R8 M  x" G3 I6 J

  69. ! j4 e0 x7 i. r, ], C" ]
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);1 R+ u6 b( ~% L/ p7 n* s
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");6 P1 L; D/ u. g' N* _: Z
  72.     string languageOption = Console.ReadLine();
    6 b9 K" E) B9 ~7 Z
  73.     var builder = factory.CreateBuilder()
    # {& R: {3 L7 Q) @7 Y; R! H
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
    ; n: K) m0 a/ b0 f5 ~! y( h
  75. 7 ^# ~# i7 S5 P/ p
  76.     if (opt.Command == "translate")# l* l4 `4 f) Q# x6 u' P
  77.     {
    0 {- t9 n6 l1 p2 A; c$ l: S0 c
  78.         builder.WithTranslate();
    * J8 o$ J9 s7 Z, S
  79.     }
    " [1 W( `6 P% N5 I9 D. [

  80. " ]+ b" i4 i, o% x6 ]) {& F
  81.     WhisperProcessor processor = builder.Build();
    # A9 u, C  c& F/ ?
  82.     * S0 C3 |- D! O# }8 W( p
  83.     Console.WriteLine("请输入wave源文件目录:");
    # F! a2 e' D( c2 b# C% i: r; J0 r
  84.     string sourceDirectory = Console.ReadLine();, B/ s% H0 N+ a/ e
  85. - E- z! e" c0 l7 D' l# `/ ]2 i
  86.     Console.WriteLine("请输入目标文件目录:");8 ~9 e4 c$ F+ D: l/ ]' Q* X+ d
  87.     string targetDirectory = Console.ReadLine();. R8 P; L0 h. x

  88. - |4 ?- w8 Y' r4 i4 i
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))& j9 I% _' ~/ X# D' O
  90.     {) [* M! h5 {2 F2 r4 A% v7 Q
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");  \. ]6 @5 J. S) T5 c; c
  92.         return;9 O/ [& O' b6 {. P9 V' I
  93.     }
    2 x' X: t+ `* i6 p# O; k# a; P

  94. - B9 x2 B/ G3 z0 _6 Z4 W
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);
    # M1 G/ L' @3 H# E$ f

  96. : w& Y+ U7 e& x" @( y
  97.     Console.WriteLine("处理完成!");+ N# m, Y- L/ B

  98. - U: {3 f+ Z7 j
  99. }1 k: ~6 m* Y; Z
  100. static async Task ProcessFilesAsync(WhisperProcessor processor, , E0 I1 Y; @; \! Z- j: X* @6 ?8 ?
  101.     string sourceDirectory, string targetDirectory)
    # V) ~9 c3 ~' x5 I) ~
  102. {
    : \* c! b, d2 \" A$ F, I5 g
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);- R5 u" P. l5 J8 c% ]$ n
  104. 1 y/ q8 t: x4 Z# p
  105.     foreach (var sourceFilePath in files)
    1 ?) M. p  j7 |1 F6 }# C2 ^8 E
  106.     {
    % k) K9 f) r, l$ x% Z$ k
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);
    9 Y! W0 U+ i" N: A+ M
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);
    - d+ q$ r5 V7 `
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");7 k) D, ]$ g/ G4 D
  110. 5 `* M3 Q. r, K
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));) X+ P) A8 g" Z% J

  112. 1 q2 o: j6 Y. f' z: l
  113. - I' |! c0 I5 d1 |4 f
  114.         if (!File.Exists(destinationFilePath))( f# ?0 L1 P( o0 S
  115.         {
    6 }( H4 c3 D; c, j# Q1 G( Y
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");
    5 q: b2 l' G# _; T
  117. 6 E+ x# I6 C; i4 Q* H
  118.             using var fileStream = File.OpenRead(sourceFilePath);* `( e6 e$ c8 W5 V) c3 l  Y8 J. O: k
  119.             var segmentIndex = 1;
    - y0 x# F9 \. b$ {5 h! y- c+ M. W
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter" E* ]: ~) o! B! X" t; U
  121.             var startTime = DateTime.Now; // 记录开始时间
    5 c, M- t8 B1 S' O- n" }" W
  122. 4 f0 ^. U# I6 w4 q, R" O
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))
    2 }' Y: U6 z4 u/ h0 ?
  124.             {, d8 B4 z7 t) _3 r% v' U
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");
    ) U/ a# Q1 f  v) I9 g9 z
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");/ B3 ?0 a" F; s# o, S* v. f# z6 M4 I. `  ^
  127.                 Console.WriteLine(segment.Text);
    : ]2 _0 Y1 t; }) o4 F( b8 [
  128.                 Console.WriteLine();  G" g, W( u) C  r% n2 L7 t% S& f4 \+ A

  129. 4 y/ c1 d9 a; ?/ _+ y( d8 B" `  y
  130.                 // 将srt内容写入文件) J2 E8 W# R" R5 D( `) O: f" P7 I2 s; O" @
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");4 ~+ u0 M7 F. `! k! G/ K
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    1 {) _3 b9 [. x# D$ [6 [% g: x1 c
  133.                 await writer.WriteLineAsync(segment.Text);
    ' I+ J, p  G  ~2 Q8 I" O& \. |
  134.                 await writer.WriteLineAsync();
    : q, w/ t% N3 n! I8 O/ ]
  135. + @4 g% ~( T; y+ }4 D. I: J" ]
  136.                 writer.Flush(); // 立即保存srt文件
    4 c9 r  J: N# a3 C
  137. 7 {5 @, v5 M; `9 \
  138.                 segmentIndex++;' v( V7 \: }; ~- p0 o: z$ W. I
  139.             }. h+ I; \1 I* b6 e
  140. + ^7 s+ ^! @0 G" O' v3 N: ?
  141.             var endTime = DateTime.Now; // 记录结束时间
    1 z7 J( m# K9 q, _# N
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;5 }$ v; a  f9 w: c4 L9 G1 W2 ^3 X
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");+ g; A6 W& `4 `2 h7 O
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");- p9 l4 M/ v' H6 w% x: M# l  ~
  145.         }2 K. \4 d8 y* N% E& [
  146.         else {  {0 N( A; h7 w- d2 m
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");2 L% ]6 s, T# x4 R4 C
  148.         }
    ; M: l1 W# |( r+ L/ @
  149.     }+ \$ K0 l' d7 _/ u
  150. }# j0 D1 \' K2 n4 B  |' T4 a, `
  151. public class Options; r7 Z4 y. U6 M7 r$ x0 `
  152. {8 ]% D+ ]0 ~: }0 _
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]3 ?5 J; h% D7 |2 v2 x# {: S
  154.     public string Command { get; set; }. b2 G* Y- R3 u3 K1 H

  155. ( _+ a' O) N7 }+ r5 |
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]! o. v. |8 J% h, X+ W& F
  157.     public string FileName { get; set; }7 b4 t7 j& ?- M
  158. 7 N" I) Q; Z" x" h. B. k! Z
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]! j0 y: O5 E4 b! G
  160.     public string Language { get; set; }
    4 G) [+ S4 f5 ^5 G; y" d; S% k3 |. _

  161. # b; A; s& M$ n1 ]) e8 b
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]
    # v3 G; g( y) c  L
  163.     public string ModelName { get; set; }. t5 S3 M! w6 M9 x
  164. ; Q( \9 U8 A! A2 N, g
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]  [0 g$ S! ?( s' m) q! w
  166.     public GgmlType ModelType { get; set; }6 }# f* g  z! e) @' e2 X! h
  167. }- `* _; [8 n% c5 H" m- k4 }9 w
复制代码
  R1 v  Q* P) o; r2 t0 L) o  t

" q& ?& c9 x. l4 g0 _6 ~  z) j
2 n& j& m4 P: y
8 x1 H7 s; @& i& j/ {$ P- _% _
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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