ngpt 3.0.6__py3-none-any.whl → 3.1.1__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/interactive.py +5 -3
- ngpt/cli/main.py +3 -3
- ngpt/cli/modes/chat.py +5 -3
- ngpt/cli/modes/code.py +5 -3
- ngpt/cli/modes/rewrite.py +6 -3
- ngpt/cli/modes/text.py +5 -3
- ngpt/cli/renderers.py +62 -6
- ngpt/utils/config.py +7 -6
- {ngpt-3.0.6.dist-info → ngpt-3.1.1.dist-info}/METADATA +1 -1
- {ngpt-3.0.6.dist-info → ngpt-3.1.1.dist-info}/RECORD +13 -13
- {ngpt-3.0.6.dist-info → ngpt-3.1.1.dist-info}/WHEEL +0 -0
- {ngpt-3.0.6.dist-info → ngpt-3.1.1.dist-info}/entry_points.txt +0 -0
- {ngpt-3.0.6.dist-info → ngpt-3.1.1.dist-info}/licenses/LICENSE +0 -0
ngpt/cli/interactive.py
CHANGED
@@ -218,7 +218,7 @@ def interactive_chat_session(client, web_search=False, no_stream=False, temperat
|
|
218
218
|
# Create a wrapper for the stream callback that handles spinner and live display
|
219
219
|
original_callback = stream_callback
|
220
220
|
|
221
|
-
def spinner_handling_callback(content):
|
221
|
+
def spinner_handling_callback(content, **kwargs):
|
222
222
|
nonlocal first_content_received
|
223
223
|
|
224
224
|
# On first content, stop the spinner and start the live display
|
@@ -239,7 +239,7 @@ def interactive_chat_session(client, web_search=False, no_stream=False, temperat
|
|
239
239
|
|
240
240
|
# Call the original callback to update content
|
241
241
|
if original_callback:
|
242
|
-
original_callback(content)
|
242
|
+
original_callback(content, **kwargs)
|
243
243
|
|
244
244
|
# Use our wrapper callback
|
245
245
|
stream_callback = spinner_handling_callback
|
@@ -269,7 +269,9 @@ def interactive_chat_session(client, web_search=False, no_stream=False, temperat
|
|
269
269
|
|
270
270
|
# Stop live display if using stream-prettify
|
271
271
|
if stream_prettify and live_display and first_content_received:
|
272
|
-
|
272
|
+
# Before stopping the live display, update with complete=True to show final formatted content
|
273
|
+
if stream_callback and response:
|
274
|
+
stream_callback(response, complete=True)
|
273
275
|
|
274
276
|
# Add AI response to conversation history
|
275
277
|
if response:
|
ngpt/cli/main.py
CHANGED
@@ -297,12 +297,12 @@ def main():
|
|
297
297
|
elif len(matching_configs) > 1:
|
298
298
|
print(f"Multiple configurations found for provider '{effective_provider}':")
|
299
299
|
for i, idx in enumerate(matching_configs):
|
300
|
-
print(f" [{i}]
|
300
|
+
print(f" Choice [{i+1}] → Config #{idx}: {configs[idx].get('model', 'Unknown model')}")
|
301
301
|
|
302
302
|
try:
|
303
303
|
choice = input("Choose a configuration to remove (or press Enter to cancel): ")
|
304
|
-
if choice and choice.isdigit() and
|
305
|
-
config_index = matching_configs[int(choice)]
|
304
|
+
if choice and choice.isdigit() and 1 <= int(choice) <= len(matching_configs):
|
305
|
+
config_index = matching_configs[int(choice)-1]
|
306
306
|
else:
|
307
307
|
print("Configuration removal cancelled.")
|
308
308
|
return
|
ngpt/cli/modes/chat.py
CHANGED
@@ -103,7 +103,7 @@ def chat_mode(client, args, logger=None):
|
|
103
103
|
original_callback = stream_callback
|
104
104
|
first_content_received = False
|
105
105
|
|
106
|
-
def spinner_handling_callback(content):
|
106
|
+
def spinner_handling_callback(content, **kwargs):
|
107
107
|
nonlocal first_content_received
|
108
108
|
|
109
109
|
# On first content, stop the spinner
|
@@ -117,7 +117,7 @@ def chat_mode(client, args, logger=None):
|
|
117
117
|
|
118
118
|
# Call the original callback to update the display
|
119
119
|
if original_callback:
|
120
|
-
original_callback(content)
|
120
|
+
original_callback(content, **kwargs)
|
121
121
|
|
122
122
|
# Use our wrapper callback
|
123
123
|
if args.stream_prettify and live_display:
|
@@ -135,7 +135,9 @@ def chat_mode(client, args, logger=None):
|
|
135
135
|
|
136
136
|
# Stop live display if using stream-prettify
|
137
137
|
if args.stream_prettify and live_display:
|
138
|
-
|
138
|
+
# Before stopping the live display, update with complete=True to show final formatted content
|
139
|
+
if stream_callback and response:
|
140
|
+
stream_callback(response, complete=True)
|
139
141
|
|
140
142
|
# Log the AI response if logging is enabled
|
141
143
|
if logger and response:
|
ngpt/cli/modes/code.py
CHANGED
@@ -88,7 +88,7 @@ def code_mode(client, args, logger=None):
|
|
88
88
|
original_callback = stream_callback
|
89
89
|
first_content_received = False
|
90
90
|
|
91
|
-
def spinner_handling_callback(content):
|
91
|
+
def spinner_handling_callback(content, **kwargs):
|
92
92
|
nonlocal first_content_received
|
93
93
|
|
94
94
|
# On first content, stop the spinner
|
@@ -102,7 +102,7 @@ def code_mode(client, args, logger=None):
|
|
102
102
|
|
103
103
|
# Call the original callback to update the display
|
104
104
|
if original_callback:
|
105
|
-
original_callback(content)
|
105
|
+
original_callback(content, **kwargs)
|
106
106
|
|
107
107
|
# Use our wrapper callback
|
108
108
|
if use_stream_prettify and live_display:
|
@@ -127,7 +127,9 @@ def code_mode(client, args, logger=None):
|
|
127
127
|
|
128
128
|
# Stop live display if using stream-prettify
|
129
129
|
if use_stream_prettify and live_display:
|
130
|
-
|
130
|
+
# Before stopping the live display, update with complete=True to show final formatted content
|
131
|
+
if stream_callback and generated_code:
|
132
|
+
stream_callback(generated_code, complete=True)
|
131
133
|
|
132
134
|
# Log the generated code if logging is enabled
|
133
135
|
if logger and generated_code:
|
ngpt/cli/modes/rewrite.py
CHANGED
@@ -172,7 +172,7 @@ def rewrite_mode(client, args, logger=None):
|
|
172
172
|
original_callback = stream_callback
|
173
173
|
first_content_received = False
|
174
174
|
|
175
|
-
def spinner_handling_callback(content):
|
175
|
+
def spinner_handling_callback(content, **kwargs):
|
176
176
|
nonlocal first_content_received
|
177
177
|
|
178
178
|
# On first content, stop the spinner
|
@@ -186,7 +186,7 @@ def rewrite_mode(client, args, logger=None):
|
|
186
186
|
|
187
187
|
# Call the original callback to update the display
|
188
188
|
if original_callback:
|
189
|
-
original_callback(content)
|
189
|
+
original_callback(content, **kwargs)
|
190
190
|
|
191
191
|
# Use our wrapper callback
|
192
192
|
if args.stream_prettify and live_display:
|
@@ -210,7 +210,10 @@ def rewrite_mode(client, args, logger=None):
|
|
210
210
|
|
211
211
|
# Stop live display if using stream-prettify
|
212
212
|
if args.stream_prettify and live_display:
|
213
|
-
|
213
|
+
# Before stopping the live display, update with complete=True to show final formatted content
|
214
|
+
if stream_callback and response:
|
215
|
+
stream_callback(response, complete=True)
|
216
|
+
# No need for else clause - the complete=True will handle stopping the live display
|
214
217
|
# Add a small delay to ensure terminal stability
|
215
218
|
time.sleep(0.2)
|
216
219
|
|
ngpt/cli/modes/text.py
CHANGED
@@ -74,7 +74,7 @@ def text_mode(client, args, logger=None):
|
|
74
74
|
original_callback = stream_callback
|
75
75
|
first_content_received = False
|
76
76
|
|
77
|
-
def spinner_handling_callback(content):
|
77
|
+
def spinner_handling_callback(content, **kwargs):
|
78
78
|
nonlocal first_content_received
|
79
79
|
|
80
80
|
# On first content, stop the spinner
|
@@ -88,7 +88,7 @@ def text_mode(client, args, logger=None):
|
|
88
88
|
|
89
89
|
# Call the original callback to update the display
|
90
90
|
if original_callback:
|
91
|
-
original_callback(content)
|
91
|
+
original_callback(content, **kwargs)
|
92
92
|
|
93
93
|
# Use our wrapper callback
|
94
94
|
if args.stream_prettify and live_display:
|
@@ -106,7 +106,9 @@ def text_mode(client, args, logger=None):
|
|
106
106
|
|
107
107
|
# Stop live display if using stream-prettify
|
108
108
|
if args.stream_prettify and live_display:
|
109
|
-
|
109
|
+
# Before stopping the live display, update with complete=True to show final formatted content
|
110
|
+
if stream_callback and response:
|
111
|
+
stream_callback(response, complete=True)
|
110
112
|
|
111
113
|
# Log the AI response if logging is enabled
|
112
114
|
if logger and response:
|
ngpt/cli/renderers.py
CHANGED
@@ -239,7 +239,14 @@ def prettify_streaming_markdown(renderer='rich', is_interactive=False, header_te
|
|
239
239
|
else:
|
240
240
|
md_obj = Markdown("")
|
241
241
|
|
242
|
-
#
|
242
|
+
# Get terminal dimensions for better display
|
243
|
+
term_width = shutil.get_terminal_size().columns
|
244
|
+
term_height = shutil.get_terminal_size().lines
|
245
|
+
|
246
|
+
# Use 2/3 of terminal height for content display (min 10 lines, max 30 lines)
|
247
|
+
display_height = max(10, min(30, int(term_height * 2/3)))
|
248
|
+
|
249
|
+
# Initialize the Live display (without height parameter)
|
243
250
|
live = Live(
|
244
251
|
md_obj,
|
245
252
|
console=console,
|
@@ -252,9 +259,18 @@ def prettify_streaming_markdown(renderer='rich', is_interactive=False, header_te
|
|
252
259
|
stop_spinner_event = None
|
253
260
|
spinner_thread = None
|
254
261
|
|
262
|
+
# Store the full content for final display
|
263
|
+
full_content = ""
|
264
|
+
|
255
265
|
# Define an update function that will be called with new content
|
256
|
-
def update_content(content):
|
257
|
-
nonlocal md_obj, first_update
|
266
|
+
def update_content(content, **kwargs):
|
267
|
+
nonlocal md_obj, first_update, full_content, live, display_height
|
268
|
+
|
269
|
+
# Store the full content for final display
|
270
|
+
full_content = content
|
271
|
+
|
272
|
+
# Check if this is the final update (complete flag)
|
273
|
+
is_complete = kwargs.get('complete', False)
|
258
274
|
|
259
275
|
# Start live display on first content
|
260
276
|
if first_update:
|
@@ -266,16 +282,55 @@ def prettify_streaming_markdown(renderer='rich', is_interactive=False, header_te
|
|
266
282
|
|
267
283
|
# Update content in live display
|
268
284
|
if is_interactive and header_text:
|
269
|
-
# Update the panel content
|
270
|
-
|
285
|
+
# Update the panel content - for streaming, only show the last portion that fits in display_height
|
286
|
+
if not is_complete:
|
287
|
+
# Calculate approximate lines needed (rough estimation)
|
288
|
+
content_lines = content.count('\n') + 1
|
289
|
+
available_height = display_height - 4 # Account for panel borders and padding
|
290
|
+
|
291
|
+
if content_lines > available_height:
|
292
|
+
# If content is too big, show only the last part that fits
|
293
|
+
lines = content.split('\n')
|
294
|
+
truncated_content = '\n'.join(lines[-available_height:])
|
295
|
+
md_obj.renderable = Markdown(truncated_content)
|
296
|
+
else:
|
297
|
+
md_obj.renderable = Markdown(content)
|
298
|
+
else:
|
299
|
+
md_obj.renderable = Markdown(content)
|
300
|
+
|
271
301
|
live.update(md_obj)
|
272
302
|
else:
|
273
|
-
|
303
|
+
# Same logic for non-interactive mode
|
304
|
+
if not is_complete:
|
305
|
+
# Calculate approximate lines needed
|
306
|
+
content_lines = content.count('\n') + 1
|
307
|
+
available_height = display_height - 1 # Account for minimal overhead
|
308
|
+
|
309
|
+
if content_lines > available_height:
|
310
|
+
# If content is too big, show only the last part that fits
|
311
|
+
lines = content.split('\n')
|
312
|
+
truncated_content = '\n'.join(lines[-available_height:])
|
313
|
+
md_obj = Markdown(truncated_content)
|
314
|
+
else:
|
315
|
+
md_obj = Markdown(content)
|
316
|
+
else:
|
317
|
+
md_obj = Markdown(content)
|
318
|
+
|
274
319
|
live.update(md_obj)
|
275
320
|
|
276
321
|
# Ensure the display refreshes with new content
|
277
322
|
live.refresh()
|
278
323
|
|
324
|
+
# If streaming is complete, stop the live display
|
325
|
+
if is_complete:
|
326
|
+
try:
|
327
|
+
# Just stop the live display when complete - no need to redisplay content
|
328
|
+
live.stop()
|
329
|
+
except Exception as e:
|
330
|
+
# Fallback if something goes wrong
|
331
|
+
sys.stderr.write(f"\nError stopping live display: {str(e)}\n")
|
332
|
+
sys.stderr.flush()
|
333
|
+
|
279
334
|
# Define a function to set up and start the spinner
|
280
335
|
def setup_spinner(stop_event, message="Waiting for AI response...", color=COLORS['cyan']):
|
281
336
|
nonlocal stop_spinner_event, spinner_thread
|
@@ -297,6 +352,7 @@ def prettify_streaming_markdown(renderer='rich', is_interactive=False, header_te
|
|
297
352
|
# Return a function that can be used to stop the spinner
|
298
353
|
return lambda: stop_event.set() if stop_event else None
|
299
354
|
|
355
|
+
# Return the necessary components for streaming to work
|
300
356
|
return live, update_content, setup_spinner
|
301
357
|
except Exception as e:
|
302
358
|
print(f"{COLORS['yellow']}Error setting up Rich streaming display: {str(e)}{COLORS['reset']}")
|
ngpt/utils/config.py
CHANGED
@@ -172,18 +172,19 @@ def load_config(custom_path: Optional[str] = None, config_index: int = 0, provid
|
|
172
172
|
elif len(matching_configs) > 1:
|
173
173
|
print(f"Warning: Multiple configurations found for provider '{provider}'.")
|
174
174
|
for i, idx in enumerate(matching_configs):
|
175
|
-
print(f" [{i}]
|
175
|
+
print(f" Choice [{i+1}] → Config #{idx}: {configs[idx].get('model', 'Unknown model')}")
|
176
176
|
|
177
177
|
try:
|
178
|
-
choice = input("
|
179
|
-
if choice and choice.isdigit() and
|
180
|
-
config_index = matching_configs[int(choice)]
|
178
|
+
choice = input("Enter choice number (or press Enter for the first one): ")
|
179
|
+
if choice and choice.isdigit() and 1 <= int(choice) <= len(matching_configs):
|
180
|
+
config_index = matching_configs[int(choice)-1]
|
181
|
+
print(f"Selected configuration #{config_index}.")
|
181
182
|
else:
|
182
183
|
config_index = matching_configs[0]
|
183
|
-
print(f"Using first matching configuration (
|
184
|
+
print(f"Using first matching configuration (config #{config_index}).")
|
184
185
|
except (ValueError, IndexError, KeyboardInterrupt):
|
185
186
|
config_index = matching_configs[0]
|
186
|
-
print(f"Using first matching configuration (
|
187
|
+
print(f"Using first matching configuration (config #{config_index}).")
|
187
188
|
else:
|
188
189
|
config_index = matching_configs[0]
|
189
190
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ngpt
|
3
|
-
Version: 3.
|
3
|
+
Version: 3.1.1
|
4
4
|
Summary: Swiss army knife for LLMs: powerful CLI, interactive chatbot, and flexible Python library. Works with OpenAI, Ollama, Groq, Claude, Gemini, 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
|
@@ -5,23 +5,23 @@ ngpt/cli/__init__.py,sha256=hebbDSMGiOd43YNnQP67uzr67Ue6rZPwm2czynr5iZY,43
|
|
5
5
|
ngpt/cli/args.py,sha256=XQvofZs_WkbgUto3Dbx7Yw-AmPAQHh8kdHUe3uWy8w4,11382
|
6
6
|
ngpt/cli/config_manager.py,sha256=NQQcWnjUppAAd0s0p9YAf8EyKS1ex5-0EB4DvKdB4dk,3662
|
7
7
|
ngpt/cli/formatters.py,sha256=HBYGlx_7eoAKyzfy0Vq5L0yn8yVKjngqYBukMmXCcz0,9401
|
8
|
-
ngpt/cli/interactive.py,sha256=
|
9
|
-
ngpt/cli/main.py,sha256=
|
10
|
-
ngpt/cli/renderers.py,sha256=
|
8
|
+
ngpt/cli/interactive.py,sha256=Zep4yiGRFPVrJV1zp7xB5lXg7hVhXhbRlaVA4DgRBbQ,13241
|
9
|
+
ngpt/cli/main.py,sha256=9um40RplKHSW5UHcUUO2cwMNqkGUhfQwikI1CHHFbnk,28926
|
10
|
+
ngpt/cli/renderers.py,sha256=ovV0IexZyrjCk8LK5ZGVvf5K7wCLco4jRhDv_tp6Kvw,15184
|
11
11
|
ngpt/cli/ui.py,sha256=m8qtd4cCSHBGHPUlHVdBEfun1G1Se4vLKTSgnS7QOKE,6775
|
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=oibPaN4LAqrzIbWpw--ql0TwU0u_jlLCeNuxxyO7wPg,5887
|
14
|
+
ngpt/cli/modes/code.py,sha256=AEsQKdL8mh4ImcI5R7TXzwEq_JBTkmS-L0AA_-dpHm0,5934
|
15
15
|
ngpt/cli/modes/gitcommsg.py,sha256=rsfMoeOupmNp-5p5fsMSPAf18BbzXWq-4PF2HjEz6SY,46991
|
16
|
-
ngpt/cli/modes/rewrite.py,sha256=
|
16
|
+
ngpt/cli/modes/rewrite.py,sha256=CrzUHxUoZc48D3ooVIvDbCjIIuERO1v-ddG3ajhETQs,10646
|
17
17
|
ngpt/cli/modes/shell.py,sha256=QkprnOxMMTg2v5DIwcofDnnr3JPNfuk-YgSQaae5Xps,3311
|
18
|
-
ngpt/cli/modes/text.py,sha256=
|
18
|
+
ngpt/cli/modes/text.py,sha256=vCwZnVxIbsTCLE8YVJIPwZsGgk7VRs8v-eeaVwCOZqI,4702
|
19
19
|
ngpt/utils/__init__.py,sha256=E46suk2-QgYBI0Qrs6WXOajOUOebF3ETAFY7ah8DTWs,942
|
20
20
|
ngpt/utils/cli_config.py,sha256=IlHnOEEGpLoGZInynM778wgpxLVcJ_STKWxg2Ypvir4,11196
|
21
|
-
ngpt/utils/config.py,sha256=
|
21
|
+
ngpt/utils/config.py,sha256=wsArA4osnh8fKqOvtsPqqBxAz3DpdjtaWUFaRtnUdyc,10452
|
22
22
|
ngpt/utils/log.py,sha256=f1jg2iFo35PAmsarH8FVL_62plq4VXH0Mu2QiP6RJGw,15934
|
23
|
-
ngpt-3.
|
24
|
-
ngpt-3.
|
25
|
-
ngpt-3.
|
26
|
-
ngpt-3.
|
27
|
-
ngpt-3.
|
23
|
+
ngpt-3.1.1.dist-info/METADATA,sha256=YPavkwb6Jg4oblYwYtBX3XrDmvcQWVhQZO2d9r5yByI,28992
|
24
|
+
ngpt-3.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
25
|
+
ngpt-3.1.1.dist-info/entry_points.txt,sha256=SqAAvLhMrsEpkIr4YFRdUeyuXQ9o0IBCeYgE6AVojoI,44
|
26
|
+
ngpt-3.1.1.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
|
27
|
+
ngpt-3.1.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|