Add unified per-speaker font support and remote transcription service
Font changes: - Consolidate font settings into single Display Settings section - Support Web-Safe, Google Fonts, and Custom File uploads for both displays - Fix Google Fonts URL encoding (use + instead of %2B for spaces) - Fix per-speaker font inline style quote escaping in Node.js display - Add font debug logging to help diagnose font issues - Update web server to sync all font settings on settings change - Remove deprecated PHP server documentation files New features: - Add remote transcription service for GPU offloading - Add instance lock to prevent multiple app instances - Add version tracking Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
108
main.py
108
main.py
@@ -41,43 +41,68 @@ if getattr(sys, 'frozen', False) and sys.platform == 'win32':
|
||||
sys.stderr = io.StringIO()
|
||||
|
||||
# Add project root to Python path
|
||||
project_root = Path(__file__).parent
|
||||
# Use resolve() to follow symlinks and get the real path
|
||||
project_root = Path(__file__).resolve().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
|
||||
# Change working directory to project root so relative paths work
|
||||
os.chdir(project_root)
|
||||
|
||||
# Import only minimal Qt components needed for splash and dialogs
|
||||
# Heavy imports (MainWindow) are deferred until after splash is shown
|
||||
from PySide6.QtWidgets import QApplication, QSplashScreen, QMessageBox
|
||||
from PySide6.QtGui import QPixmap, QPainter, QColor, QFont, QIcon
|
||||
from PySide6.QtCore import Qt
|
||||
|
||||
# Import single instance lock (lightweight module)
|
||||
from client.instance_lock import InstanceLock
|
||||
|
||||
|
||||
def get_icon_path():
|
||||
"""Get the application icon path."""
|
||||
if getattr(sys, 'frozen', False):
|
||||
# Running in PyInstaller bundle
|
||||
return Path(sys._MEIPASS) / "LocalTranscription.png"
|
||||
else:
|
||||
# Running in normal Python
|
||||
return project_root / "LocalTranscription.png"
|
||||
|
||||
|
||||
def create_splash_pixmap(message="Loading..."):
|
||||
"""Create a pixmap for the splash screen with a custom message."""
|
||||
pixmap = QPixmap(500, 300)
|
||||
"""Create a pixmap for the splash screen with the app icon."""
|
||||
pixmap = QPixmap(400, 320)
|
||||
pixmap.fill(QColor("#2b2b2b"))
|
||||
|
||||
# Draw on the pixmap
|
||||
painter = QPainter(pixmap)
|
||||
painter.setRenderHint(QPainter.Antialiasing)
|
||||
painter.setRenderHint(QPainter.SmoothPixmapTransform)
|
||||
|
||||
# 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")
|
||||
# Load and draw the icon
|
||||
icon_path = get_icon_path()
|
||||
if icon_path.exists():
|
||||
icon_pixmap = QPixmap(str(icon_path))
|
||||
# Scale icon to fit nicely (200x200)
|
||||
scaled_icon = icon_pixmap.scaled(200, 200, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||
# Center the icon horizontally, position it in upper portion
|
||||
icon_x = (pixmap.width() - scaled_icon.width()) // 2
|
||||
icon_y = 30
|
||||
painter.drawPixmap(icon_x, icon_y, scaled_icon)
|
||||
|
||||
# Draw subtitle
|
||||
# Draw loading message below icon
|
||||
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)
|
||||
subtitle_rect = pixmap.rect().adjusted(0, 0, 0, -40)
|
||||
painter.drawText(subtitle_rect, Qt.AlignHCenter | Qt.AlignBottom, message)
|
||||
|
||||
# Draw version/status at bottom
|
||||
from version import __version__
|
||||
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...")
|
||||
status_rect = pixmap.rect().adjusted(0, 0, 0, -15)
|
||||
painter.drawText(status_rect, Qt.AlignHCenter | Qt.AlignBottom, f"v{__version__}")
|
||||
|
||||
painter.end()
|
||||
return pixmap
|
||||
@@ -93,11 +118,14 @@ def create_splash_screen():
|
||||
|
||||
def main():
|
||||
"""Main application entry point."""
|
||||
# Instance lock for cleanup on exit
|
||||
instance_lock = None
|
||||
|
||||
try:
|
||||
print("Starting Local Transcription Application...")
|
||||
print("=" * 50)
|
||||
|
||||
# Create Qt application
|
||||
# Create Qt application first (needed for dialogs)
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
# Set application info
|
||||
@@ -105,19 +133,24 @@ def main():
|
||||
app.setOrganizationName("LocalTranscription")
|
||||
|
||||
# Set application icon
|
||||
# In PyInstaller frozen executables, use _MEIPASS for bundled files
|
||||
if getattr(sys, 'frozen', False):
|
||||
# Running in PyInstaller bundle
|
||||
icon_path = Path(sys._MEIPASS) / "LocalTranscription.png"
|
||||
else:
|
||||
# Running in normal Python
|
||||
icon_path = project_root / "LocalTranscription.png"
|
||||
|
||||
icon_path = get_icon_path()
|
||||
if icon_path.exists():
|
||||
from PySide6.QtGui import QIcon
|
||||
app.setWindowIcon(QIcon(str(icon_path)))
|
||||
|
||||
# Create and show splash screen
|
||||
# Check for single instance BEFORE showing splash
|
||||
instance_lock = InstanceLock()
|
||||
if not instance_lock.acquire():
|
||||
# Another instance is already running
|
||||
QMessageBox.warning(
|
||||
None,
|
||||
"Application Already Running",
|
||||
"Local Transcription is already running.\n\n"
|
||||
"Please check your taskbar or system tray for the existing instance.",
|
||||
QMessageBox.Ok
|
||||
)
|
||||
sys.exit(0)
|
||||
|
||||
# Create and show splash screen IMMEDIATELY
|
||||
splash = create_splash_screen()
|
||||
splash.show()
|
||||
app.processEvents() # Make sure splash is visible
|
||||
@@ -126,6 +159,13 @@ def main():
|
||||
splash.showMessage("Loading configuration...", Qt.AlignBottom | Qt.AlignCenter, QColor("#888888"))
|
||||
app.processEvents()
|
||||
|
||||
# NOW import heavy modules (after splash is visible)
|
||||
# This is the slow part - importing MainWindow loads many dependencies
|
||||
splash.showMessage("Loading application modules...", Qt.AlignBottom | Qt.AlignCenter, QColor("#888888"))
|
||||
app.processEvents()
|
||||
|
||||
from gui.main_window_qt import MainWindow
|
||||
|
||||
# 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)
|
||||
@@ -135,15 +175,25 @@ def main():
|
||||
window.show()
|
||||
|
||||
# Run application
|
||||
sys.exit(app.exec())
|
||||
exit_code = app.exec()
|
||||
|
||||
# Release lock on normal exit
|
||||
if instance_lock:
|
||||
instance_lock.release()
|
||||
|
||||
sys.exit(exit_code)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\nApplication interrupted by user")
|
||||
if instance_lock:
|
||||
instance_lock.release()
|
||||
sys.exit(0)
|
||||
except Exception as e:
|
||||
print(f"Fatal error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
if instance_lock:
|
||||
instance_lock.release()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user