ngpt 1.3.0__py3-none-any.whl → 1.5.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.py +143 -4
- {ngpt-1.3.0.dist-info → ngpt-1.5.1.dist-info}/METADATA +5 -1
- ngpt-1.5.1.dist-info/RECORD +9 -0
- ngpt-1.3.0.dist-info/RECORD +0 -9
- {ngpt-1.3.0.dist-info → ngpt-1.5.1.dist-info}/WHEEL +0 -0
- {ngpt-1.3.0.dist-info → ngpt-1.5.1.dist-info}/entry_points.txt +0 -0
- {ngpt-1.3.0.dist-info → ngpt-1.5.1.dist-info}/licenses/LICENSE +0 -0
ngpt/cli.py
CHANGED
@@ -103,6 +103,8 @@ def main():
|
|
103
103
|
global_group.add_argument('--model', help='Model to use')
|
104
104
|
global_group.add_argument('--web-search', action='store_true',
|
105
105
|
help='Enable web search capability (Note: Your API endpoint must support this feature)')
|
106
|
+
global_group.add_argument('-n', '--no-stream', action='store_true',
|
107
|
+
help='Return the whole response without streaming')
|
106
108
|
|
107
109
|
# Mode flags (mutually exclusive)
|
108
110
|
mode_group = parser.add_argument_group('Modes (mutually exclusive)')
|
@@ -110,7 +112,7 @@ def main():
|
|
110
112
|
mode_exclusive_group.add_argument('-s', '--shell', action='store_true', help='Generate and execute shell commands')
|
111
113
|
mode_exclusive_group.add_argument('-c', '--code', action='store_true', help='Generate code')
|
112
114
|
mode_exclusive_group.add_argument('-t', '--text', action='store_true', help='Enter multi-line text input (submit with Ctrl+D)')
|
113
|
-
|
115
|
+
mode_exclusive_group.add_argument('-i', '--interactive', action='store_true', help='Start an interactive chat session')
|
114
116
|
|
115
117
|
# Language option for code mode
|
116
118
|
parser.add_argument('--language', default="python", help='Programming language to generate code in (for code mode)')
|
@@ -228,7 +230,7 @@ def main():
|
|
228
230
|
return
|
229
231
|
|
230
232
|
# Check if prompt is required but not provided
|
231
|
-
if not args.prompt and not (args.shell or args.code or args.text):
|
233
|
+
if not args.prompt and not (args.shell or args.code or args.text or args.interactive):
|
232
234
|
parser.print_help()
|
233
235
|
return
|
234
236
|
|
@@ -277,6 +279,139 @@ def main():
|
|
277
279
|
except subprocess.CalledProcessError as e:
|
278
280
|
print(f"\nError:\n{e.stderr}")
|
279
281
|
|
282
|
+
elif args.interactive:
|
283
|
+
# Interactive chat mode
|
284
|
+
conversation_history = []
|
285
|
+
print("\033[94m\033[1m" + "Interactive Chat Mode" + "\033[0m")
|
286
|
+
print("Type your messages and press Ctrl+D to send. Type 'exit', 'quit', or use Ctrl+C to exit.")
|
287
|
+
print("Type 'clear' to start a new conversation.")
|
288
|
+
if HAS_PROMPT_TOOLKIT:
|
289
|
+
print("Use arrow keys to navigate, Enter for new line in multi-line mode.")
|
290
|
+
print()
|
291
|
+
|
292
|
+
try:
|
293
|
+
while True:
|
294
|
+
try:
|
295
|
+
# Get user input with prompt_toolkit if available
|
296
|
+
if HAS_PROMPT_TOOLKIT:
|
297
|
+
# Create key bindings
|
298
|
+
kb = KeyBindings()
|
299
|
+
|
300
|
+
# Explicitly bind Ctrl+C to exit
|
301
|
+
@kb.add('c-c')
|
302
|
+
def _(event):
|
303
|
+
event.app.exit(result=None)
|
304
|
+
print("\nExiting interactive chat mode.")
|
305
|
+
sys.exit(130)
|
306
|
+
|
307
|
+
# Explicitly bind Ctrl+D to submit
|
308
|
+
@kb.add('c-d')
|
309
|
+
def _(event):
|
310
|
+
event.app.exit(result=event.app.current_buffer.text)
|
311
|
+
|
312
|
+
# Get terminal dimensions
|
313
|
+
term_width, term_height = shutil.get_terminal_size()
|
314
|
+
|
315
|
+
# Create a styled TextArea
|
316
|
+
text_area = TextArea(
|
317
|
+
style="class:input-area",
|
318
|
+
multiline=True,
|
319
|
+
wrap_lines=True,
|
320
|
+
width=term_width - 4,
|
321
|
+
height=min(10, term_height - 8),
|
322
|
+
prompt=HTML("<ansiblue>>>> </ansiblue>"),
|
323
|
+
scrollbar=True,
|
324
|
+
focus_on_click=True,
|
325
|
+
lexer=None,
|
326
|
+
)
|
327
|
+
text_area.window.right_margins = [ScrollbarMargin(display_arrows=True)]
|
328
|
+
|
329
|
+
# Create a title bar
|
330
|
+
title_bar = FormattedTextControl(
|
331
|
+
HTML("<style bg='ansiblue' fg='ansiwhite'><b> NGPT Interactive Chat </b></style>")
|
332
|
+
)
|
333
|
+
|
334
|
+
# Create a status bar with key bindings and commands info
|
335
|
+
status_bar = FormattedTextControl(
|
336
|
+
HTML("<ansiblue><b>Ctrl+D</b></ansiblue>: Submit | <ansiblue><b>Ctrl+C</b></ansiblue>: Exit | Type <ansiblue><b>clear</b></ansiblue> to start new conversation")
|
337
|
+
)
|
338
|
+
|
339
|
+
# Create the layout
|
340
|
+
layout = Layout(
|
341
|
+
HSplit([
|
342
|
+
Window(title_bar, height=1),
|
343
|
+
Window(height=1, char="-", style="class:separator"),
|
344
|
+
text_area,
|
345
|
+
Window(height=1, char="-", style="class:separator"),
|
346
|
+
Window(status_bar, height=1),
|
347
|
+
])
|
348
|
+
)
|
349
|
+
|
350
|
+
# Create a style
|
351
|
+
style = Style.from_dict({
|
352
|
+
"separator": "ansigray",
|
353
|
+
"input-area": "bg:ansiblack fg:ansiwhite",
|
354
|
+
"cursor": "bg:ansiwhite fg:ansiblack",
|
355
|
+
})
|
356
|
+
|
357
|
+
# Create and run the application
|
358
|
+
app = Application(
|
359
|
+
layout=layout,
|
360
|
+
full_screen=False,
|
361
|
+
key_bindings=kb,
|
362
|
+
style=style,
|
363
|
+
mouse_support=True,
|
364
|
+
)
|
365
|
+
|
366
|
+
user_input = app.run()
|
367
|
+
if user_input is None:
|
368
|
+
break
|
369
|
+
else:
|
370
|
+
# Fallback to standard input
|
371
|
+
user_input = input("\033[1m\033[94m>>> \033[0m")
|
372
|
+
|
373
|
+
# Handle special commands
|
374
|
+
if user_input is None:
|
375
|
+
break
|
376
|
+
elif user_input.lower() in ['exit', 'quit', 'q']:
|
377
|
+
print("Exiting interactive chat mode.")
|
378
|
+
break
|
379
|
+
elif user_input.lower() == 'clear':
|
380
|
+
print("Starting a new conversation.")
|
381
|
+
conversation_history = []
|
382
|
+
continue
|
383
|
+
elif not user_input.strip():
|
384
|
+
continue
|
385
|
+
|
386
|
+
# Add user message to conversation history
|
387
|
+
conversation_history.append({"role": "user", "content": user_input})
|
388
|
+
|
389
|
+
# Get response from the model
|
390
|
+
print("\033[90m" + "AI is thinking..." + "\033[0m")
|
391
|
+
response = client.chat(
|
392
|
+
prompt=user_input,
|
393
|
+
stream=not args.no_stream,
|
394
|
+
messages=conversation_history,
|
395
|
+
web_search=args.web_search
|
396
|
+
)
|
397
|
+
|
398
|
+
# Add assistant message to conversation history
|
399
|
+
conversation_history.append({"role": "assistant", "content": response})
|
400
|
+
|
401
|
+
# If no streaming, print the response
|
402
|
+
if args.no_stream and response:
|
403
|
+
print("\033[92m" + response + "\033[0m")
|
404
|
+
|
405
|
+
print() # Add spacing between exchanges
|
406
|
+
|
407
|
+
except KeyboardInterrupt:
|
408
|
+
print("\nExiting interactive chat mode.")
|
409
|
+
break
|
410
|
+
|
411
|
+
except Exception as e:
|
412
|
+
print(f"\nError in interactive mode: {e}")
|
413
|
+
return
|
414
|
+
|
280
415
|
elif args.code:
|
281
416
|
if args.prompt is None:
|
282
417
|
try:
|
@@ -401,7 +536,9 @@ def main():
|
|
401
536
|
sys.exit(130)
|
402
537
|
|
403
538
|
print("\nSubmission successful. Waiting for response...")
|
404
|
-
client.chat(prompt, web_search=args.web_search)
|
539
|
+
response = client.chat(prompt, stream=not args.no_stream, web_search=args.web_search)
|
540
|
+
if args.no_stream and response:
|
541
|
+
print(response)
|
405
542
|
|
406
543
|
else:
|
407
544
|
# Default to chat mode
|
@@ -414,7 +551,9 @@ def main():
|
|
414
551
|
sys.exit(130)
|
415
552
|
else:
|
416
553
|
prompt = args.prompt
|
417
|
-
client.chat(prompt, web_search=args.web_search)
|
554
|
+
response = client.chat(prompt, stream=not args.no_stream, web_search=args.web_search)
|
555
|
+
if args.no_stream and response:
|
556
|
+
print(response)
|
418
557
|
|
419
558
|
except KeyboardInterrupt:
|
420
559
|
print("\nOperation cancelled by user. Exiting gracefully.")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ngpt
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.5.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
|
@@ -64,6 +64,9 @@ pip install ngpt
|
|
64
64
|
# Chat with default settings
|
65
65
|
ngpt "Tell me about quantum computing"
|
66
66
|
|
67
|
+
# Return response without streaming
|
68
|
+
ngpt -n "Tell me about quantum computing"
|
69
|
+
|
67
70
|
# Generate code
|
68
71
|
ngpt --code "function to calculate the Fibonacci sequence"
|
69
72
|
|
@@ -202,6 +205,7 @@ You can configure the client using the following options:
|
|
202
205
|
| `--base-url` | Base URL for the API |
|
203
206
|
| `--model` | Model to use |
|
204
207
|
| `--web-search` | Enable web search capability |
|
208
|
+
| `-n, --no-stream` | Return the whole response without streaming |
|
205
209
|
| `--config` | Path to a custom configuration file or, when used without a value, enters interactive configuration mode |
|
206
210
|
| `--config-index` | Index of the configuration to use (default: 0) |
|
207
211
|
| `--remove` | Remove the configuration at the specified index (requires --config and --config-index) |
|
@@ -0,0 +1,9 @@
|
|
1
|
+
ngpt/__init__.py,sha256=ehInP9w0MZlS1vZ1g6Cm4YE1ftmgF72CnEddQ3Le9n4,368
|
2
|
+
ngpt/cli.py,sha256=ZMBmNJfKiKAO88MecT7CDHH1uyqpupeCqGSX4-5LC_g,27117
|
3
|
+
ngpt/client.py,sha256=O0dPYeQCJlpWZWBBsroo-5UxeyBVwqC6o3Pm8lRnDiY,10329
|
4
|
+
ngpt/config.py,sha256=BF0G3QeiPma8l7EQyc37bR7LWZog7FHJQNe7uj9cr4w,6896
|
5
|
+
ngpt-1.5.1.dist-info/METADATA,sha256=eHORtsw7QD5HwfIhqRzCojOTNtfBqZ6kXCFT_8VBRq8,10086
|
6
|
+
ngpt-1.5.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
7
|
+
ngpt-1.5.1.dist-info/entry_points.txt,sha256=1cnAMujyy34DlOahrJg19lePSnb08bLbkUs_kVerqdk,39
|
8
|
+
ngpt-1.5.1.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
|
9
|
+
ngpt-1.5.1.dist-info/RECORD,,
|
ngpt-1.3.0.dist-info/RECORD
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
ngpt/__init__.py,sha256=ehInP9w0MZlS1vZ1g6Cm4YE1ftmgF72CnEddQ3Le9n4,368
|
2
|
-
ngpt/cli.py,sha256=U8A9JKOpp-GorBk9yMs2nPThSdUwm83P_e3sDgfqCYo,19880
|
3
|
-
ngpt/client.py,sha256=O0dPYeQCJlpWZWBBsroo-5UxeyBVwqC6o3Pm8lRnDiY,10329
|
4
|
-
ngpt/config.py,sha256=BF0G3QeiPma8l7EQyc37bR7LWZog7FHJQNe7uj9cr4w,6896
|
5
|
-
ngpt-1.3.0.dist-info/METADATA,sha256=mGKNDQa1ppPnBp8lXILcSGYsS_40J0TQRQWLgpF_ewQ,9939
|
6
|
-
ngpt-1.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
7
|
-
ngpt-1.3.0.dist-info/entry_points.txt,sha256=1cnAMujyy34DlOahrJg19lePSnb08bLbkUs_kVerqdk,39
|
8
|
-
ngpt-1.3.0.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
|
9
|
-
ngpt-1.3.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|