mirror of
https://github.com/HiMeditator/auto-caption.git
synced 2026-02-15 20:34:47 +08:00
release v0.2.0
- 更新和增加文档 - 添加新的图片 - 优化文档结构和内容
This commit is contained in:
116
docs/engine-manual/en.md
Normal file
116
docs/engine-manual/en.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# Caption Engine Documentation
|
||||
|
||||

|
||||
|
||||
## Introduction to the Caption Engine
|
||||
|
||||
The so-called caption engine is actually a subprocess that fetches real-time streaming audio data from system audio input (recording) or output (playing sound) and calls an audio-to-text model to generate captions for the corresponding audio. The generated captions are converted into JSON formatted string data and passed to the main program via standard output (it must be ensured that the string read by the main program can be correctly interpreted as a JSON object). The main program reads and interprets the caption data, processes it, and displays it on the window.
|
||||
|
||||
## Features the Caption Engine Needs to Implement
|
||||
|
||||
### Audio Acquisition
|
||||
|
||||
First, your caption engine needs to acquire streaming audio data from system audio input (recording) or output (playing sound). If developing with Python, you can use the PyAudio library to get microphone audio input data (cross-platform). Use the PyAudioWPatch library to get system audio output (only applicable to Windows platform).
|
||||
|
||||
The acquired audio stream data is usually in the form of short audio chunks, and the size of these chunks should be adjusted according to the model. For example, Alibaba Cloud's Gummy model performs better with 0.05-second audio chunks than with 0.2-second audio chunks.
|
||||
|
||||
### Audio Processing
|
||||
|
||||
The acquired audio stream may need preprocessing before being converted to text. For instance, Alibaba Cloud's Gummy model can only recognize single-channel audio streams, while the collected audio streams are generally dual-channel, so you need to convert the dual-channel audio stream to a single channel. The conversion of channels can be achieved using methods from the NumPy library.
|
||||
|
||||
You can directly use the audio acquisition and processing modules I've developed (path: `caption-engine/sysaudio`):
|
||||
|
||||
```python
|
||||
if sys.platform == 'win32':
|
||||
from sysaudio.win import AudioStream, mergeStreamChannels
|
||||
elif sys.platform == 'linux':
|
||||
from sysaudio.linux import AudioStream, mergeStreamChannels
|
||||
else:
|
||||
raise NotImplementedError(f"Unsupported platform: {sys.platform}")
|
||||
|
||||
# Create an instance of the audio stream object
|
||||
stream = AudioStream(audio_type)
|
||||
# Open the audio stream
|
||||
stream.openStream()
|
||||
while True: # Loop to read audio data
|
||||
# Read audio data
|
||||
data = stream.stream.read(stream.CHUNK)
|
||||
# Convert dual-channel audio data to single-channel
|
||||
data = mergeStreamChannels(data, stream.CHANNELS)
|
||||
# Call the audio-to-text model
|
||||
# ... ...
|
||||
```
|
||||
|
||||
### Audio to Text Conversion
|
||||
|
||||
Once you have the appropriate audio stream, you can convert it to text. Various models are typically used to achieve this. You can choose the model based on your requirements.
|
||||
|
||||
### Data Transmission
|
||||
|
||||
After obtaining the text for the current audio stream, you need to pass the text to the main program. The caption engine process passes the caption data to the Electron main process through standard output.
|
||||
|
||||
The content transmitted must be a JSON string, where the JSON object should include the following parameters:
|
||||
|
||||
```typescript
|
||||
export interface CaptionItem {
|
||||
index: number, // Caption sequence number
|
||||
time_s: string, // Start time of the current caption
|
||||
time_t: string, // End time of the current caption
|
||||
text: string, // Caption content
|
||||
translation: string // Caption translation
|
||||
}
|
||||
```
|
||||
|
||||
**It is essential to ensure that every time a caption JSON data is output, the buffer is flushed, ensuring that the string received by the Electron main process each time can be interpreted as a JSON object.**
|
||||
|
||||
If using Python, you can refer to the following method to pass data to the main program:
|
||||
|
||||
```python
|
||||
# caption-engine\main-gummy.py
|
||||
sys.stdout.reconfigure(line_buffering=True)
|
||||
|
||||
# caption-engine\audio2text\gummy.py
|
||||
...
|
||||
def send_to_node(self, data):
|
||||
"""
|
||||
Send data to the Node.js process
|
||||
"""
|
||||
try:
|
||||
json_data = json.dumps(data) + '\n'
|
||||
sys.stdout.write(json_data)
|
||||
sys.stdout.flush()
|
||||
except Exception as e:
|
||||
print(f"Error sending data to Node.js: {e}", file=sys.stderr)
|
||||
...
|
||||
```
|
||||
|
||||
The code for the data receiving end is as follows:
|
||||
|
||||
```typescript
|
||||
// src\main\utils\engine.ts
|
||||
...
|
||||
this.process.stdout.on('data', (data) => {
|
||||
const lines = data.toString().split('\n');
|
||||
lines.forEach((line: string) => {
|
||||
if (line.trim()) {
|
||||
try {
|
||||
const caption = JSON.parse(line);
|
||||
addCaptionLog(caption);
|
||||
} catch (e) {
|
||||
controlWindow.sendErrorMessage('Cannot parse caption engine output as JSON object: ' + e)
|
||||
console.error('[ERROR] Error parsing JSON:', e);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.process.stderr.on('data', (data) => {
|
||||
controlWindow.sendErrorMessage('Caption engine error: ' + data)
|
||||
console.error(`[ERROR] Subprocess Error: ${data}`);
|
||||
});
|
||||
...
|
||||
```
|
||||
|
||||
## Code Reference
|
||||
|
||||
The default caption engine entry point code is located in the `main-gummy.py` file under the `caption-engine` folder of this project. The `src\main\utils\engine.ts` file contains the server-side code for acquiring and processing caption engine data. You can read and understand the implementation details and the complete runtime process of the caption engine as needed.
|
||||
118
docs/engine-manual/ja.md
Normal file
118
docs/engine-manual/ja.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# キャプションエンジンの説明文書
|
||||
|
||||

