Files
local-transcription/local-transcription.spec
jknapp 7bf0af953d Set console=False for production builds
The app is working correctly - the device validation retry is normal
RealtimeSTT behavior. Set console back to False to hide the console
window for a cleaner user experience in production builds.

Users confirmed transcription and server sync are working properly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-28 20:46:31 -08:00

188 lines
5.5 KiB
Python

# -*- mode: python ; coding: utf-8 -*-
"""PyInstaller spec file for Local Transcription app."""
import sys
from pathlib import Path
import os
block_cipher = None
# Determine if we're on Windows
is_windows = sys.platform == 'win32'
# Import PyInstaller utilities
from PyInstaller.utils.hooks import collect_submodules, collect_data_files
# Find faster_whisper assets folder
import faster_whisper
faster_whisper_path = os.path.dirname(faster_whisper.__file__)
vad_assets_path = os.path.join(faster_whisper_path, 'assets')
# Find pvporcupine resources folder (needed even though we don't use wake words)
try:
import pvporcupine
pvporcupine_path = os.path.dirname(pvporcupine.__file__)
pvporcupine_resources = os.path.join(pvporcupine_path, 'resources')
pvporcupine_lib = os.path.join(pvporcupine_path, 'lib')
pvporcupine_data_files = []
if os.path.exists(pvporcupine_resources):
pvporcupine_data_files.append((pvporcupine_resources, 'pvporcupine/resources'))
if os.path.exists(pvporcupine_lib):
pvporcupine_data_files.append((pvporcupine_lib, 'pvporcupine/lib'))
except ImportError:
pvporcupine_data_files = []
# Base configuration
binaries = []
datas = [
('config/default_config.yaml', 'config'),
('LocalTranscription.png', '.'), # Include icon for runtime window icon
(vad_assets_path, 'faster_whisper/assets'), # Include VAD model
] + pvporcupine_data_files # Include pvporcupine resources
hiddenimports = [
'PySide6.QtCore',
'PySide6.QtWidgets',
'PySide6.QtGui',
'faster_whisper',
'faster_whisper.transcribe',
'faster_whisper.vad',
'ctranslate2',
'sounddevice',
'scipy',
'scipy.signal',
'numpy',
# RealtimeSTT and its dependencies
'RealtimeSTT',
'RealtimeSTT.audio_recorder',
'webrtcvad',
'webrtcvad_wheels',
'silero_vad',
'torch',
'torch.nn',
'torch.nn.functional',
'torchaudio',
'onnxruntime',
'onnxruntime.capi',
'onnxruntime.capi.onnxruntime_pybind11_state',
'pyaudio',
'halo', # RealtimeSTT progress indicator
'colorama', # Terminal colors (used by halo)
# FastAPI and dependencies
'fastapi',
'fastapi.routing',
'fastapi.responses',
'starlette',
'starlette.applications',
'starlette.routing',
'starlette.responses',
'starlette.websockets',
'starlette.middleware',
'starlette.middleware.cors',
'pydantic',
'pydantic.fields',
'pydantic.main',
'anyio',
'anyio._backends',
'anyio._backends._asyncio',
'sniffio',
# Uvicorn and dependencies
'uvicorn',
'uvicorn.logging',
'uvicorn.loops',
'uvicorn.loops.auto',
'uvicorn.protocols',
'uvicorn.protocols.http',
'uvicorn.protocols.http.auto',
'uvicorn.protocols.http.h11_impl',
'uvicorn.protocols.websockets',
'uvicorn.protocols.websockets.auto',
'uvicorn.protocols.websockets.wsproto_impl',
'uvicorn.lifespan',
'uvicorn.lifespan.on',
'h11',
'websockets',
'websockets.legacy',
'websockets.legacy.server',
# Requests (for server sync)
'requests',
'urllib3',
'certifi',
'charset_normalizer',
]
# Collect all submodules for FastAPI and related packages
# This approach is more reliable than collect_all() which has design flaws
# Particularly important for pydantic which uses compiled cpython extensions
print("Collecting submodules for FastAPI packages...")
for package in ['fastapi', 'starlette', 'pydantic', 'pydantic_core', 'anyio', 'uvicorn', 'websockets', 'h11', 'httptools', 'uvloop']:
try:
submodules = collect_submodules(package)
hiddenimports += submodules
print(f" ✓ Collected {len(submodules)} submodules from {package}")
except Exception as e:
print(f" ⚠ Warning: Could not collect {package}: {e}")
# Collect data files for packages that need them
for package in ['fastapi', 'starlette', 'pydantic', 'uvicorn', 'RealtimeSTT']:
try:
data_files = collect_data_files(package)
if data_files:
datas += data_files
print(f" ✓ Collected {len(data_files)} data files from {package}")
except Exception as e:
pass # Not all packages have data files
# Add critical pydantic dependencies that may be missed
hiddenimports += [
'colorsys', 'decimal', 'json', 'ipaddress', 'pathlib', 'uuid',
'email.message', 'typing_extensions',
]
a = Analysis(
['main.py'],
pathex=[],
binaries=binaries,
datas=datas,
hiddenimports=hiddenimports,
hookspath=['hooks'], # Add hooks directory for custom PyInstaller hooks
hooksconfig={},
runtime_hooks=[],
excludes=['enum34'], # Exclude enum34 - incompatible with PyInstaller and Python 3.4+
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='LocalTranscription',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False, # Hide console window for GUI application
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon='LocalTranscription.ico' if is_windows else 'LocalTranscription.icns', # Platform-specific icon
)
coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='LocalTranscription',
)