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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-4 12:57 编辑
- e) {9 l8 |- Q0 C& a$ G
, Y8 R+ r- U" I5 {2 h2 Z% _5 ] 本程序是在Whisper.net.Demo基础上修改的,可以批量识别wav文件,6 P: @' M0 C5 }6 Q% C. Y' z
使用时需要輸入语言,源文件路径和目标文件路径
' @' D% W' F0 |6 ?2 k  |最后是输出srt文件
0 y! d! s& E- l! Z( ?% j
# |& O1 F( a) o+ i+ F. j代码如下
6 z) J# v7 Y3 w2 \2 z/ B% ~以下这句用多线程可以增速,否则很慢
4 D& m' n8 L; R- T以下这份代码,还只能使用到CPU,速度依旧比较慢,使用CPU的方法另行研究。) o) m* H: }7 L1 x1 E

) l& n( y0 q5 r& C
. u$ z. }8 x  T% o6 m% Y8 ]" o
  1. var builder = factory.CreateBuilder()
    / k" S6 v3 P" X; Y: u! @5 o
  2. .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);
复制代码

6 J) x5 f- M, I6 ?+ b
" @2 s9 \7 K, ~4 J$ E% g
  1. // Licensed under the MIT license: https://opensource.org/licenses/MIT
    ) r* X$ g/ M5 x/ V

  2. 3 ^# s0 S8 b: w. G* C
  3. using System;
    ! G3 L% U4 ?+ w: T# J' U& @; }2 L
  4. using System.Diagnostics;
    / Z+ M- _: [2 E' H* x4 w% g
  5. using System.IO;
    - U& k* e+ n# h* Q" X! [
  6. using System.Threading;( u  J! l! [3 A* P
  7. using System.Threading.Tasks;
    0 \+ y$ }" k3 x; `% g- u
  8. using CommandLine;
    ; m7 ^9 D* U6 ~* |9 L
  9. using Whisper.net;5 `1 Q; e7 z, O! z
  10. using Whisper.net.Ggml;' e( h' S, M( k5 o
  11. using Whisper.net.Wave;
    7 q5 i! S3 o* f- ?7 p# a' t

  12. ) e3 {$ a6 ]: Z- b; `; [4 m
  13. await Parser.Default.ParseArguments<Options>(args)
    & w2 O- d6 @, y. X5 t
  14.     .WithParsedAsync(Demo);
    " n$ [- B/ {7 X3 U1 R/ Y9 p
  15. . }) }- \% U) e) ]
  16. async Task Demo(Options opt)! D8 @+ @& u% a( U8 y

  17. 6 ?1 }4 Y4 w2 \7 p
  18. {
      E" e& L! N9 }  p/ C
  19.     if (!File.Exists(opt.ModelName))
    2 U% Z; ^  z/ k# I+ I% D: x
  20.     {' v( Q% X; g. h: O4 l- @
  21.         Console.WriteLine([        DISCUZ_CODE_1        ]quot;Downloading Model {opt.ModelName}");$ J  [( o2 M# Q) ]- p- W
  22.         using var modelStream = await WhisperGgmlDownloader.GetGgmlModelAsync(opt.ModelType);1 y# f# a  g, D: O' e* Z
  23.         using var fileWriter = File.OpenWrite(opt.ModelName);
    $ i' p7 q% b( y4 u+ Q
  24.         await modelStream.CopyToAsync(fileWriter);
    " F2 C/ w( I1 }! \1 o: D7 E
  25.     }' R5 y  V# g* s. n. @+ b

  26. 1 `7 v* c9 N. E0 |8 D
  27.     switch (opt.Command)
    : _8 X% U7 h5 Z. J9 _& k
  28.     {, L: s( W! |2 `  U4 U
  29.         case "lang-detect":
    ! Z6 R' k. _9 T" i7 ^$ y- D
  30.             LanguageIdentification(opt);
    / I+ d  \) K5 y
  31.             break;
    ( Q! Z* n# u8 V0 ~2 ~! ~
  32.         case "transcribe":
    ; j  Q! X+ O" F7 N9 |/ ^% f- R
  33.         case "translate":9 N0 V8 a4 `- J$ r
  34.             await FullDetection(opt);$ f0 e7 ], m, h
  35.             break;) d- `5 D' \% [
  36.         default:
    . U2 O6 o/ k8 G% H* h
  37.             Console.WriteLine("Unknown command");
    2 O+ u6 J  K# R. M
  38.             break;
    + n# F1 e6 Q- R% v# r, W4 l! n2 K* z
  39.     }
    " _/ r) m* d8 c% N+ o' k
  40. }
    ( T* d0 o( g/ o. v' O

  41. 3 E# y4 Z  t& }% b9 n* I. P' C
  42. void LanguageIdentification(Options opt)
    , K3 d; \6 C$ P2 D
  43. {7 S9 ]" O. D/ b( B
  44.     var bufferedModel = File.ReadAllBytes(opt.ModelName);
    * G7 {4 }, g" e
  45. 4 `# A2 w: i  v# Y
  46.     // Same factory can be used by multiple task to create processors.$ G0 a6 Q/ c) z
  47.     using var factory = WhisperFactory.FromBuffer(bufferedModel);/ E! E3 ]: l/ A+ e" w
  48. ; I7 ]" v1 |, I( B7 W: a
  49. /*    var builder = factory.CreateBuilder()
    ) Q; m. w9 I" s/ o6 R1 L
  50.        .WithLanguage(opt.Language);*/8 ~' e( M& n7 q4 f3 Z6 n, i4 J9 z
  51.     var builder = factory.CreateBuilder()" i, N0 G- C% B3 @+ y! j
  52.    .WithLanguage("english");! x  P0 K0 A/ S, I+ g
  53.     using var processor = builder.Build();; s, T! n6 m5 X/ x
  54. # y/ p  Q4 y. p% V7 Q. L1 a
  55.     using var fileStream = File.OpenRead(opt.FileName);
    , J, O! L2 ?# |6 R0 H( V3 {0 [

  56. $ r% p/ d. q; `/ Q
  57.     var wave = new WaveParser(fileStream);3 H5 L9 j4 t* O1 Y. A' x
  58. ( u6 [' W0 [: U) q  b5 b
  59.     var samples = wave.GetAvgSamples();
    7 q5 M4 E1 M' }5 K

  60. $ V* G; f# k- f+ h/ m# o: L. K
  61.     var language = processor.DetectLanguage(samples, speedUp: true);
    $ V4 `9 k1 V/ W
  62.     Console.WriteLine("Language is " + language);" \, D: d0 n" J) a) H+ m+ n8 s  _- w
  63. }
    % L$ ?$ p: d+ s7 D0 }5 S
  64. 1 k; ]6 X" s* q0 M
  65. async Task FullDetection(Options opt)
    ' ?8 d7 a3 G+ a  K9 u9 }- j
  66. {$ \/ \4 i" G4 H2 b- I/ w+ N
  67.     // Same factory can be used by multiple task to create processors.
    % H% C$ K/ H4 t" J% f1 [# @
  68.     using var factory = WhisperFactory.FromPath(opt.ModelName);% P2 H$ W4 D! t/ n. m- E9 K* g

  69. 7 r9 u7 r& e2 F0 e' g! F
  70.     //   var builder = factory.CreateBuilder().WithLanguage(opt.Language);
    3 P" v6 b) V; r! T- F$ a8 E' N
  71.     Console.WriteLine("请输入语言选项(例如:english,chinese, japanese等):");
    - X- o5 @6 u) `- S% M5 x/ Y7 v
  72.     string languageOption = Console.ReadLine();, q% y* O  Y! l- @: o
  73.     var builder = factory.CreateBuilder()0 R% t, I3 B; v3 k
  74.     .WithLanguage(languageOption).WithSpeedUp2x().WithThreads(16);$ o1 T; b3 T+ D6 i3 q! X4 V8 V
  75. # H* |* T% }0 ^, ^
  76.     if (opt.Command == "translate")
    3 V+ \# B# }- K5 M+ X
  77.     {6 W+ |: Y8 O* `
  78.         builder.WithTranslate();, m6 U+ H* }6 Y0 ~
  79.     }+ o5 s' s2 H+ z0 i7 f
  80. 9 M/ P+ I7 G/ Z+ k5 p9 K
  81.     WhisperProcessor processor = builder.Build();
    ! [' U) v) ]* N5 _% y
  82.     3 d3 u  Y- l" i4 ]
  83.     Console.WriteLine("请输入wave源文件目录:");
    & o" l0 N6 S) f/ U
  84.     string sourceDirectory = Console.ReadLine();1 J$ v# b. u; f; i/ e
  85. . w  S+ q& S* W$ A1 ]: Z' ~6 J! R
  86.     Console.WriteLine("请输入目标文件目录:");
    * S8 b9 l$ T' f
  87.     string targetDirectory = Console.ReadLine();  M% Z8 V5 G, s

  88. - d4 _3 y6 \& y6 ^7 ~% Z8 h# D* l
  89.     if (!Directory.Exists(sourceDirectory) || !Directory.Exists(targetDirectory))" o6 N$ G! @4 o/ A' x& @
  90.     {' n4 ^2 h8 k' N1 p/ [
  91.         Console.WriteLine("目录不存在,请检查输入的目录路径。");/ w) E$ }! ?# ]  u
  92.         return;2 f. H- Z7 T6 v1 Q2 [' z3 }: C
  93.     }
    # D& S! h% V3 V9 O' V7 l

  94. 3 }' v5 }+ p& N4 L. d
  95.     await ProcessFilesAsync(processor ,sourceDirectory, targetDirectory);
    7 h; J% B# H7 H' ?
  96. 2 ]1 T, y" R! V9 {0 E' r
  97.     Console.WriteLine("处理完成!");6 V) J4 _/ y3 q
  98. 2 U: e" u9 {: n1 @  e. N7 ]5 F
  99. }
    : l& V& x$ W# M( w; S6 X* z
  100. static async Task ProcessFilesAsync(WhisperProcessor processor,
    3 D4 ~  m$ {1 c# Q* V; V
  101.     string sourceDirectory, string targetDirectory)
    * o/ j. D: G3 |& P+ o3 r
  102. {
    & m+ T& ]0 b  L# I
  103.     var files = Directory.GetFiles(sourceDirectory, "*.wav", SearchOption.AllDirectories);
    0 y1 `( J- ?2 H4 E+ _) [
  104. 8 H4 I( p' \( f0 I+ ^$ E% E" Y
  105.     foreach (var sourceFilePath in files)$ j4 Z4 F% Q/ e* w! O+ u% S8 j$ G
  106.     {
    - E8 R7 d9 q& \' D
  107.         string relativePath = Path.GetRelativePath(sourceDirectory, sourceFilePath);9 c3 C% A3 B1 F% [/ f
  108.         string destinationFilePath = Path.Combine(targetDirectory, relativePath);
    - ], o. R" a: W5 Z3 I' U* }
  109.         destinationFilePath = Path.ChangeExtension(destinationFilePath, ".srt");
    : }6 s# j$ ]4 Q' F/ I

  110. $ `! d# a8 @; i
  111.         Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath));
    + d; f7 Y, `7 Q0 ?4 _/ [

  112. 9 ]9 ?' E% ^/ f
  113.   m4 Y- I) N4 r, }
  114.         if (!File.Exists(destinationFilePath))' m1 v2 }3 R8 I' {
  115.         {
    + w- f# H- ^" r, M: F. p3 F1 U, g; z! }
  116.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;正在处理文件:{sourceFilePath}");
    ' E: D+ I$ r# M& w9 \. i
  117. 3 w2 V2 i% U6 {, b, w" d
  118.             using var fileStream = File.OpenRead(sourceFilePath);
    / V  ^$ p" g5 |! s1 l# `
  119.             var segmentIndex = 1;
    , i9 [5 [& R3 [0 D  s
  120.             using var writer = new StreamWriter(destinationFilePath); // 创建用于写入srt文件的StreamWriter3 j& ~+ p8 h: d+ p# H
  121.             var startTime = DateTime.Now; // 记录开始时间
    & b& j) l% Y2 Q  ], S4 c! p

  122. - F! ?) K- F9 k, |& q1 T
  123.             await foreach (var segment in processor.ProcessAsync(fileStream, CancellationToken.None))5 Q+ o) c5 ?" l# w3 N
  124.             {4 z1 p) q% \4 ?! _. P" X
  125.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segmentIndex}");- a# O7 l: C; w( E0 |
  126.                 Console.WriteLine([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");$ \7 {  C5 g5 C6 N
  127.                 Console.WriteLine(segment.Text);
    6 P1 O/ ~/ o7 d% c
  128.                 Console.WriteLine();0 p4 x8 Q0 }/ i4 X" q2 K8 N
  129. 4 U+ ~" c# O- @
  130.                 // 将srt内容写入文件! K- K4 V2 ~6 _" P6 _. y1 c% d
  131.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segmentIndex}");# T6 D7 m8 {9 R8 R% r& d% J
  132.                 await writer.WriteLineAsync([        DISCUZ_CODE_1        ]quot;{segment.Start:hh\\:mm\\:ss\\,fff} --> {segment.End:hh\\:mm\\:ss\\,fff}");, J. s/ G9 x0 A  A
  133.                 await writer.WriteLineAsync(segment.Text);
    $ x5 l0 F; w# q0 V& R' r( i
  134.                 await writer.WriteLineAsync();; M1 W! O3 ~( P' c+ B% I9 n

  135. 9 m3 P9 F# t$ f; e, z
  136.                 writer.Flush(); // 立即保存srt文件
    2 s( p" P* H  L- D2 q2 I; Y: ?

  137. . S6 X. z4 |* ?# T7 \. m( W
  138.                 segmentIndex++;
    $ q" x- x( e  ?. `
  139.             }! [" J) v# y, f; f6 E; x0 p* D
  140. 0 W  t+ M9 {( J: R$ k
  141.             var endTime = DateTime.Now; // 记录结束时间
      I8 u9 ?6 F. b& o! c" @$ \
  142.             var elapsedMinutes = (endTime - startTime).TotalMinutes;
    * E8 P! R3 s# W/ q
  143.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;已生成srt文件:{destinationFilePath}");# x' C) z2 z0 z4 Q, k
  144.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;生成耗费时间:{elapsedMinutes} 分钟");& z; A. ^+ T1 G
  145.         }
    " I# _! ~6 L/ g5 _: p- @: c) e3 k$ t
  146.         else {
    ( o' g2 R0 v" @6 j
  147.             Console.WriteLine([        DISCUZ_CODE_1        ]quot;srt文件已经存在:{destinationFilePath}");
      S9 c- k4 I  k8 Q
  148.         }
    4 F7 x+ \# R# h! @; _7 }" w" [
  149.     }
    2 t6 n4 q+ [1 A) ~7 }) g* c3 w' ~1 T
  150. }
    & I; ?" W$ J: s! k# t+ h% i
  151. public class Options) i' i% a$ n7 M; ?3 _& I9 y$ Q
  152. {+ e3 I) x4 f6 M  D1 x, |$ A( _
  153.     [Option('t', "command", Required = false, HelpText = "Command to run (lang-detect, transcribe or translate)", Default = "transcribe")]: I9 h6 }" x7 W- `
  154.     public string Command { get; set; }* v( n+ c8 ^& }) J
  155. ( k- Q' X3 F# [8 J. d8 Z, ^% k
  156.     [Option('f', "file", Required = false, HelpText = "File to process", Default = "test.mp3")]
      W9 S8 t/ n5 L1 l0 |) U: l; K
  157.     public string FileName { get; set; }
    + e, q8 A8 d/ A  x9 r/ r# }
  158. 1 g# F, L: o: }- m$ H
  159.     [Option('l', "lang", Required = false, HelpText = "Language", Default = "auto")]  J. h( O' e6 }# {* E* `0 x
  160.     public string Language { get; set; }
    $ }5 g# {  l5 R
  161. 9 c/ p; Q7 B/ S( K9 h
  162.     [Option('m', "modelFile", Required = false, HelpText = "Model to use (filename", Default = "ggml-large.bin")]0 \: j; X* \) ^6 q' U- ~
  163.     public string ModelName { get; set; }3 ^( U& f' j# `: N: l2 J
  164. 0 u% l" A1 E4 W- W) S$ F. x
  165.     [Option('g', "ggml", Required = false, HelpText = "Ggml Model type to download (if not exists)", Default = GgmlType.Base)]4 }1 v% Y0 ]: l( a. Q4 c) O
  166.     public GgmlType ModelType { get; set; }. O, b5 ^: G" D8 h
  167. }
    ! B  ~) Z0 V- B0 `* P
复制代码

. W" i$ }5 O4 r; e9 y& G7 D" M0 b* e) Y; u; E4 a

( \: c2 [: b" G0 ]/ w" a8 V2 C3 N4 r' e6 M5 f
分享到:  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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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