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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-4 12:57 编辑
/ L6 G1 y( C5 D, R0 G3 R; V- O7 m/ w
本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,% V, ?( K. r" |1 ]  ~+ g8 U9 G
使用时需要輸入语言,源文件路径和目标文件路径
: ~6 \( Y' H9 l最后是输出srt文件
3 L6 `; C5 a5 `0 X
& [2 }3 ~3 v! V* ^/ ]$ b代码如下
% S5 b: |- H% I' q7 u- t0 Y以下这句用多线程可以增速,否则很慢4 n  [4 B0 r7 m
以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。
6 P& h7 f% j( c$ u* h5 j1 S4 w# O* c, g& m
" q: V" t$ n; D& \
  1. var builder = factory.CreateBuilder()
      B. |# p; ]- S' ~- h8 B; k& M
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码

% p( R* F9 y9 F$ V; p& B: e; W. F  S5 z  j6 X7 G
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT9 ~$ J, n/ f7 W. }# e1 {/ c
  2. 2 ^2 A+ E0 O% X$ S$ s9 Q* i
  3. using System;$ O2 g5 s0 t. ?. w8 i
  4. using System.Diagnostics;
    4 w; V2 m  O- |. B" |- Q$ _& D9 h- w
  5. using System.IO;
    ) d( v% J% T3 x8 K. M
  6. using System.Threading;
    7 T7 O5 C" a0 T; G
  7. using System.Threading.Tasks;
    # B  I1 K' e# p
  8. using CommandLine;
    4 w# u4 g' |* O/ n1 N7 f
  9. using Whisper.net;
    , }7 M( H' d2 D9 n" i+ d
  10. using Whisper.net.Ggml;+ W, E+ K5 q7 x1 X# n
  11. using Whisper.net.Wave;" I3 j/ `5 K, B  h4 @' I* X
  12. 2 Y, m% K3 w' F4 L8 h
  13. await Parser.Default.ParseArguments<Options>(args)
    ( T5 k; V+ I8 u1 _2 W
  14.     .WithParsedAsync(Demo);% p% t9 F: g' ]4 ]

  15. ! Q& c" V9 M" y
  16. async Task Demo(Options opt)
    + B( u0 X+ [$ `! N% A2 i+ X4 z/ J( B

  17. " e8 }8 r) t& s6 b
  18. {3 w2 d) I/ g6 ?4 J7 m! Y1 R* t
  19.     if (!File.Exists(opt.ModelName))
    / x1 k6 Q9 m( n* q! {
  20.     {
    1 y+ \5 y( O' p4 _6 R$ M$ y; N
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");
    5 D) _8 [* S3 l; u6 `& P1 Y/ [
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);/ H# U2 J7 X& T! U; c% H; _
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);
    : `0 O( A; y7 X4 q2 I
  24.         await modelStream.CopyToAsync(fileWriter);
    ! l0 j8 U6 ^' F/ q$ h2 h: _+ H, _. s
  25.     }+ R( l- b, ~- x4 P" d
  26. 4 |  o4 T# I1 `* ]  s
  27.     switch (opt.Command)$ @4 e& X! m& r4 s% |% ^# |
  28.     {
    ' P/ A0 Q" s. I4 ~
  29.         case "lang-detect":5 y, M3 I0 j6 G! a, D4 _* E
  30.             LanguageIdentification(opt);
    / R* g+ B7 v  c8 i
  31.             break;8 u- q- \% V9 o
  32.         case "transcribe":
    % ]# `: f  T0 D1 w- @7 w! S5 w
  33.         case "translate":$ N# Y+ o/ n  _$ z" \- w9 R/ u
  34.             await FullDetection(opt);
    5 s% p2 V1 ]4 K7 U9 U2 b; _/ W
  35.             break;
    5 \( G/ x9 i( [6 H
  36.         default:9 _" P2 x7 o0 d/ @
  37.             Console.WriteLine("Unknown command");6 C% s8 R" _! {4 H0 S
  38.             break;  C/ l4 W! b& H0 _
  39.     }( J8 F* Q) }# Y1 u
  40. }
    + F6 ]9 L6 N! \. C( j8 e

  41. # A) Z2 Z: B$ Q6 e  O* \; |
  42. void LanguageIdentification(Options opt)( @/ q- y/ i; L0 _' F, W
  43. {
      `3 X, {. B2 P# R3 X' O; H* ?9 j
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);
    & {! t( [4 x7 `. A

  45. 0 \& Y: d( M" ]: x
  46.     // Same factory can be used by multiple task to create processors.
    9 e; |4 l1 {6 T  E3 N
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);
    ) d/ |  C  h( G8 H8 b$ s
  48. ) g8 K/ D% I3 k/ A& R  Q5 n) C
  49. /*    var builder = factory.CreateBuilder()
    2 A3 B- d  c' W# U. |3 I
  50.        .WithLanguage(opt.Language);*/% B+ B6 R$ u8 E; E! l/ ~( q! J
  51.     var builder = factory.CreateBuilder()" o- P7 g- C. n) D# I
  52.    .WithLanguage("english");
    ( O3 _/ M* J# u2 a/ R* R9 z
  53.     using var processor = builder.Build();& D1 R  Q* u0 R$ [1 n: v2 J7 \7 ~3 J

  54.   Y5 w1 G' C! \8 y: {8 r
  55.     using var fileStream = File.OpenRead(opt.FileName);
    , P8 F7 f! ^- Q2 T1 O4 o( i

  56. " P: ^: j' g4 {0 n4 ]2 w0 t7 Q
  57.     var wave = new WaveParser(fileStream);
    % p' N& u$ N4 M, C
  58. 5 o- A. d: q* T2 ~: G7 {
  59.     var samples = wave.GetAvgSamples();1 S, s9 X; i$ S+ z8 ]* K6 q  f
  60. ' L: |8 \8 Y  k" S7 L
  61.     var language = processor.DetectLanguage(samples, speedUp: true);- R  @: g& }8 L
  62.     Console.WriteLine("Language is " + language);' v0 j3 l+ ~3 G1 _; l* ]$ R
  63. }
    + `# B+ k6 u! @* B8 C* R

  64. " o3 T% l/ N' z- t) l; L
  65. async Task FullDetection(Options opt); o- q+ j5 @* W6 ?; n! _
  66. {  K8 w- T9 ]  k" F  h
  67.     // Same factory can be used by multiple task to create processors.7 S7 E" A  V3 |0 v+ O/ }9 k9 q
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);
    " B$ _6 m2 w: q
  69. # g7 Q4 h: V% `9 J
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);% u% w& l: Q$ ?' j1 _
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");
    4 B, Q" v$ s8 n) t' J
  72.     string languageOption = Console.ReadLine();
    1 S7 Y3 U% a4 `( K
  73.     var builder = factory.CreateBuilder()
    # k) p( Z9 A$ V/ B
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
    . a9 i% L  l1 o1 F) q
  75. ; g1 f' v. X0 o8 o+ h
  76.     if (opt.Command == "translate")! @+ A9 e- ~5 T
  77.     {
    : i1 J! y) D5 N% q$ R" D
  78.         builder.WithTranslate();! K4 A5 m; o  k; G& O& e6 v
  79.     }9 g2 \2 O, P( N9 q+ l7 B
  80. 9 [7 j* C' c+ h( G
  81.     WhisperProcessor processor = builder.Build();
    & h& c) N) K( x; c
  82.     ( Q8 a  m; N- y" E, k
  83.     Console.WriteLine("请输入wave源文件目录:");
    . E2 X( P, e8 o  O  b
  84.     string sourceDirectory = Console.ReadLine();
    , g0 N4 P8 X- o6 Y5 j
  85. % ^, B4 i1 A8 \4 d" Y3 V; H. a9 L
  86.     Console.WriteLine("请输入目标文件目录:");
    ! {) j' t" I2 U: O# D" I* t
  87.     string targetDirectory = Console.ReadLine();- [* g( p( f$ B( l7 g  J( K7 [
  88. : S" d7 t1 L0 z- ^2 o  ]
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))6 _( H+ i/ {9 D
  90.     {
    $ Z0 S# v6 T0 u+ ?5 c
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");; Y5 h# s8 `3 X0 q8 T- Z
  92.         return;
    / X2 S+ x% R8 N3 h1 R" F/ b
  93.     }' u6 h$ i- A. t+ W
  94. 0 n- A. {1 w5 `9 `9 F9 y
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);+ R% T- Z. V' U; S

  96. / {" |0 M" m$ E& ?/ g) ^- w. Y
  97.     Console.WriteLine("处理完成!");
    8 z0 x7 m: q* m( F
  98. 4 Q4 l' x6 }8 }2 @
  99. }0 m. h& F& [$ P% i5 [
  100. static async Task ProcessFilesAsync(WhisperProcessor processor,
    8 y6 }2 B2 M# U9 V% H' w* [
  101.     string sourceDirectory, string targetDirectory)
    0 R+ j* Z, K8 q
  102. {( Q* r" v# \8 ~, o; u5 X) O& q2 Y
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);: Y% D5 `- ^" {7 @
  104. ' v2 G0 w, D0 c" Q9 [
  105.     foreach (var sourceFilePath in files)
    " z; J5 D+ N: X" U! c1 s! {+ @" g
  106.     {
    4 X. H! |  G5 k: F6 z4 |. V+ g
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);
    4 D* _+ d" D: l' i( G) e, h
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);
    ) d: ^( e) J- W7 t
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");+ x( a9 @! S  B
  110. 5 y6 g1 D* S) F  y1 v# b$ S
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));
    ) X4 w- K/ h- I- q

  112. 5 Q1 L$ Q6 ~2 J4 v; X- c- A

  113. / ]  E% D' i8 K" ]
  114.         if (!File.Exists(destinationFilePath))/ h- W; H" T" |) Y8 o6 g9 y' Q# l; i
  115.         {
    3 m# v/ F$ C  S& r: `; F0 x5 P
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");% W) l% l# R" c% h

  117. ! s# n5 i; }3 O* n9 ~# e) d& h8 E
  118.             using var fileStream = File.OpenRead(sourceFilePath);4 v6 O8 d% F$ X! P) J8 L" O. d: |* S
  119.             var segmentIndex = 1;
    % Z( ?( O$ s/ C. C2 w9 L2 K8 d: W+ a0 e
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter  e$ }, \1 G, s4 r
  121.             var startTime = DateTime.Now; // 记录开始时间
    + T  |3 b# S( W/ g

  122. : |9 c" ]0 B. ~
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None)), g# c$ _: G/ z, C) i% a
  124.             {& r1 I1 S2 d8 ^( z
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");, h$ W9 z# ?' p$ A2 {/ a2 h
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");: B4 W& `3 p6 h7 X
  127.                 Console.WriteLine(segment.Text);8 u/ N% J5 r! b* \. C
  128.                 Console.WriteLine();
    & |: H  t/ q1 H2 h
  129. 4 I6 G( a) E/ @  q) o" V9 ~
  130.                 // 将srt内容写入文件! k( d8 q* M' @: C  Z
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");6 N$ U) |8 M+ {; W4 q" w8 J& ^
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");+ A  V; v, e: _6 ?
  133.                 await writer.WriteLineAsync(segment.Text);
    , E& J8 ?, X' |' v9 |
  134.                 await writer.WriteLineAsync();; T& Z# j) G* Q$ f
  135. - t& F6 q3 c% c1 \" h+ p* Q5 I
  136.                 writer.Flush(); // 立即保存srt文件
    . @/ c. V) {- w  Z2 H) y
  137. 9 m; [2 H9 v$ l  g9 j+ j
  138.                 segmentIndex++;
    - b; U! O) Y" X8 |7 B
  139.             }
    . b$ j" ], @" g% {/ x+ Z6 L
  140. * ]4 [' p( {* j5 `* a7 M% x
  141.             var endTime = DateTime.Now; // 记录结束时间3 c& v7 }* K/ Y# r2 |, s
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;
      \) o5 b1 a; O6 ~" t) p" B- O& p
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");
    7 C% w2 x; M  `$ b0 g2 |
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");
    & g4 m' ~6 P0 N6 V4 r& E
  145.         }4 F6 k6 _; g3 W  u
  146.         else {6 k: j' |6 ~. k) F' ?6 u; {
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");
    , I- ~. [  l4 }8 o- p6 P
  148.         }7 c. C, e  D& i6 ?" H
  149.     }8 {1 k/ Q: T& H+ t5 y# H7 m# p
  150. }! r+ L: Q/ b! K* n3 U8 @# A
  151. public class Options* Y; U9 \" N. J/ K$ Y: Z) r
  152. {
    4 V+ x9 R* P4 T+ v
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]
    : @! y* H/ o0 G
  154.     public string Command { get; set; }  }7 ^0 }" j; k5 o% g( m/ k% D
  155. 4 d/ E: y9 H  k5 P! f
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]4 d! F! p9 _, R2 q  n+ X
  157.     public string FileName { get; set; }3 d4 ~# S! S0 |" ~+ _* B& K0 ?

  158. - J- S3 l0 O6 f# b: ^
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]
    * V1 G6 V9 }9 T) n% X
  160.     public string Language { get; set; }
    - b5 `' H7 g+ J, Y: U

  161. 9 P: J4 {/ U3 q0 q5 L
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]
    3 j, M) y6 u: p/ ^
  163.     public string ModelName { get; set; }$ `9 p3 _, Q( W  o1 N& d( m
  164. # D" Q( _% S- A, G- Z! f
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]8 h% x2 G% r4 v1 v( O
  166.     public GgmlType ModelType { get; set; }
    7 g8 w( W7 P# R6 I' b/ F/ ~
  167. }
    & P3 J7 \9 H! S, i' V, I
复制代码
8 [/ h! f7 I5 t8 ^& d0 }
$ O" X# X1 W9 @' L1 G$ E1 `. f2 y

! O+ ~0 F# L+ G( r2 t3 ~# _- N' E4 r$ D4 m2 P# m6 ~0 f9 J) }$ V
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 很美好很美好1 很差劲很差劲
回复

使用道具 举报

沙发
发表于 2025-4-4 01:06 | 只看该作者
学习学习一下
回复 支持 反对

使用道具 举报

高级模式
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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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