diff --git a/python/voice_to_notes.spec b/python/voice_to_notes.spec index 0687bb1..17d3c3f 100644 --- a/python/voice_to_notes.spec +++ b/python/voice_to_notes.spec @@ -33,7 +33,13 @@ a = Analysis( hookspath=[], hooksconfig={}, runtime_hooks=[], - excludes=["tkinter", "test", "unittest", "pip", "setuptools"], + excludes=[ + "tkinter", "test", "unittest", "pip", "setuptools", + # ctranslate2.converters imports torch at module level and causes + # circular import crashes under PyInstaller. These modules are only + # needed for model format conversion, never for inference. + "ctranslate2.converters", + ], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, diff --git a/python/voice_to_notes/ipc/handlers.py b/python/voice_to_notes/ipc/handlers.py index dcc20ef..2e64f85 100644 --- a/python/voice_to_notes/ipc/handlers.py +++ b/python/voice_to_notes/ipc/handlers.py @@ -41,11 +41,15 @@ def ping_handler(msg: IPCMessage) -> IPCMessage: def make_transcribe_handler() -> HandlerFunc: """Create a transcription handler with a persistent TranscribeService.""" - from voice_to_notes.services.transcribe import TranscribeService, result_to_payload - - service = TranscribeService() + service = None def handler(msg: IPCMessage) -> IPCMessage: + nonlocal service + if service is None: + from voice_to_notes.services.transcribe import TranscribeService + service = TranscribeService() + from voice_to_notes.services.transcribe import result_to_payload + payload = msg.payload result = service.transcribe( request_id=msg.id, @@ -66,11 +70,15 @@ def make_transcribe_handler() -> HandlerFunc: def make_diarize_handler() -> HandlerFunc: """Create a diarization handler with a persistent DiarizeService.""" - from voice_to_notes.services.diarize import DiarizeService, diarization_to_payload - - service = DiarizeService() + service = None def handler(msg: IPCMessage) -> IPCMessage: + nonlocal service + if service is None: + from voice_to_notes.services.diarize import DiarizeService + service = DiarizeService() + from voice_to_notes.services.diarize import diarization_to_payload + payload = msg.payload result = service.diarize( request_id=msg.id, @@ -163,11 +171,15 @@ def make_diarize_download_handler() -> HandlerFunc: def make_pipeline_handler() -> HandlerFunc: """Create a full pipeline handler (transcribe + diarize + merge).""" - from voice_to_notes.services.pipeline import PipelineService, pipeline_result_to_payload - - service = PipelineService() + service = None def handler(msg: IPCMessage) -> IPCMessage: + nonlocal service + if service is None: + from voice_to_notes.services.pipeline import PipelineService + service = PipelineService() + from voice_to_notes.services.pipeline import pipeline_result_to_payload + payload = msg.payload result = service.run( request_id=msg.id, @@ -193,11 +205,15 @@ def make_pipeline_handler() -> HandlerFunc: def make_export_handler() -> HandlerFunc: """Create an export handler.""" - from voice_to_notes.services.export import ExportService, make_export_request - - service = ExportService() + service = None def handler(msg: IPCMessage) -> IPCMessage: + nonlocal service + if service is None: + from voice_to_notes.services.export import ExportService + service = ExportService() + from voice_to_notes.services.export import make_export_request + request = make_export_request(msg.payload) output_path = service.export(request) return IPCMessage( @@ -211,11 +227,14 @@ def make_export_handler() -> HandlerFunc: def make_ai_chat_handler() -> HandlerFunc: """Create an AI chat handler with persistent AIProviderService.""" - from voice_to_notes.services.ai_provider import create_default_service - - service = create_default_service() + service = None def handler(msg: IPCMessage) -> IPCMessage: + nonlocal service + if service is None: + from voice_to_notes.services.ai_provider import create_default_service + service = create_default_service() + payload = msg.payload action = payload.get("action", "chat")