Initial commit: Local Transcription App v1.0
Phase 1 Complete - Standalone Desktop Application Features: - Real-time speech-to-text with Whisper (faster-whisper) - PySide6 desktop GUI with settings dialog - Web server for OBS browser source integration - Audio capture with automatic sample rate detection and resampling - Noise suppression with Voice Activity Detection (VAD) - Configurable display settings (font, timestamps, fade duration) - Settings apply without restart (with automatic model reloading) - Auto-fade for web display transcriptions - CPU/GPU support with automatic device detection - Standalone executable builds (PyInstaller) - CUDA build support (works on systems without CUDA hardware) Components: - Audio capture with sounddevice - Noise reduction with noisereduce + webrtcvad - Transcription with faster-whisper - GUI with PySide6 - Web server with FastAPI + WebSocket - Configuration system with YAML Build System: - Standard builds (CPU-only): build.sh / build.bat - CUDA builds (universal): build-cuda.sh / build-cuda.bat - Comprehensive BUILD.md documentation - Cross-platform support (Linux, Windows) Documentation: - README.md with project overview and quick start - BUILD.md with detailed build instructions - NEXT_STEPS.md with future enhancement roadmap - INSTALL.md with setup instructions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
159
gui/transcription_display_qt.py
Normal file
159
gui/transcription_display_qt.py
Normal file
@@ -0,0 +1,159 @@
|
||||
"""PySide6 transcription display widget for showing real-time transcriptions."""
|
||||
|
||||
from PySide6.QtWidgets import QTextEdit
|
||||
from PySide6.QtGui import QFont, QTextCursor
|
||||
from PySide6.QtCore import Qt, Slot
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class TranscriptionDisplay(QTextEdit):
|
||||
"""Custom text widget for displaying transcriptions using PySide6."""
|
||||
|
||||
def __init__(self, parent=None, max_lines=100, show_timestamps=True, font_family="Courier", font_size=12):
|
||||
"""
|
||||
Initialize transcription display.
|
||||
|
||||
Args:
|
||||
parent: Parent widget
|
||||
max_lines: Maximum number of lines to keep in display
|
||||
show_timestamps: Whether to show timestamps
|
||||
font_family: Font family name
|
||||
font_size: Font size in points
|
||||
"""
|
||||
super().__init__(parent)
|
||||
|
||||
self.max_lines = max_lines
|
||||
self.show_timestamps = show_timestamps
|
||||
self.line_count = 0
|
||||
self.font_family = font_family
|
||||
self.font_size = font_size
|
||||
|
||||
# Configure text widget
|
||||
self.setReadOnly(True)
|
||||
self.setFont(QFont(font_family, font_size))
|
||||
|
||||
# Set dark theme styling
|
||||
self.setStyleSheet("""
|
||||
QTextEdit {
|
||||
background-color: #2b2b2b;
|
||||
color: #ffffff;
|
||||
border: 1px solid #3d3d3d;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
}
|
||||
""")
|
||||
|
||||
@Slot(str, str)
|
||||
def add_transcription(self, text: str, user_name: str = "", timestamp: datetime = None):
|
||||
"""
|
||||
Add a new transcription to the display.
|
||||
|
||||
Args:
|
||||
text: Transcription text
|
||||
user_name: User/speaker name
|
||||
timestamp: Timestamp of transcription
|
||||
"""
|
||||
if timestamp is None:
|
||||
timestamp = datetime.now()
|
||||
|
||||
# Build the display line
|
||||
line_parts = []
|
||||
|
||||
if self.show_timestamps:
|
||||
time_str = timestamp.strftime("%H:%M:%S")
|
||||
line_parts.append(f"[{time_str}]")
|
||||
|
||||
if user_name:
|
||||
line_parts.append(f"{user_name}:")
|
||||
|
||||
line_parts.append(text)
|
||||
|
||||
line = " ".join(line_parts)
|
||||
|
||||
# Add to display
|
||||
self.append(line)
|
||||
|
||||
# Auto-scroll to bottom
|
||||
cursor = self.textCursor()
|
||||
cursor.movePosition(QTextCursor.End)
|
||||
self.setTextCursor(cursor)
|
||||
|
||||
# Track line count
|
||||
self.line_count += 1
|
||||
|
||||
# Remove old lines if exceeding max
|
||||
if self.line_count > self.max_lines:
|
||||
self._remove_oldest_lines(self.line_count - self.max_lines)
|
||||
|
||||
def _remove_oldest_lines(self, num_lines: int):
|
||||
"""
|
||||
Remove oldest lines from the display.
|
||||
|
||||
Args:
|
||||
num_lines: Number of lines to remove
|
||||
"""
|
||||
cursor = self.textCursor()
|
||||
cursor.movePosition(QTextCursor.Start)
|
||||
|
||||
for _ in range(num_lines):
|
||||
cursor.select(QTextCursor.BlockUnderCursor)
|
||||
cursor.removeSelectedText()
|
||||
cursor.deleteChar() # Remove the newline
|
||||
|
||||
self.line_count -= num_lines
|
||||
|
||||
def clear_all(self):
|
||||
"""Clear all transcriptions."""
|
||||
self.clear()
|
||||
self.line_count = 0
|
||||
|
||||
def get_all_text(self) -> str:
|
||||
"""
|
||||
Get all transcription text.
|
||||
|
||||
Returns:
|
||||
All text in the display
|
||||
"""
|
||||
return self.toPlainText()
|
||||
|
||||
def set_max_lines(self, max_lines: int):
|
||||
"""Update maximum number of lines to keep."""
|
||||
self.max_lines = max_lines
|
||||
|
||||
# Trim if necessary
|
||||
if self.line_count > self.max_lines:
|
||||
self._remove_oldest_lines(self.line_count - self.max_lines)
|
||||
|
||||
def set_show_timestamps(self, show: bool):
|
||||
"""Update whether to show timestamps."""
|
||||
self.show_timestamps = show
|
||||
|
||||
def set_font(self, font_family: str, font_size: int):
|
||||
"""
|
||||
Update font settings.
|
||||
|
||||
Args:
|
||||
font_family: Font family name
|
||||
font_size: Font size in points
|
||||
"""
|
||||
self.font_family = font_family
|
||||
self.font_size = font_size
|
||||
super().setFont(QFont(font_family, font_size))
|
||||
|
||||
def save_to_file(self, filepath: str) -> bool:
|
||||
"""
|
||||
Save transcriptions to a file.
|
||||
|
||||
Args:
|
||||
filepath: Path to save file
|
||||
|
||||
Returns:
|
||||
True if saved successfully
|
||||
"""
|
||||
try:
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(self.toPlainText())
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error saving transcriptions: {e}")
|
||||
return False
|
||||
Reference in New Issue
Block a user