openai-pro-cli 2026.8.11.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.
- openai_pro_cli-2026.8.11.0/.env.example +9 -0
- openai_pro_cli-2026.8.11.0/CHANGELOG.md +22 -0
- openai_pro_cli-2026.8.11.0/LICENSE +21 -0
- openai_pro_cli-2026.8.11.0/PKG-INFO +144 -0
- openai_pro_cli-2026.8.11.0/README.md +99 -0
- openai_pro_cli-2026.8.11.0/openai_cli/__init__.py +3 -0
- openai_pro_cli-2026.8.11.0/openai_cli/__main__.py +6 -0
- openai_pro_cli-2026.8.11.0/openai_cli/commands/__init__.py +1 -0
- openai_pro_cli-2026.8.11.0/openai_cli/commands/_json.py +46 -0
- openai_pro_cli-2026.8.11.0/openai_cli/commands/chat.py +301 -0
- openai_pro_cli-2026.8.11.0/openai_cli/commands/embed.py +78 -0
- openai_pro_cli-2026.8.11.0/openai_cli/commands/image.py +323 -0
- openai_pro_cli-2026.8.11.0/openai_cli/commands/info.py +45 -0
- openai_pro_cli-2026.8.11.0/openai_cli/commands/realtime.py +64 -0
- openai_pro_cli-2026.8.11.0/openai_cli/commands/response.py +115 -0
- openai_pro_cli-2026.8.11.0/openai_cli/commands/speech.py +100 -0
- openai_pro_cli-2026.8.11.0/openai_cli/commands/tasks.py +136 -0
- openai_pro_cli-2026.8.11.0/openai_cli/commands/transcribe.py +124 -0
- openai_pro_cli-2026.8.11.0/openai_cli/core/__init__.py +1 -0
- openai_pro_cli-2026.8.11.0/openai_cli/core/client.py +281 -0
- openai_pro_cli-2026.8.11.0/openai_cli/core/config.py +39 -0
- openai_pro_cli-2026.8.11.0/openai_cli/core/exceptions.py +37 -0
- openai_pro_cli-2026.8.11.0/openai_cli/core/output.py +466 -0
- openai_pro_cli-2026.8.11.0/openai_cli/main.py +86 -0
- openai_pro_cli-2026.8.11.0/pyproject.toml +117 -0
- openai_pro_cli-2026.8.11.0/tests/__init__.py +1 -0
- openai_pro_cli-2026.8.11.0/tests/conftest.py +166 -0
- openai_pro_cli-2026.8.11.0/tests/test_client.py +152 -0
- openai_pro_cli-2026.8.11.0/tests/test_commands.py +1157 -0
- openai_pro_cli-2026.8.11.0/tests/test_config.py +44 -0
- openai_pro_cli-2026.8.11.0/tests/test_integration.py +19 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# AceDataCloud API Token
|
|
2
|
+
# Get yours at https://platform.acedata.cloud
|
|
3
|
+
ACEDATACLOUD_API_TOKEN=
|
|
4
|
+
|
|
5
|
+
# Optional: Custom API base URL (default: https://api.acedata.cloud)
|
|
6
|
+
# ACEDATACLOUD_API_BASE_URL=https://api.acedata.cloud
|
|
7
|
+
|
|
8
|
+
# Optional: Request timeout in seconds (default: 30)
|
|
9
|
+
# OPENAI_REQUEST_TIMEOUT=30
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.2.0] - 2026-04-30
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `chat` command: new options `--max-completion-tokens`, `--top-p`, `--frequency-penalty`, `--presence-penalty`, `--seed`, `--stop`, `--reasoning-effort`, `--user`, `--service-tier`
|
|
9
|
+
- `edit` command: new options `--mask-url`, `--partial-images`
|
|
10
|
+
- `response` command: new options `--count` (`-n`), `--response-format`
|
|
11
|
+
|
|
12
|
+
## [0.1.0] - 2025-04-25
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- Initial release
|
|
16
|
+
- `chat` command for OpenAI-compatible chat completions
|
|
17
|
+
- `embed` command for text embeddings
|
|
18
|
+
- `image` command for image generation
|
|
19
|
+
- `edit` command for image editing
|
|
20
|
+
- `response` command for Responses API
|
|
21
|
+
- `models` info command listing available models
|
|
22
|
+
- `config` command to inspect current settings
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 AceDataCloud
|
|
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.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: openai-pro-cli
|
|
3
|
+
Version: 2026.8.11.0
|
|
4
|
+
Summary: CLI tool for OpenAI-compatible APIs via AceDataCloud
|
|
5
|
+
Project-URL: Homepage, https://github.com/AceDataCloud/OpenAICli
|
|
6
|
+
Project-URL: Repository, https://github.com/AceDataCloud/OpenAICli
|
|
7
|
+
Project-URL: Issues, https://github.com/AceDataCloud/OpenAICli/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/AceDataCloud/OpenAICli/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: AceDataCloud <support@acedata.cloud>
|
|
10
|
+
Maintainer-email: AceDataCloud <support@acedata.cloud>
|
|
11
|
+
License: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: acedata,chat,cli,command-line,embeddings,gpt,image-generation,openai
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: click>=8.1.0
|
|
26
|
+
Requires-Dist: httpx>=0.27.0
|
|
27
|
+
Requires-Dist: pydantic>=2.0.0
|
|
28
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
29
|
+
Requires-Dist: rich>=13.0.0
|
|
30
|
+
Provides-Extra: all
|
|
31
|
+
Requires-Dist: openai-pro-cli[dev,release,test]; extra == 'all'
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: mypy>=1.10.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: pre-commit>=3.7.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
36
|
+
Provides-Extra: release
|
|
37
|
+
Requires-Dist: build>=1.2.0; extra == 'release'
|
|
38
|
+
Requires-Dist: twine>=6.1.0; extra == 'release'
|
|
39
|
+
Provides-Extra: test
|
|
40
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'test'
|
|
41
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == 'test'
|
|
42
|
+
Requires-Dist: pytest>=8.0.0; extra == 'test'
|
|
43
|
+
Requires-Dist: respx>=0.21.0; extra == 'test'
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
|
|
46
|
+
# OpenAI CLI
|
|
47
|
+
|
|
48
|
+
A command-line tool for OpenAI-compatible APIs via [AceDataCloud](https://platform.acedata.cloud).
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install openai-pro-cli
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
### 1. Get an API Token
|
|
59
|
+
|
|
60
|
+
Sign up at [https://platform.acedata.cloud](https://platform.acedata.cloud) and get your API token.
|
|
61
|
+
|
|
62
|
+
### 2. Configure
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
export ACEDATACLOUD_API_TOKEN=your_token_here
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Or save it to a `.env` file:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
cp .env.example .env
|
|
72
|
+
# Edit .env and set ACEDATACLOUD_API_TOKEN
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 3. Use
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# Chat with a model
|
|
79
|
+
openai-cli chat "What is the capital of France?"
|
|
80
|
+
|
|
81
|
+
# Chat with a specific model
|
|
82
|
+
openai-cli chat "Explain quantum computing" -m gpt-5.4
|
|
83
|
+
|
|
84
|
+
# Generate embeddings
|
|
85
|
+
openai-cli embed "Hello, world!" -m text-embedding-3-small
|
|
86
|
+
|
|
87
|
+
# Generate an image
|
|
88
|
+
openai-cli image "A futuristic city skyline at night"
|
|
89
|
+
|
|
90
|
+
# Edit an image
|
|
91
|
+
openai-cli edit "Add a rainbow" --image-url https://example.com/photo.jpg
|
|
92
|
+
|
|
93
|
+
# Use the Responses API
|
|
94
|
+
openai-cli response "Summarize this article" -m gpt-4o
|
|
95
|
+
|
|
96
|
+
# Synthesize speech audio
|
|
97
|
+
openai-cli speech "Hello from AceDataCloud" --voice nova --output hello.mp3
|
|
98
|
+
|
|
99
|
+
# Show realtime WebSocket connection details
|
|
100
|
+
openai-cli realtime --model gpt-realtime
|
|
101
|
+
|
|
102
|
+
# Retrieve an async task result
|
|
103
|
+
openai-cli tasks retrieve --id 7489df4c-ef03-4de0-b598-e9a590793434
|
|
104
|
+
openai-cli tasks retrieve --trace-id my-custom-trace-001
|
|
105
|
+
|
|
106
|
+
# Retrieve a batch of task results
|
|
107
|
+
openai-cli tasks batch --trace-ids trace-001 trace-002
|
|
108
|
+
|
|
109
|
+
# List available models
|
|
110
|
+
openai-cli models
|
|
111
|
+
|
|
112
|
+
# Show configuration
|
|
113
|
+
openai-cli config
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Commands
|
|
117
|
+
|
|
118
|
+
| Command | Description |
|
|
119
|
+
|---------|-------------|
|
|
120
|
+
| `chat` | Chat completions (`/openai/chat/completions`) |
|
|
121
|
+
| `embed` | Text embeddings (`/openai/embeddings`) |
|
|
122
|
+
| `image` | Image generation (`/openai/images/generations`) |
|
|
123
|
+
| `edit` | Image editing (`/openai/images/edits`) |
|
|
124
|
+
| `response` | Responses API (`/openai/responses`) |
|
|
125
|
+
| `speech` | Speech synthesis (`/v1/audio/speech`) |
|
|
126
|
+
| `realtime` | Realtime WebSocket connection info (`/v1/realtime`) |
|
|
127
|
+
| `tasks retrieve` | Retrieve a single async task result (`/openai/tasks`) |
|
|
128
|
+
| `tasks batch` | Retrieve multiple async task results (`/openai/tasks`) |
|
|
129
|
+
| `models` | List available models (`/openai/models`) |
|
|
130
|
+
| `config` | Show current configuration |
|
|
131
|
+
|
|
132
|
+
## Environment Variables
|
|
133
|
+
|
|
134
|
+
| Variable | Description | Default |
|
|
135
|
+
|----------|-------------|---------|
|
|
136
|
+
| `ACEDATACLOUD_API_TOKEN` | Your API token (required) | — |
|
|
137
|
+
| `ACEDATACLOUD_API_BASE_URL` | API base URL | `https://api.acedata.cloud` |
|
|
138
|
+
| `OPENAI_REQUEST_TIMEOUT` | Request timeout in seconds | `30` |
|
|
139
|
+
|
|
140
|
+
## Docker
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
docker compose run --rm openai-cli chat "Hello!" -m gpt-4o
|
|
144
|
+
```
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# OpenAI CLI
|
|
2
|
+
|
|
3
|
+
A command-line tool for OpenAI-compatible APIs via [AceDataCloud](https://platform.acedata.cloud).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install openai-pro-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### 1. Get an API Token
|
|
14
|
+
|
|
15
|
+
Sign up at [https://platform.acedata.cloud](https://platform.acedata.cloud) and get your API token.
|
|
16
|
+
|
|
17
|
+
### 2. Configure
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
export ACEDATACLOUD_API_TOKEN=your_token_here
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or save it to a `.env` file:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
cp .env.example .env
|
|
27
|
+
# Edit .env and set ACEDATACLOUD_API_TOKEN
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 3. Use
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Chat with a model
|
|
34
|
+
openai-cli chat "What is the capital of France?"
|
|
35
|
+
|
|
36
|
+
# Chat with a specific model
|
|
37
|
+
openai-cli chat "Explain quantum computing" -m gpt-5.4
|
|
38
|
+
|
|
39
|
+
# Generate embeddings
|
|
40
|
+
openai-cli embed "Hello, world!" -m text-embedding-3-small
|
|
41
|
+
|
|
42
|
+
# Generate an image
|
|
43
|
+
openai-cli image "A futuristic city skyline at night"
|
|
44
|
+
|
|
45
|
+
# Edit an image
|
|
46
|
+
openai-cli edit "Add a rainbow" --image-url https://example.com/photo.jpg
|
|
47
|
+
|
|
48
|
+
# Use the Responses API
|
|
49
|
+
openai-cli response "Summarize this article" -m gpt-4o
|
|
50
|
+
|
|
51
|
+
# Synthesize speech audio
|
|
52
|
+
openai-cli speech "Hello from AceDataCloud" --voice nova --output hello.mp3
|
|
53
|
+
|
|
54
|
+
# Show realtime WebSocket connection details
|
|
55
|
+
openai-cli realtime --model gpt-realtime
|
|
56
|
+
|
|
57
|
+
# Retrieve an async task result
|
|
58
|
+
openai-cli tasks retrieve --id 7489df4c-ef03-4de0-b598-e9a590793434
|
|
59
|
+
openai-cli tasks retrieve --trace-id my-custom-trace-001
|
|
60
|
+
|
|
61
|
+
# Retrieve a batch of task results
|
|
62
|
+
openai-cli tasks batch --trace-ids trace-001 trace-002
|
|
63
|
+
|
|
64
|
+
# List available models
|
|
65
|
+
openai-cli models
|
|
66
|
+
|
|
67
|
+
# Show configuration
|
|
68
|
+
openai-cli config
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Commands
|
|
72
|
+
|
|
73
|
+
| Command | Description |
|
|
74
|
+
|---------|-------------|
|
|
75
|
+
| `chat` | Chat completions (`/openai/chat/completions`) |
|
|
76
|
+
| `embed` | Text embeddings (`/openai/embeddings`) |
|
|
77
|
+
| `image` | Image generation (`/openai/images/generations`) |
|
|
78
|
+
| `edit` | Image editing (`/openai/images/edits`) |
|
|
79
|
+
| `response` | Responses API (`/openai/responses`) |
|
|
80
|
+
| `speech` | Speech synthesis (`/v1/audio/speech`) |
|
|
81
|
+
| `realtime` | Realtime WebSocket connection info (`/v1/realtime`) |
|
|
82
|
+
| `tasks retrieve` | Retrieve a single async task result (`/openai/tasks`) |
|
|
83
|
+
| `tasks batch` | Retrieve multiple async task results (`/openai/tasks`) |
|
|
84
|
+
| `models` | List available models (`/openai/models`) |
|
|
85
|
+
| `config` | Show current configuration |
|
|
86
|
+
|
|
87
|
+
## Environment Variables
|
|
88
|
+
|
|
89
|
+
| Variable | Description | Default |
|
|
90
|
+
|----------|-------------|---------|
|
|
91
|
+
| `ACEDATACLOUD_API_TOKEN` | Your API token (required) | — |
|
|
92
|
+
| `ACEDATACLOUD_API_BASE_URL` | API base URL | `https://api.acedata.cloud` |
|
|
93
|
+
| `OPENAI_REQUEST_TIMEOUT` | Request timeout in seconds | `30` |
|
|
94
|
+
|
|
95
|
+
## Docker
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
docker compose run --rm openai-cli chat "Hello!" -m gpt-4o
|
|
99
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""OpenAI CLI commands package."""
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Helpers for parsing JSON-valued CLI options."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def parse_json_value(value: str | None, option_name: str) -> Any:
|
|
10
|
+
"""Parse a CLI option as JSON."""
|
|
11
|
+
if value is None:
|
|
12
|
+
return None
|
|
13
|
+
try:
|
|
14
|
+
return json.loads(value)
|
|
15
|
+
except json.JSONDecodeError as exc:
|
|
16
|
+
raise click.BadParameter(f"{option_name} must be valid JSON.") from exc
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def parse_json_object(value: str | None, option_name: str) -> dict[str, Any] | None:
|
|
20
|
+
"""Parse a CLI option as a JSON object."""
|
|
21
|
+
parsed = parse_json_value(value, option_name)
|
|
22
|
+
if parsed is None:
|
|
23
|
+
return None
|
|
24
|
+
if not isinstance(parsed, dict):
|
|
25
|
+
raise click.BadParameter(f"{option_name} must be a JSON object.")
|
|
26
|
+
return parsed
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def parse_json_array(value: str | None, option_name: str) -> list[Any] | None:
|
|
30
|
+
"""Parse a CLI option as a JSON array."""
|
|
31
|
+
parsed = parse_json_value(value, option_name)
|
|
32
|
+
if parsed is None:
|
|
33
|
+
return None
|
|
34
|
+
if not isinstance(parsed, list):
|
|
35
|
+
raise click.BadParameter(f"{option_name} must be a JSON array.")
|
|
36
|
+
return parsed
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def parse_json_or_string(value: str | None, option_name: str) -> Any:
|
|
40
|
+
"""Parse JSON when possible, otherwise keep plain strings."""
|
|
41
|
+
if value is None:
|
|
42
|
+
return None
|
|
43
|
+
stripped = value.strip()
|
|
44
|
+
if stripped.startswith("{") or stripped.startswith("["):
|
|
45
|
+
return parse_json_value(value, option_name)
|
|
46
|
+
return value
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"""Chat completion command."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from openai_cli.commands._json import (
|
|
6
|
+
parse_json_array,
|
|
7
|
+
parse_json_object,
|
|
8
|
+
parse_json_or_string,
|
|
9
|
+
)
|
|
10
|
+
from openai_cli.core.client import get_client
|
|
11
|
+
from openai_cli.core.exceptions import OpenAIError
|
|
12
|
+
from openai_cli.core.output import (
|
|
13
|
+
CHAT_MODELS,
|
|
14
|
+
DEFAULT_CHAT_MODEL,
|
|
15
|
+
print_chat_result,
|
|
16
|
+
print_error,
|
|
17
|
+
print_json,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@click.command()
|
|
22
|
+
@click.argument("prompt")
|
|
23
|
+
@click.option(
|
|
24
|
+
"-m",
|
|
25
|
+
"--model",
|
|
26
|
+
type=click.Choice(CHAT_MODELS),
|
|
27
|
+
default=DEFAULT_CHAT_MODEL,
|
|
28
|
+
show_default=True,
|
|
29
|
+
help="Model to use for chat completion.",
|
|
30
|
+
)
|
|
31
|
+
@click.option(
|
|
32
|
+
"-s",
|
|
33
|
+
"--system",
|
|
34
|
+
default=None,
|
|
35
|
+
help="System prompt to set the assistant's behavior.",
|
|
36
|
+
)
|
|
37
|
+
@click.option(
|
|
38
|
+
"--temperature",
|
|
39
|
+
default=None,
|
|
40
|
+
type=float,
|
|
41
|
+
help="Sampling temperature (0-2). Higher values = more random.",
|
|
42
|
+
)
|
|
43
|
+
@click.option(
|
|
44
|
+
"--max-tokens",
|
|
45
|
+
default=None,
|
|
46
|
+
type=int,
|
|
47
|
+
help="Maximum number of tokens to generate.",
|
|
48
|
+
)
|
|
49
|
+
@click.option(
|
|
50
|
+
"--max-completion-tokens",
|
|
51
|
+
default=None,
|
|
52
|
+
type=int,
|
|
53
|
+
help="Upper bound for tokens generated in a completion (including reasoning tokens).",
|
|
54
|
+
)
|
|
55
|
+
@click.option(
|
|
56
|
+
"-n",
|
|
57
|
+
"--count",
|
|
58
|
+
default=None,
|
|
59
|
+
type=int,
|
|
60
|
+
help="Number of completion choices to generate.",
|
|
61
|
+
)
|
|
62
|
+
@click.option(
|
|
63
|
+
"--top-p",
|
|
64
|
+
default=None,
|
|
65
|
+
type=float,
|
|
66
|
+
help="Nucleus sampling probability mass (0-1). Alternative to temperature.",
|
|
67
|
+
)
|
|
68
|
+
@click.option(
|
|
69
|
+
"--frequency-penalty",
|
|
70
|
+
default=None,
|
|
71
|
+
type=float,
|
|
72
|
+
help="Penalize tokens by their frequency in the text so far (-2.0 to 2.0).",
|
|
73
|
+
)
|
|
74
|
+
@click.option(
|
|
75
|
+
"--presence-penalty",
|
|
76
|
+
default=None,
|
|
77
|
+
type=float,
|
|
78
|
+
help="Penalize tokens that have already appeared in the text (-2.0 to 2.0).",
|
|
79
|
+
)
|
|
80
|
+
@click.option(
|
|
81
|
+
"--seed",
|
|
82
|
+
default=None,
|
|
83
|
+
type=int,
|
|
84
|
+
help="Seed for deterministic sampling.",
|
|
85
|
+
)
|
|
86
|
+
@click.option(
|
|
87
|
+
"--stop",
|
|
88
|
+
default=None,
|
|
89
|
+
multiple=True,
|
|
90
|
+
help="Stop sequence(s) where the API will stop generating (repeatable, up to 4).",
|
|
91
|
+
)
|
|
92
|
+
@click.option(
|
|
93
|
+
"--reasoning-effort",
|
|
94
|
+
type=click.Choice(["minimal", "low", "medium", "high"]),
|
|
95
|
+
default=None,
|
|
96
|
+
help="Reasoning effort for o1/o3/o4/gpt-5 series models.",
|
|
97
|
+
)
|
|
98
|
+
@click.option(
|
|
99
|
+
"--user",
|
|
100
|
+
default=None,
|
|
101
|
+
help="Unique end-user identifier for monitoring and abuse detection.",
|
|
102
|
+
)
|
|
103
|
+
@click.option(
|
|
104
|
+
"--service-tier",
|
|
105
|
+
type=click.Choice(["auto", "default", "flex", "scale", "priority"]),
|
|
106
|
+
default=None,
|
|
107
|
+
help="Processing type for serving the request (auto, default, flex, scale, priority).",
|
|
108
|
+
)
|
|
109
|
+
@click.option(
|
|
110
|
+
"--store",
|
|
111
|
+
is_flag=True,
|
|
112
|
+
default=False,
|
|
113
|
+
help="Store the output for use in OpenAI's model distillation or evals products.",
|
|
114
|
+
)
|
|
115
|
+
@click.option(
|
|
116
|
+
"--logprobs",
|
|
117
|
+
is_flag=True,
|
|
118
|
+
default=False,
|
|
119
|
+
help="Return log probabilities of the output tokens.",
|
|
120
|
+
)
|
|
121
|
+
@click.option(
|
|
122
|
+
"--top-logprobs",
|
|
123
|
+
default=None,
|
|
124
|
+
type=click.IntRange(0, 20),
|
|
125
|
+
help="Number of most likely tokens (0-20) to return at each token position with log probabilities.",
|
|
126
|
+
)
|
|
127
|
+
@click.option(
|
|
128
|
+
"--parallel-tool-calls",
|
|
129
|
+
"parallel_tool_calls",
|
|
130
|
+
flag_value=True,
|
|
131
|
+
default=None,
|
|
132
|
+
help="Enable parallel function calling during tool use.",
|
|
133
|
+
)
|
|
134
|
+
@click.option(
|
|
135
|
+
"--no-parallel-tool-calls",
|
|
136
|
+
"parallel_tool_calls",
|
|
137
|
+
flag_value=False,
|
|
138
|
+
help="Disable parallel function calling during tool use.",
|
|
139
|
+
)
|
|
140
|
+
@click.option(
|
|
141
|
+
"--stream", is_flag=True, default=False, help="Stream partial chat completion events."
|
|
142
|
+
)
|
|
143
|
+
@click.option(
|
|
144
|
+
"--response-format",
|
|
145
|
+
default=None,
|
|
146
|
+
help='Response format as JSON (e.g. \'{"type": "json_schema", "json_schema": {...}}\').',
|
|
147
|
+
)
|
|
148
|
+
@click.option(
|
|
149
|
+
"--tools",
|
|
150
|
+
default=None,
|
|
151
|
+
help='Tool definitions as a JSON array (e.g. \'[{"type":"function","function":{...}}]\').',
|
|
152
|
+
)
|
|
153
|
+
@click.option(
|
|
154
|
+
"--tool-choice",
|
|
155
|
+
default=None,
|
|
156
|
+
help='Tool selection mode or JSON object (e.g. "auto" or \'{"type":"function","function":{"name":"lookup"}}\').',
|
|
157
|
+
)
|
|
158
|
+
@click.option(
|
|
159
|
+
"--stream-options",
|
|
160
|
+
default=None,
|
|
161
|
+
help="Streaming options as a JSON object (e.g. '{\"include_usage\": true}').",
|
|
162
|
+
)
|
|
163
|
+
@click.option(
|
|
164
|
+
"--metadata",
|
|
165
|
+
default=None,
|
|
166
|
+
help="Metadata as a JSON object.",
|
|
167
|
+
)
|
|
168
|
+
@click.option(
|
|
169
|
+
"--logit-bias",
|
|
170
|
+
default=None,
|
|
171
|
+
help="Logit bias map as a JSON object.",
|
|
172
|
+
)
|
|
173
|
+
@click.option(
|
|
174
|
+
"--modalities",
|
|
175
|
+
default=None,
|
|
176
|
+
help="Requested modalities as a JSON array.",
|
|
177
|
+
)
|
|
178
|
+
@click.option(
|
|
179
|
+
"--audio",
|
|
180
|
+
default=None,
|
|
181
|
+
help="Audio output settings as a JSON object.",
|
|
182
|
+
)
|
|
183
|
+
@click.option(
|
|
184
|
+
"--prediction",
|
|
185
|
+
default=None,
|
|
186
|
+
help="Prediction settings as a JSON object.",
|
|
187
|
+
)
|
|
188
|
+
@click.option(
|
|
189
|
+
"--web-search-options",
|
|
190
|
+
default=None,
|
|
191
|
+
help="Web search settings as a JSON object.",
|
|
192
|
+
)
|
|
193
|
+
@click.option("--json", "output_json", is_flag=True, help="Output raw JSON.")
|
|
194
|
+
@click.pass_context
|
|
195
|
+
def chat(
|
|
196
|
+
ctx: click.Context,
|
|
197
|
+
prompt: str,
|
|
198
|
+
model: str,
|
|
199
|
+
system: str | None,
|
|
200
|
+
temperature: float | None,
|
|
201
|
+
max_tokens: int | None,
|
|
202
|
+
max_completion_tokens: int | None,
|
|
203
|
+
count: int | None,
|
|
204
|
+
top_p: float | None,
|
|
205
|
+
frequency_penalty: float | None,
|
|
206
|
+
presence_penalty: float | None,
|
|
207
|
+
seed: int | None,
|
|
208
|
+
stop: tuple[str, ...],
|
|
209
|
+
reasoning_effort: str | None,
|
|
210
|
+
user: str | None,
|
|
211
|
+
service_tier: str | None,
|
|
212
|
+
store: bool,
|
|
213
|
+
logprobs: bool,
|
|
214
|
+
top_logprobs: int | None,
|
|
215
|
+
parallel_tool_calls: bool | None,
|
|
216
|
+
stream: bool,
|
|
217
|
+
response_format: str | None,
|
|
218
|
+
tools: str | None,
|
|
219
|
+
tool_choice: str | None,
|
|
220
|
+
stream_options: str | None,
|
|
221
|
+
metadata: str | None,
|
|
222
|
+
logit_bias: str | None,
|
|
223
|
+
modalities: str | None,
|
|
224
|
+
audio: str | None,
|
|
225
|
+
prediction: str | None,
|
|
226
|
+
web_search_options: str | None,
|
|
227
|
+
output_json: bool,
|
|
228
|
+
) -> None:
|
|
229
|
+
"""Chat with an OpenAI-compatible model.
|
|
230
|
+
|
|
231
|
+
PROMPT is the user message to send to the model.
|
|
232
|
+
|
|
233
|
+
\b
|
|
234
|
+
Examples:
|
|
235
|
+
openai-cli chat "What is the capital of France?"
|
|
236
|
+
openai-cli chat "Explain quantum computing" -m gpt-5.4
|
|
237
|
+
openai-cli chat "Write a poem" -m gpt-4o --temperature 0.9
|
|
238
|
+
openai-cli chat "Summarize this" -s "You are a concise summarizer"
|
|
239
|
+
openai-cli chat "Reason about this" -m o3 --reasoning-effort high
|
|
240
|
+
"""
|
|
241
|
+
client = get_client(ctx.obj.get("token"))
|
|
242
|
+
messages = []
|
|
243
|
+
if system:
|
|
244
|
+
messages.append({"role": "system", "content": system})
|
|
245
|
+
messages.append({"role": "user", "content": prompt})
|
|
246
|
+
|
|
247
|
+
try:
|
|
248
|
+
parsed_response_format = parse_json_object(response_format, "--response-format")
|
|
249
|
+
parsed_tools = parse_json_array(tools, "--tools")
|
|
250
|
+
parsed_tool_choice = parse_json_or_string(tool_choice, "--tool-choice")
|
|
251
|
+
parsed_stream_options = parse_json_object(stream_options, "--stream-options")
|
|
252
|
+
parsed_metadata = parse_json_object(metadata, "--metadata")
|
|
253
|
+
parsed_logit_bias = parse_json_object(logit_bias, "--logit-bias")
|
|
254
|
+
parsed_modalities = parse_json_array(modalities, "--modalities")
|
|
255
|
+
parsed_audio = parse_json_object(audio, "--audio")
|
|
256
|
+
parsed_prediction = parse_json_object(prediction, "--prediction")
|
|
257
|
+
parsed_web_search_options = parse_json_object(web_search_options, "--web-search-options")
|
|
258
|
+
except click.BadParameter as e:
|
|
259
|
+
print_error(e.format_message())
|
|
260
|
+
raise SystemExit(1) from None
|
|
261
|
+
payload: dict[str, object] = {
|
|
262
|
+
"model": model,
|
|
263
|
+
"messages": messages,
|
|
264
|
+
"stream": stream or None,
|
|
265
|
+
"temperature": temperature,
|
|
266
|
+
"max_tokens": max_tokens,
|
|
267
|
+
"max_completion_tokens": max_completion_tokens,
|
|
268
|
+
"n": count,
|
|
269
|
+
"response_format": parsed_response_format,
|
|
270
|
+
"tools": parsed_tools,
|
|
271
|
+
"tool_choice": parsed_tool_choice,
|
|
272
|
+
"top_p": top_p,
|
|
273
|
+
"frequency_penalty": frequency_penalty,
|
|
274
|
+
"presence_penalty": presence_penalty,
|
|
275
|
+
"seed": seed,
|
|
276
|
+
"stop": list(stop) if stop else None,
|
|
277
|
+
"stream_options": parsed_stream_options,
|
|
278
|
+
"reasoning_effort": reasoning_effort,
|
|
279
|
+
"user": user,
|
|
280
|
+
"service_tier": service_tier,
|
|
281
|
+
"store": store if store else None,
|
|
282
|
+
"metadata": parsed_metadata,
|
|
283
|
+
"logit_bias": parsed_logit_bias,
|
|
284
|
+
"logprobs": logprobs if logprobs else None,
|
|
285
|
+
"top_logprobs": top_logprobs,
|
|
286
|
+
"parallel_tool_calls": parallel_tool_calls,
|
|
287
|
+
"modalities": parsed_modalities,
|
|
288
|
+
"audio": parsed_audio,
|
|
289
|
+
"prediction": parsed_prediction,
|
|
290
|
+
"web_search_options": parsed_web_search_options,
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
try:
|
|
294
|
+
result = client.chat_completions(**payload) # type: ignore[arg-type]
|
|
295
|
+
if output_json:
|
|
296
|
+
print_json(result)
|
|
297
|
+
else:
|
|
298
|
+
print_chat_result(result)
|
|
299
|
+
except OpenAIError as e:
|
|
300
|
+
print_error(e.message)
|
|
301
|
+
raise SystemExit(1) from e
|