冒险解谜游戏中文网 ChinaAVG

标题: 【汉化工具系列 #2】指定wave格式转换为srt格式字幕(CPU版本) [打印本页]

作者: shane007    时间: 2023-9-4 11:03
标题: 【汉化工具系列 #2】指定wave格式转换为srt格式字幕(CPU版本)
本帖最后由 shane007 于 2023-9-4 12:57 编辑 1 z: \) ~$ y7 b( [+ e% p9 \9 r
* c/ ^. o# D/ o  n; Y7 {
本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,! W* W- K. {% B$ R
使用时需要輸入语言,源文件路径和目标文件路径! I/ B4 ]9 b; |; v  q6 [7 g
最后是输出srt文件
3 _& D% R9 _5 N$ V& U; [8 L; h4 Y! B0 D) J% v
代码如下; G# }: _2 ^( N2 ^
以下这句用多线程可以增速,否则很慢# b$ l. i8 l" y' ^
以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。
! k, ^; Y1 |/ {; G0 ~+ G0 x9 R: y( n0 g! R" C
; Z( k. s- q4 _# \( G
  1. var builder = factory.CreateBuilder()6 L3 h, n$ l$ k; Y- L/ P) m( A! ]
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码

) f" i( f1 o4 w2 T' c0 P; w% `! I' T7 L! C* |
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT1 y: b" V; h+ g
  2. . `- x) E  j& h: e  C
  3. using System;
    5 u% ~1 P( p% i
  4. using System.Diagnostics;
    2 |5 N2 ?$ b0 T( m! t( R
  5. using System.IO;  h5 i) Q1 F3 y
  6. using System.Threading;5 b  t4 i) {6 a( S) u$ c! {9 E
  7. using System.Threading.Tasks;
    8 K2 V6 a' W4 C; O
  8. using CommandLine;) y7 D; ?% \' q% ~3 ^& v) x
  9. using Whisper.net;8 _# ]* \6 ^7 r
  10. using Whisper.net.Ggml;
    4 d# E6 n/ l6 I: T
  11. using Whisper.net.Wave;
    5 [( @9 J/ F2 R) e
  12. 2 \& x" Z5 V% q$ J) ~) e5 N
  13. await Parser.Default.ParseArguments<Options>(args)9 Q( Q& T9 ?6 X" D  l1 I  y; k
  14.     .WithParsedAsync(Demo);
    # `! _8 ?# p( v$ h8 c
  15. - }, A' T2 U- W1 q/ ?% b+ ~; a
  16. async Task Demo(Options opt)3 J, Z8 \  B5 m1 u

  17. 4 U2 O, F2 i8 q  Y& N3 |3 z( V
  18. {2 g+ Z% {4 r* I  ~
  19.     if (!File.Exists(opt.ModelName))9 Q" R$ Z; J, b) r: z8 ~: w' V
  20.     {3 {/ l% d3 f) x3 Q2 L' w/ n
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");
    , ~  l; K# O8 d% W1 }! m
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);* W: T, {2 R# j
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);
    ' |8 g+ y3 ^. G/ M8 G
  24.         await modelStream.CopyToAsync(fileWriter);+ j- _1 F" K9 Z& ]! Q
  25.     }
    8 z$ U& t/ _% j

  26. 8 d8 V# R1 J- _# P  C
  27.     switch (opt.Command)
    ) i* H8 h' U/ q+ K9 Q( `3 F0 h
  28.     {9 @$ Y/ b) p  Z. \4 _
  29.         case "lang-detect":
    . O: ], q2 t- c; M+ R" ~3 U
  30.             LanguageIdentification(opt);* `: Z( _9 C( X- P9 E
  31.             break;
    9 `- _! |: [  `
  32.         case "transcribe":
    4 o" p3 S' F; |/ }
  33.         case "translate":8 B: }9 h% Q: n
  34.             await FullDetection(opt);
    2 Z* v/ ?9 Z1 C- }! {
  35.             break;2 [( X$ e9 Z0 z% V+ G
  36.         default:
    * F' I1 N5 \' \1 E9 s& W! a3 b
  37.             Console.WriteLine("Unknown command");
    6 A% I. i5 s1 `. p& {$ k
  38.             break;5 K/ d! G( s; M* h( t4 b/ v  a- t
  39.     }/ W; E/ s! ~* B8 \( M
  40. }: u! k7 ?4 i$ ~
  41. ' p: u( N) @  \+ D% }
  42. void LanguageIdentification(Options opt)
    4 Z4 x3 W1 X8 x- S
  43. {
    ; H; A" e8 [5 _5 R9 A0 D
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);
    9 y, T# g/ @" v3 [% T# R2 `* A+ ?
  45. 3 j& }2 p0 w  ~+ ]
  46.     // Same factory can be used by multiple task to create processors.) k+ s3 J3 K1 \# y4 ~: F, O: _
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);
    / U2 v6 ^+ g7 ^7 f% M/ B) E
  48. & P+ b' `' P5 u" _- r# y% I- [
  49. /*    var builder = factory.CreateBuilder()5 P/ @, F$ a$ O. g+ k1 \4 g; }1 H1 a
  50.        .WithLanguage(opt.Language);*/6 x- B1 ?# s( s4 E9 U1 D
  51.     var builder = factory.CreateBuilder()
    9 c1 H9 s" P+ D. h) P
  52.    .WithLanguage("english");
    + K; S  H& f1 i, m" x) I
  53.     using var processor = builder.Build();
    - `# q8 d! J4 v2 q

  54. ; z4 E5 L  ?- V& A6 {0 s" G& t
  55.     using var fileStream = File.OpenRead(opt.FileName);+ C7 e: @' p% D$ k1 t
  56. + A9 ~% Z7 V' F  E& L
  57.     var wave = new WaveParser(fileStream);6 a8 g; A6 m* O; T0 I% R. {

  58. ' s# S+ P+ [- Z& ~8 Y7 B( c) H
  59.     var samples = wave.GetAvgSamples();
    ' O7 U4 |( s+ h5 h8 N

  60. 2 P" f4 r6 Q* ?- u0 P9 I
  61.     var language = processor.DetectLanguage(samples, speedUp: true);
    1 n  n: |8 Z* z8 }: u+ Y+ j
  62.     Console.WriteLine("Language is " + language);  Z( {' K6 P4 ^/ H) t1 }9 |4 y
  63. }) x# _9 _+ p- N: M  J5 m: {

  64. 0 o7 P1 s) y/ s8 I+ W5 }+ x
  65. async Task FullDetection(Options opt)
    / K  T3 M/ e/ J$ j: ?
  66. {: n$ Z) A7 O, M  m3 L0 O& f9 O
  67.     // Same factory can be used by multiple task to create processors.
    5 r- E; M1 G6 }/ ~3 i7 h: ~
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);
    " O9 X& l; N; f7 x1 c

  69. ; y7 @" w( G  F  p2 s
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);
    $ F( m8 V, o, I. y% m; T$ l
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");
    % L' n- N: U2 p8 t3 M  K
  72.     string languageOption = Console.ReadLine();
      ?/ b! `& n4 f+ S$ g$ Z  y
  73.     var builder = factory.CreateBuilder()3 D- M# r- B$ f0 P* I
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
    ' d; _7 Y' K# |3 }  i
  75. ! |4 S% r. h8 p
  76.     if (opt.Command == "translate")2 I) b% K# }% I" m& D2 \% H: \
  77.     {% v% _7 G- [3 t4 d  t
  78.         builder.WithTranslate();1 w- s2 m; H2 y. Z
  79.     }
    9 n) e3 f1 t3 m; g  {; k/ W9 U6 t
  80. 7 g1 D  `6 M0 }! {
  81.     WhisperProcessor processor = builder.Build();
    ' }6 r% x% n+ ~$ _' ]; b5 z
  82.     * I5 N8 P% \6 a' k% {( y4 S; h
  83.     Console.WriteLine("请输入wave源文件目录:");
    $ [$ V" `8 o( {, i' l  K, K
  84.     string sourceDirectory = Console.ReadLine();
    : K/ O* q7 d8 D) `7 k0 _+ d  g
  85. ( A2 C7 b1 b) g+ d# ?6 s
  86.     Console.WriteLine("请输入目标文件目录:");! g. O5 w" x6 a& B
  87.     string targetDirectory = Console.ReadLine();
    $ G8 v* M* W% l, y% Q% e

  88. ; r5 d) `/ K# p
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))
    . P2 p5 z+ d0 m+ c1 t! E  P
  90.     {
    2 J" f; O( _4 z: q
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");- r7 X( [" @- a1 `
  92.         return;
    ; r: v  N  O6 W$ }
  93.     }
    0 f( Z+ |: o- b& N* s

  94.   i8 V6 q8 g7 H2 N" b; E
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);9 M; S6 q" L7 M  g  m: C6 \
  96. ! H1 X. [5 B8 n2 ]5 e  {
  97.     Console.WriteLine("处理完成!");* w# f) g) x( r* m: _
  98. * D+ U: p3 Z! s, Q4 t
  99. }
    ' `7 x- R) x8 E: n
  100. static async Task ProcessFilesAsync(WhisperProcessor processor,
    9 T" W2 L& u4 B- @; Z
  101.     string sourceDirectory, string targetDirectory)8 A3 w" l7 ]" E, x, I2 ]
  102. {! l' t7 E5 c+ @5 t
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);  Q9 z# x* y1 C

  104. % |$ U. v' u5 O
  105.     foreach (var sourceFilePath in files)
    9 N3 m* P* Y& C4 o* y7 P
  106.     {
    / y$ @% }' F* U0 S4 T" h
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);4 Z4 k- d& r% \5 F4 f
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);8 g/ S7 \3 K4 V: K
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");
    & @5 G# e! F3 T+ P, j+ j6 _# G
  110. 3 R6 d3 |$ r  \: A( w4 K5 _. F
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));
    - t$ y; e# O& {- h

  112. 2 h% ]$ h3 ~, i8 ~  S

  113. * T* ^  t) a' ?: q4 {! m' L
  114.         if (!File.Exists(destinationFilePath)). T. W. [( H" O" p( z6 R. G8 D7 g
  115.         {
    8 m5 ?0 i$ Z2 C. w% p* K
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");
    8 S2 I. j5 m, X. Z( |+ ~4 t

  117. 7 F6 v1 a  |) `9 j* F
  118.             using var fileStream = File.OpenRead(sourceFilePath);: s; p6 c4 J8 @( {% Y
  119.             var segmentIndex = 1;) B- H' R$ w/ l1 L' K
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter  o4 J$ W9 P: K( k) q
  121.             var startTime = DateTime.Now; // 记录开始时间
    & Q" h# w9 g9 ~5 j

  122. 1 |4 ~+ C5 L. L
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))8 ~2 e4 t0 f( x$ `
  124.             {
    6 M$ J* q0 _; Z5 i+ e9 R/ l
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");
    $ V0 B- `5 m* w, Q
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    3 {  T+ f% ~* \! e9 @- k( T
  127.                 Console.WriteLine(segment.Text);- e( P5 _( s! c
  128.                 Console.WriteLine();
    * Q. e- R* s! [5 J" F

  129. ) Q; G  h3 U) `
  130.                 // 将srt内容写入文件# e; g8 j8 A2 g" m6 X7 y, {
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");
      O9 l* J9 n$ z# q0 s! p1 b& @
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");. Z8 g9 e' @; g  O7 Z2 v
  133.                 await writer.WriteLineAsync(segment.Text);
    6 D" _% n; p  r- E5 d3 s' W7 K) Q! v
  134.                 await writer.WriteLineAsync();
    3 U" ?1 L- r6 a: k3 u) n

  135. ! x5 u" s4 F6 k6 @$ O
  136.                 writer.Flush(); // 立即保存srt文件1 h6 Q! L. b2 M/ q

  137. " C& Z; r) |( y1 Z- A- j& e9 |
  138.                 segmentIndex++;/ G$ [# G2 b6 Y& w( Q
  139.             }- ~4 L* H8 d/ I9 L7 X. g

  140.   ]) O4 b  Z: t7 G  R
  141.             var endTime = DateTime.Now; // 记录结束时间, h2 ?8 B: d/ K- a# Y6 I
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;
    + @/ h  k1 D9 M0 Y% g
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");
    ; P+ K) z; a+ T* y* l$ v- k3 x
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");
    , ?) _4 y- h9 M5 D2 V: u6 x
  145.         }
    / P9 Y# @* b$ h1 c7 D# J5 M
  146.         else {/ Z8 U7 Z9 K' ^. L+ K/ Y. O! X
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");
    , t. U& \5 W. \- p
  148.         }  w/ t& u0 e! f# F* ^! i
  149.     }* J. G' h% \4 J4 _4 p4 t* s
  150. }, A& u$ P8 \% I5 V! Q
  151. public class Options+ J. F* S% S/ _1 z- P6 v; Y
  152. {, Q) V8 h: l* v8 _, S
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]
    + \; Z+ Y4 R. `1 {( {, k
  154.     public string Command { get; set; }( R7 D1 W( s9 Q* q: c1 z
  155. , g; R" s  f- `/ u: L' I
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]8 _  M4 Y0 j# P# b' w
  157.     public string FileName { get; set; }! M. e$ d) v* A: r, }% p/ d
  158. & T: g( I- i8 F6 P2 j; g
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]4 S: R: ?6 d6 w, T8 J
  160.     public string Language { get; set; }- h) _5 c, S7 K% E
  161. # k6 G3 H' t3 v' }7 c% S+ K+ P6 \
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]
    8 X- q) N! o: J1 p
  163.     public string ModelName { get; set; }
      |" V0 F+ e& `$ k9 a$ _

  164. % P2 n: G' N7 R" Y, `0 i
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]
      }  I0 ^  W9 [! w1 X+ [6 }
  166.     public GgmlType ModelType { get; set; }9 X9 j: t7 D* b9 A$ C; d
  167. }" g! G# w% Q6 p6 h0 H; \! n4 P+ C
复制代码

; A4 U9 n8 V/ G' `1 q) ?5 a  j9 J+ V; F% ^4 a8 y9 l5 `
! v( U2 J! ]5 \. X

* s. ^1 K2 ]+ T4 S: w0 C/ u
作者: 星之韶华    时间: 2025-4-4 01:06
学习学习一下




欢迎光临 冒险解谜游戏中文网 ChinaAVG (https://www.chinaavg.com/) Powered by Discuz! X3.2