ngpt 1.1.1__py3-none-any.whl → 1.1.2__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
@@ -171,8 +171,12 @@ def main():
171
171
  # Handle modes
172
172
  if args.shell:
173
173
  if args.prompt is None:
174
- print("Enter shell command description: ", end='')
175
- prompt = input()
174
+ try:
175
+ print("Enter shell command description: ", end='')
176
+ prompt = input()
177
+ except KeyboardInterrupt:
178
+ print("\nInput cancelled by user. Exiting gracefully.")
179
+ sys.exit(130)
176
180
  else:
177
181
  prompt = args.prompt
178
182
 
@@ -182,20 +186,33 @@ def main():
182
186
 
183
187
  print(f"\nGenerated command: {command}")
184
188
 
185
- print("Do you want to execute this command? [y/N] ", end='')
186
- response = input().lower()
189
+ try:
190
+ print("Do you want to execute this command? [y/N] ", end='')
191
+ response = input().lower()
192
+ except KeyboardInterrupt:
193
+ print("\nCommand execution cancelled by user.")
194
+ return
195
+
187
196
  if response == 'y' or response == 'yes':
188
197
  import subprocess
189
198
  try:
190
- result = subprocess.run(command, shell=True, check=True, capture_output=True, text=True)
191
- print(f"\nOutput:\n{result.stdout}")
199
+ try:
200
+ print("\nExecuting command... (Press Ctrl+C to cancel)")
201
+ result = subprocess.run(command, shell=True, check=True, capture_output=True, text=True)
202
+ print(f"\nOutput:\n{result.stdout}")
203
+ except KeyboardInterrupt:
204
+ print("\nCommand execution cancelled by user.")
192
205
  except subprocess.CalledProcessError as e:
193
206
  print(f"\nError:\n{e.stderr}")
194
207
 
195
208
  elif args.code:
196
209
  if args.prompt is None:
197
- print("Enter code description: ", end='')
198
- prompt = input()
210
+ try:
211
+ print("Enter code description: ", end='')
212
+ prompt = input()
213
+ except KeyboardInterrupt:
214
+ print("\nInput cancelled by user. Exiting gracefully.")
215
+ sys.exit(130)
199
216
  else:
200
217
  prompt = args.prompt
201
218
 
@@ -206,16 +223,23 @@ def main():
206
223
  else:
207
224
  # Default to chat mode
208
225
  if args.prompt is None:
209
- print("Enter your prompt: ", end='')
210
- prompt = input()
226
+ try:
227
+ print("Enter your prompt: ", end='')
228
+ prompt = input()
229
+ except KeyboardInterrupt:
230
+ print("\nInput cancelled by user. Exiting gracefully.")
231
+ sys.exit(130)
211
232
  else:
212
233
  prompt = args.prompt
213
234
  client.chat(prompt, web_search=args.web_search)
214
235
 
215
236
  except KeyboardInterrupt:
216
- print("\nOperation cancelled by user.")
237
+ print("\nOperation cancelled by user. Exiting gracefully.")
238
+ # Make sure we exit with a non-zero status code to indicate the operation was cancelled
239
+ sys.exit(130) # 130 is the standard exit code for SIGINT (Ctrl+C)
217
240
  except Exception as e:
218
241
  print(f"Error: {e}")
242
+ sys.exit(1) # Exit with error code
219
243
 
220
244
  if __name__ == "__main__":
221
245
  main()
ngpt/client.py CHANGED
@@ -82,43 +82,51 @@ class NGPTClient:
82
82
  try:
83
83
  if not stream:
84
84
  # Regular request
85
- response = requests.post(url, headers=self.headers, json=payload)
86
- response.raise_for_status() # Raise exception for HTTP errors
87
- result = response.json()
88
-
89
- # Extract content from response
90
- if "choices" in result and len(result["choices"]) > 0:
91
- return result["choices"][0]["message"]["content"]
92
- return ""
85
+ try:
86
+ response = requests.post(url, headers=self.headers, json=payload)
87
+ response.raise_for_status() # Raise exception for HTTP errors
88
+ result = response.json()
89
+
90
+ # Extract content from response
91
+ if "choices" in result and len(result["choices"]) > 0:
92
+ return result["choices"][0]["message"]["content"]
93
+ return ""
94
+ except KeyboardInterrupt:
95
+ print("\nRequest cancelled by user.")
96
+ return ""
93
97
  else:
94
98
  # Streaming request
95
99
  collected_content = ""
96
100
  with requests.post(url, headers=self.headers, json=payload, stream=True) as response:
97
101
  response.raise_for_status() # Raise exception for HTTP errors
98
102
 
99
- for line in response.iter_lines():
100
- if not line:
101
- continue
102
-
103
- # Handle SSE format
104
- line = line.decode('utf-8')
105
- if line.startswith('data: '):
106
- line = line[6:] # Remove 'data: ' prefix
107
-
108
- # Skip keep-alive lines
109
- if line == "[DONE]":
110
- break
103
+ try:
104
+ for line in response.iter_lines():
105
+ if not line:
106
+ continue
107
+
108
+ # Handle SSE format
109
+ line = line.decode('utf-8')
110
+ if line.startswith('data: '):
111
+ line = line[6:] # Remove 'data: ' prefix
111
112
 