|
||||
|
||||
この文書は大規模モデルを使用して翻訳されていますので、内容に正確でない部分があるかもしれません。
|
||||
|
||||
## キャプションエンジンの紹介
|
||||
|
||||
キャプションエンジンとは、実際にはサブプログラムであり、システムの音声入力(録音)または出力(音声再生)のストリーミングデータをリアルタイムで取得し、音声をテキストに変換するモデルを呼び出して対応する音声のキャプションを生成します。生成されたキャプションはJSON形式の文字列データに変換され、標準出力を通じてメインプログラムに渡されます(メインプログラムが読み取った文字列がJSONオブジェクトとして正しく解釈できるようにする必要があります)。メインプログラムはキャプションデータを読み取り、解釈し、処理してウィンドウ上に表示します。
|
||||
|
||||
## キャプションエンジンが必要とする機能
|
||||
|
||||
### 音声の取得
|
||||
|
||||
まず、あなたのキャプションエンジンはシステムの音声入力(録音)または出力(音声再生)のストリーミングデータを取得する必要があります。Pythonを使用して開発する場合、PyAudioライブラリを使用してマイクからの音声入力データを取得できます(全プラットフォーム対応)。PyAudioWPatchライブラリを使用してシステムの音声出力を取得することができます(Windowsプラットフォームのみ対応)。
|
||||
|
||||
一般的に取得される音声ストリームデータは、比較的短い時間の音声ブロックで構成されています。モデルに合わせて音声ブロックのサイズを調整する必要があります。例えば、アリババクラウドのGummyモデルでは、0.05秒の音声ブロックを使用した認識精度が0.2秒の音声ブロックよりも優れています。
|
||||
|
||||
### 音声の処理
|
||||
|
||||
取得した音声ストリームは、テキストに変換する前に前処理を行う必要があるかもしれません。例えば、アリババクラウドのGummyモデルは単一チャンネルの音声ストリームしか認識できませんが、収集された音声ストリームは通常二重チャンネルです。そのため、二重チャンネルの音声ストリームを単一チャンネルに変換する必要があります。チャンネル数の変換はNumPyライブラリのメソッドを使用して行うことができます。
|
||||
|
||||
既に開発済みの音声取得と音声処理モジュール(パス:`caption-engine/sysaudio`)を使用することもできます:
|
||||
|
||||
```python
|
||||
if sys.platform == 'win32':
|
||||
from sysaudio.win import AudioStream, mergeStreamChannels
|
||||
elif sys.platform == 'linux':
|
||||
from sysaudio.linux import AudioStream, mergeStreamChannels
|
||||
else:
|
||||
raise NotImplementedError(f"サポートされていないプラットフォーム: {sys.platform}")
|
||||
|
||||
# 音声ストリームオブジェクトのインスタンスを作成
|
||||
stream = AudioStream(audio_type)
|
||||
# 音声ストリームを開く
|
||||
stream.openStream()
|
||||
while True: # 音声データを繰り返し読み込む
|
||||
# 音声データを読み込む
|
||||
data = stream.stream.read(stream.CHUNK)
|
||||
# 二重チャンネルの音声データを単一チャンネルに変換
|
||||
data = mergeStreamChannels(data, stream.CHANNELS)
|
||||
# 音声をテキストに変換するモデルを呼び出す
|
||||
# ... ...
|
||||
```
|
||||
|
||||
### 音声からテキストへの変換
|
||||
|
||||
適切な音声ストリームを得た後、それをテキストに変換することができます。通常、様々なモデルを使用してこの変換を行います。必要に応じてモデルを選択してください。
|
||||
|
||||
### データの伝送
|
||||
|
||||
現在の音声ストリームのテキストを取得したら、それをメインプログラムに伝送する必要があります。キャプションエンジンプロセスは標準出力を通じてキャプションデータをElectronのメインプロセスに伝送します。
|
||||
|
||||
伝送する内容はJSON文字列でなければならず、JSONオブジェクトには以下のパラメータを含める必要があります:
|
||||
|
||||
```typescript
|
||||
export interface CaptionItem {
|
||||
index: number, // キャプション番号
|
||||
time_s: string, // 現在のキャプションの開始時間
|
||||
time_t: string, // 現在のキャプションの終了時間
|
||||
text: string, // キャプションの内容
|
||||
translation: string // キャプションの翻訳
|
||||
}
|
||||
```
|
||||
|
||||
**注意:キャプションJSONデータを出力するたびに必ずバッファをフラッシュし、Electronのメインプロセスが受け取る文字列が常にJSONオブジェクトとして解釈できるようにする必要があります。**
|
||||
|
||||
Pythonを使用する場合、以下のようにデータをメインプログラムに伝送できます:
|
||||
|
||||
```python
|
||||
# caption-engine\main-gummy.py
|
||||
sys.stdout.reconfigure(line_buffering=True)
|
||||
|
||||
# caption-engine\audio2text\gummy.py
|
||||
...
|
||||
def send_to_node(self, data):
|
||||
"""
|
||||
データをNode.jsプロセスに送信
|
||||
"""
|
||||
try:
|
||||
json_data = json.dumps(data) + '\n'
|
||||
sys.stdout.write(json_data)
|
||||
sys.stdout.flush()
|
||||
except Exception as e:
|
||||
print(f"Node.jsへのデータ送信エラー: {e}", file=sys.stderr)
|
||||
...
|
||||
```
|
||||
|
||||
データ受信側のコードは以下の通りです:
|
||||
|
||||
```typescript
|
||||
// src\main\utils\engine.ts
|
||||
...
|
||||
this.process.stdout.on('data', (data) => {
|
||||
const lines = data.toString().split('\n');
|
||||
lines.forEach((line: string) => {
|
||||
if (line.trim()) {
|
||||
try {
|
||||
const caption = JSON.parse(line);
|
||||
addCaptionLog(caption);
|
||||
} catch (e) {
|
||||
controlWindow.sendErrorMessage('キャプションエンジンの出力内容がJSONオブジェクトとして解析できません: ' + e)
|
||||
console.error('[ERROR] JSON解析エラー:', e);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.process.stderr.on('data', (data) => {
|
||||
controlWindow.sendErrorMessage('キャプションエンジンエラー: ' + data)
|
||||
console.error(`[ERROR] サブプロセスエラー: ${data}`);
|
||||
});
|
||||
...
|
||||
```
|
||||
|
||||
## 参考コード
|
||||
|
||||
本プロジェクトの `caption-engine` フォルダにある `main-gummy.py` ファイルは、デフォルトのキャプションエンジンのエントリポイントコードです。`src\main\utils\engine.ts` はサーバーサイドでキャプションエンジンのデータを取得および処理するためのコードです。必要に応じて、キャプションエンジンの実装詳細と完全な実行プロセスを理解するために読み込むことができます。
|
||||
117
docs/engine-manual/zh.md
Normal file
117
docs/engine-manual/zh.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# 字幕引擎说明文档
|
||||
|
||||

