ngpt 2.15.2__tar.gz → 2.16.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. {ngpt-2.15.2 → ngpt-2.16.1}/PKG-INFO +34 -2
  2. {ngpt-2.15.2 → ngpt-2.16.1}/README.md +33 -1
  3. {ngpt-2.15.2 → ngpt-2.16.1}/docs/README.md +1 -1
  4. {ngpt-2.15.2 → ngpt-2.16.1}/docs/configuration.md +30 -1
  5. {ngpt-2.15.2 → ngpt-2.16.1}/docs/overview.md +1 -1
  6. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/modes/gitcommsg.py +72 -9
  7. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/ui.py +21 -11
  8. {ngpt-2.15.2 → ngpt-2.16.1}/pyproject.toml +1 -1
  9. {ngpt-2.15.2 → ngpt-2.16.1}/uv.lock +1 -1
  10. {ngpt-2.15.2 → ngpt-2.16.1}/.github/workflows/python-publish.yml +0 -0
  11. {ngpt-2.15.2 → ngpt-2.16.1}/.gitignore +0 -0
  12. {ngpt-2.15.2 → ngpt-2.16.1}/.python-version +0 -0
  13. {ngpt-2.15.2 → ngpt-2.16.1}/COMMIT_GUIDELINES.md +0 -0
  14. {ngpt-2.15.2 → ngpt-2.16.1}/CONTRIBUTING.md +0 -0
  15. {ngpt-2.15.2 → ngpt-2.16.1}/LICENSE +0 -0
  16. {ngpt-2.15.2 → ngpt-2.16.1}/docs/CONTRIBUTING.md +0 -0
  17. {ngpt-2.15.2 → ngpt-2.16.1}/docs/LICENSE.md +0 -0
  18. {ngpt-2.15.2 → ngpt-2.16.1}/docs/_config.yml +0 -0
  19. {ngpt-2.15.2 → ngpt-2.16.1}/docs/api/README.md +0 -0
  20. {ngpt-2.15.2 → ngpt-2.16.1}/docs/api/cli.md +0 -0
  21. {ngpt-2.15.2 → ngpt-2.16.1}/docs/api/cli_config.md +0 -0
  22. {ngpt-2.15.2 → ngpt-2.16.1}/docs/api/client.md +0 -0
  23. {ngpt-2.15.2 → ngpt-2.16.1}/docs/api/config.md +0 -0
  24. {ngpt-2.15.2 → ngpt-2.16.1}/docs/api/logging.md +0 -0
  25. {ngpt-2.15.2 → ngpt-2.16.1}/docs/assets/css/style.scss +0 -0
  26. {ngpt-2.15.2 → ngpt-2.16.1}/docs/examples/README.md +0 -0
  27. {ngpt-2.15.2 → ngpt-2.16.1}/docs/examples/advanced.md +0 -0
  28. {ngpt-2.15.2 → ngpt-2.16.1}/docs/examples/basic.md +0 -0
  29. {ngpt-2.15.2 → ngpt-2.16.1}/docs/examples/cli_components.md +0 -0
  30. {ngpt-2.15.2 → ngpt-2.16.1}/docs/examples/integrations.md +0 -0
  31. {ngpt-2.15.2 → ngpt-2.16.1}/docs/installation.md +0 -0
  32. {ngpt-2.15.2 → ngpt-2.16.1}/docs/usage/README.md +0 -0
  33. {ngpt-2.15.2 → ngpt-2.16.1}/docs/usage/cli_config.md +0 -0
  34. {ngpt-2.15.2 → ngpt-2.16.1}/docs/usage/cli_framework.md +0 -0
  35. {ngpt-2.15.2 → ngpt-2.16.1}/docs/usage/cli_usage.md +0 -0
  36. {ngpt-2.15.2 → ngpt-2.16.1}/docs/usage/gitcommsg.md +0 -0
  37. {ngpt-2.15.2 → ngpt-2.16.1}/docs/usage/library_usage.md +0 -0
  38. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/__init__.py +0 -0
  39. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/__main__.py +0 -0
  40. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/__init__.py +0 -0
  41. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/args.py +0 -0
  42. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/config_manager.py +0 -0
  43. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/formatters.py +0 -0
  44. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/interactive.py +0 -0
  45. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/main.py +0 -0
  46. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/modes/__init__.py +0 -0
  47. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/modes/chat.py +0 -0
  48. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/modes/code.py +0 -0
  49. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/modes/rewrite.py +0 -0
  50. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/modes/shell.py +0 -0
  51. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/modes/text.py +0 -0
  52. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/cli/renderers.py +0 -0
  53. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/client.py +0 -0
  54. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/utils/__init__.py +0 -0
  55. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/utils/cli_config.py +0 -0
  56. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/utils/config.py +0 -0
  57. {ngpt-2.15.2 → ngpt-2.16.1}/ngpt/utils/log.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ngpt
