ngpt 2.16.2__py3-none-any.whl → 2.16.4__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.
- ngpt/cli/modes/chat.py +40 -3
- ngpt/cli/modes/code.py +40 -3
- ngpt/cli/modes/rewrite.py +40 -4
- ngpt/cli/modes/shell.py +25 -3
- ngpt/cli/modes/text.py +41 -4
- ngpt/cli/renderers.py +47 -6
- ngpt/cli/ui.py +5 -18
- {ngpt-2.16.2.dist-info → ngpt-2.16.4.dist-info}/METADATA +5 -4
- {ngpt-2.16.2.dist-info → ngpt-2.16.4.dist-info}/RECORD +12 -12
- {ngpt-2.16.2.dist-info → ngpt-2.16.4.dist-info}/WHEEL +0 -0
- {ngpt-2.16.2.dist-info → ngpt-2.16.4.dist-info}/entry_points.txt +0 -0
- {ngpt-2.16.2.dist-info → ngpt-2.16.4.dist-info}/licenses/LICENSE +0 -0
ngpt/cli/modes/chat.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
from ..formatters import COLORS
|
2
2
|
from ..renderers import prettify_markdown, prettify_streaming_markdown
|
3
|
+
from ..ui import spinner
|
3
4
|
import sys
|
5
|
+
import threading
|
4
6
|
|
5
7
|
def chat_mode(client, args, logger=None):
|
6
8
|
"""Handle the standard chat mode with a single prompt.
|
@@ -70,11 +72,12 @@ def chat_mode(client, args, logger=None):
|
|
70
72
|
# If stream-prettify is enabled
|
71
73
|
stream_callback = None
|
72
74
|
live_display = None
|
75
|
+
stop_spinner_func = None
|
73
76
|
|
74
77
|
if args.stream_prettify:
|
75
78
|
should_stream = True # Enable streaming
|
76
79
|
# This is the standard mode, not interactive
|
77
|
-
live_display, stream_callback = prettify_streaming_markdown(args.renderer)
|
80
|
+
live_display, stream_callback, setup_spinner = prettify_streaming_markdown(args.renderer)
|
78
81
|
if not live_display:
|
79
82
|
# Fallback to normal prettify if live display setup failed
|
80
83
|
args.prettify = True
|
@@ -86,9 +89,39 @@ def chat_mode(client, args, logger=None):
|
|
86
89
|
if args.prettify and not args.no_stream:
|
87
90
|
print(f"{COLORS['yellow']}Note: Streaming disabled to enable markdown rendering.{COLORS['reset']}")
|
88
91
|
|
89
|
-
#
|
92
|
+
# Show a static message if live_display is not available
|
93
|
+
if args.stream_prettify and not live_display:
|
94
|
+
print("\nWaiting for AI response...")
|
95
|
+
|
96
|
+
# Set up the spinner if we have a live display
|
97
|
+
stop_spinner_event = None
|
98
|
+
if args.stream_prettify and live_display:
|
99
|
+
stop_spinner_event = threading.Event()
|
100
|
+
stop_spinner_func = setup_spinner(stop_spinner_event)
|
101
|
+
|
102
|
+
# Create a wrapper for the stream callback that will stop the spinner on first content
|
103
|
+
original_callback = stream_callback
|
104
|
+
first_content_received = False
|
105
|
+
|
106
|
+
def spinner_handling_callback(content):
|
107
|
+
nonlocal first_content_received
|
108
|
+
|
109
|
+
# On first content, stop the spinner
|
110
|
+
if not first_content_received and stop_spinner_func:
|
111
|
+
first_content_received = True
|
112
|
+
# Stop the spinner
|
113
|
+
stop_spinner_func()
|
114
|
+
# Ensure spinner message is cleared with an extra blank line
|
115
|
+
sys.stdout.write("\r" + " " * 100 + "\r")
|
116
|
+
sys.stdout.flush()
|
117
|
+
|
118
|
+
# Call the original callback to update the display
|
119
|
+
if original_callback:
|
120
|
+
original_callback(content)
|
121
|
+
|
122
|
+
# Use our wrapper callback
|
90
123
|
if args.stream_prettify and live_display:
|
91
|
-
|
124
|
+
stream_callback = spinner_handling_callback
|
92
125
|
|
93
126
|
response = client.chat(prompt, stream=should_stream, web_search=args.web_search,
|
94
127
|
temperature=args.temperature, top_p=args.top_p,
|
@@ -96,6 +129,10 @@ def chat_mode(client, args, logger=None):
|
|
96
129
|
markdown_format=args.prettify or args.stream_prettify,
|
97
130
|
stream_callback=stream_callback)
|
98
131
|
|
132
|
+
# Ensure spinner is stopped if no content was received
|
133
|
+
if stop_spinner_event and not first_content_received:
|
134
|
+
stop_spinner_event.set()
|
135
|
+
|
99
136
|
# Stop live display if using stream-prettify
|
100
137
|
if args.stream_prettify and live_display:
|
101
138
|
live_display.stop()
|
ngpt/cli/modes/code.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
from ..formatters import COLORS
|
2
2
|
from ..renderers import prettify_markdown, prettify_streaming_markdown, has_markdown_renderer, show_available_renderers
|
3
|
+
from ..ui import spinner
|
3
4
|
import sys
|
5
|
+
import threading
|
4
6
|
|
5
7
|
def code_mode(client, args, logger=None):
|
6
8
|
"""Handle the code generation mode.
|
@@ -27,6 +29,7 @@ def code_mode(client, args, logger=None):
|
|
27
29
|
# Setup for streaming and prettify logic
|
28
30
|
stream_callback = None
|
29
31
|
live_display = None
|
32
|
+
stop_spinner_func = None
|
30
33
|
should_stream = True # Default to streaming
|
31
34
|
use_stream_prettify = False
|
32
35
|
use_regular_prettify = False
|
@@ -37,7 +40,7 @@ def code_mode(client, args, logger=None):
|
|
37
40
|
if has_markdown_renderer('rich'):
|
38
41
|
should_stream = True
|
39
42
|
use_stream_prettify = True
|
40
|
-
live_display, stream_callback = prettify_streaming_markdown(args.renderer)
|
43
|
+
live_display, stream_callback, setup_spinner = prettify_streaming_markdown(args.renderer)
|
41
44
|
if not live_display:
|
42
45
|
# Fallback if live display fails
|
43
46
|
use_stream_prettify = False
|
@@ -71,9 +74,39 @@ def code_mode(client, args, logger=None):
|
|
71
74
|
|
72
75
|
print("\nGenerating code...")
|
73
76
|
|
74
|
-
#
|
77
|
+
# Show a static message if no live_display is available
|
78
|
+
if use_stream_prettify and not live_display:
|
79
|
+
print("Waiting for AI response...")
|
80
|
+
|
81
|
+
# Set up the spinner if we have a live display
|
82
|
+
stop_spinner_event = None
|
83
|
+
if use_stream_prettify and live_display:
|
84
|
+
stop_spinner_event = threading.Event()
|
85
|
+
stop_spinner_func = setup_spinner(stop_spinner_event)
|
86
|
+
|
87
|
+
# Create a wrapper for the stream callback that will stop the spinner on first content
|
88
|
+
original_callback = stream_callback
|
89
|
+
first_content_received = False
|
90
|
+
|
91
|
+
def spinner_handling_callback(content):
|
92
|
+
nonlocal first_content_received
|
93
|
+
|
94
|
+
# On first content, stop the spinner
|
95
|
+
if not first_content_received and stop_spinner_func:
|
96
|
+
first_content_received = True
|
97
|
+
# Stop the spinner
|
98
|
+
stop_spinner_func()
|
99
|
+
# Ensure spinner message is cleared with an extra blank line
|
100
|
+
sys.stdout.write("\r" + " " * 100 + "\r")
|
101
|
+
sys.stdout.flush()
|
102
|
+
|
103
|
+
# Call the original callback to update the display
|
104
|
+
if original_callback:
|
105
|
+
original_callback(content)
|
106
|
+
|
107
|
+
# Use our wrapper callback
|
75
108
|
if use_stream_prettify and live_display:
|
76
|
-
|
109
|
+
stream_callback = spinner_handling_callback
|
77
110
|
|
78
111
|
generated_code = client.generate_code(
|
79
112
|
prompt=prompt,
|
@@ -88,6 +121,10 @@ def code_mode(client, args, logger=None):
|
|
88
121
|
stream_callback=stream_callback
|
89
122
|
)
|
90
123
|
|
124
|
+
# Ensure spinner is stopped if no content was received
|
125
|
+
if stop_spinner_event and not first_content_received:
|
126
|
+
stop_spinner_event.set()
|
127
|
+
|
91
128
|
# Stop live display if using stream-prettify
|
92
129
|
if use_stream_prettify and live_display:
|
93
130
|
live_display.stop()
|
ngpt/cli/modes/rewrite.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
import sys
|
2
2
|
import platform
|
3
|
+
import threading
|
3
4
|
from ..formatters import COLORS
|
4
5
|
from ..renderers import prettify_markdown, prettify_streaming_markdown
|
5
|
-
from ..ui import get_multiline_input
|
6
|
+
from ..ui import get_multiline_input, spinner
|
6
7
|
|
7
8
|
# System prompt for rewriting text
|
8
9
|
REWRITE_SYSTEM_PROMPT = """You are an expert text editor and rewriter. Your task is to rewrite the user's text to improve readability and flow while carefully preserving the original meaning, tone, and style.
|
@@ -143,10 +144,11 @@ def rewrite_mode(client, args, logger=None):
|
|
143
144
|
# If stream-prettify is enabled
|
144
145
|
stream_callback = None
|
145
146
|
live_display = None
|
147
|
+
stop_spinner_func = None
|
146
148
|
|
147
149
|
if args.stream_prettify:
|
148
150
|
should_stream = True # Enable streaming
|
149
|
-
live_display, stream_callback = prettify_streaming_markdown(args.renderer)
|
151
|
+
live_display, stream_callback, setup_spinner = prettify_streaming_markdown(args.renderer)
|
150
152
|
if not live_display:
|
151
153
|
# Fallback to normal prettify if live display setup failed
|
152
154
|
args.prettify = True
|
@@ -158,9 +160,39 @@ def rewrite_mode(client, args, logger=None):
|
|
158
160
|
if args.prettify and not args.no_stream:
|
159
161
|
print(f"{COLORS['yellow']}Note: Streaming disabled to enable markdown rendering.{COLORS['reset']}")
|
160
162
|
|
161
|
-
#
|
163
|
+
# Show a static message if live_display is not available
|
164
|
+
if args.stream_prettify and not live_display:
|
165
|
+
print("\nWaiting for AI response...")
|
166
|
+
|
167
|
+
# Set up the spinner if we have a live display
|
168
|
+
stop_spinner_event = None
|
162
169
|
if args.stream_prettify and live_display:
|
163
|
-
|
170
|
+
stop_spinner_event = threading.Event()
|
171
|
+
stop_spinner_func = setup_spinner(stop_spinner_event)
|
172
|
+
|
173
|
+
# Create a wrapper for the stream callback that will stop the spinner on first content
|
174
|
+
original_callback = stream_callback
|
175
|
+
first_content_received = False
|
176
|
+
|
177
|
+
def spinner_handling_callback(content):
|
178
|
+
nonlocal first_content_received
|
179
|
+
|
180
|
+
# On first content, stop the spinner
|
181
|
+
if not first_content_received and stop_spinner_func:
|
182
|
+
first_content_received = True
|
183
|
+
# Stop the spinner
|
184
|
+
stop_spinner_func()
|
185
|
+
# Ensure spinner message is cleared with an extra blank line
|
186
|
+
sys.stdout.write("\r" + " " * 100 + "\r")
|
187
|
+
sys.stdout.flush()
|
188
|
+
|
189
|
+
# Call the original callback to update the display
|
190
|
+
if original_callback:
|
191
|
+
original_callback(content)
|
192
|
+
|
193
|
+
# Use our wrapper callback
|
194
|
+
if args.stream_prettify and live_display:
|
195
|
+
stream_callback = spinner_handling_callback
|
164
196
|
|
165
197
|
response = client.chat(
|
166
198
|
prompt=None, # Not used when messages are provided
|
@@ -174,6 +206,10 @@ def rewrite_mode(client, args, logger=None):
|
|
174
206
|
messages=messages # Use messages array instead of prompt
|
175
207
|
)
|
176
208
|
|
209
|
+
# Ensure spinner is stopped if no content was received
|
210
|
+
if stop_spinner_event and not first_content_received:
|
211
|
+
stop_spinner_event.set()
|
212
|
+
|
177
213
|
# Stop live display if using stream-prettify
|
178
214
|
if args.stream_prettify and live_display:
|
179
215
|
live_display.stop()
|
ngpt/cli/modes/shell.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
from ..formatters import COLORS
|
2
|
+
from ..ui import spinner
|
2
3
|
import subprocess
|
3
4
|
import sys
|
5
|
+
import threading
|
4
6
|
|
5
7
|
def shell_mode(client, args, logger=None):
|
6
8
|
"""Handle the shell command generation mode.
|
@@ -23,10 +25,30 @@ def shell_mode(client, args, logger=None):
|
|
23
25
|
# Log the user prompt if logging is enabled
|
24
26
|
if logger:
|
25
27
|
logger.log("user", prompt)
|
28
|
+
|
29
|
+
# Start spinner while waiting for command generation
|
30
|
+
stop_spinner = threading.Event()
|
31
|
+
spinner_thread = threading.Thread(
|
32
|
+
target=spinner,
|
33
|
+
args=("Generating command...",),
|
34
|
+
kwargs={"stop_event": stop_spinner}
|
35
|
+
)
|
36
|
+
spinner_thread.daemon = True
|
37
|
+
spinner_thread.start()
|
38
|
+
|
39
|
+
try:
|
40
|
+
command = client.generate_shell_command(prompt, web_search=args.web_search,
|
41
|
+
temperature=args.temperature, top_p=args.top_p,
|
42
|
+
max_tokens=args.max_tokens)
|
43
|
+
finally:
|
44
|
+
# Stop the spinner
|
45
|
+
stop_spinner.set()
|
46
|
+
spinner_thread.join()
|
26
47
|
|
27
|
-
|
28
|
-
|
29
|
-
|
48
|
+
# Clear the spinner line completely
|
49
|
+
sys.stdout.write("\r" + " " * 100 + "\r")
|
50
|
+
sys.stdout.flush()
|
51
|
+
|
30
52
|
if not command:
|
31
53
|
return # Error already printed by client
|
32
54
|
|
ngpt/cli/modes/text.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
from ..formatters import COLORS
|
2
2
|
from ..renderers import prettify_markdown, prettify_streaming_markdown
|
3
|
-
from ..ui import get_multiline_input
|
3
|
+
from ..ui import get_multiline_input, spinner
|
4
|
+
import threading
|
5
|
+
import sys
|
4
6
|
|
5
7
|
def text_mode(client, args, logger=None):
|
6
8
|
"""Handle the multi-line text input mode.
|
@@ -43,11 +45,12 @@ def text_mode(client, args, logger=None):
|
|
43
45
|
# If stream-prettify is enabled
|
44
46
|
stream_callback = None
|
45
47
|
live_display = None
|
48
|
+
stop_spinner_func = None
|
46
49
|
|
47
50
|
if args.stream_prettify:
|
48
51
|
should_stream = True # Enable streaming
|
49
52
|
# This is the standard mode, not interactive
|
50
|
-
live_display, stream_callback = prettify_streaming_markdown(args.renderer)
|
53
|
+
live_display, stream_callback, setup_spinner = prettify_streaming_markdown(args.renderer)
|
51
54
|
if not live_display:
|
52
55
|
# Fallback to normal prettify if live display setup failed
|
53
56
|
args.prettify = True
|
@@ -59,9 +62,39 @@ def text_mode(client, args, logger=None):
|
|
59
62
|
if args.prettify and not args.no_stream:
|
60
63
|
print(f"{COLORS['yellow']}Note: Streaming disabled to enable markdown rendering.{COLORS['reset']}")
|
61
64
|
|
62
|
-
#
|
65
|
+
# Show a static message if live_display is not available
|
66
|
+
if args.stream_prettify and not live_display:
|
67
|
+
print("\nWaiting for AI response...")
|
68
|
+
|
69
|
+
# Set up the spinner if we have a live display
|
70
|
+
stop_spinner_event = None
|
71
|
+
if args.stream_prettify and live_display:
|
72
|
+
stop_spinner_event = threading.Event()
|
73
|
+
stop_spinner_func = setup_spinner(stop_spinner_event)
|
74
|
+
|
75
|
+
# Create a wrapper for the stream callback that will stop the spinner on first content
|
76
|
+
original_callback = stream_callback
|
77
|
+
first_content_received = False
|
78
|
+
|
79
|
+
def spinner_handling_callback(content):
|
80
|
+
nonlocal first_content_received
|
81
|
+
|
82
|
+
# On first content, stop the spinner
|
83
|
+
if not first_content_received and stop_spinner_func:
|
84
|
+
first_content_received = True
|
85
|
+
# Stop the spinner
|
86
|
+
stop_spinner_func()
|
87
|
+
# Ensure spinner message is cleared with an extra blank line
|
88
|
+
sys.stdout.write("\r" + " " * 100 + "\r")
|
89
|
+
sys.stdout.flush()
|
90
|
+
|
91
|
+
# Call the original callback to update the display
|
92
|
+
if original_callback:
|
93
|
+
original_callback(content)
|
94
|
+
|
95
|
+
# Use our wrapper callback
|
63
96
|
if args.stream_prettify and live_display:
|
64
|
-
|
97
|
+
stream_callback = spinner_handling_callback
|
65
98
|
|
66
99
|
response = client.chat(prompt, stream=should_stream, web_search=args.web_search,
|
67
100
|
temperature=args.temperature, top_p=args.top_p,
|
@@ -69,6 +102,10 @@ def text_mode(client, args, logger=None):
|
|
69
102
|
markdown_format=args.prettify or args.stream_prettify,
|
70
103
|
stream_callback=stream_callback)
|
71
104
|
|
105
|
+
# Ensure spinner is stopped if no content was received
|
106
|
+
if stop_spinner_event and not first_content_received:
|
107
|
+
stop_spinner_event.set()
|
108
|
+
|
72
109
|
# Stop live display if using stream-prettify
|
73
110
|
if args.stream_prettify and live_display:
|
74
111
|
live_display.stop()
|
ngpt/cli/renderers.py
CHANGED
@@ -2,6 +2,7 @@ import os
|
|
2
2
|
import shutil
|
3
3
|
import subprocess
|
4
4
|
import tempfile
|
5
|
+
import sys
|
5
6
|
from .formatters import COLORS
|
6
7
|
|
7
8
|
# Try to import markdown rendering libraries
|
@@ -191,7 +192,8 @@ def prettify_streaming_markdown(renderer='rich', is_interactive=False, header_te
|
|
191
192
|
header_text (str): Header text to include at the top (for interactive mode)
|
192
193
|
|
193
194
|
Returns:
|
194
|
-
tuple: (live_display, update_function) if successful, (None, None) otherwise
|
195
|
+
tuple: (live_display, update_function, stop_spinner_func) if successful, (None, None, None) otherwise
|
196
|
+
stop_spinner_func is a function that should be called when first content is received
|
195
197
|
"""
|
196
198
|
# Only warn if explicitly specifying a renderer other than 'rich' or 'auto'
|
197
199
|
if renderer != 'rich' and renderer != 'auto':
|
@@ -204,7 +206,7 @@ def prettify_streaming_markdown(renderer='rich', is_interactive=False, header_te
|
|
204
206
|
if not HAS_RICH:
|
205
207
|
print(f"{COLORS['yellow']}Warning: Rich is not available for streaming prettify.{COLORS['reset']}")
|
206
208
|
print(f"{COLORS['yellow']}Install with: pip install \"ngpt[full]\" or pip install rich{COLORS['reset']}")
|
207
|
-
return None, None
|
209
|
+
return None, None, None
|
208
210
|
|
209
211
|
try:
|
210
212
|
from rich.live import Live
|
@@ -238,11 +240,26 @@ def prettify_streaming_markdown(renderer='rich', is_interactive=False, header_te
|
|
238
240
|
md_obj = Markdown("")
|
239
241
|
|
240
242
|
# Initialize the Live display with an empty markdown
|
241
|
-
live = Live(md_obj, console=console, refresh_per_second=10)
|
243
|
+
live = Live(md_obj, console=console, refresh_per_second=10, auto_refresh=False)
|
244
|
+
|
245
|
+
# Track if this is the first content update
|
246
|
+
first_update = True
|
247
|
+
stop_spinner_event = None
|
248
|
+
spinner_thread = None
|
242
249
|
|
243
250
|
# Define an update function that will be called with new content
|
244
251
|
def update_content(content):
|
245
|
-
nonlocal md_obj
|
252
|
+
nonlocal md_obj, first_update
|
253
|
+
|
254
|
+
# Start live display on first content
|
255
|
+
if first_update:
|
256
|
+
first_update = False
|
257
|
+
# Clear the spinner line completely before starting the display
|
258
|
+
sys.stdout.write("\r" + " " * 100 + "\r")
|
259
|
+
sys.stdout.flush()
|
260
|
+
live.start()
|
261
|
+
|
262
|
+
# Update content
|
246
263
|
if is_interactive and header_text:
|
247
264
|
# Update the panel content
|
248
265
|
md_obj.renderable = Markdown(content)
|
@@ -250,8 +267,32 @@ def prettify_streaming_markdown(renderer='rich', is_interactive=False, header_te
|
|
250
267
|
else:
|
251
268
|
md_obj = Markdown(content)
|
252
269
|
live.update(md_obj)
|
270
|
+
|
271
|
+
# Ensure the display refreshes with new content
|
272
|
+
live.refresh()
|
273
|
+
|
274
|
+
# Define a function to set up and start the spinner
|
275
|
+
def setup_spinner(stop_event, message="Waiting for AI response..."):
|
276
|
+
nonlocal stop_spinner_event, spinner_thread
|
277
|
+
from .ui import spinner
|
278
|
+
import threading
|
279
|
+
|
280
|
+
# Store the event so the update function can access it
|
281
|
+
stop_spinner_event = stop_event
|
282
|
+
|
283
|
+
# Create and start spinner thread
|
284
|
+
spinner_thread = threading.Thread(
|
285
|
+
target=spinner,
|
286
|
+
args=(message,),
|
287
|
+
kwargs={"stop_event": stop_event}
|
288
|
+
)
|
289
|
+
spinner_thread.daemon = True
|
290
|
+
spinner_thread.start()
|
253
291
|
|
254
|
-
|
292
|
+
# Return a function that can be used to stop the spinner
|
293
|
+
return lambda: stop_event.set() if stop_event else None
|
294
|
+
|
295
|
+
return live, update_content, setup_spinner
|
255
296
|
except Exception as e:
|
256
297
|
print(f"{COLORS['yellow']}Error setting up Rich streaming display: {str(e)}{COLORS['reset']}")
|
257
|
-
return None, None
|
298
|
+
return None, None, None
|
ngpt/cli/ui.py
CHANGED
@@ -165,34 +165,21 @@ def spinner(message, duration=5, spinner_chars="⣾⣽⣻⢿⡿⣟⣯⣷", color
|
|
165
165
|
stop_event: Optional threading.Event to signal when to stop the spinner
|
166
166
|
If provided, duration is ignored and spinner runs until event is set
|
167
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
168
|
char_duration = 0.2
|
177
|
-
|
169
|
+
|
178
170
|
if stop_event:
|
179
|
-
# Run until stop_event is set
|
180
171
|
i = 0
|
181
172
|
while not stop_event.is_set():
|
182
173
|
char = spinner_chars[i % len(spinner_chars)]
|
183
|
-
|
184
|
-
sys.stdout.flush()
|
174
|
+
print(f"\r{message} {char}", end="", flush=True)
|
185
175
|
i += 1
|
186
176
|
time.sleep(char_duration)
|
187
177
|
else:
|
188
|
-
# Run for fixed duration
|
189
178
|
total_chars = int(duration / char_duration)
|
190
179
|
for i in range(total_chars):
|
191
180
|
char = spinner_chars[i % len(spinner_chars)]
|
192
|
-
|
193
|
-
sys.stdout.flush()
|
181
|
+
print(f"\r{message} {char}", end="", flush=True)
|
194
182
|
time.sleep(char_duration)
|
195
|
-
|
183
|
+
|
196
184
|
# Clear the line when done
|
197
|
-
|
198
|
-
sys.stdout.flush()
|
185
|
+
print("\r" + " " * (len(message) + 10) + "\r", end="", flush=True)
|
@@ -1,14 +1,14 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ngpt
|
3
|
-
Version: 2.16.
|
4
|
-
Summary:
|
3
|
+
Version: 2.16.4
|
4
|
+
Summary: Swiss army knife for LLMs: powerful CLI, interactive chatbot, and flexible Python library. Works with OpenAI, Ollama, Groq, Claude, and any OpenAI-compatible API.
|
5
5
|
Project-URL: Homepage, https://github.com/nazdridoy/ngpt
|
6
6
|
Project-URL: Repository, https://github.com/nazdridoy/ngpt
|
7
7
|
Project-URL: Bug Tracker, https://github.com/nazdridoy/ngpt/issues
|
8
8
|
Author-email: nazDridoy <nazdridoy399@gmail.com>
|
9
9
|
License: MIT
|
10
10
|
License-File: LICENSE
|
11
|
-
Keywords: ai,api-client,chatgpt,cli,gpt,
|
11
|
+
Keywords: ai,api-client,chatbot,chatgpt,claude,cli,cli-tool,code-generation,git-commit,gpt,groq,llm,markdown-rendering,ollama,openai,shell-commands,text-rewriting
|
12
12
|
Classifier: Environment :: Console
|
13
13
|
Classifier: Intended Audience :: Developers
|
14
14
|
Classifier: Intended Audience :: End Users/Desktop
|
@@ -36,12 +36,13 @@ Description-Content-Type: text/markdown
|
|
36
36
|
|
37
37
|
# nGPT
|
38
38
|
|
39
|
+
🤖 nGPT: A Swiss army knife for LLMs: powerful CLI, interactive chatbot, and flexible library all in one package. Seamlessly work with OpenAI, Ollama, Groq, Claude, or any OpenAI-compatible API to generate code, craft git commits, rewrite text, and execute shell commands. Fast, lightweight, and designed for both casual users and developers.
|
40
|
+
|
39
41
|
[](https://pypi.org/project/ngpt/)
|
40
42
|
[](https://opensource.org/licenses/MIT)
|
41
43
|
[](https://pypi.org/project/ngpt/)
|
42
44
|
[](https://nazdridoy.github.io/ngpt/)
|
43
45
|
|
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
46
|
|
46
47
|

|
47
48
|
|
@@ -7,21 +7,21 @@ ngpt/cli/config_manager.py,sha256=NQQcWnjUppAAd0s0p9YAf8EyKS1ex5-0EB4DvKdB4dk,36
|
|
7
7
|
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
|
-
ngpt/cli/renderers.py,sha256=
|
11
|
-
ngpt/cli/ui.py,sha256=
|
10
|
+
ngpt/cli/renderers.py,sha256=0ditb6F8uKIAX70jS8bnzcXUd9xttLv3zIYfDCBixgw,12221
|
11
|
+
ngpt/cli/ui.py,sha256=B4dgipuJsH66gjpfKXfjJ0ANBveFciTkepmkZXtqJvg,6579
|
12
12
|
ngpt/cli/modes/__init__.py,sha256=R3aO662RIzWEOvr3moTrEI8Tpg0zDDyMGGh1-OxiRgM,285
|
13
|
-
ngpt/cli/modes/chat.py,sha256=
|
14
|
-
ngpt/cli/modes/code.py,sha256=
|
13
|
+
ngpt/cli/modes/chat.py,sha256=XmRmPxHr2W_t8D_9JGTbEUWydnfm5BmGA5ODAu0u2oU,5679
|
14
|
+
ngpt/cli/modes/code.py,sha256=On3JQZO79FOeUK5Tw89jsQF_lI8rAIHHe_zu2bHX99c,5712
|
15
15
|
ngpt/cli/modes/gitcommsg.py,sha256=Bhgg9UArrfRUwosgVlNLUB7i1B8j-1ngpkmCm5iZBkM,46786
|
16
|
-
ngpt/cli/modes/rewrite.py,sha256=
|
17
|
-
ngpt/cli/modes/shell.py,sha256
|
18
|
-
ngpt/cli/modes/text.py,sha256=
|
16
|
+
ngpt/cli/modes/rewrite.py,sha256=8QDhjzAjWDnDAHEBXRWIGg7xx6fqRhIPse_GVHMBe4o,10157
|
17
|
+
ngpt/cli/modes/shell.py,sha256=-uZ3CeWdZBidUnfStNGX0sr20WSovn5DSfwsMkBWaEo,3286
|
18
|
+
ngpt/cli/modes/text.py,sha256=Q5vfBwDPyEtFubs8fPS_pPQBlyTxcDgOF-tCsz3oIH0,4559
|
19
19
|
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.16.
|
24
|
-
ngpt-2.16.
|
25
|
-
ngpt-2.16.
|
26
|
-
ngpt-2.16.
|
27
|
-
ngpt-2.16.
|
23
|
+
ngpt-2.16.4.dist-info/METADATA,sha256=LMstFvIe9EaUm9w1pbDxJJrTzquFGYzu_-6gRbBKBgs,24938
|
24
|
+
ngpt-2.16.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
25
|
+
ngpt-2.16.4.dist-info/entry_points.txt,sha256=SqAAvLhMrsEpkIr4YFRdUeyuXQ9o0IBCeYgE6AVojoI,44
|
26
|
+
ngpt-2.16.4.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
|
27
|
+
ngpt-2.16.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|