Whisperでのリアルタイム文字起こしの手法は「Whisperを使ったリアルタイム音声認識と字幕描画方法の紹介」を参考にした。
mlxのwhisperセットアップは前回の記事を参考ください。
本題
ストリーミング処理を行うには音声の無音検知が必要となるので調べたところ、faster-whisperでもVAD(Voice Activity Detector)にSilero VADを使っている。
それのJS版であるricky0123/vadで書かれているコードがあったのでmlx用に一部書き直して試してみた。
ファイル構成
├── server.py
├── static
│ └── jimaku.css
├── templates
│ └── index.html
コード
import os
import time
from flask import Flask, request, render_template
import whisper
import threading
UPLOAD_FOLDER = 'uploads'
ALLOWED_EXTENSIONS = {'m4a','mp3','wav'}
CSS_TEMPLATE_PATH = 'static/jimaku.css'
WHISPER_MODEL_NAME = "mlx-community/whisper-large-v3-mlx"
with open(CSS_TEMPLATE_PATH) as f:
CSS_TEMPLATE = f.read()
print('loading whisper model', WHISPER_MODEL_NAME)
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
app = Flask(__name__, static_url_path='/')
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
lock = threading.Lock()
@app.route('/')
def index():
return render_template('index.html')
@app.route('/api/transcribe', methods=['POST'])
def transcribe():
time_sta = time.perf_counter()
print('start transcribe ' + str(time_sta))
file = request.files['file']
ext = file.filename.rsplit('.', 1)[1].lower()
if ext and ext in ALLOWED_EXTENSIONS:
filename = str(int(time.time())) + '.' + ext
saved_filename = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(saved_filename)
lock.acquire()
result = whisper.transcribe(saved_filename, path_or_hf_repo=WHISPER_MODEL_NAME,
language='ja', fp16=True, verbose=True)
lock.release()
return result, 200
result={'error':'something wrong'}
print(result)
return result, 400
app.run(host='localhost', port=9000)
元のコードから大きな変更はない。
mlxのwhisper.transcribe
は最初の一回目だけモデルの初期化を行うので、都度呼び出しても問題ないようだ。
positiveSpeechThreshold: 0.5,
negativeSpeechThreshold: 0.5 - 0.15,
preSpeechPadFrames: 2,
redemptionFrames: 8,
frameSamples: 1536,
minSpeechFrames: 3,
元のコードのindex.htmlのパラメータ部分だけricky0123/vadのデフォルト値にした方が私の環境ではいい感じに動いた。
あとは、preSpeechPadFrames=2
にした方が喋り出しの取りこぼしが少ないように感じた。
感想など
mlxもv0.10.0で少し速くなったようだが、手元のM1 Macはメモリ8GBなのでlarge-v3を読み込むとスワップしまくりもあってとても遅い。
今回、ストリーミングの方法を調べて、音声検知を組み込むと結構いい感じにかつシンプルなコードで作れることがわかったので興味のある方は試してみると良い。