112
- try:
113
- chunk = json.loads(line)
114
- if "choices" in chunk and len(chunk["choices"]) > 0:
115
- delta = chunk["choices"][0].get("delta", {})
116
- content = delta.get("content", "")
117
- if content:
118
- print(content, end="", flush=True)
119
- collected_content += content
120
- except json.JSONDecodeError:
121
- pass # Skip invalid JSON
113
+ # Skip keep-alive lines
114
+ if line == "[DONE]":
115
+ break
116
+
117
+ try:
118
+ chunk = json.loads(line)
119
+ if "choices" in chunk and len(chunk["choices"]) > 0:
120
+ delta = chunk["choices"][0].get("delta", {})
121
+ content = delta.get("content", "")
122
+ if content:
123
+ print(content, end="", flush=True)
124
+ collected_content += content
125
+ except json.JSONDecodeError:
126
+ pass # Skip invalid JSON
127
+ except KeyboardInterrupt:
128
+ print("\nGeneration cancelled by user.")
129
+ return collected_content
122
130
 
123
131
  print() # Add a final newline
124
132
  return collected_content
ngpt/config.py CHANGED
@@ -56,22 +56,26 @@ def add_config_entry(config_path: Path, config_index: Optional[int] = None) -> N
56
56
 
57
57
  # Interactive configuration
58
58
  print("Enter configuration details (press Enter to use default values):")
59
- new_entry["api_key"] = input(f"API Key: ") or new_entry["api_key"]
60
- new_entry["base_url"] = input(f"Base URL [{new_entry['base_url']}]: ") or new_entry["base_url"]
61
- new_entry["provider"] = input(f"Provider [{new_entry['provider']}]: ") or new_entry["provider"]
62
- new_entry["model"] = input(f"Model [{new_entry['model']}]: ") or new_entry["model"]
63
-
64
- # Add or update the entry
65
- if config_index is not None and config_index < len(configs):
66
- configs[config_index] = new_entry
67
- print(f"Updated configuration at index {config_index}")
68
- else:
69
- configs.append(new_entry)
70
- print(f"Added new configuration at index {len(configs)-1}")
71
-
72
- # Save the updated configs
73
- with open(config_path, "w") as f:
74
- json.dump(configs, f, indent=2)
59
+ try:
60
+ new_entry["api_key"] = input(f"API Key: ") or new_entry["api_key"]
61
+ new_entry["base_url"] = input(f"Base URL [{new_entry['base_url']}]: ") or new_entry["base_url"]
62
+ new_entry["provider"] = input(f"Provider [{new_entry['provider']}]: ") or new_entry["provider"]
63
+ new_entry["model"] = input(f"Model [{new_entry['model']}]: ") or new_entry["model"]
64
+
65
+ # Add or update the entry
66
+ if config_index is not None and config_index < len(configs):
67
+ configs[config_index] = new_entry
68
+ print(f"Updated configuration at index {config_index}")
69
+ else:
70
+ configs.append(new_entry)
71
+ print(f"Added new configuration at index {len(configs)-1}")
72
+
73
+ # Save the updated configs
74
+ with open(config_path, "w") as f:
75
+ json.dump(configs, f, indent=2)
76
+ except KeyboardInterrupt:
77
+ print("\nConfiguration cancelled by user. Exiting.")
78
+ sys.exit(130) # Exit with standard keyboard interrupt code
75
79
 
76
80
  def load_configs(custom_path: Optional[str] = None) -> List[Dict[str, Any]]:
77
81
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ngpt
3
- Version: 1.1.1
3
+ Version: 1.1.2
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
@@ -0,0 +1,9 @@
1
+ ngpt/__init__.py,sha256=ehInP9w0MZlS1vZ1g6Cm4YE1ftmgF72CnEddQ3Le9n4,368
2
+ ngpt/cli.py,sha256=LIXr3NWgdsrddbcYmOxRsWYbNeKNILJZWnIkO7iCSzc,10672
3
+ ngpt/client.py,sha256=j7UCX_nkFRQJ_15ynxdu0Tj3HxxsI7Ll4__HdTbD7zE,10400
4
+ ngpt/config.py,sha256=JWCEp1aMq96i8owi4z_poKigaA_s2UTfzY0fjBM5MoQ,5295
5
+ ngpt-1.1.2.dist-info/METADATA,sha256=GBuRNy3W9JGtdH4NMHriYVOQ2KClYlczYIjmyGcK0xM,6299
6
+ ngpt-1.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
+ ngpt-1.1.2.dist-info/entry_points.txt,sha256=1cnAMujyy34DlOahrJg19lePSnb08bLbkUs_kVerqdk,39
8
+ ngpt-1.1.2.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
9
+ ngpt-1.1.2.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- ngpt/__init__.py,sha256=ehInP9w0MZlS1vZ1g6Cm4YE1ftmgF72CnEddQ3Le9n4,368
2
- ngpt/cli.py,sha256=HA85u1-ajsOBO7Zp-Hngyr4NbYxdktn-uM1VuCvy4CU,9495
3
- ngpt/client.py,sha256=DfOjE2qQQZq3JF6wNa4YxEfUALq4B0ycP_3v9ZKw2ds,9940
4
- ngpt/config.py,sha256=qkOd4pNk8pW191u4EzHORecPpRDX2yVPrMQkJ35UsNw,5063
5
- ngpt-1.1.1.dist-info/METADATA,sha256=g7JncpCt4beu2lsc3-8x7LBnQxROCcD9hMvH5IYWk8w,6299
6
- ngpt-1.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
- ngpt-1.1.1.dist-info/entry_points.txt,sha256=1cnAMujyy34DlOahrJg19lePSnb08bLbkUs_kVerqdk,39
8
- ngpt-1.1.1.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
9
- ngpt-1.1.1.dist-info/RECORD,,
File without changes