3
- Version: 2.15.2
3
+ Version: 2.16.1
4
4
  Summary: A lightweight Python CLI and library for interacting with OpenAI-compatible APIs, supporting both official and self-hosted LLM endpoints.
5
5
  Project-URL: Homepage, https://github.com/nazdridoy/ngpt
6
6
  Project-URL: Repository, https://github.com/nazdridoy/ngpt
@@ -41,7 +41,7 @@ Description-Content-Type: text/markdown
41
41
  [![Python Versions](https://img.shields.io/pypi/pyversions/ngpt.svg)](https://pypi.org/project/ngpt/)
42
42
  [![Documentation](https://img.shields.io/badge/docs-available-brightgreen.svg)](https://nazdridoy.github.io/ngpt/)
43
43
 
44
- A lightweight Python CLI and library for interacting with OpenAI-compatible APIs, supporting both official and self-hosted LLM endpoints.
44
+ A versatile Python LLM client that functions as a CLI utility, library, and development framework. Supports multiple providers (OpenAI, Ollama, Groq, Claude) with features including interactive chat, code generation, shell command execution, git commit messages generation, and markdown rendering.
45
45
 
46
46
  ![2025-04-23_16-18-01](https://github.com/user-attachments/assets/b8e58926-5165-4352-b48b-9f4a982da86e)
47
47
 
@@ -62,6 +62,9 @@ A lightweight Python CLI and library for interacting with OpenAI-compatible APIs
62
62
  - [Interactive Configuration](#interactive-configuration)
63
63
  - [Configuration File](#configuration-file)
64
64
  - [Configuration Priority](#configuration-priority)
65
+ - [API Key Setup](#api-key-setup)
66
+ - [OpenAI API Key](#openai-api-key)
67
+ - [Google Gemini API Key](#google-gemini-api-key)
65
68
  - [Contributing](#contributing)
66
69
  - [License](#license)
67
70
 
@@ -397,6 +400,35 @@ For detailed information about building CLI tools with nGPT, see the [CLI Framew
397
400
 
398
401
  ## Configuration
399
402
 
403
+ ### API Key Setup
404
+
405
+ #### OpenAI API Key
406
+ 1. Create an account at [OpenAI](https://platform.openai.com/)
407
+ 2. Navigate to API keys: https://platform.openai.com/api-keys
408
+ 3. Click "Create new secret key" and copy your API key
409
+ 4. Configure nGPT with your key:
410
+ ```bash
411
+ ngpt --config
412
+ # Enter provider: OpenAI
413
+ # Enter API key: your-openai-api-key
414
+ # Enter base URL: https://api.openai.com/v1/
415
+ # Enter model: gpt-3.5-turbo (or other model)
416
+ ```
417
+
418
+ #### Google Gemini API Key
419
+ 1. Create or use an existing Google account
420
+ 2. Go to [Google AI Studio](https://aistudio.google.com/)
421
+ 3. Navigate to API keys in the left sidebar (or visit https://aistudio.google.com/app/apikeys)
422
+ 4. Create an API key and copy it
423
+ 5. Configure nGPT with your key:
424
+ ```bash
425
+ ngpt --config
426
+ # Enter provider: Gemini
427
+ # Enter API key: your-gemini-api-key
428
+ # Enter base URL: https://generativelanguage.googleapis.com/v1beta/openai
429
+ # Enter model: gemini-2.0-flash
430
+ ```
431
+
400
432
  ### Command Line Options
401
433
 
402
434
  You can configure nGPT using the following options:
@@ -5,7 +5,7 @@
5
5
  [![Python Versions](https://img.shields.io/pypi/pyversions/ngpt.svg)](https://pypi.org/project/ngpt/)
6
6
  [![Documentation](https://img.shields.io/badge/docs-available-brightgreen.svg)](https://nazdridoy.github.io/ngpt/)
7
7
 
8
- A lightweight Python CLI and library for interacting with OpenAI-compatible APIs, supporting both official and self-hosted LLM endpoints.
8
+ A versatile Python LLM client that functions as a CLI utility, library, and development framework. Supports multiple providers (OpenAI, Ollama, Groq, Claude) with features including interactive chat, code generation, shell command execution, git commit messages generation, and markdown rendering.
9
9
 
10
10
  ![2025-04-23_16-18-01](https://github.com/user-attachments/assets/b8e58926-5165-4352-b48b-9f4a982da86e)
11
11
 
@@ -26,6 +26,9 @@ A lightweight Python CLI and library for interacting with OpenAI-compatible APIs
26
26
  - [Interactive Configuration](#interactive-configuration)
27
27
  - [Configuration File](#configuration-file)
28
28
  - [Configuration Priority](#configuration-priority)
29
+ - [API Key Setup](#api-key-setup)
30
+ - [OpenAI API Key](#openai-api-key)
31
+ - [Google Gemini API Key](#google-gemini-api-key)
29
32
  - [Contributing](#contributing)
30
33
  - [License](#license)
31
34
 
@@ -361,6 +364,35 @@ For detailed information about building CLI tools with nGPT, see the [CLI Framew
361
364
 
362
365
  ## Configuration
363
366
 
367
+ ### API Key Setup
368
+
369
+ #### OpenAI API Key
370
+ 1. Create an account at [OpenAI](https://platform.openai.com/)
371
+ 2. Navigate to API keys: https://platform.openai.com/api-keys
372
+ 3. Click "Create new secret key" and copy your API key
373
+ 4. Configure nGPT with your key:
374
+ ```bash
375
+ ngpt --config
376
+ # Enter provider: OpenAI
377
+ # Enter API key: your-openai-api-key
378
+ # Enter base URL: https://api.openai.com/v1/
379
+ # Enter model: gpt-3.5-turbo (or other model)
380
+ ```
381
+
382
+ #### Google Gemini API Key
383
+ 1. Create or use an existing Google account
384
+ 2. Go to [Google AI Studio](https://aistudio.google.com/)
385
+ 3. Navigate to API keys in the left sidebar (or visit https://aistudio.google.com/app/apikeys)
386
+ 4. Create an API key and copy it
387
+ 5. Configure nGPT with your key:
388
+ ```bash
389
+ ngpt --config
390
+ # Enter provider: Gemini
391
+ # Enter API key: your-gemini-api-key
392
+ # Enter base URL: https://generativelanguage.googleapis.com/v1beta/openai
393
+ # Enter model: gemini-2.0-flash
394
+ ```
395
+
364
396
  ### Command Line Options
365
397
 
366
398
  You can configure nGPT using the following options:
@@ -1,6 +1,6 @@
1
1
  # nGPT Documentation
2
2
 
3
- Welcome to the documentation for nGPT, a lightweight Python CLI and library for interacting with OpenAI-compatible APIs, supporting both official and self-hosted LLM endpoints. nGPT offers three main modes of use:
3
+ Welcome to the documentation for nGPT, a versatile Python LLM client that functions as a CLI utility, library, and development framework. It supports multiple providers (OpenAI, Ollama, Groq, Claude) with features including interactive chat, code generation, shell command execution, git commit messages generation, and markdown rendering. nGPT offers three main modes of use:
4
4
 
5
5
  - A command-line interface (CLI) tool for quick AI interactions
6
6
  - A Python library for integration into your applications
@@ -2,6 +2,35 @@
2
2
 
3
3
  nGPT uses a flexible configuration system that supports multiple profiles for different API providers and models. This guide explains how to configure and manage your nGPT settings.
4
4
 
5
+ ## API Key Setup
6
+
7
+ ### OpenAI API Key
8
+ 1. Create an account at [OpenAI](https://platform.openai.com/)
9
+ 2. Navigate to API keys: https://platform.openai.com/api-keys
10
+ 3. Click "Create new secret key" and copy your API key
11
+ 4. Configure nGPT with your key:
12
+ ```bash
13
+ ngpt --config
14
+ # Enter provider: OpenAI
15
+ # Enter API key: your-openai-api-key
16
+ # Enter base URL: https://api.openai.com/v1/
17
+ # Enter model: gpt-3.5-turbo (or other model)
18
+ ```
19
+
20
+ ### Google Gemini API Key
21
+ 1. Create or use an existing Google account
22
+ 2. Go to [Google AI Studio](https://aistudio.google.com/)
23
+ 3. Navigate to API keys in the left sidebar (or visit https://aistudio.google.com/app/apikeys)
24
+ 4. Create an API key and copy it
25
+ 5. Configure nGPT with your key:
26
+ ```bash
27
+ ngpt --config
28
+ # Enter provider: Gemini
29
+ # Enter API key: your-gemini-api-key
30
+ # Enter base URL: https://generativelanguage.googleapis.com/v1beta/openai
31
+ # Enter model: gemini-2.0-flash
32
+ ```
33
+
5
34
  ## Configuration File Location
6
35
 
7
36
  nGPT stores its configuration in a JSON file located at:
@@ -17,7 +46,7 @@ The configuration file uses a JSON list format that allows you to store multiple
17
46
  ```json
18
47
  [
19
48
  {
20
- "api_key": "your-openai-api-key-here",
49
+ "api_key": "your-openai-api-key",
21
50
  "base_url": "https://api.openai.com/v1/",
22
51
  "provider": "OpenAI",
23
52
  "model": "gpt-4o"
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## What is nGPT?
4
4
 
5
- nGPT is a lightweight Python library and command-line interface (CLI) tool designed for interacting with OpenAI-compatible APIs. It provides a simple, flexible way to communicate with various large language model (LLM) endpoints, including official OpenAI services and self-hosted alternatives.
5
+ nGPT is a versatile Python LLM client that functions as a CLI utility, library, and development framework. It supports multiple providers (OpenAI, Ollama, Groq, Claude) with features including interactive chat, code generation, shell command execution, git commit messages generation, and markdown rendering.
6
6
 
7
7
  ## Key Features
8
8
 
@@ -4,6 +4,7 @@ import sys
4
4
  import tempfile
5
5
  import time
6
6
  import subprocess
7
+ import threading
7
8
  from datetime import datetime
8
9
  import logging
9
10
  from ..formatters import COLORS
@@ -498,12 +499,27 @@ def process_with_chunking(client, diff_content, context, chunk_size=200, recursi
498
499
  logger.log_template("DEBUG", "CHUNK", chunk_prompt)
499
500
 
500
501
  # Process chunk - use technical system prompt for analysis
501
- print(f"{COLORS['yellow']}Analyzing changes...{COLORS['reset']}")
502
+ stop_spinner = threading.Event()
503
+ spinner_thread = threading.Thread(
504
+ target=spinner,
505
+ args=("Analyzing changes...",),
506
+ kwargs={"stop_event": stop_spinner, "color": COLORS['yellow']}
507
+ )
508
+ spinner_thread.daemon = True
509
+ spinner_thread.start()
510
+
502
511
  try:
503
512
  result = handle_api_call(client, chunk_prompt, technical_system_prompt, logger)
504
- partial_analyses.append(result)
513
+ # Stop the spinner
514
+ stop_spinner.set()
515
+ spinner_thread.join()
516
+ # Show success message
505
517
  print(f"{COLORS['green']}✓ Chunk {i+1} processed{COLORS['reset']}")
518
+ partial_analyses.append(result)
506
519
  except Exception as e:
520
+ # Stop the spinner
521
+ stop_spinner.set()
522
+ spinner_thread.join()
507
523
  print(f"{COLORS['red']}Error processing chunk {i+1}: {str(e)}{COLORS['reset']}")
508
524
  if logger:
509
525
  logger.error(f"Error processing chunk {i+1}: {str(e)}")
@@ -511,7 +527,7 @@ def process_with_chunking(client, diff_content, context, chunk_size=200, recursi
511
527
 
512
528
  # Rate limit protection between chunks
513
529
  if i < chunk_count - 1:
514
- # Use the spinner function
530
+ # Use the spinner function with fixed duration
515
531
  spinner("Waiting to avoid rate limits...", 5, color=COLORS['yellow'])
516
532
 
517
533
  # Combine partial analyses
@@ -539,7 +555,16 @@ def process_with_chunking(client, diff_content, context, chunk_size=200, recursi
539
555
  )
540
556
  else:
541
557
  # Combined analysis is under the chunk size limit, generate the commit message
542
- print(f"{COLORS['green']}Generating commit message from combined analysis...{COLORS['reset']}")
558
+ # Start spinner for generating commit message
559
+ stop_spinner = threading.Event()
560
+ spinner_thread = threading.Thread(
561
+ target=spinner,
562
+ args=("Generating commit message from combined analysis...",),
563
+ kwargs={"stop_event": stop_spinner, "color": COLORS['green']}
564
+ )
565
+ spinner_thread.daemon = True
566
+ spinner_thread.start()
567
+
543
568
  combine_prompt = create_combine_prompt(partial_analyses)
544
569
 
545
570
  # Log combine template
@@ -550,6 +575,10 @@ def process_with_chunking(client, diff_content, context, chunk_size=200, recursi
550
575
  # Use commit message system prompt for final generation
551
576
  commit_message = handle_api_call(client, combine_prompt, commit_system_prompt, logger)
552
577
 
578
+ # Stop the spinner
579
+ stop_spinner.set()
580
+ spinner_thread.join()
581
+
553
582
  # If the commit message is too long, we need to condense it
554
583
  if len(commit_message.splitlines()) > max_msg_lines:
555
584
  return condense_commit_message(
@@ -563,6 +592,10 @@ def process_with_chunking(client, diff_content, context, chunk_size=200, recursi
563
592
  )
564
593
  return commit_message
565
594
  except Exception as e:
595
+ # Stop the spinner
596
+ stop_spinner.set()
597
+ spinner_thread.join()
598
+
566
599
  print(f"{COLORS['red']}Error combining analyses: {str(e)}{COLORS['reset']}")
567
600
  if logger:
568
601
  logger.error(f"Error combining analyses: {str(e)}")
@@ -683,18 +716,33 @@ SECTION OF ANALYSIS TO CONDENSE:
683
716
  if logger:
684
717
  logger.log_template("DEBUG", f"CONDENSE_ANALYSIS_DEPTH_{current_depth}_CHUNK_{i+1}", condense_prompt)
685
718
 
686
- print(f"{COLORS['yellow']}Condensing analysis chunk {i+1}/{analysis_chunk_count}...{COLORS['reset']}")
719
+ # Start spinner for analysis
720
+ stop_spinner = threading.Event()
721
+ spinner_thread = threading.Thread(
722
+ target=spinner,
723
+ args=(f"Condensing analysis chunk {i+1}/{analysis_chunk_count}...",),
724
+ kwargs={"stop_event": stop_spinner, "color": COLORS['yellow']}
725
+ )
726
+ spinner_thread.daemon = True
727
+ spinner_thread.start()
687
728
 
688
729
  # Condense this analysis chunk - use technical system prompt for condensing analysis
689
730
  try:
690
731
  condensed_chunk = handle_api_call(client, condense_prompt, technical_system_prompt, logger)
732
+ # Stop the spinner
733
+ stop_spinner.set()
734
+ spinner_thread.join()
735
+
736
+ print(f"{COLORS['green']}✓ Analysis chunk {i+1}/{analysis_chunk_count} condensed{COLORS['reset']}")
691
737
  condensed_chunks.append(condensed_chunk)
692
738
 
693
739
  if logger:
694
740
  logger.log_content("DEBUG", f"CONDENSED_ANALYSIS_DEPTH_{current_depth}_CHUNK_{i+1}", condensed_chunk)
695
-
696
- print(f"{COLORS['green']}✓ Analysis chunk {i+1}/{analysis_chunk_count} condensed{COLORS['reset']}")
697
741
  except Exception as e:
742
+ # Stop the spinner
743
+ stop_spinner.set()
744
+ spinner_thread.join()
745
+
698
746
  print(f"{COLORS['red']}Error condensing analysis chunk {i+1}: {str(e)}{COLORS['reset']}")
699
747
  if logger:
700
748
  logger.error(f"Error condensing analysis chunk {i+1} at depth {current_depth}: {str(e)}")
@@ -702,7 +750,7 @@ SECTION OF ANALYSIS TO CONDENSE:
702
750
 
703
751
  # Rate limit protection between chunks
704
752
  if i < analysis_chunk_count - 1:
705
- # Use the spinner function
753
+ # Use the spinner function with fixed duration
706
754
  spinner("Waiting to avoid rate limits...", 5, color=COLORS['yellow'])
707
755
 
708
756
  # Combine condensed chunks
@@ -812,10 +860,21 @@ REQUIREMENTS:
812
860
  if logger:
813
861
  logger.log_template("DEBUG", f"CONDENSE_PROMPT_DEPTH_{current_depth}", condense_prompt)
814
862
 
815
- print(f"{COLORS['yellow']}Condensing commit message (depth {current_depth}/{max_recursion_depth})...{COLORS['reset']}")
863
+ # Start spinner for condensing
864
+ stop_spinner = threading.Event()
865
+ spinner_thread = threading.Thread(
866
+ target=spinner,
867
+ args=(f"Condensing commit message (depth {current_depth}/{max_recursion_depth})...",),
868
+ kwargs={"stop_event": stop_spinner, "color": COLORS['yellow']}
869
+ )
870
+ spinner_thread.daemon = True
871
+ spinner_thread.start()
816
872
 
817
873
  try:
818
874
  condensed_result = handle_api_call(client, condense_prompt, system_prompt, logger)
875
+ # Stop the spinner
876
+ stop_spinner.set()
877
+ spinner_thread.join()
819
878
 
820
879
  if logger:
821
880
  logger.log_content("DEBUG", f"CONDENSED_RESULT_DEPTH_{current_depth}", condensed_result)
@@ -842,6 +901,10 @@ REQUIREMENTS:
842
901
  else:
843
902
  return condensed_result
844
903
  except Exception as e:
904
+ # Stop the spinner
905
+ stop_spinner.set()
906
+ spinner_thread.join()
907
+
845
908
  print(f"{COLORS['red']}Error condensing commit message: {str(e)}{COLORS['reset']}")
846
909
  if logger:
847
910
  logger.error(f"Error condensing commit message at depth {current_depth}: {str(e)}")
@@ -154,14 +154,16 @@ def get_multiline_input():
154
154
  print("\nInput cancelled by user. Exiting gracefully.")
155
155
  return None
156
156
 
157
- def spinner(message, duration=5, spinner_chars="⣾⣽⣻⢿⡿⣟⣯⣷", color=None):
157
+ def spinner(message, duration=5, spinner_chars="⣾⣽⣻⢿⡿⣟⣯⣷", color=None, stop_event=None):
158
158
  """Display a spinner animation with a message.
159
159
 
160
160
  Args:
161
161
  message: The message to display alongside the spinner
162
- duration: Duration in seconds to show the spinner
162
+ duration: Duration in seconds to show the spinner (used if stop_event is None)
163
163
  spinner_chars: Characters to use for the spinner animation
164
164
  color: Optional color from COLORS dict to use for the message
165
+ stop_event: Optional threading.Event to signal when to stop the spinner
166
+ If provided, duration is ignored and spinner runs until event is set
165
167
  """
166
168
  # Default color handling
167
169
  color_start = ""
@@ -172,16 +174,24 @@ def spinner(message, duration=5, spinner_chars="⣾⣽⣻⢿⡿⣟⣯⣷", color
172
174
 
173
175
  # Each character shows for 0.2 seconds
174
176
  char_duration = 0.2
175
- # Total number of characters to show (not iterations through the entire spinner sequence)
176
- total_chars = int(duration / char_duration)
177
177
 
178
- # Run the spinner
179
- for i in range(total_chars):
180
- # Get the appropriate character by cycling through the spinner characters
181
- char = spinner_chars[i % len(spinner_chars)]
182
- sys.stdout.write(f"\r{color_start}{message} {char}{color_end}")
183
- sys.stdout.flush()
184
- time.sleep(char_duration)
178
+ if stop_event:
179
+ # Run until stop_event is set
180
+ i = 0
181
+ while not stop_event.is_set():
182
+ char = spinner_chars[i % len(spinner_chars)]
183
+ sys.stdout.write(f"\r{color_start}{message} {char}{color_end}")
184
+ sys.stdout.flush()
185
+ i += 1
186
+ time.sleep(char_duration)
187
+ else:
188
+ # Run for fixed duration
189
+ total_chars = int(duration / char_duration)
190
+ for i in range(total_chars):
191
+ char = spinner_chars[i % len(spinner_chars)]
192
+ sys.stdout.write(f"\r{color_start}{message} {char}{color_end}")
193
+ sys.stdout.flush()
194
+ time.sleep(char_duration)
185
195
 
186
196
  # Clear the line when done
187
197
  sys.stdout.write("\r" + " " * (len(message) + 10) + "\r")
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ngpt"
3
- version = "2.15.2"
3
+ version = "2.16.1"
4
4
  description = "A lightweight Python CLI and library for interacting with OpenAI-compatible APIs, supporting both official and self-hosted LLM endpoints."
5
5
  authors = [
6
6
  {name = "nazDridoy", email = "nazdridoy399@gmail.com"},
@@ -134,7 +134,7 @@ wheels = [
134
134
 
135
135
  [[package]]
136
136
  name = "ngpt"
137
- version = "2.15.2"
137
+ version = "2.16.1"
138
138
  source = { editable = "." }
139
139
  dependencies = [
140
140
  { name = "prompt-toolkit" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes