h2ogpte 1.6.41rc5__py3-none-any.whl → 1.6.43rc1__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.
Files changed (98) hide show
  1. h2ogpte/__init__.py +1 -1
  2. h2ogpte/cli/__init__.py +0 -0
  3. h2ogpte/cli/commands/__init__.py +0 -0
  4. h2ogpte/cli/commands/command_handlers/__init__.py +0 -0
  5. h2ogpte/cli/commands/command_handlers/agent.py +41 -0
  6. h2ogpte/cli/commands/command_handlers/chat.py +37 -0
  7. h2ogpte/cli/commands/command_handlers/clear.py +8 -0
  8. h2ogpte/cli/commands/command_handlers/collection.py +67 -0
  9. h2ogpte/cli/commands/command_handlers/config.py +113 -0
  10. h2ogpte/cli/commands/command_handlers/disconnect.py +36 -0
  11. h2ogpte/cli/commands/command_handlers/exit.py +37 -0
  12. h2ogpte/cli/commands/command_handlers/help.py +8 -0
  13. h2ogpte/cli/commands/command_handlers/history.py +29 -0
  14. h2ogpte/cli/commands/command_handlers/rag.py +146 -0
  15. h2ogpte/cli/commands/command_handlers/research_agent.py +45 -0
  16. h2ogpte/cli/commands/command_handlers/session.py +77 -0
  17. h2ogpte/cli/commands/command_handlers/status.py +33 -0
  18. h2ogpte/cli/commands/dispatcher.py +79 -0
  19. h2ogpte/cli/core/__init__.py +0 -0
  20. h2ogpte/cli/core/app.py +105 -0
  21. h2ogpte/cli/core/config.py +199 -0
  22. h2ogpte/cli/core/encryption.py +104 -0
  23. h2ogpte/cli/core/session.py +171 -0
  24. h2ogpte/cli/integrations/__init__.py +0 -0
  25. h2ogpte/cli/integrations/agent.py +338 -0
  26. h2ogpte/cli/integrations/rag.py +442 -0
  27. h2ogpte/cli/main.py +90 -0
  28. h2ogpte/cli/ui/__init__.py +0 -0
  29. h2ogpte/cli/ui/hbot_prompt.py +435 -0
  30. h2ogpte/cli/ui/prompts.py +129 -0
  31. h2ogpte/cli/ui/status_bar.py +133 -0
  32. h2ogpte/cli/utils/__init__.py +0 -0
  33. h2ogpte/cli/utils/file_manager.py +411 -0
  34. h2ogpte/h2ogpte.py +471 -67
  35. h2ogpte/h2ogpte_async.py +482 -68
  36. h2ogpte/h2ogpte_sync_base.py +8 -1
  37. h2ogpte/rest_async/__init__.py +6 -3
  38. h2ogpte/rest_async/api/chat_api.py +29 -0
  39. h2ogpte/rest_async/api/collections_api.py +293 -0
  40. h2ogpte/rest_async/api/extractors_api.py +2874 -70
  41. h2ogpte/rest_async/api/prompt_templates_api.py +32 -32
  42. h2ogpte/rest_async/api_client.py +1 -1
  43. h2ogpte/rest_async/configuration.py +1 -1
  44. h2ogpte/rest_async/models/__init__.py +5 -2
  45. h2ogpte/rest_async/models/chat_completion.py +4 -2
  46. h2ogpte/rest_async/models/chat_completion_delta.py +5 -3
  47. h2ogpte/rest_async/models/chat_completion_request.py +1 -1
  48. h2ogpte/rest_async/models/chat_session.py +4 -2
  49. h2ogpte/rest_async/models/chat_settings.py +1 -1
  50. h2ogpte/rest_async/models/collection.py +4 -2
  51. h2ogpte/rest_async/models/collection_create_request.py +4 -2
  52. h2ogpte/rest_async/models/create_chat_session_request.py +87 -0
  53. h2ogpte/rest_async/models/extraction_request.py +1 -1
  54. h2ogpte/rest_async/models/extractor.py +4 -2
  55. h2ogpte/rest_async/models/guardrails_settings.py +8 -4
  56. h2ogpte/rest_async/models/guardrails_settings_create_request.py +1 -1
  57. h2ogpte/rest_async/models/process_document_job_request.py +1 -1
  58. h2ogpte/rest_async/models/question_request.py +1 -1
  59. h2ogpte/rest_async/models/{reset_and_share_prompt_template_request.py → reset_and_share_request.py} +6 -6
  60. h2ogpte/{rest_sync/models/reset_and_share_prompt_template_with_groups_request.py → rest_async/models/reset_and_share_with_groups_request.py} +6 -6
  61. h2ogpte/rest_async/models/summarize_request.py +1 -1
  62. h2ogpte/rest_async/models/update_collection_workspace_request.py +87 -0
  63. h2ogpte/rest_async/models/update_extractor_privacy_request.py +87 -0
  64. h2ogpte/rest_sync/__init__.py +6 -3
  65. h2ogpte/rest_sync/api/chat_api.py +29 -0
  66. h2ogpte/rest_sync/api/collections_api.py +293 -0
  67. h2ogpte/rest_sync/api/extractors_api.py +2874 -70
  68. h2ogpte/rest_sync/api/prompt_templates_api.py +32 -32
  69. h2ogpte/rest_sync/api_client.py +1 -1
  70. h2ogpte/rest_sync/configuration.py +1 -1
  71. h2ogpte/rest_sync/models/__init__.py +5 -2
  72. h2ogpte/rest_sync/models/chat_completion.py +4 -2
  73. h2ogpte/rest_sync/models/chat_completion_delta.py +5 -3
  74. h2ogpte/rest_sync/models/chat_completion_request.py +1 -1
  75. h2ogpte/rest_sync/models/chat_session.py +4 -2
  76. h2ogpte/rest_sync/models/chat_settings.py +1 -1
  77. h2ogpte/rest_sync/models/collection.py +4 -2
  78. h2ogpte/rest_sync/models/collection_create_request.py +4 -2
  79. h2ogpte/rest_sync/models/create_chat_session_request.py +87 -0
  80. h2ogpte/rest_sync/models/extraction_request.py +1 -1
  81. h2ogpte/rest_sync/models/extractor.py +4 -2
  82. h2ogpte/rest_sync/models/guardrails_settings.py +8 -4
  83. h2ogpte/rest_sync/models/guardrails_settings_create_request.py +1 -1
  84. h2ogpte/rest_sync/models/process_document_job_request.py +1 -1
  85. h2ogpte/rest_sync/models/question_request.py +1 -1
  86. h2ogpte/rest_sync/models/{reset_and_share_prompt_template_request.py → reset_and_share_request.py} +6 -6
  87. h2ogpte/{rest_async/models/reset_and_share_prompt_template_with_groups_request.py → rest_sync/models/reset_and_share_with_groups_request.py} +6 -6
  88. h2ogpte/rest_sync/models/summarize_request.py +1 -1
  89. h2ogpte/rest_sync/models/update_collection_workspace_request.py +87 -0
  90. h2ogpte/rest_sync/models/update_extractor_privacy_request.py +87 -0
  91. h2ogpte/session.py +3 -2
  92. h2ogpte/session_async.py +22 -6
  93. h2ogpte/types.py +6 -0
  94. {h2ogpte-1.6.41rc5.dist-info → h2ogpte-1.6.43rc1.dist-info}/METADATA +5 -1
  95. {h2ogpte-1.6.41rc5.dist-info → h2ogpte-1.6.43rc1.dist-info}/RECORD +98 -59
  96. h2ogpte-1.6.43rc1.dist-info/entry_points.txt +2 -0
  97. {h2ogpte-1.6.41rc5.dist-info → h2ogpte-1.6.43rc1.dist-info}/WHEEL +0 -0
  98. {h2ogpte-1.6.41rc5.dist-info → h2ogpte-1.6.43rc1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,435 @@
1
+ import sys
2
+ import os
3
+ import termios
4
+ import tty
5
+ from typing import List, Optional, Dict
6
+ from rich.console import Console
7
+
8
+ console = Console()
9
+
10
+
11
+ class HBOTPrompt:
12
+ def __init__(self):
13
+ self.commands = {
14
+ "/help": "Show help information",
15
+ "/register": "Connect/disconnect H2OGPTE",
16
+ "/disconnect": "Disconnect and clear credentials",
17
+ "/upload": "Upload files to collection",
18
+ "/analyze": "Analyze directory",
19
+ "/agent": "Use AI agent mode",
20
+ "/research": "Deep research with AI agent",
21
+ "/config": "Configure settings",
22
+ "/status": "Show session status",
23
+ "/clear": "Clear screen",
24
+ "/exit": "Exit H2OGPTE CLI",
25
+ "/quit": "Exit H2OGPTE CLI",
26
+ "/history": "Show command history",
27
+ "/save": "Save session",
28
+ "/load": "Load session",
29
+ "/session": "Create chat session",
30
+ "/collection": "Create new collection",
31
+ }
32
+ self.max_suggestions_shown = 5
33
+ self.command_history = []
34
+ self.history_position = -1
35
+ self._status_bar = None
36
+
37
+ def getch(self):
38
+ fd = sys.stdin.fileno()
39
+ old_settings = termios.tcgetattr(fd)
40
+ try:
41
+ tty.setraw(sys.stdin.fileno())
42
+ ch = sys.stdin.read(1)
43
+ finally:
44
+ termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
45
+ return ch
46
+
47
+ def get_matching_commands(self, text: str) -> List[str]:
48
+ if not text.startswith("/"):
49
+ return []
50
+ return [cmd for cmd in self.commands.keys() if cmd.startswith(text)]
51
+
52
+ def add_to_history(self, command: str):
53
+ if command and command.strip():
54
+ # Remove if it's already the last command to avoid duplicates
55
+ if self.command_history and self.command_history[-1] == command:
56
+ return
57
+ # Remove from middle if it exists
58
+ if command in self.command_history:
59
+ self.command_history.remove(command)
60
+ # Add to end
61
+ self.command_history.append(command)
62
+ # Keep only last 100 commands
63
+ if len(self.command_history) > 100:
64
+ self.command_history = self.command_history[-100:]
65
+
66
+ def update_suggestions(self, current_text: str, selected: int = 0):
67
+ matches = self.get_matching_commands(current_text)
68
+
69
+ # Clear lines below
70
+ print("\033[J", end="")
71
+
72
+ if matches and current_text.startswith("/"):
73
+ # Show suggestions without separator - cleaner look
74
+ print() # One newline to separate from input
75
+
76
+ # Calculate scrolling window
77
+ total_matches = len(matches)
78
+
79
+ if total_matches <= self.max_suggestions_shown:
80
+ # Show all matches if they fit
81
+ start_idx = 0
82
+ end_idx = total_matches
83
+ scroll_indicator = ""
84
+ else:
85
+ # Calculate scrolling window around selected item
86
+ if selected < self.max_suggestions_shown // 2:
87
+ # Near the beginning
88
+ start_idx = 0
89
+ end_idx = self.max_suggestions_shown
90
+ elif selected >= total_matches - (self.max_suggestions_shown // 2):
91
+ # Near the end
92
+ start_idx = total_matches - self.max_suggestions_shown
93
+ end_idx = total_matches
94
+ else:
95
+ # In the middle
96
+ start_idx = selected - (self.max_suggestions_shown // 2)
97
+ end_idx = start_idx + self.max_suggestions_shown
98
+
99
+ # Create scroll indicator
100
+ scroll_indicator = (
101
+ f" \033[90m[{selected + 1}/{total_matches}] ↕ scroll\033[0m"
102
+ )
103
+
104
+ # Show the visible window of suggestions
105
+ for i in range(start_idx, end_idx):
106
+ cmd = matches[i]
107
+ desc = self.commands.get(cmd, "")
108
+ if i == selected:
109
+ # Highlighted selection
110
+ print(f"\033[K → \033[92m{cmd}\033[0m {desc}")
111
+ else:
112
+ # Normal display
113
+ print(f"\033[K \033[36m{cmd}\033[0m \033[90m{desc}\033[0m")
114
+
115
+ # Show scroll indicator if there are more items
116
+ if scroll_indicator:
117
+ print(f"\033[K{scroll_indicator}")
118
+
119
+ # Move cursor back to input line
120
+ lines_up = min(total_matches, self.max_suggestions_shown) + 1
121
+ if scroll_indicator:
122
+ lines_up += 1
123
+ print(f"\033[{lines_up}A", end="")
124
+
125
+ sys.stdout.flush()
126
+
127
+ def _show_status_bar(self):
128
+ if self._status_bar and sys.stdin.isatty():
129
+ self._status_bar.print_status_line()
130
+
131
+ def get_input(self, prompt_text: str = "❯ ") -> str:
132
+ # Non-interactive mode fallback
133
+ if not sys.stdin.isatty():
134
+ try:
135
+ user_input = input(prompt_text).strip()
136
+ return user_input if user_input else ""
137
+ except EOFError:
138
+ return "/exit"
139
+
140
+ # Show status bar right before input prompt
141
+ self._show_status_bar()
142
+
143
+ # Show prompt (no extra newline)
144
+ print(f"{prompt_text}", end="", flush=True)
145
+
146
+ current_text = ""
147
+ cursor_pos = 0
148
+ selected_suggestion = 0
149
+
150
+ while True:
151
+ char = self.getch()
152
+
153
+ # Handle special characters
154
+ if ord(char) == 3: # Ctrl+C
155
+ print("\033[J", end="") # Clear below
156
+ print() # Single newline
157
+ raise KeyboardInterrupt()
158
+
159
+ elif ord(char) == 4: # Ctrl+D
160
+ print("\033[J", end="") # Clear below
161
+ print() # Single newline
162
+ return "/exit"
163
+
164
+ elif char == "\r" or char == "\n": # Enter
165
+ matches = self.get_matching_commands(current_text)
166
+
167
+ # If there are suggestions and current text is incomplete, auto-complete first
168
+ if (
169
+ matches
170
+ and selected_suggestion < len(matches)
171
+ and current_text != matches[selected_suggestion]
172
+ ):
173
+ # Auto-complete the selected suggestion
174
+ current_text = matches[selected_suggestion]
175
+ cursor_pos = len(current_text)
176
+
177
+ # Add a space for easy argument typing
178
+ current_text += " "
179
+ cursor_pos += 1
180
+
181
+ # Redraw with the completed command
182
+ print(f"\r{prompt_text}{current_text}", end="", flush=True)
183
+
184
+ # Clear suggestions and reset selection
185
+ print("\033[J", end="")
186
+ selected_suggestion = 0
187
+ continue # Don't return, let user continue typing or press Enter again
188
+
189
+ else:
190
+ # No suggestions or already completed - execute the command
191
+ print("\033[J", end="") # Clear suggestions
192
+ print() # Single newline only
193
+ command = current_text.strip()
194
+ if command:
195
+ self.add_to_history(command)
196
+ # Reset history position for next command
197
+ self.history_position = -1
198
+ return command
199
+
200
+ elif ord(char) == 127 or ord(char) == 8: # Backspace/Delete
201
+ if cursor_pos > 0:
202
+ # Reset history position when user modifies text
203
+ self.history_position = -1
204
+
205
+ # Delete character
206
+ current_text = (
207
+ current_text[: cursor_pos - 1] + current_text[cursor_pos:]
208
+ )
209
+ cursor_pos -= 1
210
+
211
+ # Clear and redraw the line properly
212
+ print(f"\r\033[K{prompt_text}{current_text}", end="", flush=True)
213
+
214
+ # Reset selection and update suggestions
215
+ selected_suggestion = 0
216
+ self.update_suggestions(current_text, selected_suggestion)
217
+
218
+ elif char == "\t": # Tab - auto-complete
219
+ matches = self.get_matching_commands(current_text)
220
+ if matches:
221
+ current_text = (
222
+ matches[selected_suggestion]
223
+ if selected_suggestion < len(matches)
224
+ else matches[0]
225
+ )
226
+ cursor_pos = len(current_text)
227
+ print(f"\r{prompt_text}{current_text}", end="", flush=True)
228
+ selected_suggestion = 0
229
+ self.update_suggestions(current_text, selected_suggestion)
230
+
231
+ elif char == "\033": # Escape sequence (arrow keys)
232
+ next1 = self.getch()
233
+ next2 = self.getch()
234
+
235
+ if next1 == "[":
236
+ if next2 == "A": # Up arrow
237
+ if current_text == "":
238
+ # Navigate command history ONLY when text is empty
239
+ if self.command_history:
240
+ if self.history_position == -1:
241
+ # From empty, go to most recent command
242
+ self.history_position = (
243
+ len(self.command_history) - 1
244
+ )
245
+ elif self.history_position > 0:
246
+ # Go to previous command in history
247
+ self.history_position -= 1
248
+ # else: already at oldest command, stay there
249
+
250
+ if (
251
+ 0
252
+ <= self.history_position
253
+ < len(self.command_history)
254
+ ):
255
+ current_text = self.command_history[
256
+ self.history_position
257
+ ]
258
+ cursor_pos = len(current_text)
259
+ print(
260
+ f"\r{prompt_text}{current_text}",
261
+ end="",
262
+ flush=True,
263
+ )
264
+ print("\033[J", end="") # Clear suggestions
265
+ else:
266
+ # Navigate command suggestions when user has typed something
267
+ matches = self.get_matching_commands(current_text)
268
+ if matches and selected_suggestion > 0:
269
+ selected_suggestion -= 1
270
+ self.update_suggestions(
271
+ current_text, selected_suggestion
272
+ )
273
+
274
+ elif next2 == "B": # Down arrow
275
+ if current_text == "":
276
+ # Navigate command history ONLY when text is empty
277
+ if self.command_history:
278
+ if self.history_position == -1:
279
+ # From empty, can't go down further, stay empty
280
+ pass
281
+ elif (
282
+ self.history_position
283
+ < len(self.command_history) - 1
284
+ ):
285
+ # Go to next command in history
286
+ self.history_position += 1
287
+ current_text = self.command_history[
288
+ self.history_position
289
+ ]
290
+ cursor_pos = len(current_text)
291
+ print(
292
+ f"\r{prompt_text}{current_text}",
293
+ end="",
294
+ flush=True,
295
+ )
296
+ print("\033[J", end="") # Clear suggestions
297
+ else:
298
+ # At newest command, go back to empty
299
+ self.history_position = -1
300
+ current_text = ""
301
+ cursor_pos = 0
302
+ print(f"\r{prompt_text}", end="", flush=True)
303
+ print("\033[J", end="") # Clear suggestions
304
+ else:
305
+ # Navigate command suggestions when user has typed something
306
+ matches = self.get_matching_commands(current_text)
307
+ if matches and selected_suggestion < len(matches) - 1:
308
+ selected_suggestion += 1
309
+ self.update_suggestions(
310
+ current_text, selected_suggestion
311
+ )
312
+
313
+ elif next2 == "C": # Right arrow
314
+ if cursor_pos < len(current_text):
315
+ cursor_pos += 1
316
+ print("\033[C", end="", flush=True)
317
+
318
+ elif next2 == "D": # Left arrow
319
+ if cursor_pos > 0:
320
+ cursor_pos -= 1
321
+ print("\033[D", end="", flush=True)
322
+
323
+ elif char.isprintable(): # Regular character
324
+ # Reset history position when user starts typing
325
+ self.history_position = -1
326
+
327
+ # Add character
328
+ current_text = (
329
+ current_text[:cursor_pos] + char + current_text[cursor_pos:]
330
+ )
331
+ cursor_pos += 1
332
+
333
+ # Redraw line
334
+ print(f"\r{prompt_text}{current_text}", end="", flush=True)
335
+
336
+ # Reset selection and update suggestions
337
+ selected_suggestion = 0
338
+ self.update_suggestions(current_text, selected_suggestion)
339
+
340
+ def confirm(self, message: str, default: bool = False) -> bool:
341
+ """Get confirmation from user."""
342
+ if not sys.stdin.isatty():
343
+ console.print(f"{message} (non-interactive mode, using default: {default})")
344
+ return default
345
+
346
+ default_str = "Y/n" if default else "y/N"
347
+ try:
348
+ response = input(f"{message} ({default_str}): ").strip().lower()
349
+ if not response:
350
+ return default
351
+ return response in ["y", "yes", "true", "1"]
352
+ except (EOFError, KeyboardInterrupt):
353
+ return False
354
+
355
+ def select_from_list(
356
+ self, choices: List[str], message: str = "Select an option:"
357
+ ) -> str:
358
+ """Present a selection list."""
359
+ if not choices:
360
+ return ""
361
+
362
+ console.print(f"{message}")
363
+ for i, choice in enumerate(choices, 1):
364
+ console.print(f" {i}. {choice}")
365
+
366
+ while True:
367
+ try:
368
+ selection = input("Enter choice number: ").strip()
369
+ if selection.isdigit():
370
+ idx = int(selection) - 1
371
+ if 0 <= idx < len(choices):
372
+ return choices[idx]
373
+ console.print("[red]Please enter a valid number[/red]")
374
+ except (EOFError, KeyboardInterrupt):
375
+ return choices[0] if choices else ""
376
+
377
+ def get_multiselect(
378
+ self, choices: List[str], message: str = "Select options:"
379
+ ) -> List[str]:
380
+ """Present a multi-selection list."""
381
+ if not choices:
382
+ return []
383
+
384
+ console.print(f"{message}")
385
+ console.print("[dim]Enter numbers separated by commas[/dim]")
386
+ for i, choice in enumerate(choices, 1):
387
+ console.print(f" {i}. {choice}")
388
+
389
+ try:
390
+ selection = input("Enter choices: ").strip()
391
+ selected = []
392
+ for num in selection.split(","):
393
+ try:
394
+ idx = int(num.strip()) - 1
395
+ if 0 <= idx < len(choices):
396
+ selected.append(choices[idx])
397
+ except ValueError:
398
+ continue
399
+ return selected
400
+ except (EOFError, KeyboardInterrupt):
401
+ return []
402
+
403
+ def get_secret(self, message: str, default: str = "") -> str:
404
+ """Get secret input (like API keys) - doesn't go to history."""
405
+ try:
406
+ import getpass
407
+
408
+ # Use getpass to hide input
409
+ user_input = getpass.getpass(f"{message}: ").strip()
410
+ return user_input if user_input else default
411
+ except (EOFError, KeyboardInterrupt):
412
+ return ""
413
+
414
+ def get_input_with_default(self, message: str, default: str = "") -> str:
415
+ """Get input with a default value shown in prompt."""
416
+ try:
417
+ prompt_with_default = f"{message}"
418
+ if default:
419
+ prompt_with_default += f" [{default}]"
420
+ prompt_with_default += ": "
421
+
422
+ user_input = input(prompt_with_default).strip()
423
+ return user_input if user_input else default
424
+ except (EOFError, KeyboardInterrupt):
425
+ return default
426
+
427
+ def get_path(self, message: str = "Enter path:", only_directories: bool = False):
428
+ """Get a file or directory path."""
429
+ from pathlib import Path
430
+
431
+ try:
432
+ path_str = input(f"{message} ").strip()
433
+ return Path(path_str) if path_str else None
434
+ except (EOFError, KeyboardInterrupt):
435
+ return None
@@ -0,0 +1,129 @@
1
+ from rich.console import Console
2
+ from rich.panel import Panel
3
+ from rich.table import Table
4
+ from rich.syntax import Syntax
5
+ from rich.markdown import Markdown
6
+ from typing import Optional
7
+
8
+
9
+ class UIManager:
10
+ def __init__(self):
11
+ self.console = Console()
12
+ from .hbot_prompt import HBOTPrompt
13
+ from .status_bar import StatusBar
14
+
15
+ self.prompt = HBOTPrompt()
16
+ self.status_bar = StatusBar()
17
+ self.prompt._status_bar = self.status_bar
18
+
19
+ def show_welcome(self):
20
+ welcome_text = """
21
+ [bold cyan]╔═══════════════════════════════════════╗[/bold cyan]
22
+ [bold cyan]║[/bold cyan] [bold white]H2OGPTE CLI Tool[/bold white] [bold cyan]║[/bold cyan]
23
+ [bold cyan]║[/bold cyan] [dim]RAG & AI Agent Operations[/dim] [bold cyan]║[/bold cyan]
24
+ [bold cyan]╚═══════════════════════════════════════╝[/bold cyan]
25
+
26
+ [green]Type /help for commands or start typing your prompt[/green]
27
+
28
+ [dim]Live Suggestions:
29
+ • Type [white]/[/white] to see all commands below the input
30
+ • Use [white]↑↓[/white] arrows to navigate suggestions
31
+ • Press [white]Tab[/white] or [white]Enter[/white] to select[/dim]
32
+ """
33
+ self.console.print(Panel(welcome_text, border_style="cyan"))
34
+
35
+ def show_help(self):
36
+ help_table = Table(title="Available Commands", show_header=True)
37
+ help_table.add_column("Command", style="cyan", no_wrap=True)
38
+ help_table.add_column("Description", style="white")
39
+ help_table.add_column("Usage", style="dim")
40
+
41
+ commands = [
42
+ ("/help", "Show this help message", "/help"),
43
+ ("/register", "Connect to H2OGPTE", "/register [address] [api_key]"),
44
+ ("/register", "Clear credentials", "/register clear"),
45
+ ("/disconnect", "Disconnect and clear creds", "/disconnect"),
46
+ ("", "Chat with H2OGPTE (RAG)", "Type any message"),
47
+ ("/collection", "Switch/create collection", "/collection [name]"),
48
+ ("/upload", "Upload files to collection", "/upload <file_path>"),
49
+ ("/analyze", "Analyze directory", "/analyze [directory]"),
50
+ ("/agent", "Use AI agent mode", "/agent <message>"),
51
+ ("/research", "Deep research with AI agent", "/research <query>"),
52
+ ("/config", "Configure settings", "/config"),
53
+ ("/status", "Show session status", "/status"),
54
+ ("/history", "Show command history", "/history [n]"),
55
+ ("/clear", "Clear screen", "/clear"),
56
+ ("/save", "Save current session", "/save [filename]"),
57
+ ("/load", "Load saved session", "/load <filename>"),
58
+ ("/session", "Create chat session", "/session [name]"),
59
+ ("/exit", "Exit H2OGPTE CLI", "/exit [y]"),
60
+ ("/quit", "Exit H2OGPTE CLI (same as /exit)", "/quit [y]"),
61
+ ]
62
+
63
+ for cmd, desc, usage in commands:
64
+ help_table.add_row(cmd, desc, usage)
65
+
66
+ self.console.print(help_table)
67
+
68
+ shortcuts_table = Table(title="Keyboard Shortcuts", show_header=False)
69
+ shortcuts_table.add_column("Key", style="cyan")
70
+ shortcuts_table.add_column("Action", style="white")
71
+
72
+ shortcuts = [
73
+ ("Ctrl+C", "Interrupt current operation"),
74
+ ("Ctrl+D", "Exit (when line is empty)"),
75
+ ("Tab", "Autocomplete"),
76
+ ("↑/↓", "Navigate suggestions"),
77
+ ("Enter", "Select suggestion or execute"),
78
+ ]
79
+
80
+ for key, action in shortcuts:
81
+ shortcuts_table.add_row(key, action)
82
+
83
+ self.console.print(shortcuts_table)
84
+
85
+ def show_error(self, message: str, details: Optional[str] = None):
86
+ error_panel = Panel(
87
+ f"[red bold]✗ Error:[/red bold] {message}", border_style="red", expand=False
88
+ )
89
+ self.console.print(error_panel)
90
+
91
+ if details:
92
+ self.console.print(f"[dim]{details}[/dim]")
93
+
94
+ def show_success(self, message: str):
95
+ self.console.print(f"[green]✓[/green] {message}")
96
+
97
+ def show_info(self, message: str):
98
+ self.console.print(f"[blue]ℹ[/blue] {message}")
99
+
100
+ def show_warning(self, message: str):
101
+ self.console.print(f"[yellow]⚠[/yellow] {message}")
102
+
103
+ def show_code(self, code: str, language: str = "python"):
104
+ syntax = Syntax(code, language, theme="monokai", line_numbers=True)
105
+ self.console.print(Panel(syntax, title=f"[{language}]", border_style="blue"))
106
+
107
+ def show_markdown(self, content: str):
108
+ md = Markdown(content)
109
+ self.console.print(Panel(md, border_style="green"))
110
+
111
+ def clear_screen(self):
112
+ self.console.clear()
113
+
114
+ def show_status_bar(self):
115
+ self.status_bar.print_status_line()
116
+
117
+ def update_status(
118
+ self,
119
+ connected: bool = None,
120
+ username: str = None,
121
+ collection: str = None,
122
+ session: str = None,
123
+ ):
124
+ if connected is not None:
125
+ self.status_bar.update_connection_status(connected, username)
126
+ if collection is not None:
127
+ self.status_bar.update_collection(collection)
128
+ if session is not None:
129
+ self.status_bar.update_session(session)