Ich habe eine leistungsstarke Anwendung namens „Audio Transcriber“ entwickelt, die Audiodaten aufzeichnet, transkribiert und vieles mehr – alles mit einer benutzerfreundlichen GUI basierend auf PyQt5. Sie nutzt das KI-Modell Whisper von OpenAI für präzise Transkripte und bietet erweiterte Funktionen wie Sprachauswahl, Modellwahl und Export. In diesem Beitrag erkläre ich euch, wie ihr sie installiert, zeige den vollständigen Code und beschreibe mögliche Einsatzgebiete.
Funktionen der Anwendung
- Audioaufnahme: Nimmt Sprache über ein Mikrofon auf (maximal 20 Sekunden).
- Einzeltranskript: Transkribiert eine einzelne Audiodatei (WAV, MP3, M4A).
- Massentranskript: Verarbeitet mehrere Audiodateien aus einem Ordner.
- Sprachauswahl: Wählt die Sprache für die Transkription (z. B. Deutsch, Englisch).
- Modellwahl: Passt die Whisper-Modellgröße an (von tiny bis large).
- Export: Speichert Transkripte als Textdateien.
- Vorlesen: Liest Ergebnisse mit pyttsx3 vor.
- Zwischenablage: Kopiert Text mit pyperclip und fügt ihn ein.
Voraussetzungen und Installation
Um die Anwendung zu nutzen, braucht ihr ein paar Tools:
1. Python installieren
Ladet euch Python 3.8+ herunter und installiert es.
2. Abhängigkeiten installieren
Öffnet ein Terminal und führt diesen Befehl aus:
bash
pip install sounddevice numpy scipy pyttsx3 pyperclip pyautogui PyQt5
- sounddevice: Für die Audioaufnahme.
- numpy und scipy: Für die Audiobearbeitung.
- pyautogui: Für die Zwischenablage-Steuerung.
3. Whisper installieren
Installiert Whisper mit:
bash
pip install -U openai-whisper
Falls ihr eine GPU nutzen wollt (empfohlen für große Modelle), installiert CUDA und die passenden PyTorch-Versionen.
4. Mikrofon prüfen
Stellt sicher, dass ein Mikrofon angeschlossen ist und in den Systemeinstellungen erkannt wird.
Der vollständige Code
Hier ist mein optimierter Code:
python
import sys
import os
import subprocess
import sounddevice as sd
import numpy as np
from scipy.io.wavfile import write
import pyttsx3
import pyperclip
import pyautogui
from PyQt5.QtWidgets import (QApplication, QMainWindow, QPushButton, QTextEdit,
QLabel, QVBoxLayout, QWidget, QFileDialog, QMessageBox,
QComboBox, QCheckBox)
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtGui import QFont
class AudioWorker(QThread):
finished = pyqtSignal(str)
status_update = pyqtSignal(str)
def __init__(self, fs=44100, mode="record", input_file=None, input_dir=None,
language="auto", model="medium", export=False):
super().__init__()
self.fs = fs
self.mode = mode
self.recording = False
self.buffer = []
self.input_file = input_file
self.input_dir = input_dir
self.language = language
self.model = model
self.export = export
def run(self):
if self.mode == "record":
self.record_audio()
elif self.mode == "single":
self.transcribe_single()
elif self.mode == "batch":
self.transcribe_batch()
def record_audio(self):
self.audio_stream = sd.InputStream(samplerate=self.fs, channels=1, dtype='int16')
self.audio_stream.start()
while self.recording:
try:
audiodaten, _ = self.audio_stream.read(self.fs)
self.buffer.extend(audiodaten)
if len(self.buffer) > self.fs * 20:
self.stop_recording()
except Exception as e:
self.status_update.emit(f"Fehler bei der Aufnahme: {str(e)}")
break
self.audio_stream.stop()
self.audio_stream.close()
buffer_array = np.array(self.buffer)
output_file = "aufnahme.wav"
write(output_file, self.fs, buffer_array)
self.status_update.emit("Verarbeite Aufnahme...")
result = self.process_audio(output_file)
self.finished.emit(result)
def transcribe_single(self):
if not self.input_file or not os.path.exists(self.input_file):
self.finished.emit("Fehler: Datei nicht gefunden.")
return
self.status_update.emit(f"Transkribiere {os.path.basename(self.input_file)}...")
result = self.process_audio(self.input_file)
self.finished.emit(result)
def transcribe_batch(self):
if not self.input_dir or not os.path.isdir(self.input_dir):
self.finished.emit("Fehler: Ordner nicht gefunden.")
return
audio_files = [f for f in os.listdir(self.input_dir) if f.endswith(('.wav', '.mp3', '.m4a'))]
if not audio_files:
self.finished.emit("Keine Audiodateien im Ordner gefunden.")
return
results = []
for audio_file in audio_files:
full_path = os.path.join(self.input_dir, audio_file)
self.status_update.emit(f"Transkribiere {audio_file}...")
result = self.process_audio(full_path)
results.append(f"{audio_file}: {result}")
self.finished.emit("\n\n".join(results))
def process_audio(self, audio_file):
try:
lang_param = f"--language {self.language}" if self.language != "auto" else ""
cmd = f"whisper {audio_file} --device cuda --model {self.model} {lang_param} --output_dir transkrip"
subprocess.run(cmd, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
transkrip_file = os.path.join("transkrip", f"{os.path.splitext(os.path.basename(audio_file))[0]}.txt")
if os.path.exists(transkrip_file):
with open(transkrip_file, 'r', encoding='utf-8') as file:
content = file.read()
if self.export:
export_path = os.path.splitext(audio_file)[0] + "_transkript.txt"
with open(export_path, 'w', encoding='utf-8') as export_file:
export_file.write(content)
self.status_update.emit(f"Exportiert nach: {export_path}")
return content
return "Transkription fehlgeschlagen."
except subprocess.CalledProcessError as e:
return f"Fehler bei der Verarbeitung: {e.stderr.decode()}"
except Exception as e:
return f"Fehler: {str(e)}"
def stop_recording(self):
self.recording = False
class AudioTranscriberWindow(QMainWindow):
def __init__(self):
super().__init__()
self.fs = 44100
self.worker = None
self.init_ui()
def init_ui(self):
self.setWindowTitle("Audio Transcriber")
self.setGeometry(100, 100, 600, 600)
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QVBoxLayout(central_widget)
self.setStyleSheet("""
QMainWindow { background-color: #f0f0f0; }
QPushButton {
background-color: #4CAF50;
color: white;
padding: 8px;
border: none;
border-radius: 4px;
}
QPushButton:disabled { background-color: #cccccc; }
QTextEdit { border: 1px solid #ddd; border-radius: 4px; }
QComboBox { padding: 4px; }
""")
title = QLabel("Audio Transcriber")
title.setFont(QFont("Helvetica", 16, QFont.Bold))
title.setAlignment(Qt.AlignCenter)
layout.addWidget(title)
self.status_label = QLabel("Bereit")
self.status_label.setAlignment(Qt.AlignCenter)
layout.addWidget(self.status_label)
self.language_combo = QComboBox()
self.language_combo.addItems(["auto", "de", "en", "fr", "es", "it"])
self.language_combo.setCurrentText("auto")
layout.addWidget(QLabel("Sprache:"))
layout.addWidget(self.language_combo)
self.model_combo = QComboBox()
self.model_combo.addItems(["tiny", "base", "small", "medium", "large"])
self.model_combo.setCurrentText("medium")
layout.addWidget(QLabel("Modell:"))
layout.addWidget(self.model_combo)
self.export_check = QCheckBox("Transkript exportieren")
layout.addWidget(self.export_check)
self.record_btn = QPushButton("Aufnahme starten")
self.record_btn.clicked.connect(self.start_recording)
layout.addWidget(self.record_btn)
self.stop_btn = QPushButton("Aufnahme stoppen")
self.stop_btn.clicked.connect(self.stop_recording)
self.stop_btn.setEnabled(False)
layout.addWidget(self.stop_btn)
self.single_btn = QPushButton("Einzeltranskript")
self.single_btn.clicked.connect(self.transcribe_single_file)
layout.addWidget(self.single_btn)
self.batch_btn = QPushButton("Massentranskript")
self.batch_btn.clicked.connect(self.transcribe_batch_files)
layout.addWidget(self.batch_btn)
self.result_text = QTextEdit()
self.result_text.setReadOnly(True)
layout.addWidget(self.result_text)
self.copy_btn = QPushButton("In Zwischenablage kopieren")
self.copy_btn.clicked.connect(self.copy_to_clipboard)
self.copy_btn.setEnabled(False)
layout.addWidget(self.copy_btn)
def start_recording(self):
self.worker = AudioWorker(
fs=self.fs, mode="record",
language=self.language_combo.currentText(),
model=self.model_combo.currentText(),
export=self.export_check.isChecked()
)
self.worker.recording = True
self.worker.finished.connect(self.on_task_finished)
self.worker.status_update.connect(self.update_status)
self.worker.start()
self.toggle_buttons(recording=True)
self.status_label.setText("Aufnahme läuft...")
def stop_recording(self):
if self.worker and self.worker.mode == "record":
self.worker.stop_recording()
def transcribe_single_file(self):
file_path, _ = QFileDialog.getOpenFileName(self, "Audiodatei auswählen", "", "Audio Files (*.wav *.mp3 *.m4a)")
if file_path:
self.worker = AudioWorker(
mode="single", input_file=file_path,
language=self.language_combo.currentText(),
model=self.model_combo.currentText(),
export=self.export_check.isChecked()
)
self.worker.finished.connect(self.on_task_finished)
self.worker.status_update.connect(self.update_status)
self.worker.start()
self.toggle_buttons(recording=True)
def transcribe_batch_files(self):
dir_path = QFileDialog.getExistingDirectory(self, "Ordner auswählen")
if dir_path:
self.worker = AudioWorker(
mode="batch", input_dir=dir_path,
language=self.language_combo.currentText(),
model=self.model_combo.currentText(),
export=self.export_check.isChecked()
)
self.worker.finished.connect(self.on_task_finished)
self.worker.status_update.connect(self.update_status)
self.worker.start()
self.toggle_buttons(recording=True)
def on_task_finished(self, result):
self.result_text.setText(result)
self.status_label.setText("Abgeschlossen")
self.toggle_buttons(recording=False)
self.copy_btn.setEnabled(True)
try:
tts = pyttsx3.init()
tts.say(result)
tts.runAndWait()
except Exception as e:
QMessageBox.warning(self, "Fehler", f"Text-to-Speech fehlgeschlagen: {str(e)}")
def update_status(self, status):
self.status_label.setText(status)
def copy_to_clipboard(self):
content = self.result_text.toPlainText()
pyperclip.copy(content)
pyautogui.hotkey('ctrl', 'v')
self.status_label.setText("Text kopiert und eingefügt!")
def toggle_buttons(self, recording):
self.record_btn.setEnabled(not recording)
self.stop_btn.setEnabled(recording and self.worker.mode == "record")
self.single_btn.setEnabled(not recording)
self.batch_btn.setEnabled(not recording)
self.language_combo.setEnabled(not recording)
self.model_combo.setEnabled(not recording)
self.export_check.setEnabled(not recording)
def main():
app = QApplication(sys.argv)
window = AudioTranscriberWindow()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Speichert den Code als audio_transcriber.py und startet ihn mit python audio_transcriber.py.
Wie funktioniert die Anwendung?
- GUI: Die Oberfläche basiert auf PyQt5 und bietet Buttons, Dropdowns und eine Checkbox.
- Aufnahme: Mit sounddevice zeichne ich Audio auf und speichere es als WAV-Datei.
- Transkription: Whisper verarbeitet die Audiodaten – live, einzeln oder im Batch.
- Erweiterungen: Sprache und Modell sind wählbar, Ergebnisse können exportiert werden.
Einsatzgebiete
Meine Anwendung ist vielseitig einsetzbar:
- Journalismus: Transkribiert Interviews schnell und präzise – ideal für Artikel oder Podcasts. Tools wie Audacity ergänzen sie perfekt.
- Bildung: Wandelt Vorlesungen oder Seminare in Text um, z. B. für Notizen oder Lernplattformen wie Moodle.
- Content Creation: Erstellt Untertitel für Videos – kombinierbar mit FFmpeg für die Nachbearbeitung.
- Forschung: Analysiert gesprochene Daten, z. B. in der Linguistik oder Soziologie, unterstützt durch Praat.
- Barrierefreiheit: Macht Audioinhalte für Hörgeschädigte zugänglich – ein Thema, das auch die W3C betont.
- Dokumentation: Protokolliert Meetings oder Telefonate, z. B. mit Zoom oder Microsoft Teams.
Nützliche Links
- Whisper Dokumentation: Alles über das KI-Modell.
- PyQt5 Tutorials: GUI-Programmierung lernen.
- sounddevice Beispiele: Audioaufnahmen verstehen.
- CUDA Toolkit: GPU-Beschleunigung einrichten.
- Python Dokumentation: Grundlagen nachschlagen.
- OpenAI Blog: Neuigkeiten zu KI-Entwicklungen.
Schreibe einen Kommentar