ngpt 1.0.0__tar.gz
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-1.0.0/.gitignore +13 -0
- ngpt-1.0.0/.python-version +1 -0
- ngpt-1.0.0/LICENSE +21 -0
- ngpt-1.0.0/PKG-INFO +180 -0
- ngpt-1.0.0/README.md +147 -0
- ngpt-1.0.0/ngpt/__init__.py +15 -0
- ngpt-1.0.0/ngpt/cli.py +167 -0
- ngpt-1.0.0/ngpt/client.py +253 -0
- ngpt-1.0.0/ngpt/config.py +81 -0
- ngpt-1.0.0/pyproject.toml +49 -0
- ngpt-1.0.0/uv.lock +166 -0
ngpt-1.0.0/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.13
|
ngpt-1.0.0/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 nazdridoy
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
ngpt-1.0.0/PKG-INFO
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: ngpt
|
3
|
+
Version: 1.0.0
|
4
|
+
Summary: A Python CLI and library for interacting with custom OpenAI API endpoints
|
5
|
+
Project-URL: Homepage, https://github.com/nazdridoy/ngpt
|
6
|
+
Project-URL: Repository, https://github.com/nazdridoy/ngpt
|
7
|
+
Project-URL: Bug Tracker, https://github.com/nazdridoy/ngpt/issues
|
8
|
+
Author-email: nazDridoy <nazdridoy399@gmail.com>
|
9
|
+
License: MIT
|
10
|
+
License-File: LICENSE
|
11
|
+
Keywords: ai,api-client,chatgpt,cli,gpt,gpt4free,llm,ngpt,openai
|
12
|
+
Classifier: Environment :: Console
|
13
|
+
Classifier: Intended Audience :: Developers
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
15
|
+
Classifier: Intended Audience :: System Administrators
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
17
|
+
Classifier: Operating System :: OS Independent
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
19
|
+
Classifier: Programming Language :: Python :: 3.8
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
25
|
+
Classifier: Topic :: Communications :: Chat
|
26
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
27
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
28
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
29
|
+
Classifier: Topic :: Utilities
|
30
|
+
Requires-Python: >=3.8
|
31
|
+
Requires-Dist: requests>=2.28.0
|
32
|
+
Description-Content-Type: text/markdown
|
33
|
+
|
34
|
+
# nGPT
|
35
|
+
|
36
|
+
A lightweight Python CLI and library for interacting with custom OpenAI API endpoints.
|
37
|
+
|
38
|
+
## Features
|
39
|
+
|
40
|
+
- Dual mode: Use as a CLI tool or import as a library
|
41
|
+
- Minimal dependencies
|
42
|
+
- Customizable API endpoints and providers
|
43
|
+
- Streaming responses
|
44
|
+
- Web search capability (supported by compatible API endpoints)
|
45
|
+
- Cross-platform configuration system
|
46
|
+
- Experimental features:
|
47
|
+
- Shell command generation and execution (OS-aware)
|
48
|
+
- Code generation with clean output
|
49
|
+
|
50
|
+
## Installation
|
51
|
+
|
52
|
+
```bash
|
53
|
+
pip install ngpt
|
54
|
+
```
|
55
|
+
|
56
|
+
## Usage
|
57
|
+
|
58
|
+
### As a CLI Tool
|
59
|
+
|
60
|
+
```bash
|
61
|
+
# Basic chat (default mode)
|
62
|
+
ngpt "Hello, how are you?"
|
63
|
+
|
64
|
+
# Show version information
|
65
|
+
ngpt -v
|
66
|
+
|
67
|
+
# With custom options
|
68
|
+
ngpt --api-key your-key --base-url http://your-endpoint "Hello"
|
69
|
+
|
70
|
+
# Enable web search (if your API endpoint supports it)
|
71
|
+
ngpt --web-search "What's the latest news about AI?"
|
72
|
+
|
73
|
+
# Generate and execute shell commands (using -s or --shell flag)
|
74
|
+
ngpt -s "list all files in current directory"
|
75
|
+
|
76
|
+
# Generate code (using -c or --code flag)
|
77
|
+
ngpt -c "create a python function that calculates fibonacci numbers"
|
78
|
+
```
|
79
|
+
|
80
|
+
### As a Library
|
81
|
+
|
82
|
+
```python
|
83
|
+
from ngpt import NGPTClient, load_config
|
84
|
+
|
85
|
+
# Load from config file
|
86
|
+
config = load_config()
|
87
|
+
|
88
|
+
# Initialize the client with config
|
89
|
+
client = NGPTClient(**config)
|
90
|
+
|
91
|
+
# Or initialize with custom parameters
|
92
|
+
client = NGPTClient(
|
93
|
+
api_key="your-key",
|
94
|
+
base_url="http://your-endpoint",
|
95
|
+
provider="openai",
|
96
|
+
model="o3-mini"
|
97
|
+
)
|
98
|
+
|
99
|
+
# Chat
|
100
|
+
response = client.chat("Hello, how are you?")
|
101
|
+
|
102
|
+
# Chat with web search (if your API endpoint supports it)
|
103
|
+
response = client.chat("What's the latest news about AI?", web_search=True)
|
104
|
+
|
105
|
+
# Generate shell command
|
106
|
+
command = client.generate_shell_command("list all files")
|
107
|
+
|
108
|
+
# Generate code
|
109
|
+
code = client.generate_code("create a python function that calculates fibonacci numbers")
|
110
|
+
```
|
111
|
+
|
112
|
+
## Configuration
|
113
|
+
|
114
|
+
### Command Line Options
|
115
|
+
|
116
|
+
You can configure the client using the following options:
|
117
|
+
|
118
|
+
- `--api-key`: API key for the service
|
119
|
+
- `--base-url`: Base URL for the API
|
120
|
+
- `--provider`: Provider name
|
121
|
+
- `--model`: Model to use
|
122
|
+
- `--web-search`: Enable web search capability (Note: Your API endpoint must support this feature)
|
123
|
+
- `--config`: Path to a custom configuration file
|
124
|
+
|
125
|
+
### Configuration File
|
126
|
+
|
127
|
+
nGPT uses a configuration file stored in the standard user config directory for your operating system:
|
128
|
+
|
129
|
+
- **Linux**: `~/.config/ngpt/ngpt.conf` or `$XDG_CONFIG_HOME/ngpt/ngpt.conf`
|
130
|
+
- **macOS**: `~/Library/Application Support/ngpt/ngpt.conf`
|
131
|
+
- **Windows**: `%APPDATA%\ngpt\ngpt.conf`
|
132
|
+
|
133
|
+
The configuration file uses JSON format:
|
134
|
+
|
135
|
+
#### OpenAI API Example
|
136
|
+
```json
|
137
|
+
{
|
138
|
+
"api_key": "your_openai_api_key_here",
|
139
|
+
"base_url": "https://api.openai.com/v1/",
|
140
|
+
"provider": "OpenAI",
|
141
|
+
"model": "gpt-3.5-turbo"
|
142
|
+
}
|
143
|
+
```
|
144
|
+
|
145
|
+
#### Custom Endpoint Example
|
146
|
+
```json
|
147
|
+
{
|
148
|
+
"api_key": "your_api_key_here",
|
149
|
+
"base_url": "http://127.0.0.1:1337/v1/",
|
150
|
+
"provider": "Blackbox",
|
151
|
+
"model": "DeepSeek-V3"
|
152
|
+
}
|
153
|
+
```
|
154
|
+
|
155
|
+
### Configuration Priority
|
156
|
+
|
157
|
+
nGPT determines configuration values in the following order (highest priority first):
|
158
|
+
|
159
|
+
1. Command line arguments
|
160
|
+
2. Environment variables (`OPENAI_API_KEY`, `OPENAI_BASE_URL`, `OPENAI_PROVIDER`, `OPENAI_MODEL`)
|
161
|
+
3. Configuration file
|
162
|
+
4. Default values
|
163
|
+
|
164
|
+
## Special Features
|
165
|
+
|
166
|
+
### OS-Aware Shell Commands
|
167
|
+
|
168
|
+
Shell command generation is OS-aware, providing appropriate commands for your operating system (Windows, macOS, or Linux) and shell type (bash, powershell, etc.).
|
169
|
+
|
170
|
+
### Clean Code Generation
|
171
|
+
|
172
|
+
Code generation uses an improved prompt that ensures only clean code is returned, without markdown formatting or unnecessary explanations.
|
173
|
+
|
174
|
+
## Implementation Notes
|
175
|
+
|
176
|
+
This library uses direct HTTP requests instead of the OpenAI client library, allowing it to work with custom API endpoints that support additional parameters like `provider` and `web_search`. All parameters are sent directly in the request body, similar to the format shown in the curl example.
|
177
|
+
|
178
|
+
## License
|
179
|
+
|
180
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
ngpt-1.0.0/README.md
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
# nGPT
|
2
|
+
|
3
|
+
A lightweight Python CLI and library for interacting with custom OpenAI API endpoints.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
- Dual mode: Use as a CLI tool or import as a library
|
8
|
+
- Minimal dependencies
|
9
|
+
- Customizable API endpoints and providers
|
10
|
+
- Streaming responses
|
11
|
+
- Web search capability (supported by compatible API endpoints)
|
12
|
+
- Cross-platform configuration system
|
13
|
+
- Experimental features:
|
14
|
+
- Shell command generation and execution (OS-aware)
|
15
|
+
- Code generation with clean output
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
```bash
|
20
|
+
pip install ngpt
|
21
|
+
```
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
### As a CLI Tool
|
26
|
+
|
27
|
+
```bash
|
28
|
+
# Basic chat (default mode)
|
29
|
+
ngpt "Hello, how are you?"
|
30
|
+
|
31
|
+
# Show version information
|
32
|
+
ngpt -v
|
33
|
+
|
34
|
+
# With custom options
|
35
|
+
ngpt --api-key your-key --base-url http://your-endpoint "Hello"
|
36
|
+
|
37
|
+
# Enable web search (if your API endpoint supports it)
|
38
|
+
ngpt --web-search "What's the latest news about AI?"
|
39
|
+
|
40
|
+
# Generate and execute shell commands (using -s or --shell flag)
|
41
|
+
ngpt -s "list all files in current directory"
|
42
|
+
|
43
|
+
# Generate code (using -c or --code flag)
|
44
|
+
ngpt -c "create a python function that calculates fibonacci numbers"
|
45
|
+
```
|
46
|
+
|
47
|
+
### As a Library
|
48
|
+
|
49
|
+
```python
|
50
|
+
from ngpt import NGPTClient, load_config
|
51
|
+
|
52
|
+
# Load from config file
|
53
|
+
config = load_config()
|
54
|
+
|
55
|
+
# Initialize the client with config
|
56
|
+
client = NGPTClient(**config)
|
57
|
+
|
58
|
+
# Or initialize with custom parameters
|
59
|
+
client = NGPTClient(
|
60
|
+
api_key="your-key",
|
61
|
+
base_url="http://your-endpoint",
|
62
|
+
provider="openai",
|
63
|
+
model="o3-mini"
|
64
|
+
)
|
65
|
+
|
66
|
+
# Chat
|
67
|
+
response = client.chat("Hello, how are you?")
|
68
|
+
|
69
|
+
# Chat with web search (if your API endpoint supports it)
|
70
|
+
response = client.chat("What's the latest news about AI?", web_search=True)
|
71
|
+
|
72
|
+
# Generate shell command
|
73
|
+
command = client.generate_shell_command("list all files")
|
74
|
+
|
75
|
+
# Generate code
|
76
|
+
code = client.generate_code("create a python function that calculates fibonacci numbers")
|
77
|
+
```
|
78
|
+
|
79
|
+
## Configuration
|
80
|
+
|
81
|
+
### Command Line Options
|
82
|
+
|
83
|
+
You can configure the client using the following options:
|
84
|
+
|
85
|
+
- `--api-key`: API key for the service
|
86
|
+
- `--base-url`: Base URL for the API
|
87
|
+
- `--provider`: Provider name
|
88
|
+
- `--model`: Model to use
|
89
|
+
- `--web-search`: Enable web search capability (Note: Your API endpoint must support this feature)
|
90
|
+
- `--config`: Path to a custom configuration file
|
91
|
+
|
92
|
+
### Configuration File
|
93
|
+
|
94
|
+
nGPT uses a configuration file stored in the standard user config directory for your operating system:
|
95
|
+
|
96
|
+
- **Linux**: `~/.config/ngpt/ngpt.conf` or `$XDG_CONFIG_HOME/ngpt/ngpt.conf`
|
97
|
+
- **macOS**: `~/Library/Application Support/ngpt/ngpt.conf`
|
98
|
+
- **Windows**: `%APPDATA%\ngpt\ngpt.conf`
|
99
|
+
|
100
|
+
The configuration file uses JSON format:
|
101
|
+
|
102
|
+
#### OpenAI API Example
|
103
|
+
```json
|
104
|
+
{
|
105
|
+
"api_key": "your_openai_api_key_here",
|
106
|
+
"base_url": "https://api.openai.com/v1/",
|
107
|
+
"provider": "OpenAI",
|
108
|
+
"model": "gpt-3.5-turbo"
|
109
|
+
}
|
110
|
+
```
|
111
|
+
|
112
|
+
#### Custom Endpoint Example
|
113
|
+
```json
|
114
|
+
{
|
115
|
+
"api_key": "your_api_key_here",
|
116
|
+
"base_url": "http://127.0.0.1:1337/v1/",
|
117
|
+
"provider": "Blackbox",
|
118
|
+
"model": "DeepSeek-V3"
|
119
|
+
}
|
120
|
+
```
|
121
|
+
|
122
|
+
### Configuration Priority
|
123
|
+
|
124
|
+
nGPT determines configuration values in the following order (highest priority first):
|
125
|
+
|
126
|
+
1. Command line arguments
|
127
|
+
2. Environment variables (`OPENAI_API_KEY`, `OPENAI_BASE_URL`, `OPENAI_PROVIDER`, `OPENAI_MODEL`)
|
128
|
+
3. Configuration file
|
129
|
+
4. Default values
|
130
|
+
|
131
|
+
## Special Features
|
132
|
+
|
133
|
+
### OS-Aware Shell Commands
|
134
|
+
|
135
|
+
Shell command generation is OS-aware, providing appropriate commands for your operating system (Windows, macOS, or Linux) and shell type (bash, powershell, etc.).
|
136
|
+
|
137
|
+
### Clean Code Generation
|
138
|
+
|
139
|
+
Code generation uses an improved prompt that ensures only clean code is returned, without markdown formatting or unnecessary explanations.
|
140
|
+
|
141
|
+
## Implementation Notes
|
142
|
+
|
143
|
+
This library uses direct HTTP requests instead of the OpenAI client library, allowing it to work with custom API endpoints that support additional parameters like `provider` and `web_search`. All parameters are sent directly in the request body, similar to the format shown in the curl example.
|
144
|
+
|
145
|
+
## License
|
146
|
+
|
147
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
@@ -0,0 +1,15 @@
|
|
1
|
+
try:
|
2
|
+
from importlib.metadata import version as get_version
|
3
|
+
__version__ = get_version("ngpt")
|
4
|
+
except ImportError:
|
5
|
+
# For Python < 3.8 or package not installed
|
6
|
+
__version__ = "1.0.0" # fallback version
|
7
|
+
|
8
|
+
from .client import NGPTClient
|
9
|
+
from .config import load_config, get_config_path, get_config_dir
|
10
|
+
|
11
|
+
__all__ = ["NGPTClient", "__version__", "load_config", "get_config_path", "get_config_dir"]
|
12
|
+
|
13
|
+
# Import cli last to avoid circular imports
|
14
|
+
from .cli import main
|
15
|
+
__all__.append("main")
|
ngpt-1.0.0/ngpt/cli.py
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
import argparse
|
2
|
+
import sys
|
3
|
+
import os
|
4
|
+
from .client import NGPTClient
|
5
|
+
from .config import load_config, get_config_path
|
6
|
+
from . import __version__
|
7
|
+
|
8
|
+
def show_config_help():
|
9
|
+
"""Display help information about configuration."""
|
10
|
+
print("\nConfiguration Help:")
|
11
|
+
print(" 1. Create a config file at one of these locations:")
|
12
|
+
if sys.platform == "win32":
|
13
|
+
print(f" - %APPDATA%\\ngpt\\ngpt.conf")
|
14
|
+
elif sys.platform == "darwin":
|
15
|
+
print(f" - ~/Library/Application Support/ngpt/ngpt.conf")
|
16
|
+
else:
|
17
|
+
print(f" - ~/.config/ngpt/ngpt.conf")
|
18
|
+
|
19
|
+
print(" 2. Format your config file as JSON:")
|
20
|
+
print(""" {
|
21
|
+
"api_key": "your-api-key-here",
|
22
|
+
"base_url": "https://api.openai.com/v1/",
|
23
|
+
"provider": "OpenAI",
|
24
|
+
"model": "gpt-3.5-turbo"
|
25
|
+
}""")
|
26
|
+
|
27
|
+
print(" 3. Or set environment variables:")
|
28
|
+
print(" - OPENAI_API_KEY")
|
29
|
+
print(" - OPENAI_BASE_URL")
|
30
|
+
print(" - OPENAI_PROVIDER")
|
31
|
+
print(" - OPENAI_MODEL")
|
32
|
+
|
33
|
+
print(" 4. Or provide command line arguments:")
|
34
|
+
print(" ngpt --api-key your-key --base-url https://api.example.com \"Your prompt\"")
|
35
|
+
|
36
|
+
def check_config(config):
|
37
|
+
"""Check config for common issues and provide guidance."""
|
38
|
+
if not config.get("api_key"):
|
39
|
+
print("Error: API key is not set.")
|
40
|
+
show_config_help()
|
41
|
+
return False
|
42
|
+
|
43
|
+
# Check for common URL mistakes
|
44
|
+
base_url = config.get("base_url", "")
|
45
|
+
if base_url and not (base_url.startswith("http://") or base_url.startswith("https://")):
|
46
|
+
print(f"Warning: Base URL '{base_url}' doesn't start with http:// or https://")
|
47
|
+
|
48
|
+
return True
|
49
|
+
|
50
|
+
def main():
|
51
|
+
parser = argparse.ArgumentParser(description="nGPT - A CLI tool for interacting with custom OpenAI API endpoints")
|
52
|
+
|
53
|
+
# Version flag
|
54
|
+
parser.add_argument('-v', '--version', action='version', version=f'nGPT {__version__}', help='Show version information and exit')
|
55
|
+
|
56
|
+
# Config option
|
57
|
+
parser.add_argument('--config', help='Path to a custom configuration file')
|
58
|
+
|
59
|
+
# Global options
|
60
|
+
parser.add_argument('--api-key', help='API key for the service')
|
61
|
+
parser.add_argument('--base-url', help='Base URL for the API')
|
62
|
+
parser.add_argument('--provider', help='Provider name')
|
63
|
+
parser.add_argument('--model', help='Model to use')
|
64
|
+
parser.add_argument('--web-search', action='store_true',
|
65
|
+
help='Enable web search capability (Note: Your API endpoint must support this feature)')
|
66
|
+
|
67
|
+
# Mode flags (mutually exclusive)
|
68
|
+
mode_group = parser.add_mutually_exclusive_group()
|
69
|
+
mode_group.add_argument('-s', '--shell', action='store_true', help='Generate and execute shell commands')
|
70
|
+
mode_group.add_argument('-c', '--code', action='store_true', help='Generate code')
|
71
|
+
mode_group.add_argument('--show-config', action='store_true', help='Show the current configuration and exit')
|
72
|
+
|
73
|
+
# Language option for code mode
|
74
|
+
parser.add_argument('--language', default="python", help='Programming language to generate code in (for code mode)')
|
75
|
+
|
76
|
+
# Prompt argument
|
77
|
+
parser.add_argument('prompt', nargs='?', default=None, help='The prompt to send')
|
78
|
+
|
79
|
+
args = parser.parse_args()
|
80
|
+
|
81
|
+
# Load configuration
|
82
|
+
config = load_config(args.config)
|
83
|
+
|
84
|
+
# Command-line arguments override config settings
|
85
|
+
if args.api_key:
|
86
|
+
config["api_key"] = args.api_key
|
87
|
+
if args.base_url:
|
88
|
+
config["base_url"] = args.base_url
|
89
|
+
if args.provider:
|
90
|
+
config["provider"] = args.provider
|
91
|
+
if args.model:
|
92
|
+
config["model"] = args.model
|
93
|
+
|
94
|
+
# Show config if requested
|
95
|
+
if args.show_config:
|
96
|
+
config_path = get_config_path(args.config)
|
97
|
+
print(f"Configuration file: {config_path}")
|
98
|
+
print(f"API Key: {'[Set]' if config['api_key'] else '[Not Set]'}")
|
99
|
+
print(f"Base URL: {config['base_url']}")
|
100
|
+
print(f"Provider: {config['provider']}")
|
101
|
+
print(f"Model: {config['model']}")
|
102
|
+
return
|
103
|
+
|
104
|
+
# Check if prompt is required but not provided
|
105
|
+
if not args.prompt and not (args.shell or args.code):
|
106
|
+
parser.print_help()
|
107
|
+
return
|
108
|
+
|
109
|
+
# Check configuration
|
110
|
+
if not check_config(config):
|
111
|
+
return
|
112
|
+
|
113
|
+
# Initialize client
|
114
|
+
client = NGPTClient(**config)
|
115
|
+
|
116
|
+
try:
|
117
|
+
# Handle modes
|
118
|
+
if args.shell:
|
119
|
+
if args.prompt is None:
|
120
|
+
print("Enter shell command description: ", end='')
|
121
|
+
prompt = input()
|
122
|
+
else:
|
123
|
+
prompt = args.prompt
|
124
|
+
|
125
|
+
command = client.generate_shell_command(prompt, web_search=args.web_search)
|
126
|
+
if not command:
|
127
|
+
return # Error already printed by client
|
128
|
+
|
129
|
+
print(f"\nGenerated command: {command}")
|
130
|
+
|
131
|
+
print("Do you want to execute this command? [y/N] ", end='')
|
132
|
+
response = input().lower()
|
133
|
+
if response == 'y' or response == 'yes':
|
134
|
+
import subprocess
|
135
|
+
try:
|
136
|
+
result = subprocess.run(command, shell=True, check=True, capture_output=True, text=True)
|
137
|
+
print(f"\nOutput:\n{result.stdout}")
|
138
|
+
except subprocess.CalledProcessError as e:
|
139
|
+
print(f"\nError:\n{e.stderr}")
|
140
|
+
|
141
|
+
elif args.code:
|
142
|
+
if args.prompt is None:
|
143
|
+
print("Enter code description: ", end='')
|
144
|
+
prompt = input()
|
145
|
+
else:
|
146
|
+
prompt = args.prompt
|
147
|
+
|
148
|
+
generated_code = client.generate_code(prompt, args.language, web_search=args.web_search)
|
149
|
+
if generated_code:
|
150
|
+
print(f"\nGenerated code:\n{generated_code}")
|
151
|
+
|
152
|
+
else:
|
153
|
+
# Default to chat mode
|
154
|
+
if args.prompt is None:
|
155
|
+
print("Enter your prompt: ", end='')
|
156
|
+
prompt = input()
|
157
|
+
else:
|
158
|
+
prompt = args.prompt
|
159
|
+
client.chat(prompt, web_search=args.web_search)
|
160
|
+
|
161
|
+
except KeyboardInterrupt:
|
162
|
+
print("\nOperation cancelled by user.")
|
163
|
+
except Exception as e:
|
164
|
+
print(f"Error: {e}")
|
165
|
+
|
166
|
+
if __name__ == "__main__":
|
167
|
+
main()
|
@@ -0,0 +1,253 @@
|
|
1
|
+
from typing import Optional, Dict, Any, List
|
2
|
+
import os
|
3
|
+
import json
|
4
|
+
import requests
|
5
|
+
import platform
|
6
|
+
import subprocess
|
7
|
+
|
8
|
+
class NGPTClient:
|
9
|
+
def __init__(
|
10
|
+
self,
|
11
|
+
api_key: str = "",
|
12
|
+
base_url: str = "https://api.openai.com/v1/",
|
13
|
+
provider: str = "OpenAI",
|
14
|
+
model: str = "gpt-3.5-turbo"
|
15
|
+
):
|
16
|
+
self.api_key = api_key
|
17
|
+
# Ensure base_url ends with /
|
18
|
+
self.base_url = base_url if base_url.endswith('/') else base_url + '/'
|
19
|
+
self.provider = provider
|
20
|
+
self.model = model
|
21
|
+
|
22
|
+
# Default headers
|
23
|
+
self.headers = {
|
24
|
+
"Content-Type": "application/json",
|
25
|
+
"Authorization": f"Bearer {self.api_key}"
|
26
|
+
}
|
27
|
+
|
28
|
+
def chat(
|
29
|
+
self,
|
30
|
+
prompt: str,
|
31
|
+
stream: bool = True,
|
32
|
+
temperature: float = 0.7,
|
33
|
+
max_tokens: Optional[int] = None,
|
34
|
+
messages: Optional[List[Dict[str, str]]] = None,
|
35
|
+
web_search: bool = False,
|
36
|
+
**kwargs
|
37
|
+
) -> str:
|
38
|
+
"""
|
39
|
+
Send a chat message to the API and get a response.
|
40
|
+
|
41
|
+
Args:
|
42
|
+
prompt: The user's message
|
43
|
+
stream: Whether to stream the response
|
44
|
+
temperature: Controls randomness in the response
|
45
|
+
max_tokens: Maximum number of tokens to generate
|
46
|
+
messages: Optional list of message objects to override default behavior
|
47
|
+
web_search: Whether to enable web search capability
|
48
|
+
**kwargs: Additional arguments to pass to the API
|
49
|
+
|
50
|
+
Returns:
|
51
|
+
The generated response as a string
|
52
|
+
"""
|
53
|
+
if not self.api_key:
|
54
|
+
print("Error: API key is not set. Please configure your API key in the config file or provide it with --api-key.")
|
55
|
+
return ""
|
56
|
+
|
57
|
+
if messages is None:
|
58
|
+
messages = [{"role": "user", "content": prompt}]
|
59
|
+
|
60
|
+
# Prepare API parameters
|
61
|
+
payload = {
|
62
|
+
"model": self.model,
|
63
|
+
"messages": messages,
|
64
|
+
"stream": stream,
|
65
|
+
"temperature": temperature,
|
66
|
+
"provider": self.provider,
|
67
|
+
"web_search": web_search
|
68
|
+
}
|
69
|
+
|
70
|
+
# Add max_tokens if provided
|
71
|
+
if max_tokens is not None:
|
72
|
+
payload["max_tokens"] = max_tokens
|
73
|
+
|
74
|
+
# Add any additional parameters
|
75
|
+
payload.update(kwargs)
|
76
|
+
|
77
|
+
# Endpoint for chat completions
|
78
|
+
endpoint = "chat/completions"
|
79
|
+
url = f"{self.base_url}{endpoint}"
|
80
|
+
|
81
|
+
try:
|
82
|
+
if not stream:
|
83
|
+
# Regular request
|
84
|
+
response = requests.post(url, headers=self.headers, json=payload)
|
85
|
+
response.raise_for_status() # Raise exception for HTTP errors
|
86
|
+
result = response.json()
|
87
|
+
|
88
|
+
# Extract content from response
|
89
|
+
if "choices" in result and len(result["choices"]) > 0:
|
90
|
+
return result["choices"][0]["message"]["content"]
|
91
|
+
return ""
|
92
|
+
else:
|
93
|
+
# Streaming request
|
94
|
+
collected_content = ""
|
95
|
+
with requests.post(url, headers=self.headers, json=payload, stream=True) as response:
|
96
|
+
response.raise_for_status() # Raise exception for HTTP errors
|
97
|
+
|
98
|
+
for line in response.iter_lines():
|
99
|
+
if not line:
|
100
|
+
continue
|
101
|
+
|
102
|
+
# Handle SSE format
|
103
|
+
line = line.decode('utf-8')
|
104
|
+
if line.startswith('data: '):
|
105
|
+
line = line[6:] # Remove 'data: ' prefix
|
106
|
+
|
107
|
+
# Skip keep-alive lines
|
108
|
+
if line == "[DONE]":
|
109
|
+
break
|
110
|
+
|
111
|
+
try:
|
112
|
+
chunk = json.loads(line)
|
113
|
+
if "choices" in chunk and len(chunk["choices"]) > 0:
|
114
|
+
delta = chunk["choices"][0].get("delta", {})
|
115
|
+
content = delta.get("content", "")
|
116
|
+
if content:
|
117
|
+
print(content, end="", flush=True)
|
118
|
+
collected_content += content
|
119
|
+
except json.JSONDecodeError:
|
120
|
+
pass # Skip invalid JSON
|
121
|
+
|
122
|
+
print() # Add a final newline
|
123
|
+
return collected_content
|
124
|
+
|
125
|
+
except requests.exceptions.HTTPError as e:
|
126
|
+
if e.response.status_code == 401:
|
127
|
+
print("Error: Authentication failed. Please check your API key.")
|
128
|
+
elif e.response.status_code == 404:
|
129
|
+
print(f"Error: Endpoint not found at {url}")
|
130
|
+
elif e.response.status_code == 429:
|
131
|
+
print("Error: Rate limit exceeded. Please try again later.")
|
132
|
+
else:
|
133
|
+
print(f"HTTP Error: {e}")
|
134
|
+
return ""
|
135
|
+
|
136
|
+
except requests.exceptions.ConnectionError:
|
137
|
+
print(f"Error: Could not connect to {self.base_url}. Please check your internet connection and base URL.")
|
138
|
+
return ""
|
139
|
+
|
140
|
+
except requests.exceptions.Timeout:
|
141
|
+
print("Error: Request timed out. Please try again later.")
|
142
|
+
return ""
|
143
|
+
|
144
|
+
except requests.exceptions.RequestException as e:
|
145
|
+
print(f"Error: An error occurred while making the request: {e}")
|
146
|
+
return ""
|
147
|
+
|
148
|
+
except Exception as e:
|
149
|
+
print(f"Error: An unexpected error occurred: {e}")
|
150
|
+
return ""
|
151
|
+
|
152
|
+
def generate_shell_command(self, prompt: str, web_search: bool = False) -> str:
|
153
|
+
"""
|
154
|
+
Generate a shell command based on the prompt.
|
155
|
+
|
156
|
+
Args:
|
157
|
+
prompt: Description of the command to generate
|
158
|
+
web_search: Whether to enable web search capability
|
159
|
+
|
160
|
+
Returns:
|
161
|
+
The generated shell command
|
162
|
+
"""
|
163
|
+
# Check for API key first
|
164
|
+
if not self.api_key:
|
165
|
+
print("Error: API key is not set. Please configure your API key in the config file or provide it with --api-key.")
|
166
|
+
return ""
|
167
|
+
|
168
|
+
# Determine OS type
|
169
|
+
os_type = platform.system()
|
170
|
+
if os_type == "Darwin":
|
171
|
+
operating_system = "MacOS"
|
172
|
+
elif os_type == "Linux":
|
173
|
+
# Try to get Linux distribution name
|
174
|
+
try:
|
175
|
+
result = subprocess.run(["lsb_release", "-si"], capture_output=True, text=True)
|
176
|
+
distro = result.stdout.strip()
|
177
|
+
operating_system = f"Linux/{distro}" if distro else "Linux"
|
178
|
+
except:
|
179
|
+
operating_system = "Linux"
|
180
|
+
elif os_type == "Windows":
|
181
|
+
operating_system = "Windows"
|
182
|
+
else:
|
183
|
+
operating_system = os_type
|
184
|
+
|
185
|
+
# Determine shell type
|
186
|
+
if os_type == "Windows":
|
187
|
+
shell_name = "powershell.exe" if os.environ.get("PSModulePath") else "cmd.exe"
|
188
|
+
else:
|
189
|
+
shell_name = os.environ.get("SHELL", "/bin/bash")
|
190
|
+
shell_name = os.path.basename(shell_name)
|
191
|
+
|
192
|
+
system_prompt = f"""Your role: Provide only plain text without Markdown formatting. Do not show any warnings or information regarding your capabilities. Do not provide any description. If you need to store any data, assume it will be stored in the chat. Provide only {shell_name} command for {operating_system} without any description. If there is a lack of details, provide most logical solution. Ensure the output is a valid shell command. If multiple steps required try to combine them together. Prompt: {prompt}
|
193
|
+
|
194
|
+
Command:"""
|
195
|
+
|
196
|
+
messages = [
|
197
|
+
{"role": "system", "content": system_prompt},
|
198
|
+
{"role": "user", "content": prompt}
|
199
|
+
]
|
200
|
+
|
201
|
+
try:
|
202
|
+
return self.chat(
|
203
|
+
prompt=prompt,
|
204
|
+
stream=False,
|
205
|
+
messages=messages,
|
206
|
+
web_search=web_search
|
207
|
+
)
|
208
|
+
except Exception as e:
|
209
|
+
print(f"Error generating shell command: {e}")
|
210
|
+
return ""
|
211
|
+
|
212
|
+
def generate_code(self, prompt: str, language: str = "python", web_search: bool = False) -> str:
|
213
|
+
"""
|
214
|
+
Generate code based on the prompt.
|
215
|
+
|
216
|
+
Args:
|
217
|
+
prompt: Description of the code to generate
|
218
|
+
language: Programming language to generate code in
|
219
|
+
web_search: Whether to enable web search capability
|
220
|
+
|
221
|
+
Returns:
|
222
|
+
The generated code
|
223
|
+
"""
|
224
|
+
# Check for API key first
|
225
|
+
if not self.api_key:
|
226
|
+
print("Error: API key is not set. Please configure your API key in the config file or provide it with --api-key.")
|
227
|
+
return ""
|
228
|
+
|
229
|
+
system_prompt = f"""Your Role: Provide only code as output without any description.
|
230
|
+
IMPORTANT: Provide only plain text without Markdown formatting.
|
231
|
+
IMPORTANT: Do not include markdown formatting.
|
232
|
+
If there is a lack of details, provide most logical solution. You are not allowed to ask for more details.
|
233
|
+
Ignore any potential risk of errors or confusion.
|
234
|
+
|
235
|
+
Language: {language}
|
236
|
+
Request: {prompt}
|
237
|
+
Code:"""
|
238
|
+
|
239
|
+
messages = [
|
240
|
+
{"role": "system", "content": system_prompt},
|
241
|
+
{"role": "user", "content": prompt}
|
242
|
+
]
|
243
|
+
|
244
|
+
try:
|
245
|
+
return self.chat(
|
246
|
+
prompt=prompt,
|
247
|
+
stream=False,
|
248
|
+
messages=messages,
|
249
|
+
web_search=web_search
|
250
|
+
)
|
251
|
+
except Exception as e:
|
252
|
+
print(f"Error generating code: {e}")
|
253
|
+
return ""
|
@@ -0,0 +1,81 @@
|
|
1
|
+
import os
|
2
|
+
import sys
|
3
|
+
import json
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import Dict, Optional, Any
|
6
|
+
|
7
|
+
# Default configuration
|
8
|
+
DEFAULT_CONFIG = {
|
9
|
+
"api_key": "",
|
10
|
+
"base_url": "https://api.openai.com/v1/",
|
11
|
+
"provider": "OpenAI",
|
12
|
+
"model": "gpt-3.5-turbo"
|
13
|
+
}
|
14
|
+
|
15
|
+
def get_config_dir() -> Path:
|
16
|
+
"""Get the appropriate config directory based on OS."""
|
17
|
+
if sys.platform == "win32":
|
18
|
+
# Windows
|
19
|
+
config_dir = Path(os.environ.get("APPDATA", "")) / "ngpt"
|
20
|
+
elif sys.platform == "darwin":
|
21
|
+
# macOS
|
22
|
+
config_dir = Path.home() / "Library" / "Application Support" / "ngpt"
|
23
|
+
else:
|
24
|
+
# Linux and other Unix-like systems
|
25
|
+
xdg_config_home = os.environ.get("XDG_CONFIG_HOME")
|
26
|
+
if xdg_config_home:
|
27
|
+
config_dir = Path(xdg_config_home) / "ngpt"
|
28
|
+
else:
|
29
|
+
config_dir = Path.home() / ".config" / "ngpt"
|
30
|
+
|
31
|
+
# Ensure the directory exists
|
32
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
33
|
+
return config_dir
|
34
|
+
|
35
|
+
def get_config_path(custom_path: Optional[str] = None) -> Path:
|
36
|
+
"""Get the path to the config file."""
|
37
|
+
if custom_path:
|
38
|
+
return Path(custom_path)
|
39
|
+
return get_config_dir() / "ngpt.conf"
|
40
|
+
|
41
|
+
def create_default_config(config_path: Path) -> None:
|
42
|
+
"""Create a default configuration file."""
|
43
|
+
with open(config_path, "w") as f:
|
44
|
+
json.dump(DEFAULT_CONFIG, f, indent=2)
|
45
|
+
print(f"Created default configuration file at {config_path}")
|
46
|
+
|
47
|
+
def load_config(custom_path: Optional[str] = None) -> Dict[str, Any]:
|
48
|
+
"""
|
49
|
+
Load configuration from file and environment variables.
|
50
|
+
Environment variables take precedence over the config file.
|
51
|
+
"""
|
52
|
+
config_path = get_config_path(custom_path)
|
53
|
+
|
54
|
+
# Start with default config
|
55
|
+
config = DEFAULT_CONFIG.copy()
|
56
|
+
|
57
|
+
# Load from config file if it exists
|
58
|
+
if config_path.exists():
|
59
|
+
try:
|
60
|
+
with open(config_path, "r") as f:
|
61
|
+
file_config = json.load(f)
|
62
|
+
config.update(file_config)
|
63
|
+
except (json.JSONDecodeError, IOError) as e:
|
64
|
+
print(f"Warning: Could not read config file: {e}", file=sys.stderr)
|
65
|
+
else:
|
66
|
+
# Create default config file if it doesn't exist
|
67
|
+
create_default_config(config_path)
|
68
|
+
|
69
|
+
# Override with environment variables if they exist
|
70
|
+
env_mapping = {
|
71
|
+
"OPENAI_API_KEY": "api_key",
|
72
|
+
"OPENAI_BASE_URL": "base_url",
|
73
|
+
"OPENAI_PROVIDER": "provider",
|
74
|
+
"OPENAI_MODEL": "model"
|
75
|
+
}
|
76
|
+
|
77
|
+
for env_var, config_key in env_mapping.items():
|
78
|
+
if env_var in os.environ and os.environ[env_var]:
|
79
|
+
config[config_key] = os.environ[env_var]
|
80
|
+
|
81
|
+
return config
|
@@ -0,0 +1,49 @@
|
|
1
|
+
[project]
|
2
|
+
name = "ngpt"
|
3
|
+
version = "1.0.0"
|
4
|
+
description = "A Python CLI and library for interacting with custom OpenAI API endpoints"
|
5
|
+
authors = [
|
6
|
+
{name = "nazDridoy", email = "nazdridoy399@gmail.com"},
|
7
|
+
]
|
8
|
+
dependencies = [
|
9
|
+
"requests>=2.28.0",
|
10
|
+
]
|
11
|
+
requires-python = ">=3.8"
|
12
|
+
readme = "README.md"
|
13
|
+
license = {text = "MIT"}
|
14
|
+
keywords = ["openai", "cli", "api-client", "llm", "ai", "gpt", "chatgpt", "gpt4free", "ngpt"]
|
15
|
+
classifiers = [
|
16
|
+
"Programming Language :: Python :: 3",
|
17
|
+
"Programming Language :: Python :: 3.8",
|
18
|
+
"Programming Language :: Python :: 3.9",
|
19
|
+
"Programming Language :: Python :: 3.10",
|
20
|
+
"Programming Language :: Python :: 3.11",
|
21
|
+
"Programming Language :: Python :: 3.12",
|
22
|
+
"Programming Language :: Python :: 3.13",
|
23
|
+
"License :: OSI Approved :: MIT License",
|
24
|
+
"Operating System :: OS Independent",
|
25
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
26
|
+
"Topic :: Utilities",
|
27
|
+
"Topic :: Communications :: Chat",
|
28
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
29
|
+
"Topic :: Internet :: WWW/HTTP",
|
30
|
+
"Environment :: Console",
|
31
|
+
"Intended Audience :: Developers",
|
32
|
+
"Intended Audience :: End Users/Desktop",
|
33
|
+
"Intended Audience :: System Administrators",
|
34
|
+
]
|
35
|
+
|
36
|
+
[project.urls]
|
37
|
+
"Homepage" = "https://github.com/nazdridoy/ngpt"
|
38
|
+
"Repository" = "https://github.com/nazdridoy/ngpt"
|
39
|
+
"Bug Tracker" = "https://github.com/nazdridoy/ngpt/issues"
|
40
|
+
|
41
|
+
[project.scripts]
|
42
|
+
ngpt = "ngpt.cli:main"
|
43
|
+
|
44
|
+
[build-system]
|
45
|
+
requires = ["hatchling"]
|
46
|
+
build-backend = "hatchling.build"
|
47
|
+
|
48
|
+
[dependency-groups]
|
49
|
+
dev = []
|
ngpt-1.0.0/uv.lock
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
version = 1
|
2
|
+
revision = 1
|
3
|
+
requires-python = ">=3.8"
|
4
|
+
resolution-markers = [
|
5
|
+
"python_full_version >= '3.9'",
|
6
|
+
"python_full_version < '3.9'",
|
7
|
+
]
|
8
|
+
|
9
|
+
[[package]]
|
10
|
+
name = "certifi"
|
11
|
+
version = "2025.1.31"
|
12
|
+
source = { registry = "https://pypi.org/simple" }
|
13
|
+
sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 }
|
14
|
+
wheels = [
|
15
|
+
{ url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 },
|
16
|
+
]
|
17
|
+
|
18
|
+
[[package]]
|
19
|
+
name = "charset-normalizer"
|
20
|
+
version = "3.4.1"
|
21
|
+
source = { registry = "https://pypi.org/simple" }
|
22
|
+
sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 }
|
23
|
+
wheels = [
|
24
|
+
{ url = "https://files.pythonhosted.org/packages/0d/58/5580c1716040bc89206c77d8f74418caf82ce519aae06450393ca73475d1/charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", size = 198013 },
|
25
|
+
{ url = "https://files.pythonhosted.org/packages/d0/11/00341177ae71c6f5159a08168bcb98c6e6d196d372c94511f9f6c9afe0c6/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", size = 141285 },
|
26
|
+
{ url = "https://files.pythonhosted.org/packages/01/09/11d684ea5819e5a8f5100fb0b38cf8d02b514746607934134d31233e02c8/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", size = 151449 },
|
27
|
+
{ url = "https://files.pythonhosted.org/packages/08/06/9f5a12939db324d905dc1f70591ae7d7898d030d7662f0d426e2286f68c9/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", size = 143892 },
|
28
|
+
{ url = "https://files.pythonhosted.org/packages/93/62/5e89cdfe04584cb7f4d36003ffa2936681b03ecc0754f8e969c2becb7e24/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", size = 146123 },
|
29
|
+
{ url = "https://files.pythonhosted.org/packages/a9/ac/ab729a15c516da2ab70a05f8722ecfccc3f04ed7a18e45c75bbbaa347d61/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", size = 147943 },
|
30
|
+
{ url = "https://files.pythonhosted.org/packages/03/d2/3f392f23f042615689456e9a274640c1d2e5dd1d52de36ab8f7955f8f050/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", size = 142063 },
|
31
|
+
{ url = "https://files.pythonhosted.org/packages/f2/e3/e20aae5e1039a2cd9b08d9205f52142329f887f8cf70da3650326670bddf/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", size = 150578 },
|
32
|
+
{ url = "https://files.pythonhosted.org/packages/8d/af/779ad72a4da0aed925e1139d458adc486e61076d7ecdcc09e610ea8678db/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", size = 153629 },
|
33
|
+
{ url = "https://files.pythonhosted.org/packages/c2/b6/7aa450b278e7aa92cf7732140bfd8be21f5f29d5bf334ae987c945276639/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", size = 150778 },
|
34
|
+
{ url = "https://files.pythonhosted.org/packages/39/f4/d9f4f712d0951dcbfd42920d3db81b00dd23b6ab520419626f4023334056/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", size = 146453 },
|
35
|
+
{ url = "https://files.pythonhosted.org/packages/49/2b/999d0314e4ee0cff3cb83e6bc9aeddd397eeed693edb4facb901eb8fbb69/charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", size = 95479 },
|
36
|
+
{ url = "https://files.pythonhosted.org/packages/2d/ce/3cbed41cff67e455a386fb5e5dd8906cdda2ed92fbc6297921f2e4419309/charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", size = 102790 },
|
37
|
+
{ url = "https://files.pythonhosted.org/packages/72/80/41ef5d5a7935d2d3a773e3eaebf0a9350542f2cab4eac59a7a4741fbbbbe/charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", size = 194995 },
|
38
|
+
{ url = "https://files.pythonhosted.org/packages/7a/28/0b9fefa7b8b080ec492110af6d88aa3dea91c464b17d53474b6e9ba5d2c5/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", size = 139471 },
|
39
|
+
{ url = "https://files.pythonhosted.org/packages/71/64/d24ab1a997efb06402e3fc07317e94da358e2585165930d9d59ad45fcae2/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", size = 149831 },
|
40
|
+
{ url = "https://files.pythonhosted.org/packages/37/ed/be39e5258e198655240db5e19e0b11379163ad7070962d6b0c87ed2c4d39/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", size = 142335 },
|
41
|
+
{ url = "https://files.pythonhosted.org/packages/88/83/489e9504711fa05d8dde1574996408026bdbdbd938f23be67deebb5eca92/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", size = 143862 },
|
42
|
+
{ url = "https://files.pythonhosted.org/packages/c6/c7/32da20821cf387b759ad24627a9aca289d2822de929b8a41b6241767b461/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", size = 145673 },
|
43
|
+
{ url = "https://files.pythonhosted.org/packages/68/85/f4288e96039abdd5aeb5c546fa20a37b50da71b5cf01e75e87f16cd43304/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", size = 140211 },
|
44
|
+
{ url = "https://files.pythonhosted.org/packages/28/a3/a42e70d03cbdabc18997baf4f0227c73591a08041c149e710045c281f97b/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", size = 148039 },
|
45
|
+
{ url = "https://files.pythonhosted.org/packages/85/e4/65699e8ab3014ecbe6f5c71d1a55d810fb716bbfd74f6283d5c2aa87febf/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", size = 151939 },
|
46
|
+
{ url = "https://files.pythonhosted.org/packages/b1/82/8e9fe624cc5374193de6860aba3ea8070f584c8565ee77c168ec13274bd2/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", size = 149075 },
|
47
|
+
{ url = "https://files.pythonhosted.org/packages/3d/7b/82865ba54c765560c8433f65e8acb9217cb839a9e32b42af4aa8e945870f/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", size = 144340 },
|
48
|
+
{ url = "https://files.pythonhosted.org/packages/b5/b6/9674a4b7d4d99a0d2df9b215da766ee682718f88055751e1e5e753c82db0/charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", size = 95205 },
|
49
|
+
{ url = "https://files.pythonhosted.org/packages/1e/ab/45b180e175de4402dcf7547e4fb617283bae54ce35c27930a6f35b6bef15/charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", size = 102441 },
|
50
|
+
{ url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105 },
|
51
|
+
{ url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404 },
|
52
|
+
{ url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423 },
|
53
|
+
{ url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184 },
|
54
|
+
{ url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268 },
|
55
|
+
{ url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601 },
|
56
|
+
{ url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098 },
|
57
|
+
{ url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520 },
|
58
|
+
{ url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852 },
|
59
|
+
{ url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488 },
|
60
|
+
{ url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192 },
|
61
|
+
{ url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550 },
|
62
|
+
{ url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785 },
|
63
|
+
{ url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698 },
|
64
|
+
{ url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162 },
|
65
|
+
{ url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263 },
|
66
|
+
{ url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966 },
|
67
|
+
{ url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992 },
|
68
|
+
{ url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162 },
|
69
|
+
{ url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972 },
|
70
|
+
{ url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095 },
|
71
|
+
{ url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668 },
|
72
|
+
{ url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073 },
|
73
|
+
{ url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732 },
|
74
|
+
{ url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391 },
|
75
|
+
{ url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702 },
|
76
|
+
{ url = "https://files.pythonhosted.org/packages/10/bd/6517ea94f2672e801011d50b5d06be2a0deaf566aea27bcdcd47e5195357/charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c", size = 195653 },
|
77
|
+
{ url = "https://files.pythonhosted.org/packages/e5/0d/815a2ba3f283b4eeaa5ece57acade365c5b4135f65a807a083c818716582/charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9", size = 140701 },
|
78
|
+
{ url = "https://files.pythonhosted.org/packages/aa/17/c94be7ee0d142687e047fe1de72060f6d6837f40eedc26e87e6e124a3fc6/charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8", size = 150495 },
|
79
|
+
{ url = "https://files.pythonhosted.org/packages/f7/33/557ac796c47165fc141e4fb71d7b0310f67e05cb420756f3a82e0a0068e0/charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6", size = 142946 },
|
80
|
+
{ url = "https://files.pythonhosted.org/packages/1e/0d/38ef4ae41e9248d63fc4998d933cae22473b1b2ac4122cf908d0f5eb32aa/charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c", size = 144737 },
|
81
|
+
{ url = "https://files.pythonhosted.org/packages/43/01/754cdb29dd0560f58290aaaa284d43eea343ad0512e6ad3b8b5c11f08592/charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a", size = 147471 },
|
82
|
+
{ url = "https://files.pythonhosted.org/packages/ba/cd/861883ba5160c7a9bd242c30b2c71074cda2aefcc0addc91118e0d4e0765/charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd", size = 140801 },
|
83
|
+
{ url = "https://files.pythonhosted.org/packages/6f/7f/0c0dad447819e90b93f8ed238cc8f11b91353c23c19e70fa80483a155bed/charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd", size = 149312 },
|
84
|
+
{ url = "https://files.pythonhosted.org/packages/8e/09/9f8abcc6fff60fb727268b63c376c8c79cc37b833c2dfe1f535dfb59523b/charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824", size = 152347 },
|
85
|
+
{ url = "https://files.pythonhosted.org/packages/be/e5/3f363dad2e24378f88ccf63ecc39e817c29f32e308ef21a7a6d9c1201165/charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca", size = 149888 },
|
86
|
+
{ url = "https://files.pythonhosted.org/packages/e4/10/a78c0e91f487b4ad0ef7480ac765e15b774f83de2597f1b6ef0eaf7a2f99/charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b", size = 145169 },
|
87
|
+
{ url = "https://files.pythonhosted.org/packages/d3/81/396e7d7f5d7420da8273c91175d2e9a3f569288e3611d521685e4b9ac9cc/charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e", size = 95094 },
|
88
|
+
{ url = "https://files.pythonhosted.org/packages/40/bb/20affbbd9ea29c71ea123769dc568a6d42052ff5089c5fe23e21e21084a6/charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4", size = 102139 },
|
89
|
+
{ url = "https://files.pythonhosted.org/packages/7f/c0/b913f8f02836ed9ab32ea643c6fe4d3325c3d8627cf6e78098671cafff86/charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41", size = 197867 },
|
90
|
+
{ url = "https://files.pythonhosted.org/packages/0f/6c/2bee440303d705b6fb1e2ec789543edec83d32d258299b16eed28aad48e0/charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f", size = 141385 },
|
91
|
+
{ url = "https://files.pythonhosted.org/packages/3d/04/cb42585f07f6f9fd3219ffb6f37d5a39b4fd2db2355b23683060029c35f7/charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2", size = 151367 },
|
92
|
+
{ url = "https://files.pythonhosted.org/packages/54/54/2412a5b093acb17f0222de007cc129ec0e0df198b5ad2ce5699355269dfe/charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770", size = 143928 },
|
93
|
+
{ url = "https://files.pythonhosted.org/packages/5a/6d/e2773862b043dcf8a221342954f375392bb2ce6487bcd9f2c1b34e1d6781/charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4", size = 146203 },
|
94
|
+
{ url = "https://files.pythonhosted.org/packages/b9/f8/ca440ef60d8f8916022859885f231abb07ada3c347c03d63f283bec32ef5/charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537", size = 148082 },
|
95
|
+
{ url = "https://files.pythonhosted.org/packages/04/d2/42fd330901aaa4b805a1097856c2edf5095e260a597f65def493f4b8c833/charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496", size = 142053 },
|
96
|
+
{ url = "https://files.pythonhosted.org/packages/9e/af/3a97a4fa3c53586f1910dadfc916e9c4f35eeada36de4108f5096cb7215f/charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78", size = 150625 },
|
97
|
+
{ url = "https://files.pythonhosted.org/packages/26/ae/23d6041322a3556e4da139663d02fb1b3c59a23ab2e2b56432bd2ad63ded/charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7", size = 153549 },
|
98
|
+
{ url = "https://files.pythonhosted.org/packages/94/22/b8f2081c6a77cb20d97e57e0b385b481887aa08019d2459dc2858ed64871/charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6", size = 150945 },
|
99
|
+
{ url = "https://files.pythonhosted.org/packages/c7/0b/c5ec5092747f801b8b093cdf5610e732b809d6cb11f4c51e35fc28d1d389/charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294", size = 146595 },
|
100
|
+
{ url = "https://files.pythonhosted.org/packages/0c/5a/0b59704c38470df6768aa154cc87b1ac7c9bb687990a1559dc8765e8627e/charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5", size = 95453 },
|
101
|
+
{ url = "https://files.pythonhosted.org/packages/85/2d/a9790237cb4d01a6d57afadc8573c8b73c609ade20b80f4cda30802009ee/charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765", size = 102811 },
|
102
|
+
{ url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 },
|
103
|
+
]
|
104
|
+
|
105
|
+
[[package]]
|
106
|
+
name = "idna"
|
107
|
+
version = "3.10"
|
108
|
+
source = { registry = "https://pypi.org/simple" }
|
109
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 }
|
110
|
+
wheels = [
|
111
|
+
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
|
112
|
+
]
|
113
|
+
|
114
|
+
[[package]]
|
115
|
+
name = "ngpt"
|
116
|
+
version = "1.0.0"
|
117
|
+
source = { editable = "." }
|
118
|
+
dependencies = [
|
119
|
+
{ name = "requests" },
|
120
|
+
]
|
121
|
+
|
122
|
+
[package.metadata]
|
123
|
+
requires-dist = [{ name = "requests", specifier = ">=2.28.0" }]
|
124
|
+
|
125
|
+
[package.metadata.requires-dev]
|
126
|
+
dev = []
|
127
|
+
|
128
|
+
[[package]]
|
129
|
+
name = "requests"
|
130
|
+
version = "2.32.3"
|
131
|
+
source = { registry = "https://pypi.org/simple" }
|
132
|
+
dependencies = [
|
133
|
+
{ name = "certifi" },
|
134
|
+
{ name = "charset-normalizer" },
|
135
|
+
{ name = "idna" },
|
136
|
+
{ name = "urllib3", version = "2.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
|
137
|
+
{ name = "urllib3", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" },
|
138
|
+
]
|
139
|
+
sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 }
|
140
|
+
wheels = [
|
141
|
+
{ url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 },
|
142
|
+
]
|
143
|
+
|
144
|
+
[[package]]
|
145
|
+
name = "urllib3"
|
146
|
+
version = "2.2.3"
|
147
|
+
source = { registry = "https://pypi.org/simple" }
|
148
|
+
resolution-markers = [
|
149
|
+
"python_full_version < '3.9'",
|
150
|
+
]
|
151
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677 }
|
152
|
+
wheels = [
|
153
|
+
{ url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 },
|
154
|
+
]
|
155
|
+
|
156
|
+
[[package]]
|
157
|
+
name = "urllib3"
|
158
|
+
version = "2.4.0"
|
159
|
+
source = { registry = "https://pypi.org/simple" }
|
160
|
+
resolution-markers = [
|
161
|
+
"python_full_version >= '3.9'",
|
162
|
+
]
|
163
|
+
sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672 }
|
164
|
+
wheels = [
|
165
|
+
{ url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680 },
|
166
|
+
]
|