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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-4 12:57 编辑
1 b6 ~0 M5 L( D- {
9 B' @; H: `& P1 s9 ?+ ] 本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,2 v. ?0 _) j2 Q+ `
使用时需要輸入语言,源文件路径和目标文件路径
1 ?8 T- v) [1 b6 e6 e最后是输出srt文件+ v: S. P9 J, U# B

0 O9 K, I9 y5 s3 t! L! y+ \1 g代码如下8 i  B9 F+ S. w7 d4 X
以下这句用多线程可以增速,否则很慢) v8 A& M" z- m( X4 i
以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。5 r- e2 j+ _5 g3 h" F  O2 l
6 L( ~& D- ^% {8 b' H% {
" n4 y2 T6 q4 W: t) P; ~* E
  1. var builder = factory.CreateBuilder()0 U0 l- z4 |8 I, i/ j/ t; `+ b
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码

; r4 o* ^  B1 J" _' K/ A! n1 L
, R4 _) L- F$ l- R. ~* M, O: y
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT
    * p, M7 [. @8 n5 m
  2. ! g: c: ]) O+ E- X2 {$ l
  3. using System;! K/ f) z2 d* f: |/ {
  4. using System.Diagnostics;
    + Z! E2 y4 }3 {$ ]$ v$ ~2 O4 k9 a
  5. using System.IO;6 L8 n2 |3 i# c) @- \% Y6 r, }! s
  6. using System.Threading;& r/ j& ~$ e0 n; B- ~
  7. using System.Threading.Tasks;
    ' q. R8 V' T. |" [
  8. using CommandLine;( D3 }/ b  ]4 q$ H- L
  9. using Whisper.net;9 ^9 k8 f7 e& T# d$ Y) b
  10. using Whisper.net.Ggml;
    7 Y/ M5 W  w  n2 O# b9 l: s$ x
  11. using Whisper.net.Wave;( l+ @/ H7 y+ a+ }4 d
  12. , W- [4 d" S3 y& ^; U, k* H
  13. await Parser.Default.ParseArguments<Options>(args)! J. o2 e8 N4 C$ V4 B& H, O
  14.     .WithParsedAsync(Demo);1 |, ?( z) w" ~4 K: D' b
  15. 8 H& N; G7 w% A0 t7 R
  16. async Task Demo(Options opt)$ z! _3 D/ j" j# h

  17. 1 V/ B% u! f" w: [% C8 Q& w, s
  18. {' `. c% T% C' Y- s& q+ r
  19.     if (!File.Exists(opt.ModelName))9 g3 W- N2 Z- d2 ~, E9 J
  20.     {
    " s6 L* p+ l9 [1 o- C
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");
    / u/ {% q0 x& E' M' F
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);- g: m) G4 Y; l; ^  N
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);
    " [" s+ U/ p3 G5 U2 B' B9 F
  24.         await modelStream.CopyToAsync(fileWriter);  ~' F& b; x: {  @" L5 }( f9 ]
  25.     }) k/ D& S( \. P5 a+ X. ~

  26. 3 Q5 i! @3 _/ j# f; A
  27.     switch (opt.Command)6 w* J% L; k% U8 o5 t$ t$ |. C) Y5 U/ X
  28.     {
    . o9 r$ r1 k) g% k1 e+ @
  29.         case "lang-detect":0 `: e, B' u1 I1 V/ t# w$ ]8 M
  30.             LanguageIdentification(opt);* m' m5 c; L0 W
  31.             break;
    " o3 U  X# ]; [" X5 J7 L: J
  32.         case "transcribe":
    & o2 ^2 r; `0 o0 C; w  Z% z- C
  33.         case "translate":
    . N3 z8 e4 l4 a. d/ l
  34.             await FullDetection(opt);, p0 q1 C4 W5 P( t2 t
  35.             break;8 U% `, F+ S  ~, x# }2 s
  36.         default:$ a: R5 D& v4 T4 h, S
  37.             Console.WriteLine("Unknown command");
    6 a4 r+ \% `; r7 y+ }7 e* r7 ]# H
  38.             break;
    : ?* W, f6 t) g! E
  39.     }* x  r2 t/ ~" ~& E
  40. }
    * a" P# f; {6 V  {) N/ V+ G: ?
  41. 9 S2 q; ^3 O) J! M! s
  42. void LanguageIdentification(Options opt)2 f) O, K* M+ o0 k; ~4 G% c: O
  43. {
    # ?8 A. w# d$ A* L
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);
    ) _7 G$ K. j; p3 z7 m9 |

  45. , o+ N/ X6 X* a3 ]6 D
  46.     // Same factory can be used by multiple task to create processors.- K$ @: k& i6 h
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);
    " \% B# h, O8 d  x2 \

  48. ; i. R& X$ l2 X2 ^6 D
  49. /*    var builder = factory.CreateBuilder()& K7 F2 F& l4 F0 X$ ^- I
  50.        .WithLanguage(opt.Language);*/
      x! T' |5 i8 |9 M9 s
  51.     var builder = factory.CreateBuilder()$ _8 E6 ]9 S$ g) E( v* p' Q
  52.    .WithLanguage("english");
    4 ~( }, J; \5 g9 K9 B( N
  53.     using var processor = builder.Build();
    ( u7 d' h" {$ f8 W2 D* P) y
  54. 5 q4 j, Z! l1 P) k8 B
  55.     using var fileStream = File.OpenRead(opt.FileName);9 _; [# e; z' a" P$ n/ O
  56. & V& N, h8 ~8 b6 N0 W
  57.     var wave = new WaveParser(fileStream);
      M. I( C& g7 m* O5 y. j0 O
  58. 3 L1 @6 y: t: x
  59.     var samples = wave.GetAvgSamples();% z8 c" _2 r$ ~( w+ K. ]3 k& ~- k

  60. 1 d" e8 x2 k1 D% f
  61.     var language = processor.DetectLanguage(samples, speedUp: true);
      A* i+ |  U5 X1 F, i* i% v0 D/ z
  62.     Console.WriteLine("Language is " + language);7 X& D$ Y+ M- R, X
  63. }
    3 b1 k" k$ k6 W* ^
  64. . Z9 b' [/ ^; o4 x- z* X, k
  65. async Task FullDetection(Options opt)
    0 U1 l# S9 ?1 e7 r- y  F
  66. {1 P4 j& K/ I9 j; _
  67.     // Same factory can be used by multiple task to create processors.7 N3 N9 L% b) I2 R7 H/ s  m* a4 E
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);
    9 Q. ~" y) P/ U; _6 g7 \% F
  69. 2 r/ M, l0 _' ]/ z" J& @# v9 H
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);
    + Q4 f+ y# b( @# T6 ^. _& X+ }
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");
    : W7 x8 a- n& T. n
  72.     string languageOption = Console.ReadLine();) F7 l* l. u) Q' w$ [% A1 E. A
  73.     var builder = factory.CreateBuilder()
    / W, l# p3 k1 k5 p* F) T1 i
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);( b+ w! W: g! K* ]/ F9 o: N

  75. + f/ I0 r) C( {. J4 V  \5 Y) l
  76.     if (opt.Command == "translate")2 o6 K5 p- c+ S2 p' x
  77.     {
    & W; O7 j0 \) [
  78.         builder.WithTranslate();$ L. o; H2 q8 ?2 Q. [
  79.     }( Q. e' C$ j) ]

  80. ) R# {$ v* O3 J. Y$ U& y
  81.     WhisperProcessor processor = builder.Build();
    ! s) o6 H7 l" C6 Z  @% }
  82.     # v* R' n2 ^/ A2 @- A3 d
  83.     Console.WriteLine("请输入wave源文件目录:");) T" h: ]" P- ^; \* w6 O* }
  84.     string sourceDirectory = Console.ReadLine();- ?* n/ G2 V. M( N+ o. |
  85. 7 _2 L' \: L9 l; H+ }9 p/ g
  86.     Console.WriteLine("请输入目标文件目录:");( W4 c5 Y: \$ W* z! a! _4 a
  87.     string targetDirectory = Console.ReadLine();
    ; B! \" o+ t; `7 y
  88. 7 H9 V. J; X5 `' ?$ b
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))
    0 T& [3 d0 x, M& z" ~- H3 H0 y3 w1 a
  90.     {
    6 }' Q7 |: w4 q  q  N
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");6 m0 R7 b1 \' p  M) C/ k
  92.         return;
    , I* D- d: N  l! p# J
  93.     }
    4 S! _! N+ J$ Z+ H
  94.   Z2 a: X3 }0 W' A' q% f
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);; y9 r: S3 J$ O- ?9 _. \8 F

  96. ! o5 h3 X, X8 q
  97.     Console.WriteLine("处理完成!");
    ! p! G" @" i' d/ @, y  c
  98. ) `9 D# n) p' j# Z7 V
  99. }* ~- T  s6 l* T2 W' S4 f) T
  100. static async Task ProcessFilesAsync(WhisperProcessor processor, % M' [+ S# K1 Q2 j- V
  101.     string sourceDirectory, string targetDirectory)% H; _5 S1 i% |6 A
  102. {
    - @% E, f3 c, [
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);
    7 T7 J- z" C/ T; x2 v9 i4 m, k: \
  104. * U& `. x3 `  g, u$ V8 a/ k
  105.     foreach (var sourceFilePath in files)
    4 Z0 E& L6 i" O( L! [
  106.     {
    1 {1 Z5 A5 w9 Y* ?
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);3 ]% p+ t+ G+ Q8 c
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);# j. ^3 F$ `6 V+ U; L
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");, O' y$ i6 ?0 K2 a' g
  110. 9 _: ]( y- Z4 r5 ?% L% C) r2 \/ B
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));
    6 @+ m' y6 k; E, _6 ~. k

  112. . B# Q& P5 `9 Y+ `
  113. 4 Y1 F2 m& y. ]
  114.         if (!File.Exists(destinationFilePath))6 r) h, {' L1 a' Q
  115.         {
    + L" _8 d# k+ e$ @9 B5 n
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");
    1 j0 m2 M6 g# N+ N1 v
  117. $ o+ W$ a5 y( q; |' H
  118.             using var fileStream = File.OpenRead(sourceFilePath);
    & R2 A" C! C* ^% P, c; I8 g9 H
  119.             var segmentIndex = 1;
    ( ?7 l5 }6 i- U: U" Z- d
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter/ g  t, a3 _: a" [" K+ k
  121.             var startTime = DateTime.Now; // 记录开始时间
    8 ^. U2 ~8 y- b: H( C3 n4 [

  122. 1 E7 L4 U& S! F: n7 T3 r" B4 o2 u
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))# ?: N& _+ {2 J! s! U
  124.             {+ G" j# t- F: g4 F+ S
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");( \( t' x" k9 m. `& C1 X* P0 o6 T7 G
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");
    3 `# V- A& X. o5 _
  127.                 Console.WriteLine(segment.Text);
    - V" v& D9 |& @. h, Z' Q7 y
  128.                 Console.WriteLine();* V* f9 |$ c) Z8 D  m
  129. 2 y3 S+ z& V; f2 {0 V2 h
  130.                 // 将srt内容写入文件
    5 A1 n/ @- j+ Q2 ^' D
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");5 h, L3 i, ?" z4 `, s
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");1 E1 Z1 U6 P8 t( b6 f0 i
  133.                 await writer.WriteLineAsync(segment.Text);' W4 }7 g0 a+ Z
  134.                 await writer.WriteLineAsync();
    ; j  h5 F( g, J
  135. / H5 J0 t7 w! h/ `( }" C% M0 i
  136.                 writer.Flush(); // 立即保存srt文件) L, f% ?2 |" i- R! C/ d

  137.   `1 F, W" E/ n' f! K& F8 M
  138.                 segmentIndex++;
    ) h' X( j" L9 F* ~
  139.             }+ M, p+ f2 k# f; H( \

  140. * U0 Z0 }! ^: ~! [% h) [
  141.             var endTime = DateTime.Now; // 记录结束时间' F7 H# @! C& e4 a. L; L
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;! v$ u, I" ^; t  Z/ P
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");
    # z+ O  q7 b, g2 [+ e5 B; I
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");
    . _1 ?% B+ m& t3 `* h
  145.         }
    4 Y# W8 l( s8 b
  146.         else {9 \0 o7 P+ d3 l: X1 h
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");# w9 E( B5 }; T, P8 V4 T, h
  148.         }
    - X  o) ?3 l* c4 `* d2 q
  149.     }
    - t1 l% ~2 i) v/ `& S7 `  N
  150. }
    ; Q( t& `7 r. M* J# t
  151. public class Options( Q- E8 J9 O) K9 O9 x1 Z# I
  152. {
    . w5 X/ b: H6 n
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]  n% O) ^* i! u6 j
  154.     public string Command { get; set; }
    1 [! _; O% N$ P' X, B/ w7 r3 G
  155. ( Q, a! M2 ]+ q. H" C0 J9 `* W* i6 _
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]
    0 b/ k- F$ S# R
  157.     public string FileName { get; set; }% E7 b9 b/ d  [' Z- x
  158. * [1 b5 Z3 z$ |5 B
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]
    6 z) t+ M7 P0 K( V' j8 I8 ~
  160.     public string Language { get; set; }
    " ~$ Y0 W3 ]; c2 p% U
  161.   v9 N* J! d4 [0 x) s
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]8 n7 u  V1 s2 I* I. b
  163.     public string ModelName { get; set; }/ q; e& O2 D( e9 S& I9 E
  164. 9 ~2 n4 X  Z, F# M5 |$ z  O' U. \
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]
      w. R# k* `9 T4 }2 T1 K
  166.     public GgmlType ModelType { get; set; }
    7 [" O4 E( t: {$ h
  167. }
    , W- U. `# x$ Q7 Q3 }+ ?9 P
复制代码
6 L! N! ~2 n' ?, r& I
; o; ?% v3 ?6 ?/ z# q5 R9 X

+ u( U( E, j6 N1 I, x' A- l$ ^& j' J6 c' v) k/ p4 z6 y
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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