以下の内容はhttps://touch-sp.hatenablog.com/entry/2024/10/21/211514より取得しました。


【拡張】ReazonSpeechをPySide6から使う(Claude 3.5 Sonnetに機能を拡張してもらいました)

はじめに

前回のスクリプトを拡張してもらいました。
touch-sp.hatenablog.com
録音すれば、録音した順にどんどん勝手に文字起こししてくれるようにしました。

Claude 3.5 Sonnetとのやりとり

2回のやり取りで終わりました。
1回目に出力されたスクリプトはうまく動きませんでした。
エラー内容を伝えると2回目できちんと動作するスクリプトを書いてくれました。

以下は音声を録音して文字おこしするプログラムです。録音音声をQueueにいれて、Queueの中身が0になるまで自動的に文字おこしをするように書き換えて下さい。文字おこしは別スレッドで実行したいです。
以下のプログラムで一つ目のファイルはうまく読み込めますが二つ目以降のファイルを読み込めません。

Pythonスクリプト

import sys
import os
from pathlib import Path
from datetime import datetime
from queue import Queue
from threading import Thread
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QTextEdit, QLabel
from PySide6.QtCore import QUrl, Signal, QObject, QTimer
from PySide6.QtMultimedia import QMediaRecorder, QMediaCaptureSession, QAudioInput, QMediaFormat
from reazonspeech.nemo.asr import load_model, transcribe, audio_from_path

model = load_model()

class TranscriptionSignals(QObject):
    transcription_done = Signal(str)
    error_occurred = Signal(str)

class AudioTranscriptionApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("音声録音と自動文字起こし")
        self.setGeometry(100, 100, 400, 300)

        layout = QVBoxLayout()

        self.record_button = QPushButton("録音開始")
        self.record_button.clicked.connect(self.toggle_recording)
        layout.addWidget(self.record_button)

        self.status_label = QLabel("待機中")
        layout.addWidget(self.status_label)

        self.text_edit = QTextEdit()
        layout.addWidget(self.text_edit)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

        # メディアコンポーネントの設定
        self.audio_input = QAudioInput()
        self.media_recorder = QMediaRecorder()
        self.capture_session = QMediaCaptureSession()
        self.capture_session.setAudioInput(self.audio_input)
        self.capture_session.setRecorder(self.media_recorder)

        # 録音フォーマットの設定
        audio_settings = self.media_recorder.mediaFormat()
        audio_settings.setFileFormat(QMediaFormat.FileFormat.Wave)
        audio_settings.setAudioCodec(QMediaFormat.AudioCodec.Wave)
        self.media_recorder.setMediaFormat(audio_settings)

        # 品質設定
        self.media_recorder.setQuality(QMediaRecorder.Quality.HighQuality)

        self.is_recording = False
        self.temp_file = None

        # 録音キューと文字起こしスレッドの設定
        self.audio_queue = Queue()
        self.transcription_thread = Thread(target=self.transcribe_audio_thread, daemon=True)
        self.transcription_thread.start()

        # シグナルの設定
        self.signals = TranscriptionSignals()
        self.signals.transcription_done.connect(self.update_transcription)
        self.signals.error_occurred.connect(self.show_error)

        # メディアレコーダーのシグナル接続
        self.media_recorder.recorderStateChanged.connect(self.on_recorder_state_changed)

    def toggle_recording(self):
        if not self.is_recording:
            self.start_recording()
        else:
            self.stop_recording()

    def start_recording(self):
        now = datetime.now()
        current_time = now.strftime("%Y%m%d_%H%M%S")
        current_directory = Path.cwd()
        self.temp_file = Path(current_directory, f"{current_time}.wav")

        self.media_recorder.setOutputLocation(QUrl.fromLocalFile(str(self.temp_file)))
        self.media_recorder.record()
        self.is_recording = True
        self.record_button.setText("録音停止")
        self.status_label.setText("録音中...")

    def stop_recording(self):
        self.media_recorder.stop()
        self.is_recording = False
        self.record_button.setText("録音開始")
        self.status_label.setText("録音停止中...")

    def on_recorder_state_changed(self, state):
        if state == QMediaRecorder.StoppedState:
            QTimer.singleShot(1000, self.process_recorded_file)

    def process_recorded_file(self):
        if self.temp_file and os.path.exists(self.temp_file):
            self.status_label.setText("文字起こし中...")
            self.audio_queue.put(str(self.temp_file))
            self.temp_file = None
        else:
            self.signals.error_occurred.emit("録音ファイルが見つかりません。")

    def transcribe_audio_thread(self):
        while True:
            audio_file = self.audio_queue.get()
            try:
                audio = audio_from_path(audio_file)
                ret = transcribe(model, audio)
                self.signals.transcription_done.emit(ret.text)
            except Exception as e:
                self.signals.error_occurred.emit(f"文字起こし中にエラーが発生しました: {str(e)}")
            finally:
                self.audio_queue.task_done()

    def update_transcription(self, text):
        self.text_edit.append(text)
        self.status_label.setText("待機中")

    def show_error(self, error_message):
        self.status_label.setText("エラー")
        self.text_edit.append(f"エラー: {error_message}")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = AudioTranscriptionApp()
    window.show()
    sys.exit(app.exec())

実行画面








以上の内容はhttps://touch-sp.hatenablog.com/entry/2024/10/21/211514より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14