|
||||
|
||||
## 字幕引擎介绍
|
||||
|
||||
所谓的字幕引擎实际上是一个子程序,它会实时获取系统音频输入(录音)或输出(播放声音)的流式数据,并调用音频转文字的模型生成对应音频的字幕。生成的字幕转换为 JSON 格式的字符串数据,并通过标准输出传递给主程序(需要保证主程序读取到的字符串可以被正确解释为 JSON 对象)。主程序读取并解释字幕数据,处理后显示在窗口上。
|
||||
|
||||
## 字幕引擎需要实现的功能
|
||||
|
||||
### 音频获取
|
||||
|
||||
首先,你的字幕引擎需要获取系统音频输入(录音)或输出(播放声音)的流式数据。如果使用 Python 开发,可以使用 PyAudio 库获取麦克风音频输入数据(全平台通用)。使用 PyAudioWPatch 库获取系统音频输出(仅适用于 Windows 平台)。
|
||||
|
||||
一般获取的音频流数据实际上是一个一个的时间比较短的音频块,需要根据模型调整音频块的大小。比如阿里云的 Gummy 模型使用 0.05 秒大小的音频块识别效果优于使用 0.2 秒大小的音频块。
|
||||
|
||||
### 音频处理
|
||||
|
||||
获取到的音频流在转文字之前可能需要进行预处理。比如阿里云的 Gummy 模型只能识别单通道的音频流,而收集的音频流一般是双通道的,因此要将双通道音频流转换为单通道。通道数的转换可以使用 NumPy 库中的方法实现。
|
||||
|
||||
你可以直接使用我开发好的音频获取和音频处理模块(路径:`caption-engine/sysaudio`):
|
||||
|
||||
```python
|
||||
if sys.platform == 'win32':
|
||||
from sysaudio.win import AudioStream, mergeStreamChannels
|
||||
elif sys.platform == 'linux':
|
||||
from sysaudio.linux import AudioStream, mergeStreamChannels
|
||||
else:
|
||||
raise NotImplementedError(f"Unsupported platform: {sys.platform}")
|
||||
|
||||
# 创建音频流对象实例
|
||||
stream = AudioStream(audio_type)
|
||||
# 打开音频流
|
||||
stream.openStream()
|
||||
while True: # 循环读取音频数据
|
||||
# 读取音频数据
|
||||
data = stream.stream.read(stream.CHUNK)
|
||||
# 将双通道音频数据转换为单通道
|
||||
data = mergeStreamChannels(data, stream.CHANNELS)
|
||||
# 调用音频转文字模型
|
||||
# ... ...
|
||||
```
|
||||
|
||||
### 音频转文字
|
||||
|
||||
在得到了合适的音频流后,就可以将音频流转换为文字了。一般使用各种模型来实现音频流转文字。可根据需求自行选择模型。
|
||||
|
||||
### 数据传递
|
||||
|
||||
在获取到当前音频流的文字后,需要将文字传递给主程序。字幕引擎进程通过标准输出将字幕数据传递给 electron 主进程。
|
||||
|
||||
传递的内容必须是 JSON 字符串,其中 JSON 对象需要包含的参数如下:
|
||||
|
||||
```typescript
|
||||
export interface CaptionItem {
|
||||
index: number, // 字幕序号
|
||||
time_s: string, // 当前字幕开始时间
|
||||
time_t: string, // 当前字幕结束时间
|
||||
text: string, // 字幕内容
|
||||
translation: string // 字幕翻译
|
||||
}
|
||||
```
|
||||
|
||||
**注意必须确保咱们一起每输出一次字幕 JSON 数据就得刷新缓冲区,确保 electron 主进程每次接收到的字符串都可以被解释为 JSON 对象。**
|
||||
|
||||
如果使用 python 语言,可以参考以下方式将数据传递给主程序:
|
||||
|
||||
```python
|
||||
# caption-engine\main-gummy.py
|
||||
sys.stdout.reconfigure(line_buffering=True)
|
||||
|
||||
# caption-engine\audio2text\gummy.py
|
||||
...
|
||||
def send_to_node(self, data):
|
||||
"""
|
||||
将数据发送到 Node.js 进程
|
||||
"""
|
||||
try:
|
||||
json_data = json.dumps(data) + '\n'
|
||||
sys.stdout.write(json_data)
|
||||
sys.stdout.flush()
|
||||
except Exception as e:
|
||||
print(f"Error sending data to Node.js: {e}", file=sys.stderr)
|
||||
...
|
||||
```
|
||||
|
||||
数据接收端代码如下:
|
||||
|
||||
|
||||
```typescript
|
||||
// src\main\utils\engine.ts
|
||||
...
|
||||
this.process.stdout.on('data', (data) => {
|
||||
const lines = data.toString().split('\n');
|
||||
lines.forEach((line: string) => {
|
||||
if (line.trim()) {
|
||||
try {
|
||||
const caption = JSON.parse(line);
|
||||
addCaptionLog(caption);
|
||||
} catch (e) {
|
||||
controlWindow.sendErrorMessage('字幕引擎输出内容无法解析为 JSON 对象:' + e)
|
||||
console.error('[ERROR] Error parsing JSON:', e);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.process.stderr.on('data', (data) => {
|
||||
controlWindow.sendErrorMessage('字幕引擎错误:' + data)
|
||||
console.error(`[ERROR] Subprocess Error: ${data}`);
|
||||
});
|
||||
...
|
||||
```
|
||||
|
||||
## 参考代码
|
||||
|
||||
本项目 `caption-engine` 文件夹下的 `main-gummy.py` 文件为默认字幕引擎的入口代码。`src\main\utils\engine.ts` 为服务端获取字幕引擎数据和进行处理的代码。可以根据需要阅读了解字幕引擎的实现细节和完整运行过程。
|
||||
Reference in New Issue
Block a user