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 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
- # Note: --show-config is handled separately and implicitly acts as a mode
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.0
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,,
@@ -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