chatatp-cli 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.
- chatatp_cli-1.0.0/PKG-INFO +14 -0
- chatatp_cli-1.0.0/README.md +341 -0
- chatatp_cli-1.0.0/chatatp_cli/__init__.py +0 -0
- chatatp_cli-1.0.0/chatatp_cli/api_client.py +183 -0
- chatatp_cli-1.0.0/chatatp_cli/config.py +68 -0
- chatatp_cli-1.0.0/chatatp_cli/main.py +830 -0
- chatatp_cli-1.0.0/chatatp_cli.egg-info/PKG-INFO +14 -0
- chatatp_cli-1.0.0/chatatp_cli.egg-info/SOURCES.txt +12 -0
- chatatp_cli-1.0.0/chatatp_cli.egg-info/dependency_links.txt +1 -0
- chatatp_cli-1.0.0/chatatp_cli.egg-info/entry_points.txt +2 -0
- chatatp_cli-1.0.0/chatatp_cli.egg-info/requires.txt +5 -0
- chatatp_cli-1.0.0/chatatp_cli.egg-info/top_level.txt +1 -0
- chatatp_cli-1.0.0/pyproject.toml +29 -0
- chatatp_cli-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chatatp-cli
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: ChatATP CLI - Terminal Interface for ChatATP API
|
|
5
|
+
Author-email: ChatATP Team <support@chatatp.com>
|
|
6
|
+
Project-URL: Homepage, https://chat-atp.com
|
|
7
|
+
Project-URL: Documentation, https://docs.chat-atp.com
|
|
8
|
+
Project-URL: Repository, https://github.com/sam-14uel/ChatATP-Python-Cli
|
|
9
|
+
Project-URL: Issues, https://github.com/sam-14uel/ChatATP-Python-Cli/issues
|
|
10
|
+
Requires-Dist: requests
|
|
11
|
+
Requires-Dist: click
|
|
12
|
+
Requires-Dist: rich
|
|
13
|
+
Requires-Dist: pyyaml
|
|
14
|
+
Requires-Dist: python-dotenv
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
# ChatATP CLI
|
|
2
|
+
|
|
3
|
+
A powerful terminal interface for the ChatATP API, built with Python. Interact with ChatATP's AI models, manage chatrooms, toolkits, integrations, and more directly from your command line.
|
|
4
|
+
|
|
5
|
+
## ✨ What's New (v1.0.0)
|
|
6
|
+
|
|
7
|
+
### 🚀 Agentic Loop Support
|
|
8
|
+
- **Interactive Conversations**: Back-and-forth chat with persistent context
|
|
9
|
+
- **Real-time Streaming**: Responses appear as they're generated with tool call visualization
|
|
10
|
+
- **Auto-enter Chatrooms**: `chat new` now creates AND enters chat automatically
|
|
11
|
+
- **In-chat Commands**: Rich command system during conversations (`/exit`, `/help`, `/clear`, `/history`)
|
|
12
|
+
|
|
13
|
+
### 🔄 Chat Evolution
|
|
14
|
+
- **Before**: One-shot messages that exit immediately
|
|
15
|
+
- **Now**: Persistent interactive sessions with agentic conversations
|
|
16
|
+
- **Streaming**: Tool calls, thinking blocks, and responses all visualized in real-time
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- **Account Management**: View your ChatATP account information
|
|
21
|
+
- **Model Management**: List and manage AI models
|
|
22
|
+
- **Interactive Chat**: Agentic loop support with back-and-forth conversations
|
|
23
|
+
- **Toolkit Management**: Browse and manage your toolkits and collections
|
|
24
|
+
- **Integration Management**: Manage OAuth and custom integrations
|
|
25
|
+
- **AI Configuration**: Configure AI providers, models, and settings
|
|
26
|
+
- **Media Management**: Browse and manage uploaded media files
|
|
27
|
+
- **Store Access**: Browse featured and popular toolkits
|
|
28
|
+
- **MCP Support**: Manage MCP servers and connections
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
### From PyPI (Recommended)
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install chatatp-cli
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### From Source
|
|
39
|
+
|
|
40
|
+
1. Clone or download this repository
|
|
41
|
+
2. Install dependencies:
|
|
42
|
+
```bash
|
|
43
|
+
pip install -r requirements.txt
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
3. Make the script executable (optional):
|
|
47
|
+
```bash
|
|
48
|
+
chmod +x main.py
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Configuration
|
|
52
|
+
|
|
53
|
+
Before using the CLI, you need to configure your API token:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
python main.py config set-token YOUR_API_TOKEN_HERE
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
You can also configure other settings:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Set custom API base URL (default: https://api.chat-atp.com)
|
|
63
|
+
python main.py config set-base-url https://your-custom-api-url.com
|
|
64
|
+
|
|
65
|
+
# Set default model
|
|
66
|
+
python main.py config set-default-model gpt-oss-120b
|
|
67
|
+
|
|
68
|
+
# View current configuration
|
|
69
|
+
python main.py config show
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Usage
|
|
73
|
+
|
|
74
|
+
### Getting Help
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
python main.py --help
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Account Information
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
python main.py account
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Models
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# List available models
|
|
90
|
+
python main.py models
|
|
91
|
+
|
|
92
|
+
# List models for a specific provider
|
|
93
|
+
python main.py ai provider-models PROVIDER_ID
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## 🎯 Interactive Chat System
|
|
97
|
+
|
|
98
|
+
The ChatATP CLI now supports **true agentic conversations** with persistent context, just like chatting with ChatGPT or Claude!
|
|
99
|
+
|
|
100
|
+
### New Interactive Commands
|
|
101
|
+
|
|
102
|
+
#### **Start New Interactive Chat**
|
|
103
|
+
```bash
|
|
104
|
+
python main.py chat new "Tell me about machine learning"
|
|
105
|
+
```
|
|
106
|
+
- Creates a new chatroom
|
|
107
|
+
- Automatically enters interactive mode
|
|
108
|
+
- Sends your initial message
|
|
109
|
+
- Starts back-and-forth conversation loop
|
|
110
|
+
|
|
111
|
+
#### **Enter Existing Chatroom**
|
|
112
|
+
```bash
|
|
113
|
+
python main.py chat converse ROOM_ID
|
|
114
|
+
```
|
|
115
|
+
- Enter any existing chatroom for interactive chat
|
|
116
|
+
- Continue conversations where you left off
|
|
117
|
+
- Same interactive experience as new chats
|
|
118
|
+
|
|
119
|
+
### In-Chat Commands
|
|
120
|
+
|
|
121
|
+
While in interactive mode, you have access to these commands:
|
|
122
|
+
|
|
123
|
+
- **`/exit`**, **`/quit`**, **`/q`** - Exit the current chat session
|
|
124
|
+
- **`/help`**, **`/h`** - Show available commands
|
|
125
|
+
- **`/clear`** - Clear the screen and show current chat info
|
|
126
|
+
- **`/history`** - Show recent messages from chat history
|
|
127
|
+
|
|
128
|
+
### Interactive Chat Flow
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
$ python main.py chat new "Hello, let's discuss AI"
|
|
132
|
+
|
|
133
|
+
Chatroom created: abc123
|
|
134
|
+
Entered chatroom: abc123
|
|
135
|
+
Type your message or '/exit' to quit, '/help' for commands
|
|
136
|
+
|
|
137
|
+
You: Hello, let's discuss AI
|
|
138
|
+
|
|
139
|
+
ChatATP ·
|
|
140
|
+
|
|
141
|
+
Hello! I'd be happy to discuss AI with you. What specific aspects of artificial intelligence are you interested in? Whether it's machine learning algorithms, current trends, ethical considerations, or practical applications, I'm here to help!
|
|
142
|
+
|
|
143
|
+
─────────────────────────────────
|
|
144
|
+
You: Tell me about neural networks
|
|
145
|
+
|
|
146
|
+
ChatATP ·
|
|
147
|
+
|
|
148
|
+
Neural networks are fascinating! Let me explain them step by step:
|
|
149
|
+
|
|
150
|
+
A neural network is a computational model inspired by the human brain's neural structure. It consists of interconnected nodes (neurons) organized in layers...
|
|
151
|
+
|
|
152
|
+
─────────────────────────────────
|
|
153
|
+
You: /help
|
|
154
|
+
|
|
155
|
+
Available commands:
|
|
156
|
+
/exit, /quit, /q - Exit the chat
|
|
157
|
+
/help, /h - Show this help
|
|
158
|
+
/clear - Clear the screen
|
|
159
|
+
/history - Show chat history
|
|
160
|
+
|
|
161
|
+
You: /exit
|
|
162
|
+
Exiting chat...
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Legacy Commands (Still Supported)
|
|
166
|
+
|
|
167
|
+
#### **One-shot Message Sending**
|
|
168
|
+
```bash
|
|
169
|
+
# Send single message (legacy - exits immediately)
|
|
170
|
+
python main.py chat send ROOM_ID "Your message here"
|
|
171
|
+
|
|
172
|
+
# Send with specific model and toolkits
|
|
173
|
+
python main.py chat send ROOM_ID "Analyze this data" --model gpt-oss-120b --toolkits TOOLKIT_ID1 TOOLKIT_ID2
|
|
174
|
+
|
|
175
|
+
# Debug mode to see raw chunks
|
|
176
|
+
python main.py chat send ROOM_ID "Debug message" --debug
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### **Chatroom Management**
|
|
180
|
+
```bash
|
|
181
|
+
# List your chatrooms
|
|
182
|
+
python main.py chat rooms
|
|
183
|
+
|
|
184
|
+
# Show details of a specific chatroom
|
|
185
|
+
python main.py chat show ROOM_ID
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Toolkits
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# List your toolkits
|
|
192
|
+
python main.py toolkits
|
|
193
|
+
|
|
194
|
+
# Browse featured toolkits
|
|
195
|
+
python main.py store featured
|
|
196
|
+
|
|
197
|
+
# Browse popular toolkits
|
|
198
|
+
python main.py store popular
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Integrations
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
# List OAuth integrations
|
|
205
|
+
python main.py integrations list
|
|
206
|
+
|
|
207
|
+
# List custom integrations
|
|
208
|
+
python main.py integrations custom
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### AI Management
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# List AI providers
|
|
215
|
+
python main.py ai providers
|
|
216
|
+
|
|
217
|
+
# List AI configurations
|
|
218
|
+
python main.py ai configs
|
|
219
|
+
|
|
220
|
+
# Show AI settings
|
|
221
|
+
python main.py ai settings
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Media
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
# List your media files
|
|
228
|
+
python main.py media
|
|
229
|
+
|
|
230
|
+
# Search media
|
|
231
|
+
python main.py media --search "document name"
|
|
232
|
+
|
|
233
|
+
# Filter by type
|
|
234
|
+
python main.py media --type image
|
|
235
|
+
|
|
236
|
+
# Pagination
|
|
237
|
+
python main.py media --page 2 --page-size 20
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Pricing
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# View pricing plans
|
|
244
|
+
python main.py pricing
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Authentication
|
|
248
|
+
|
|
249
|
+
All commands require authentication. Make sure you've set your API token using:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
python main.py config set-token YOUR_TOKEN
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
The token will be stored securely in your home directory under `~/.chatatp/config.yaml`.
|
|
256
|
+
|
|
257
|
+
## Advanced Features
|
|
258
|
+
|
|
259
|
+
### Real-time Streaming with Tool Visualization
|
|
260
|
+
|
|
261
|
+
The CLI now provides rich visualization of:
|
|
262
|
+
|
|
263
|
+
- **Tool Calls**: See when tools are being executed with timing
|
|
264
|
+
- **Thinking Blocks**: Visual indicators when AI is reasoning
|
|
265
|
+
- **Progress Indicators**: Spinners and status updates during processing
|
|
266
|
+
- **Error Handling**: Graceful handling of network issues and API errors
|
|
267
|
+
|
|
268
|
+
### Example with Tool Calls
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
You: Search for information about OpenClaw AI
|
|
272
|
+
|
|
273
|
+
ChatATP ·
|
|
274
|
+
|
|
275
|
+
I need to search for information about OpenClaw AI. Let me use the search tool.
|
|
276
|
+
|
|
277
|
+
┌ search_web · web_search_toolkit
|
|
278
|
+
└ done 0.34s
|
|
279
|
+
|
|
280
|
+
Based on my search, OpenClaw is...
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Interactive vs One-shot Mode Comparison
|
|
284
|
+
|
|
285
|
+
| Feature | Interactive Mode (`chat new/converse`) | One-shot Mode (`chat send`) |
|
|
286
|
+
|---------|----------------------------------------|----------------------------|
|
|
287
|
+
| **Persistence** | ✅ Back-and-forth conversation | ❌ Single message only |
|
|
288
|
+
| **Context** | ✅ Full conversation history | ❌ No context retention |
|
|
289
|
+
| **Commands** | ✅ Rich in-chat commands | ❌ None |
|
|
290
|
+
| **Tool Visualization** | ✅ Real-time with progress | ✅ Basic streaming |
|
|
291
|
+
| **Exit Behavior** | Manual exit with `/exit` | Auto-exit after response |
|
|
292
|
+
| **Use Case** | Deep conversations, exploration | Quick questions, automation |
|
|
293
|
+
|
|
294
|
+
## Error Handling
|
|
295
|
+
|
|
296
|
+
The CLI provides clear error messages for common issues:
|
|
297
|
+
- Missing API token
|
|
298
|
+
- Invalid room IDs
|
|
299
|
+
- Network errors
|
|
300
|
+
- Authentication failures
|
|
301
|
+
- Streaming interruptions
|
|
302
|
+
|
|
303
|
+
## Dependencies
|
|
304
|
+
|
|
305
|
+
- requests: HTTP client
|
|
306
|
+
- click: Command line interface
|
|
307
|
+
- rich: Beautiful terminal output with progress indicators
|
|
308
|
+
- pyyaml: Configuration file handling
|
|
309
|
+
- python-dotenv: Environment variable support
|
|
310
|
+
|
|
311
|
+
## Migration Guide
|
|
312
|
+
|
|
313
|
+
### From v1.x to v2.0
|
|
314
|
+
|
|
315
|
+
**Old workflow:**
|
|
316
|
+
```bash
|
|
317
|
+
# Create room
|
|
318
|
+
python main.py chat new "Hello"
|
|
319
|
+
# Copy room ID
|
|
320
|
+
# Send messages one by one
|
|
321
|
+
python main.py chat send ROOM_ID "Follow up question"
|
|
322
|
+
python main.py chat send ROOM_ID "Another question"
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**New workflow:**
|
|
326
|
+
```bash
|
|
327
|
+
# Single command starts interactive session
|
|
328
|
+
python main.py chat new "Hello, let's have a conversation"
|
|
329
|
+
# Now chat back and forth naturally!
|
|
330
|
+
# Type /exit when done
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Legacy commands still work:** All v1.x commands (`chat send`, etc.) remain fully functional for scripts and automation.
|
|
334
|
+
|
|
335
|
+
## Contributing
|
|
336
|
+
|
|
337
|
+
Feel free to submit issues and pull requests to improve the ChatATP CLI.
|
|
338
|
+
|
|
339
|
+
## License
|
|
340
|
+
|
|
341
|
+
This project is licensed under the MIT License.
|
|
File without changes
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from typing import Dict, List, Optional, Any
|
|
3
|
+
import json
|
|
4
|
+
from config import Config
|
|
5
|
+
|
|
6
|
+
class ChatATPAPI:
|
|
7
|
+
def __init__(self, config: Config):
|
|
8
|
+
self.config = config
|
|
9
|
+
self.session = requests.Session()
|
|
10
|
+
self.session.headers.update(self.config.get_headers())
|
|
11
|
+
|
|
12
|
+
def _get(self, endpoint: str, params: Optional[Dict] = None) -> Dict:
|
|
13
|
+
"""Make GET request"""
|
|
14
|
+
url = f"{self.config.api_base_url}{endpoint}"
|
|
15
|
+
response = self.session.get(url, params=params)
|
|
16
|
+
response.raise_for_status()
|
|
17
|
+
return response.json()
|
|
18
|
+
|
|
19
|
+
def _post(self, endpoint: str, data: Optional[Dict] = None) -> Dict:
|
|
20
|
+
"""Make POST request"""
|
|
21
|
+
url = f"{self.config.api_base_url}{endpoint}"
|
|
22
|
+
response = self.session.post(url, json=data)
|
|
23
|
+
response.raise_for_status()
|
|
24
|
+
return response.json()
|
|
25
|
+
|
|
26
|
+
def _patch(self, endpoint: str, data: Optional[Dict] = None) -> Dict:
|
|
27
|
+
"""Make PATCH request"""
|
|
28
|
+
url = f"{self.config.api_base_url}{endpoint}"
|
|
29
|
+
response = self.session.patch(url, json=data)
|
|
30
|
+
response.raise_for_status()
|
|
31
|
+
return response.json()
|
|
32
|
+
|
|
33
|
+
def _delete(self, endpoint: str) -> Dict:
|
|
34
|
+
"""Make DELETE request"""
|
|
35
|
+
url = f"{self.config.api_base_url}{endpoint}"
|
|
36
|
+
response = self.session.delete(url)
|
|
37
|
+
response.raise_for_status()
|
|
38
|
+
return response.json() if response.content else {}
|
|
39
|
+
|
|
40
|
+
# Account endpoints
|
|
41
|
+
def get_account(self) -> Dict:
|
|
42
|
+
"""Get user account information"""
|
|
43
|
+
return self._get('/api/v1/account/')
|
|
44
|
+
|
|
45
|
+
# Models endpoints
|
|
46
|
+
def list_models(self) -> List[Dict]:
|
|
47
|
+
"""List available models"""
|
|
48
|
+
return self._get('/api/v1/list-models/')
|
|
49
|
+
|
|
50
|
+
# Collections/Toolkits endpoints
|
|
51
|
+
def list_collections(self) -> Dict:
|
|
52
|
+
"""List toolkits collections"""
|
|
53
|
+
return self._get('/api/v1/collections/toolkits/')
|
|
54
|
+
|
|
55
|
+
# MCP endpoints
|
|
56
|
+
def list_mcp_connections(self) -> Dict:
|
|
57
|
+
"""List MCP connections"""
|
|
58
|
+
return self._get('/api/v1/mcp/connections/')
|
|
59
|
+
|
|
60
|
+
def list_mcp_servers(self) -> Dict:
|
|
61
|
+
"""List MCP servers"""
|
|
62
|
+
return self._get('/api/v1/mcp/servers/')
|
|
63
|
+
|
|
64
|
+
# Chat endpoints
|
|
65
|
+
def list_chatrooms(self) -> Dict:
|
|
66
|
+
"""List chatrooms"""
|
|
67
|
+
return self._get('/api/v1/chatrooms/')
|
|
68
|
+
|
|
69
|
+
def get_chatroom(self, room_id: str) -> Dict:
|
|
70
|
+
"""Get chatroom details"""
|
|
71
|
+
return self._get(f'/api/v1/chats/{room_id}/')
|
|
72
|
+
|
|
73
|
+
def create_chatroom(self, message: str, model: str = None, toolkit_ids: List[str] = None,
|
|
74
|
+
mcp_server_connection_ids: List[str] = None) -> Dict:
|
|
75
|
+
"""Create new chatroom"""
|
|
76
|
+
data = {'message': message}
|
|
77
|
+
if model:
|
|
78
|
+
data['model'] = model
|
|
79
|
+
if toolkit_ids:
|
|
80
|
+
data['toolkit_ids'] = toolkit_ids
|
|
81
|
+
if mcp_server_connection_ids:
|
|
82
|
+
data['mcp_server_connection_ids'] = mcp_server_connection_ids
|
|
83
|
+
return self._post('/api/v1/chats/new/', data)
|
|
84
|
+
|
|
85
|
+
def send_chat_message_stream(self, room_id: str, message: str, model: str = None,
|
|
86
|
+
toolkit_ids: List[str] = None, mcp_server_connection_ids: List[str] = None,
|
|
87
|
+
attachments: List = None):
|
|
88
|
+
"""Send chat message and yield streaming response chunks"""
|
|
89
|
+
url = f"{self.config.api_base_url}/api/v1/chats/{room_id}/completions/stream/"
|
|
90
|
+
data = {
|
|
91
|
+
'message_type': 'chat_message',
|
|
92
|
+
'message': message,
|
|
93
|
+
'model': model or self.config.default_model,
|
|
94
|
+
'toolkit_ids': toolkit_ids or [],
|
|
95
|
+
'mcp_server_connection_ids': mcp_server_connection_ids or [],
|
|
96
|
+
'attachments': attachments or []
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
with self.session.post(url, json=data, stream=True) as response:
|
|
100
|
+
response.raise_for_status()
|
|
101
|
+
buffer = ""
|
|
102
|
+
|
|
103
|
+
for line in response.iter_lines():
|
|
104
|
+
if not line:
|
|
105
|
+
continue
|
|
106
|
+
|
|
107
|
+
line = line.decode('utf-8')
|
|
108
|
+
|
|
109
|
+
# Handle SSE format: "data: {...}"
|
|
110
|
+
if line.startswith('data: '):
|
|
111
|
+
line = line[6:]
|
|
112
|
+
|
|
113
|
+
# Skip SSE comments or keep-alive
|
|
114
|
+
if line.startswith(':'):
|
|
115
|
+
continue
|
|
116
|
+
|
|
117
|
+
buffer += line
|
|
118
|
+
|
|
119
|
+
# Try to parse whatever is in the buffer
|
|
120
|
+
while buffer:
|
|
121
|
+
buffer = buffer.strip()
|
|
122
|
+
if not buffer:
|
|
123
|
+
break
|
|
124
|
+
try:
|
|
125
|
+
chunk, idx = json.JSONDecoder().raw_decode(buffer)
|
|
126
|
+
yield chunk
|
|
127
|
+
buffer = buffer[idx:].strip()
|
|
128
|
+
except json.JSONDecodeError:
|
|
129
|
+
# Incomplete JSON, wait for more data
|
|
130
|
+
break
|
|
131
|
+
|
|
132
|
+
# Media endpoints
|
|
133
|
+
def list_media(self, page: int = 1, page_size: int = 12, media_type: str = None, search: str = None) -> Dict:
|
|
134
|
+
"""List user media"""
|
|
135
|
+
params = {'page': page, 'page_size': page_size}
|
|
136
|
+
if media_type:
|
|
137
|
+
params['type'] = media_type
|
|
138
|
+
if search:
|
|
139
|
+
params['search'] = search
|
|
140
|
+
return self._get('/api/v1/media/', params)
|
|
141
|
+
|
|
142
|
+
# Integrations endpoints
|
|
143
|
+
def list_integrations(self) -> Dict:
|
|
144
|
+
"""List integrated accounts"""
|
|
145
|
+
return self._get('/api/v1/integrations/')
|
|
146
|
+
|
|
147
|
+
def list_custom_integrations(self) -> Dict:
|
|
148
|
+
"""List custom integrated accounts"""
|
|
149
|
+
return self._get('/api/v1/integrations/custom/')
|
|
150
|
+
|
|
151
|
+
def list_ai_configs(self) -> List[Dict]:
|
|
152
|
+
"""List AI provider configurations"""
|
|
153
|
+
return self._get('/api/v1/integrations/ai/providers/configs/')
|
|
154
|
+
|
|
155
|
+
def list_ai_providers(self) -> List[Dict]:
|
|
156
|
+
"""List AI providers"""
|
|
157
|
+
return self._get('/api/v1/integrations/ai/providers/')
|
|
158
|
+
|
|
159
|
+
def list_provider_models(self, provider_id: str) -> List[Dict]:
|
|
160
|
+
"""List models for a provider"""
|
|
161
|
+
return self._get('/api/v1/list-provider-models/', {'provider': provider_id})
|
|
162
|
+
|
|
163
|
+
def get_ai_settings(self) -> Dict:
|
|
164
|
+
"""Get AI settings"""
|
|
165
|
+
return self._get('/api/v1/integrations/ai/settings/')
|
|
166
|
+
|
|
167
|
+
# Store endpoints
|
|
168
|
+
def list_featured_toolkits(self) -> Dict:
|
|
169
|
+
"""List featured toolkits"""
|
|
170
|
+
return self._get('/api/v1/store/toolkits/featured/')
|
|
171
|
+
|
|
172
|
+
def list_popular_toolkits(self) -> Dict:
|
|
173
|
+
"""List popular toolkits"""
|
|
174
|
+
return self._get('/api/v1/store/toolkits/popular/')
|
|
175
|
+
|
|
176
|
+
def list_recommended_toolkits(self) -> Dict:
|
|
177
|
+
"""List recommended toolkits"""
|
|
178
|
+
return self._get('/api/v1/store/toolkits/for_you/')
|
|
179
|
+
|
|
180
|
+
# Pricing endpoints
|
|
181
|
+
def get_pricing(self) -> List[Dict]:
|
|
182
|
+
"""Get pricing information"""
|
|
183
|
+
return self._get('/api/v1/payments/pricing/')
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional
|
|
3
|
+
import yaml
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
class Config:
|
|
7
|
+
def __init__(self, config_file: str = None):
|
|
8
|
+
self.config_file = config_file or os.path.join(Path.home(), '.chatatp', 'config.yaml')
|
|
9
|
+
self._config = {}
|
|
10
|
+
self.load_config()
|
|
11
|
+
|
|
12
|
+
def load_config(self):
|
|
13
|
+
"""Load configuration from file"""
|
|
14
|
+
try:
|
|
15
|
+
if os.path.exists(self.config_file):
|
|
16
|
+
with open(self.config_file, 'r') as f:
|
|
17
|
+
self._config = yaml.safe_load(f) or {}
|
|
18
|
+
else:
|
|
19
|
+
self._config = {}
|
|
20
|
+
except Exception as e:
|
|
21
|
+
print(f"Warning: Could not load config file: {e}")
|
|
22
|
+
self._config = {}
|
|
23
|
+
|
|
24
|
+
def save_config(self):
|
|
25
|
+
"""Save configuration to file"""
|
|
26
|
+
try:
|
|
27
|
+
os.makedirs(os.path.dirname(self.config_file), exist_ok=True)
|
|
28
|
+
with open(self.config_file, 'w') as f:
|
|
29
|
+
yaml.dump(self._config, f, default_flow_style=False)
|
|
30
|
+
except Exception as e:
|
|
31
|
+
print(f"Error saving config: {e}")
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def api_base_url(self) -> str:
|
|
35
|
+
return self._config.get('api_base_url', 'https://api.chat-atp.com')
|
|
36
|
+
|
|
37
|
+
@api_base_url.setter
|
|
38
|
+
def api_base_url(self, value: str):
|
|
39
|
+
self._config['api_base_url'] = value
|
|
40
|
+
self.save_config()
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def api_token(self) -> Optional[str]:
|
|
44
|
+
return self._config.get('api_token')
|
|
45
|
+
|
|
46
|
+
@api_token.setter
|
|
47
|
+
def api_token(self, value: str):
|
|
48
|
+
self._config['api_token'] = value
|
|
49
|
+
self.save_config()
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def default_model(self) -> str:
|
|
53
|
+
return self._config.get('default_model', 'gpt-oss-120b')
|
|
54
|
+
|
|
55
|
+
@default_model.setter
|
|
56
|
+
def default_model(self, value: str):
|
|
57
|
+
self._config['default_model'] = value
|
|
58
|
+
self.save_config()
|
|
59
|
+
|
|
60
|
+
def get_headers(self) -> dict:
|
|
61
|
+
"""Get headers for API requests"""
|
|
62
|
+
headers = {
|
|
63
|
+
'Content-Type': 'application/json',
|
|
64
|
+
'Accept': 'application/json'
|
|
65
|
+
}
|
|
66
|
+
if self.api_token:
|
|
67
|
+
headers['Authorization'] = f'Token {self.api_token}'
|
|
68
|
+
return headers
|