ngpt 2.15.1__py3-none-any.whl → 2.16.0__py3-none-any.whl

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.
@@ -4,9 +4,11 @@ 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
11
+ from ..ui import spinner
10
12
  from ...utils.log import create_gitcommsg_logger
11
13
  from ...utils.cli_config import get_cli_config_option
12
14
 
@@ -436,15 +438,8 @@ def handle_api_call(client, prompt, system_prompt=None, logger=None, max_retries
436
438
  print(f"{COLORS['yellow']}{error_msg}{COLORS['reset']}")
437
439
  print(f"{COLORS['yellow']}Retrying in {wait_seconds} seconds...{COLORS['reset']}")
438
440
 
439
- # Create a spinner effect for waiting
440
- spinner = "⣾⣽⣻⢿⡿⣟⣯⣷"
441
- for _ in range(wait_seconds * 5):
442
- for char in spinner:
443
- sys.stdout.write(f"\r{COLORS['yellow']}Waiting... {char}{COLORS['reset']}")
444
- sys.stdout.flush()
445
- time.sleep(0.2)
446
-
447
- print("\r" + " " * 20 + "\r", end="")
441
+ # Use the spinner function
442
+ spinner(f"Retrying in {wait_seconds} seconds...", wait_seconds, color=COLORS['yellow'])
448
443
 
449
444
  # Exponential backoff
450
445
  wait_seconds *= 2
@@ -504,12 +499,27 @@ def process_with_chunking(client, diff_content, context, chunk_size=200, recursi
504
499
  logger.log_template("DEBUG", "CHUNK", chunk_prompt)
505
500
 
506
501
  # Process chunk - use technical system prompt for analysis
507
- 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
+
508
511
  try:
509
512
  result = handle_api_call(client, chunk_prompt, technical_system_prompt, logger)
510
- partial_analyses.append(result)
513
+ # Stop the spinner
514
+ stop_spinner.set()
515
+ spinner_thread.join()
516
+ # Show success message
511
517
  print(f"{COLORS['green']}✓ Chunk {i+1} processed{COLORS['reset']}")
518
+ partial_analyses.append(result)
512
519
  except Exception as e:
520
+ # Stop the spinner
521
+ stop_spinner.set()
522
+ spinner_thread.join()
513
523
  print(f"{COLORS['red']}Error processing chunk {i+1}: {str(e)}{COLORS['reset']}")
514
524
  if logger:
515
525
  logger.error(f"Error processing chunk {i+1}: {str(e)}")
@@ -517,8 +527,8 @@ def process_with_chunking(client, diff_content, context, chunk_size=200, recursi
517
527
 
518
528
  # Rate limit protection between chunks
519
529
  if i < chunk_count - 1:
520
- print(f"{COLORS['yellow']}Waiting to avoid rate limits...{COLORS['reset']}")
521
- time.sleep(5)
530
+ # Use the spinner function with fixed duration
531
+ spinner("Waiting to avoid rate limits...", 5, color=COLORS['yellow'])
522
532
 
523
533
  # Combine partial analyses
524
534
  print(f"\n{COLORS['cyan']}Combining analyses from {len(partial_analyses)} chunks...{COLORS['reset']}")
@@ -545,7 +555,16 @@ def process_with_chunking(client, diff_content, context, chunk_size=200, recursi
545
555
  )
546
556
  else:
547
557
  # Combined analysis is under the chunk size limit, generate the commit message
548
- 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
+
549
568
  combine_prompt = create_combine_prompt(partial_analyses)
550
569
 
551
570
  # Log combine template
@@ -556,6 +575,10 @@ def process_with_chunking(client, diff_content, context, chunk_size=200, recursi
556
575
  # Use commit message system prompt for final generation
557
576
  commit_message = handle_api_call(client, combine_prompt, commit_system_prompt, logger)
558
577
 
578
+ # Stop the spinner
579
+ stop_spinner.set()
580
+ spinner_thread.join()
581
+
559
582
  # If the commit message is too long, we need to condense it
560
583
  if len(commit_message.splitlines()) > max_msg_lines:
561
584
  return condense_commit_message(
@@ -569,6 +592,10 @@ def process_with_chunking(client, diff_content, context, chunk_size=200, recursi
569
592
  )
570
593
  return commit_message
571
594
  except Exception as e:
595
+ # Stop the spinner
596
+ stop_spinner.set()
597
+ spinner_thread.join()
598
+
572
599
  print(f"{COLORS['red']}Error combining analyses: {str(e)}{COLORS['reset']}")
573
600
  if logger:
574
601
  logger.error(f"Error combining analyses: {str(e)}")
@@ -689,18 +716,33 @@ SECTION OF ANALYSIS TO CONDENSE:
689
716
  if logger:
690
717
  logger.log_template("DEBUG", f"CONDENSE_ANALYSIS_DEPTH_{current_depth}_CHUNK_{i+1}", condense_prompt)
691
718
 
692
- 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()
693
728
 
694
729
  # Condense this analysis chunk - use technical system prompt for condensing analysis
695
730
  try:
696
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']}")
697
737
  condensed_chunks.append(condensed_chunk)
698
738
 
699
739
  if logger:
700
740
  logger.log_content("DEBUG", f"CONDENSED_ANALYSIS_DEPTH_{current_depth}_CHUNK_{i+1}", condensed_chunk)
701
-
702
- print(f"{COLORS['green']}✓ Analysis chunk {i+1}/{analysis_chunk_count} condensed{COLORS['reset']}")
703
741
  except Exception as e:
742
+ # Stop the spinner
743
+ stop_spinner.set()
744
+ spinner_thread.join()
745
+
704
746
  print(f"{COLORS['red']}Error condensing analysis chunk {i+1}: {str(e)}{COLORS['reset']}")
705
747
  if logger:
706
748
  logger.error(f"Error condensing analysis chunk {i+1} at depth {current_depth}: {str(e)}")
@@ -708,8 +750,8 @@ SECTION OF ANALYSIS TO CONDENSE:
708
750
 
709
751
  # Rate limit protection between chunks
710
752
  if i < analysis_chunk_count - 1:
711
- print(f"{COLORS['yellow']}Waiting to avoid rate limits...{COLORS['reset']}")
712
- time.sleep(5)
753
+ # Use the spinner function with fixed duration
754
+ spinner("Waiting to avoid rate limits...", 5, color=COLORS['yellow'])
713
755
 
714
756
  # Combine condensed chunks
715
757
  combined_condensed = "\n\n".join(condensed_chunks)
@@ -818,10 +860,21 @@ REQUIREMENTS:
818
860
  if logger:
819
861
  logger.log_template("DEBUG", f"CONDENSE_PROMPT_DEPTH_{current_depth}", condense_prompt)
820
862
 
821
- 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()
822
872
 
823
873
  try:
824
874
  condensed_result = handle_api_call(client, condense_prompt, system_prompt, logger)
875
+ # Stop the spinner
876
+ stop_spinner.set()
877
+ spinner_thread.join()
825
878
 
826
879
  if logger:
827
880
  logger.log_content("DEBUG", f"CONDENSED_RESULT_DEPTH_{current_depth}", condensed_result)
@@ -848,6 +901,10 @@ REQUIREMENTS:
848
901
  else:
849
902
  return condensed_result
850
903
  except Exception as e:
904
+ # Stop the spinner
905
+ stop_spinner.set()
906
+ spinner_thread.join()
907
+
851
908
  print(f"{COLORS['red']}Error condensing commit message: {str(e)}{COLORS['reset']}")
852
909
  if logger:
853
910
  logger.error(f"Error condensing commit message at depth {current_depth}: {str(e)}")
ngpt/cli/ui.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import sys
2
+ import time
2
3
  import shutil
3
4
 
4
5
  # Optional imports for enhanced UI
@@ -151,4 +152,47 @@ def get_multiline_input():
151
152
 
152
153
  except KeyboardInterrupt:
153
154
  print("\nInput cancelled by user. Exiting gracefully.")
154
- return None
155
+ return None
156
+
157
+ def spinner(message, duration=5, spinner_chars="⣾⣽⣻⢿⡿⣟⣯⣷", color=None, stop_event=None):
158
+ """Display a spinner animation with a message.
159
+
160
+ Args:
161
+ message: The message to display alongside the spinner
162
+ duration: Duration in seconds to show the spinner (used if stop_event is None)
163
+ spinner_chars: Characters to use for the spinner animation
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
167
+ """
168
+ # Default color handling
169
+ color_start = ""
170
+ color_end = ""
171
+ if color:
172
+ color_start = color
173
+ color_end = "\033[0m" # Reset
174
+
175
+ # Each character shows for 0.2 seconds
176
+ char_duration = 0.2
177
+
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)
195
+
196
+ # Clear the line when done
197
+ sys.stdout.write("\r" + " " * (len(message) + 10) + "\r")
198
+ sys.stdout.flush()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ngpt
3
- Version: 2.15.1
3
+ Version: 2.16.0
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
@@ -8,11 +8,11 @@ ngpt/cli/formatters.py,sha256=HBYGlx_7eoAKyzfy0Vq5L0yn8yVKjngqYBukMmXCcz0,9401
8
8
  ngpt/cli/interactive.py,sha256=DZFbExcXd7RylkpBiZBhiI6N8FBaT0m_lBes0Pvhi48,10894
9
9
  ngpt/cli/main.py,sha256=6GO4r9e9su7FFukj9JeVmJt1bJsqPOJBj6xo3iyMZXU,28911
10
10
  ngpt/cli/renderers.py,sha256=gJ3WdVvCGkNxrLEkLCh6gk9HBFMK8y7an6CsEkqt2Z8,10535
11
- ngpt/cli/ui.py,sha256=iMinm_QdsmwrEUpb7CBRexyyBqf4sviFI9M3E8D-hhA,5303
11
+ ngpt/cli/ui.py,sha256=j3i1Zyv5Yop8zpl1EqP03VmzEmbu4LamCxCsDlnvc58,6962
12
12
  ngpt/cli/modes/__init__.py,sha256=R3aO662RIzWEOvr3moTrEI8Tpg0zDDyMGGh1-OxiRgM,285
13
13
  ngpt/cli/modes/chat.py,sha256=4a5EgM_5A1zCSrLrjgQMDnBwIHd1Rnu5_BjSKSm7p24,4255
14
14
  ngpt/cli/modes/code.py,sha256=RjOAj7BDO5vLUdIPkUfPtyIkI_W6qEHsZvYh-sIdVaM,4293
15
- ngpt/cli/modes/gitcommsg.py,sha256=Kx9pWGWB2bMNFhpBPAa4q7VwHmJQwnZ2qoFrWK7t3gs,45080
15
+ ngpt/cli/modes/gitcommsg.py,sha256=Bhgg9UArrfRUwosgVlNLUB7i1B8j-1ngpkmCm5iZBkM,46786
16
16
  ngpt/cli/modes/rewrite.py,sha256=Zb0PFvWRKXs4xJCF3GEdYc-LSmy6qRszz8-QJuldHc0,8595
17
17
  ngpt/cli/modes/shell.py,sha256=lF9f7w-0bl_FdZl-WJnZuV736BKrWQtrwoKr3ejPXFE,2682
18
18
  ngpt/cli/modes/text.py,sha256=ncYnfLFMdTPuHiOvAaHNiOWhox6GF6S-2fTwMIrAz-g,3140
@@ -20,8 +20,8 @@ ngpt/utils/__init__.py,sha256=E46suk2-QgYBI0Qrs6WXOajOUOebF3ETAFY7ah8DTWs,942
20
20
  ngpt/utils/cli_config.py,sha256=tQxR3a2iXyc5TfRBPQHSUXPInO2dv_zTPGn04eWfmoo,11285
21
21
  ngpt/utils/config.py,sha256=WYOk_b1eiYjo6hpV3pfXr2RjqhOnmKqwZwKid1T41I4,10363
22
22
  ngpt/utils/log.py,sha256=f1jg2iFo35PAmsarH8FVL_62plq4VXH0Mu2QiP6RJGw,15934
23
- ngpt-2.15.1.dist-info/METADATA,sha256=vKoeQ_IrjV2UtPpEGsThb-i8wg6OE46qXw-UDZdj9YQ,23523
24
- ngpt-2.15.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
25
- ngpt-2.15.1.dist-info/entry_points.txt,sha256=SqAAvLhMrsEpkIr4YFRdUeyuXQ9o0IBCeYgE6AVojoI,44
26
- ngpt-2.15.1.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
27
- ngpt-2.15.1.dist-info/RECORD,,
23
+ ngpt-2.16.0.dist-info/METADATA,sha256=T5OEQ8AtdLDyct1rLRKElBBUCZgehw1iesLMhZrcnKA,23523
24
+ ngpt-2.16.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
25
+ ngpt-2.16.0.dist-info/entry_points.txt,sha256=SqAAvLhMrsEpkIr4YFRdUeyuXQ9o0IBCeYgE6AVojoI,44
26
+ ngpt-2.16.0.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
27
+ ngpt-2.16.0.dist-info/RECORD,,
File without changes