CRITICAL FIX: Added multiprocessing.freeze_support() to prevent the frozen executable from spawning infinite copies of itself on Windows. The issue: When PyInstaller bundles Python apps that use multiprocessing (which PyTorch, faster-whisper, and RealtimeSTT all use), Windows treats each spawn as a new process that re-executes the script. Without freeze_support(), this creates an infinite loop of processes spawning until the system crashes. The fix: - Added multiprocessing.freeze_support() at the very top of main.py - Called before any imports that might use multiprocessing - Windows-only (wrapped in sys.platform check) - Must be before QApplication or any Qt imports This is a standard requirement for all PyInstaller apps that use multiprocessing on Windows. Resolves: App spawns infinite copies when running from PyInstaller build 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
121 lines
3.6 KiB
Python
121 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Local Transcription Application
|
|
|
|
A standalone desktop application for real-time speech-to-text transcription
|
|
using Whisper models. Supports CPU/GPU processing, noise suppression, and
|
|
optional multi-user server synchronization.
|
|
"""
|
|
|
|
import sys
|
|
import multiprocessing
|
|
from pathlib import Path
|
|
|
|
# CRITICAL: Must be called before anything else on Windows with PyInstaller
|
|
# This prevents the infinite spawning loop when the frozen executable runs
|
|
if sys.platform == 'win32':
|
|
multiprocessing.freeze_support()
|
|
|
|
# Add project root to Python path
|
|
project_root = Path(__file__).parent
|
|
sys.path.insert(0, str(project_root))
|
|
|
|
from PySide6.QtWidgets import QApplication, QSplashScreen
|
|
from PySide6.QtGui import QPixmap, QPainter, QColor, QFont
|
|
from PySide6.QtCore import Qt, QTimer
|
|
from gui.main_window_qt import MainWindow
|
|
|
|
|
|
def create_splash_pixmap(message="Loading..."):
|
|
"""Create a pixmap for the splash screen with a custom message."""
|
|
pixmap = QPixmap(500, 300)
|
|
pixmap.fill(QColor("#2b2b2b"))
|
|
|
|
# Draw on the pixmap
|
|
painter = QPainter(pixmap)
|
|
painter.setRenderHint(QPainter.Antialiasing)
|
|
|
|
# Draw title
|
|
title_font = QFont("Arial", 28, QFont.Bold)
|
|
painter.setFont(title_font)
|
|
painter.setPen(QColor("#ffffff"))
|
|
painter.drawText(pixmap.rect(), Qt.AlignCenter, "Local Transcription")
|
|
|
|
# Draw subtitle
|
|
subtitle_font = QFont("Arial", 12)
|
|
painter.setFont(subtitle_font)
|
|
painter.setPen(QColor("#888888"))
|
|
subtitle_rect = pixmap.rect().adjusted(0, 60, 0, 0)
|
|
painter.drawText(subtitle_rect, Qt.AlignCenter, message)
|
|
|
|
# Draw version/status at bottom
|
|
status_font = QFont("Arial", 10)
|
|
painter.setFont(status_font)
|
|
painter.setPen(QColor("#666666"))
|
|
status_rect = pixmap.rect().adjusted(0, 0, 0, -20)
|
|
painter.drawText(status_rect, Qt.AlignHCenter | Qt.AlignBottom, "Please wait...")
|
|
|
|
painter.end()
|
|
return pixmap
|
|
|
|
|
|
def create_splash_screen():
|
|
"""Create a splash screen for startup."""
|
|
pixmap = create_splash_pixmap("Initializing...")
|
|
splash = QSplashScreen(pixmap)
|
|
splash.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.SplashScreen)
|
|
return splash
|
|
|
|
|
|
def main():
|
|
"""Main application entry point."""
|
|
try:
|
|
print("Starting Local Transcription Application...")
|
|
print("=" * 50)
|
|
|
|
# Create Qt application
|
|
app = QApplication(sys.argv)
|
|
|
|
# Set application info
|
|
app.setApplicationName("Local Transcription")
|
|
app.setOrganizationName("LocalTranscription")
|
|
|
|
# Set application icon
|
|
icon_path = project_root / "LocalTranscription.png"
|
|
if icon_path.exists():
|
|
from PySide6.QtGui import QIcon
|
|
app.setWindowIcon(QIcon(str(icon_path)))
|
|
|
|
# Create and show splash screen
|
|
splash = create_splash_screen()
|
|
splash.show()
|
|
app.processEvents() # Make sure splash is visible
|
|
|
|
# Update splash with progress
|
|
splash.showMessage("Loading configuration...", Qt.AlignBottom | Qt.AlignCenter, QColor("#888888"))
|
|
app.processEvents()
|
|
|
|
# Create main window (this takes time due to model loading)
|
|
# Pass splash to window so it can update the message
|
|
window = MainWindow(splash_screen=splash)
|
|
|
|
# Close splash and show main window
|
|
splash.finish(window)
|
|
window.show()
|
|
|
|
# Run application
|
|
sys.exit(app.exec())
|
|
|
|
except KeyboardInterrupt:
|
|
print("\nApplication interrupted by user")
|
|
sys.exit(0)
|
|
except Exception as e:
|
|
print(f"Fatal error: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|