Skip to content

Fix CLI mode not exiting after transcription completes#260

Closed
alex-pradas wants to merge 2 commits intokaixxx:mainfrom
alex-pradas:fix-cli-exit-hang
Closed

Fix CLI mode not exiting after transcription completes#260
alex-pradas wants to merge 2 commits intokaixxx:mainfrom
alex-pradas:fix-cli-exit-hang

Conversation

@alex-pradas
Copy link

@alex-pradas alex-pradas commented Dec 22, 2025

Summary

  • Adds proper headless mode support for CLI operation (--no-gui flag)
  • Fixes process hanging after transcription completes in CLI mode
  • Prevents GUI window from appearing when using CLI

Changes

  • Add headless parameter to App.__init__ to skip GUI widget creation
  • Add _cleanup_app() function for proper process termination (handles mp_proc, ffmpeg, worker threads)
  • Guard GUI-dependent methods against headless mode: set_progress, update_queue_table, update_queue_controls, logr
  • Skip auto-launching noScribeEdit in headless CLI mode

Test plan

  • Run transcription with --no-gui flag
  • Verify process exits cleanly after completion
  • Verify no GUI window appears
  • Verify noScribeEdit doesn't auto-open

🤖 Generated with Claude Code

Add app.quit() and app.destroy() calls before return statements in
run_cli_mode() and show_available_models() to properly shut down the
Tkinter event loop. Without this cleanup, the process would stall
indefinitely after printing success message.

Also add uv script metadata shebang for easier CLI invocation.
- Add headless parameter to App.__init__ to skip GUI widget creation
- Add _cleanup_app() function for proper process termination
- Guard GUI-dependent methods (set_progress, update_queue_table,
  update_queue_controls, logr) against headless mode
- Skip auto-launching noScribeEdit in headless CLI mode
- Prevents GUI window from appearing and process from hanging
  when using --no-gui flag
@kaixxx
Copy link
Owner

kaixxx commented Dec 23, 2025

Thank you. I did not encounter the same issue, maybe because I mainly work on Windows. But I wanted to get rid of Tkinter in headless mode anyway, since this should also allow the script to run on Linux servers without any GUI framework installed, which is not possible atm. I will take a look at your changes after the holidays.

@syssi
Copy link

syssi commented Feb 9, 2026

@alex-pradas It looks like a DISPLAY is still required if I use your fork?

$ /opt/noScribePatched/noScribe --no-gui 84-121123-0000.flac test.txt  --no-gui

noScribe
AI-powered Audio Transcription 

Error: no display name and no $DISPLAY environment variable

@kaixxx
Copy link
Owner

kaixxx commented Feb 9, 2026

@syssi: Interesting, and thank you for testing. I have no truly headless system to test on.

@kaixxx
Copy link
Owner

kaixxx commented Feb 10, 2026

OK, I have taken inspiration from this PR and introduced what should be a true headless mode: https://github.com/kaixxx/noScribe/tree/true_headless_mode

(One could also say that [my] Codex took inspiration from [@alex-pradas] Claude Code.)

@syssi : Could you test this new branch? I hope you can run noScribe from source, haven't compiled this version yet. It should not require any kind of display when used with --no-gui.

@syssi
Copy link

syssi commented Feb 10, 2026

@kaixxx Did you see my headless branch? syssi/noScribe@main...headless

@syssi
Copy link

syssi commented Feb 10, 2026

@syssi : Could you test this new branch? I hope you can run noScribe from source, haven't compiled this version yet. > It should not require any kind of display when used with --no-gui.

I will give it a try!

@kaixxx
Copy link
Owner

kaixxx commented Feb 11, 2026

Did you see my headless branch?

No, I didn't... Anyhow, our approach seems very similar. Looking forward to your results. If my branch is still giving you problems, we can switch to your version instead.

@syssi
Copy link

syssi commented Feb 11, 2026

$ noScribe

noScribe
AI-powered Audio Transcription 

Traceback (most recent call last):
  File "noScribe.py", line 3573, in <module>
  File "noScribe.py", line 1051, in __init__
  File "customtkinter/windows/ctk_tk.py", line 40, in __init__
  File "tkinter/__init__.py", line 2346, in __init__
_tkinter.TclError: no display name and no $DISPLAY environment variable
[PYI-3693682:ERROR] Failed to execute script 'noScribe' due to unhandled exception!
$ noScribe --no-gui

noScribe
AI-powered Audio Transcription 

Error: --no-gui requires both audio_file and output_file.
Usage: python noScribe.py <audio_file> <output_file> [options] --no-gui
$ noScribe 84-121123-0000.wav test.txt  --no-gui

noScribe
AI-powered Audio Transcription 

Starting transcription of '84-121123-0000.wav'...
Output will be saved to 'test.txt'
Language: Auto
Model: precise
Speaker detection: auto


=== Starting queue ===
Processing 1 transcription job(s)

Starting job: 84-121123-0000.wav

Converting audio...
Audio conversion finished

Speaker identification...
Loading pyannote
pyannote/audio/core/io.py:47: UserWarning: 
torchcodec is not installed correctly so built-in audio decoding will fail. Solutions are:
* use audio preloaded in-memory as a {'waveform': (channel, time) torch.Tensor, 'sample_rate': int} dictionary;
* fix torchcodec installation. Error message was:

Could not load libtorchcodec. Likely causes:
          1. FFmpeg is not properly installed in your environment. We support
             versions 4, 5, 6, 7, and 8, and we attempt to load libtorchcodec
             for each of those versions. Errors for versions not installed on
             your system are expected; only the error for your installed FFmpeg
             version is relevant. On Windows, ensure you've installed the
             "full-shared" version which ships DLLs.
          2. The PyTorch version (2.8.0+cpu) is not compatible with
             this version of TorchCodec. Refer to the version compatibility
             table:
             https://github.com/pytorch/torchcodec?tab=readme-ov-file#installing-torchcodec.
          3. Another runtime dependency; see exceptions below.

        The following exceptions were raised as we tried to load libtorchcodec:
        
[start of libtorchcodec loading traceback]
FFmpeg version 8:
Traceback (most recent call last):
  File "torchcodec/_core/ops.py", line 56, in load_torchcodec_shared_libraries
  File "torchcodec/_internally_replaced_utils.py", line 36, in _get_extension_path
ImportError: No spec found for libtorchcodec_core8

FFmpeg version 7:
Traceback (most recent call last):
  File "torchcodec/_core/ops.py", line 56, in load_torchcodec_shared_libraries
  File "torchcodec/_internally_replaced_utils.py", line 36, in _get_extension_path
ImportError: No spec found for libtorchcodec_core7

FFmpeg version 6:
Traceback (most recent call last):
  File "torchcodec/_core/ops.py", line 56, in load_torchcodec_shared_libraries
  File "torchcodec/_internally_replaced_utils.py", line 36, in _get_extension_path
ImportError: No spec found for libtorchcodec_core6

FFmpeg version 5:
Traceback (most recent call last):
  File "torchcodec/_core/ops.py", line 56, in load_torchcodec_shared_libraries
  File "torchcodec/_internally_replaced_utils.py", line 36, in _get_extension_path
ImportError: No spec found for libtorchcodec_core5

FFmpeg version 4:
Traceback (most recent call last):
  File "torchcodec/_core/ops.py", line 56, in load_torchcodec_shared_libraries
  File "torchcodec/_internally_replaced_utils.py", line 36, in _get_extension_path
ImportError: No spec found for libtorchcodec_core4
[end of libtorchcodec loading traceback].
torchaudio/_backend/utils.py:213: UserWarning: In 2.9, this function's implementation will be changed to use torchaudio.load_with_torchcodec` under the hood. Some parameters like ``normalize``, ``format``, ``buffer_size``, and ``backend`` will be ignored. We recommend that you port your code to rely directly on TorchCodec's decoder instead: https://docs.pytorch.org/torchcodec/stable/generated/torchcodec.decoders.AudioDecoder.html#torchcodec.decoders.AudioDecoder.
  warnings.warn(
pyannote/audio/models/blocks/pooling.py:103: UserWarning: std(): degrees of freedom is <= 0. Correction should be strictly less than the reduction factor (input numel divided by output numel). (Triggered internally at /pytorch/aten/src/ATen/native/ReduceOps.cpp:1839.)
numpy/_core/fromnumeric.py:3824: RuntimeWarning: Mean of empty slice
numpy/_core/_methods.py:134: RuntimeWarning: invalid value encountered in divide
segmentation: 0%segmentation: 100%segmentation: 100%speaker_counting: 100%embeddings: 0%embeddings: 100%embeddings: 100%discrete_diarization: 100%

Transcription...
Loading whisper
[2026-02-11 15:38:04.760] [ctranslate2] [thread 3693876] [warning] The compute type inferred from the saved model is float16, but the target device or backend do not support efficient float16 computation. The model weights have been automatically converted to use the float32 compute type instead.
Voice activity detection...
Detected language "en" with probability 1.00
Transcription...

S00: Go, do you hear?

Transcription finished.
Saved to: test.txt
Duration: 0:25 minutes

=== Queue processing complete ===
Total jobs: 1
Completed: 1
Failed: 0
Canceled: 0
Total processing time: 0:25

Transcription completed successfully!
Output saved to: test.txt
multiprocessing/resource_tracker.py:279: UserWarning: resource_tracker: There appear to be 1 leaked semaphore objects to clean up at shutdown
$
$ cat test.txt 


84-121123-0000

Transcribed with noScribe vers. 0.7
Audio file: 84-121123-0000.wav
(Language: Auto (auto) | Speaker detection: auto | Overlapping speech: True | Timestamps: False | Disfluencies: True | Mark pause: 1)



S00: Go, do you hear?

$ cat 84-121123-0000.trans.txt 
GO DO YOU HEAR
$ 

Goods good to me! May be

multiprocessing/resource_tracker.py:279: UserWarning: resource_tracker: There appear to be 1 leaked semaphore objects to clean up at shutdown

should be fixed?

@kaixxx
Copy link
Owner

kaixxx commented Feb 11, 2026

Looks good.

multiprocessing/resource_tracker.py:279: UserWarning: resource_tracker: There appear to be 1 leaked semaphore objects to clean up at shutdown

Good point. Fixed it here I hope: d12a8c3

@syssi
Copy link

syssi commented Feb 11, 2026

The latest commit did not fix the issue.

@kaixxx
Copy link
Owner

kaixxx commented Feb 11, 2026

The latest commit did not fix the issue.

Hmm. My problem is that I don't see the warning. But, it is not a very serious issue, as far as I can tell. So we might as well ignore it for now. What do you think?

@syssi
Copy link

syssi commented Feb 11, 2026

Yes. Let's ignore it.

@kaixxx kaixxx mentioned this pull request Feb 19, 2026
@kaixxx
Copy link
Owner

kaixxx commented Feb 19, 2026

OK, I have now implemented the changes here: #274
Thank you @alex-pradas and @syssi!

@kaixxx kaixxx closed this Feb 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants