# -*- mode: python ; coding: utf-8 -*- """PyInstaller spec file for headless Local Transcription backend (no PySide6/Qt). This builds the Python sidecar for the Tauri frontend. Much simpler than local-transcription.spec since all Qt dependencies are removed. """ import sys import os block_cipher = None is_windows = sys.platform == 'win32' 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') # pvporcupine resources (indirect dependency from RealtimeSTT) 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 = [] # Data files datas = [ ('config/default_config.yaml', 'config'), (vad_assets_path, 'faster_whisper/assets'), ] + pvporcupine_data_files # Hidden imports -- NO PySide6/Qt needed for headless backend hiddenimports = [ # Transcription engine 'faster_whisper', 'faster_whisper.transcribe', 'faster_whisper.vad', 'ctranslate2', 'sounddevice', 'scipy', 'scipy.signal', 'numpy', # RealtimeSTT 'RealtimeSTT', 'RealtimeSTT.audio_recorder', 'webrtcvad', 'webrtcvad_wheels', 'silero_vad', # PyTorch 'torch', 'torch.nn', 'torch.nn.functional', 'torchaudio', 'onnxruntime', 'onnxruntime.capi', 'onnxruntime.capi.onnxruntime_pybind11_state', 'pyaudio', 'halo', 'colorama', # 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 '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', # HTTP client 'requests', 'urllib3', 'certifi', 'charset_normalizer', ] # Collect submodules for key packages print("Collecting submodules for backend 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 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: pass # Pydantic critical deps hiddenimports += [ 'colorsys', 'decimal', 'json', 'ipaddress', 'pathlib', 'uuid', 'email.message', 'typing_extensions', ] a = Analysis( ['backend/main_headless.py'], pathex=[], binaries=[], datas=datas, hiddenimports=hiddenimports, hookspath=['hooks'], hooksconfig={}, runtime_hooks=[], excludes=['enum34', 'PySide6', 'PyQt5', 'PyQt6', 'tkinter'], 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='local-transcription-backend', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=True, # Headless backend needs console for JSON output disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, icon='LocalTranscription.ico' if is_windows else None, ) coll = COLLECT( exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, upx_exclude=[], name='local-transcription-backend', )