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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-4 12:57 编辑
8 K' P. \) k, u9 |& P8 ?
5 F8 h) J* b/ |1 o! J" e 本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,
; y( a6 u$ @  n5 b$ [( B$ v 使用时需要輸入语言,源文件路径和目标文件路径/ d) a0 N  T  h7 z) p0 v
最后是输出srt文件( K' [7 o6 M' e2 M! `

, v$ k  R) v- _- J代码如下, u) T% Y6 T  o4 s
以下这句用多线程可以增速,否则很慢
2 |1 S4 I$ @0 `0 C以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。7 R$ b6 L0 g  J. t+ `

% V2 ^: `, g; I. q6 n+ P
$ n/ x! k" Q3 l% V* P! q- }
  1. var builder = factory.CreateBuilder()
    / \$ I% s% R0 B& i3 q+ ?8 Z
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码
* @* \0 f2 V- K* X' p2 A
! c1 J5 o. ~6 N7 `1 j
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT
    1 j2 g$ C6 E# P+ `2 r1 G

  2. 4 l0 U1 K+ d7 M0 n( I. P* N+ k+ r
  3. using System;3 [: w* Q( [% f" z
  4. using System.Diagnostics;( k$ f5 c( s9 H$ l7 V- e  v& a8 n
  5. using System.IO;
    9 _7 J6 c  L+ w7 q
  6. using System.Threading;- U. K% M; n' G
  7. using System.Threading.Tasks;
    ( g6 }5 d0 e& K
  8. using CommandLine;
    ) e% ]9 }/ F5 x
  9. using Whisper.net;0 @; w6 |- h/ x* l" h! D% r
  10. using Whisper.net.Ggml;' c+ q- v  V, m$ @5 D9 @
  11. using Whisper.net.Wave;
    9 R: {4 u. O) b) ?% V0 o# v

  12. ) _. T$ ]% N! E- a6 m$ k  o
  13. await Parser.Default.ParseArguments<Options>(args)& s# I+ k; _% M, d
  14.     .WithParsedAsync(Demo);
    / T2 |* q: |: c6 N0 ~6 b" Y$ W  ^& a

  15. # L4 e+ f/ ]% t/ m2 ~' @( j: |( {
  16. async Task Demo(Options opt)
    ' H# b. g) ^$ Y, F8 Y
  17. 7 z) L$ ~, A- f/ ]+ M- Q
  18. {% C% y* F+ d, K# K4 h8 W
  19.     if (!File.Exists(opt.ModelName))# k* \2 B* e: e6 f; |% e1 j' U
  20.     {8 d4 ~2 P4 c% x9 ^4 f' B
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");" ]) c& ~3 M8 n1 B) e" ^# P
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);
    # W3 i" |2 O$ h
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);
    9 ^( Y6 m* y2 Z& Z" i7 B" [
  24.         await modelStream.CopyToAsync(fileWriter);
      a4 ]( z2 N3 I1 v
  25.     }
    ( @) W! S2 g- I# e+ F! ~, C$ C5 W! s  h
  26. . t1 E; q' A5 s- W! {
  27.     switch (opt.Command); X+ \. b; K& L1 Z5 u% w
  28.     {
    8 [% u/ M: W5 D( D  a% o# s2 Y' W
  29.         case "lang-detect":
    6 w: d% O/ r3 @% W$ C$ \5 j
  30.             LanguageIdentification(opt);$ c6 {1 E# A8 J: L: ]  B, v
  31.             break;
      I# m; M1 j5 I# k
  32.         case "transcribe":
    2 }2 \2 }5 G1 X6 k* Q
  33.         case "translate":
    : C6 o$ ~" P: ]2 P
  34.             await FullDetection(opt);
    $ M/ A9 F, T- G, r
  35.             break;7 [' t2 R) u# q" i
  36.         default:2 `) J4 x1 c. ~* m" Q
  37.             Console.WriteLine("Unknown command");
    $ q! R; z2 w2 C/ v/ ~; t% n
  38.             break;4 K$ }1 t& M2 Q
  39.     }
    ) M2 t7 x4 O8 M2 J- w  z
  40. }8 u& v2 Q" H) ?# X
  41. 6 H* a2 h: X+ Y* c$ F5 F$ |0 q. _* J
  42. void LanguageIdentification(Options opt)+ D2 s9 K; ?+ P9 ^
  43. {
    6 i' V& r) _0 E9 \& U
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);
    " X! I( ?! E9 W& U( n6 V

  45.   C: c% l" h1 A( o: H* j
  46.     // Same factory can be used by multiple task to create processors.
    6 }$ A1 e4 Q$ e8 F0 U; T
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);
    ' Q+ Z* Q# d, A$ _! M; J; E& ~

  48. / Z, g7 J, d$ o0 u
  49. /*    var builder = factory.CreateBuilder()
    - L* u/ ^- `9 H' R( g) P$ t" l
  50.        .WithLanguage(opt.Language);*// T- n) o: f6 [+ S1 F7 Z9 S; f
  51.     var builder = factory.CreateBuilder()
    / y4 o+ n; r4 H9 T- U
  52.    .WithLanguage("english");# D1 e& U8 @9 u1 A
  53.     using var processor = builder.Build();
    ! s0 e( p  S9 g- T
  54. % J9 I0 U6 C! b8 T
  55.     using var fileStream = File.OpenRead(opt.FileName);
    1 w6 U" q/ k8 m1 f$ V

  56. 8 P; Z  i9 R2 g) a  Z
  57.     var wave = new WaveParser(fileStream);
    ! y, n* b( p5 ?0 x9 @6 O! A1 ]

  58. 3 H" d& p  V+ W  j& n
  59.     var samples = wave.GetAvgSamples();% m* E, x/ K: d8 }# }- g

  60. 2 N) U, s: l* Y7 o- b
  61.     var language = processor.DetectLanguage(samples, speedUp: true);
    , o* v4 \) S& F7 |. v; F6 q- ^
  62.     Console.WriteLine("Language is " + language);& ?' F# x& ^2 H( c% e; q
  63. }
    * Y2 ~' s! \4 g7 v

  64. ! O0 N" \- P0 S
  65. async Task FullDetection(Options opt)$ Y' v9 _3 X% `/ z9 I5 E
  66. {3 t5 O  u" V# n- I
  67.     // Same factory can be used by multiple task to create processors.
    * y8 U8 @' s& i' E' C6 a
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);
    # S9 W/ z* B- ?) a

  69. , P' ^' ~) A, C% Y6 Y% ~8 O. u$ k
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);0 y8 H4 Z4 x3 |: x) B5 |/ i# ^9 a
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");% h- m6 ?! Y6 b
  72.     string languageOption = Console.ReadLine();
    . X- d3 |0 G+ r3 ^- `
  73.     var builder = factory.CreateBuilder()
    & D5 N/ g( V5 X: b7 [% L, |
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);$ T' E; m! c4 {3 e
  75. / l+ v9 Z+ I% }) O3 b
  76.     if (opt.Command == "translate")
    6 Y% t' ^& ^' [! y6 g! _
  77.     {
    9 N' M% I+ U' x4 t% t
  78.         builder.WithTranslate();
    1 b. I8 A: N  j/ T8 ~
  79.     }" B; O5 N. t7 @6 V8 ~6 V- Z8 e
  80. ! Q! t6 M1 d, {% z5 q" u; ]
  81.     WhisperProcessor processor = builder.Build();
    2 K3 p$ e  J4 A! ^
  82.     " z: c8 ]* C8 o' L  _# R: `/ ]
  83.     Console.WriteLine("请输入wave源文件目录:");( N% g. P4 {; \) Z5 S/ K; m7 f
  84.     string sourceDirectory = Console.ReadLine();
    ( J) x& Q5 M, {- W
  85. % n( i; y6 b# q' s) a% r
  86.     Console.WriteLine("请输入目标文件目录:");
    ) z$ b) F, a( [* H7 g1 N. m" t. J
  87.     string targetDirectory = Console.ReadLine();7 y2 s7 d, B- j& U! ^
  88. ( n& A4 K: X' K: a8 W3 U
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))
    $ V7 p! v$ |/ D# r+ D/ v7 c
  90.     {! T( x! A7 `/ L7 `" K2 u1 s
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");5 N' k0 W2 N2 W5 Z2 O
  92.         return;6 v/ J! q5 w' F  e7 r3 a
  93.     }! g" C6 @' c( R5 [) B7 p: q# q+ q! l1 _

  94. 2 g3 g7 N  |0 m" A& a
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);
    / ^6 ^  ?3 {- X/ I4 i& O
  96. + m9 `5 F0 u2 d
  97.     Console.WriteLine("处理完成!");
    ; C8 _  L" u" y; v; ]6 Y
  98. 6 R( ?2 a* ~+ l
  99. }2 Q6 @+ A( }0 d1 d/ ~1 z3 m2 A
  100. static async Task ProcessFilesAsync(WhisperProcessor processor, . Z' u3 q% O" m+ z& M2 e& N% c
  101.     string sourceDirectory, string targetDirectory)! r* f$ }& ?: l* i+ p$ F* C" m
  102. {: c" E) U) r+ G
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);
    6 S! {# R( {/ U

  104. , y8 m7 C: H0 J. g2 |
  105.     foreach (var sourceFilePath in files)  n3 J6 N4 p5 Q- t! C, m4 s+ [& _) u
  106.     {
    ; |& o5 d: Y2 M
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);  D: Y6 x0 G# x( z
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);
    * F/ ^  a3 f) c% _2 y, y
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");
    - d1 G: p, v& S" l+ G  n5 P7 R
  110.   Q- ~# Z( v8 `' `( w' ~) M3 R3 M4 O
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));
    1 x! e0 q* E$ A! [

  112. , B( ^5 G# s* R/ d- q! C: G3 Y
  113. ) c) f/ X/ {6 H+ U" r; `
  114.         if (!File.Exists(destinationFilePath))" U- J5 [" M, U& z2 d- H
  115.         {
    . K- B% k1 X5 M" I/ w  e# j3 h
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");
    " t: n. w# N1 C! H
  117. " N) L9 i  W( f1 f, ^9 |9 W2 S
  118.             using var fileStream = File.OpenRead(sourceFilePath);
    ' }8 Y8 q8 w) I( N2 p" d9 ?
  119.             var segmentIndex = 1;5 q/ L, f/ A6 g- H: B7 e& \
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter; i, n! D3 I* `5 N" t- \& y3 a
  121.             var startTime = DateTime.Now; // 记录开始时间
    . C- A0 _( R  p' a5 t/ V
  122. 0 z$ K- \; n/ Z% X) R# S
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))
    : d6 \  b- u  M0 u/ ?& G+ t0 M
  124.             {
    - j9 L" s- x* v, V0 \  h1 w
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");
    6 m# A( j3 ^( ^' @' c& a
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    ) V$ o% E( r- i5 d! w8 V
  127.                 Console.WriteLine(segment.Text);0 g& z1 \4 I; H6 @1 `
  128.                 Console.WriteLine();
    0 M0 L7 g) O8 U

  129. 1 y* ]- ^, s: _7 D# [
  130.                 // 将srt内容写入文件
    ) y1 P* Q& D+ R1 U
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");
    7 f; @- r& W1 d' ]8 W+ q
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    & a0 k8 _; l6 V9 N. k, f- o6 g
  133.                 await writer.WriteLineAsync(segment.Text);* P, H6 M5 x. F1 C! u
  134.                 await writer.WriteLineAsync();% C4 {: O0 g8 f& n; _" H( E/ U

  135. ' ~  j  `  P' o5 d( i
  136.                 writer.Flush(); // 立即保存srt文件
    ( W% \8 Y1 ]3 J. G' L7 @% M

  137. ) Q2 b; q; X- B( }9 K, q& O8 V6 S
  138.                 segmentIndex++;
    4 l0 X" |# j$ G( ?# A3 ^
  139.             }) I% U, Y" i+ K# E# Z9 z$ u

  140. ; ^! e5 X5 C( M0 v1 r' S- P
  141.             var endTime = DateTime.Now; // 记录结束时间' Q, p- e* Y' V  X* B
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;
    * a9 S" G5 z, t" F. S0 H9 T5 c
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");
    - w% c, `- _9 ^. r4 ?
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");
    % K, I# f9 I3 p
  145.         }& y7 X6 f- C9 C! d3 L+ L/ ?
  146.         else {8 W& p6 q  ^5 m2 X7 Z4 {
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");
    ! u9 i, |, X# h) q9 O  r, U
  148.         }
    - H& E# T/ [6 T7 c8 Q/ _" ^; Z- C
  149.     }" M% Y7 F. l' U: z
  150. }, a1 ], {4 R: j3 D) A
  151. public class Options
    9 X+ }* V: Y, v/ @2 e/ c* \
  152. {9 G. }( G) D" p/ j: u: W
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]. L& W% M, f% @- {6 b
  154.     public string Command { get; set; }7 K# v2 W+ ]+ L0 X* Z% p$ H, W
  155. $ Y0 j0 x. d. M  _
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]
    $ r, E: B: t  B& f, x1 w
  157.     public string FileName { get; set; }
    * u% t* ~, f8 c9 N, d2 B

  158. 0 s+ n4 B) I) O7 S' p2 D
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]* p7 r9 ]# K9 d2 z, r+ B
  160.     public string Language { get; set; }, e0 O2 X  X. d. R& k

  161. 2 o# s+ _  V' q
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]; r$ L. o. \) D1 z' X1 \( S8 L4 u# m
  163.     public string ModelName { get; set; }6 v. l% k) q6 b5 g& f
  164. ! _* _% d1 ]7 B& O
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]
    . O! C% e4 C. H! @* J5 H8 }/ O. D
  166.     public GgmlType ModelType { get; set; }1 ~# Z  v+ |, \! c) n  a
  167. }
    , {$ `6 ]: s- b3 o5 F1 i
复制代码
, R& W  [1 u0 _) D% o  E
  n4 t9 J& e) x' Q1 M+ ~9 T
# S0 U3 N* T1 m
# m6 b/ u  y( Q: `, J9 m9 f& M$ v
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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