recallrai 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of recallrai might be problematic. Click here for more details.
- recallrai/__init__.py +2 -1
- recallrai/client.py +42 -127
- recallrai/exceptions/__init__.py +28 -0
- recallrai/exceptions/auth.py +24 -0
- recallrai/exceptions/base.py +37 -0
- recallrai/exceptions/network.py +58 -0
- recallrai/exceptions/server.py +82 -0
- recallrai/exceptions/sessions.py +60 -0
- recallrai/exceptions/users.py +61 -0
- recallrai/exceptions/validation.py +24 -0
- recallrai/session.py +157 -47
- recallrai/user.py +93 -12
- recallrai/utils/__init__.py +2 -4
- recallrai/utils/http_client.py +123 -0
- recallrai-0.1.1.dist-info/METADATA +440 -0
- recallrai-0.1.1.dist-info/RECORD +20 -0
- recallrai/utils/exceptions.py +0 -61
- recallrai/utils/http.py +0 -167
- recallrai-0.1.0.dist-info/METADATA +0 -268
- recallrai-0.1.0.dist-info/RECORD +0 -13
- {recallrai-0.1.0.dist-info → recallrai-0.1.1.dist-info}/WHEEL +0 -0
recallrai/session.py
CHANGED
|
@@ -6,13 +6,19 @@ Session management functionality for the RecallrAI SDK.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from typing import List
|
|
9
|
-
from .utils import HTTPClient
|
|
9
|
+
from .utils import HTTPClient
|
|
10
10
|
from .models import (
|
|
11
11
|
Context,
|
|
12
12
|
Message,
|
|
13
13
|
SessionStatus,
|
|
14
14
|
MessageRole
|
|
15
15
|
)
|
|
16
|
+
from .exceptions import (
|
|
17
|
+
UserNotFoundError,
|
|
18
|
+
SessionNotFoundError,
|
|
19
|
+
InvalidSessionStateError,
|
|
20
|
+
RecallrAIError
|
|
21
|
+
)
|
|
16
22
|
from logging import getLogger
|
|
17
23
|
|
|
18
24
|
logger = getLogger(__name__)
|
|
@@ -51,21 +57,16 @@ class Session:
|
|
|
51
57
|
message: Content of the user message
|
|
52
58
|
|
|
53
59
|
Raises:
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
UserNotFoundError: If the user is not found
|
|
61
|
+
SessionNotFoundError: If the session is not found
|
|
62
|
+
InvalidSessionStateError: If the session is already processed or processing
|
|
63
|
+
AuthenticationError: If the API key or project ID is invalid
|
|
64
|
+
InternalServerError: If the server encounters an error
|
|
65
|
+
NetworkError: If there are network issues
|
|
66
|
+
TimeoutError: If the request times out
|
|
67
|
+
RecallrAIError: For other API-related errors
|
|
56
68
|
"""
|
|
57
|
-
|
|
58
|
-
status = self.get_status()
|
|
59
|
-
if status == SessionStatus.PROCESSED:
|
|
60
|
-
raise RecallrAIError("Cannot add message to a session that has already been processed")
|
|
61
|
-
elif status == SessionStatus.PROCESSING:
|
|
62
|
-
raise RecallrAIError("Cannot add message to a session that is currently being processed")
|
|
63
|
-
|
|
64
|
-
# Add the user message
|
|
65
|
-
self._http.post(
|
|
66
|
-
f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/add-message",
|
|
67
|
-
data={"message": message, "role": MessageRole.USER},
|
|
68
|
-
)
|
|
69
|
+
self._add_message(message, MessageRole.USER)
|
|
69
70
|
|
|
70
71
|
def add_assistant_message(self, message: str) -> None:
|
|
71
72
|
"""
|
|
@@ -75,21 +76,56 @@ class Session:
|
|
|
75
76
|
message: Content of the assistant message
|
|
76
77
|
|
|
77
78
|
Raises:
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
UserNotFoundError: If the user is not found
|
|
80
|
+
SessionNotFoundError: If the session is not found
|
|
81
|
+
InvalidSessionStateError: If the session is already processed or processing
|
|
82
|
+
AuthenticationError: If the API key or project ID is invalid
|
|
83
|
+
InternalServerError: If the server encounters an error
|
|
84
|
+
NetworkError: If there are network issues
|
|
85
|
+
TimeoutError: If the request times out
|
|
86
|
+
RecallrAIError: For other API-related errors
|
|
80
87
|
"""
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
raise RecallrAIError("Cannot add message to a session that is currently being processed")
|
|
88
|
+
self._add_message(message, MessageRole.ASSISTANT)
|
|
89
|
+
|
|
90
|
+
def _add_message(self, message: str, role: MessageRole) -> None:
|
|
91
|
+
"""
|
|
92
|
+
Internal helper to add a message to the session.
|
|
87
93
|
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
Args:
|
|
95
|
+
message: Content of the message
|
|
96
|
+
role: Role of the message sender
|
|
97
|
+
|
|
98
|
+
Raises:
|
|
99
|
+
UserNotFoundError: If the user is not found
|
|
100
|
+
SessionNotFoundError: If the session is not found
|
|
101
|
+
InvalidSessionStateError: If the session is already processed or processing
|
|
102
|
+
AuthenticationError: If the API key or project ID is invalid
|
|
103
|
+
InternalServerError: If the server encounters an error
|
|
104
|
+
NetworkError: If there are network issues
|
|
105
|
+
TimeoutError: If the request times out
|
|
106
|
+
RecallrAIError: For other API-related errors
|
|
107
|
+
"""
|
|
108
|
+
response = self._http.post(
|
|
90
109
|
f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/add-message",
|
|
91
|
-
data={"message": message, "role":
|
|
110
|
+
data={"message": message, "role": role.value},
|
|
92
111
|
)
|
|
112
|
+
|
|
113
|
+
if response.status_code == 404:
|
|
114
|
+
# Check if it's a user not found or session not found error
|
|
115
|
+
detail = response.json().get('detail', '')
|
|
116
|
+
if f"User {self.user_id} not found" in detail:
|
|
117
|
+
raise UserNotFoundError(user_id=self.user_id)
|
|
118
|
+
else:
|
|
119
|
+
raise SessionNotFoundError(session_id=self.session_id)
|
|
120
|
+
elif response.status_code == 400:
|
|
121
|
+
raise InvalidSessionStateError(
|
|
122
|
+
message=f"Cannot add message to session with status {self.get_status()}",
|
|
123
|
+
)
|
|
124
|
+
elif response.status_code != 200:
|
|
125
|
+
raise RecallrAIError(
|
|
126
|
+
message=f"Failed to add message: {response.json().get('detail', 'Unknown error')}",
|
|
127
|
+
http_status=response.status_code
|
|
128
|
+
)
|
|
93
129
|
|
|
94
130
|
def get_context(self) -> Context:
|
|
95
131
|
"""
|
|
@@ -102,17 +138,36 @@ class Session:
|
|
|
102
138
|
Context information with the memory text and whether memory was used
|
|
103
139
|
|
|
104
140
|
Raises:
|
|
105
|
-
|
|
141
|
+
UserNotFoundError: If the user is not found
|
|
142
|
+
SessionNotFoundError: If the session is not found
|
|
143
|
+
AuthenticationError: If the API key or project ID is invalid
|
|
144
|
+
InternalServerError: If the server encounters an error
|
|
145
|
+
NetworkError: If there are network issues
|
|
146
|
+
TimeoutError: If the request times out
|
|
147
|
+
RecallrAIError: For other API-related errors
|
|
106
148
|
"""
|
|
149
|
+
response = self._http.get(
|
|
150
|
+
f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/context"
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
if response.status_code == 404:
|
|
154
|
+
# Check if it's a user not found or session not found error
|
|
155
|
+
detail = response.json().get('detail', '')
|
|
156
|
+
if f"User {self.user_id} not found" in detail:
|
|
157
|
+
raise UserNotFoundError(user_id=self.user_id)
|
|
158
|
+
else:
|
|
159
|
+
raise SessionNotFoundError(session_id=self.session_id)
|
|
160
|
+
elif response.status_code != 200:
|
|
161
|
+
raise RecallrAIError(
|
|
162
|
+
message=f"Failed to get context: {response.json().get('detail', 'Unknown error')}",
|
|
163
|
+
http_status=response.status_code
|
|
164
|
+
)
|
|
107
165
|
status = self.get_status()
|
|
108
166
|
if status == SessionStatus.PROCESSED:
|
|
109
167
|
logger.warning("Cannot add message to a session that has already been processed")
|
|
110
168
|
elif status == SessionStatus.PROCESSING:
|
|
111
169
|
logger.warning("Cannot add message to a session that is currently being processed")
|
|
112
|
-
|
|
113
|
-
f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/context"
|
|
114
|
-
)
|
|
115
|
-
return Context.from_api_response(response)
|
|
170
|
+
return Context.from_api_response(response.json())
|
|
116
171
|
|
|
117
172
|
def process(self) -> None:
|
|
118
173
|
"""
|
|
@@ -122,21 +177,35 @@ class Session:
|
|
|
122
177
|
the user's memory.
|
|
123
178
|
|
|
124
179
|
Raises:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
180
|
+
UserNotFoundError: If the user is not found
|
|
181
|
+
SessionNotFoundError: If the session is not found
|
|
182
|
+
InvalidSessionStateError: If the session is already processed or being processed
|
|
183
|
+
AuthenticationError: If the API key or project ID is invalid
|
|
184
|
+
InternalServerError: If the server encounters an error
|
|
185
|
+
NetworkError: If there are network issues
|
|
186
|
+
TimeoutError: If the request times out
|
|
187
|
+
RecallrAIError: For other API-related errors
|
|
128
188
|
"""
|
|
129
|
-
|
|
130
|
-
status = self.get_status()
|
|
131
|
-
if status == SessionStatus.PROCESSED:
|
|
132
|
-
raise RecallrAIError("Cannot process a session that has already been processed")
|
|
133
|
-
elif status == SessionStatus.PROCESSING:
|
|
134
|
-
raise RecallrAIError("Cannot process a session that is currently being processed")
|
|
135
|
-
|
|
136
|
-
# Process the session
|
|
137
|
-
self._http.post(
|
|
189
|
+
response = self._http.post(
|
|
138
190
|
f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/process"
|
|
139
191
|
)
|
|
192
|
+
|
|
193
|
+
if response.status_code == 404:
|
|
194
|
+
# Check if it's a user not found or session not found error
|
|
195
|
+
detail = response.json().get('detail', '')
|
|
196
|
+
if f"User {self.user_id} not found" in detail:
|
|
197
|
+
raise UserNotFoundError(user_id=self.user_id)
|
|
198
|
+
else:
|
|
199
|
+
raise SessionNotFoundError(session_id=self.session_id)
|
|
200
|
+
elif response.status_code == 400:
|
|
201
|
+
raise InvalidSessionStateError(
|
|
202
|
+
message=f"{response.json().get('detail', f'Cannot process session with status {self.get_status()}')}",
|
|
203
|
+
)
|
|
204
|
+
elif response.status_code != 200:
|
|
205
|
+
raise RecallrAIError(
|
|
206
|
+
message=f"Failed to process session: {response.json().get('detail', 'Unknown error')}",
|
|
207
|
+
http_status=response.status_code
|
|
208
|
+
)
|
|
140
209
|
|
|
141
210
|
def get_status(self) -> SessionStatus:
|
|
142
211
|
"""
|
|
@@ -146,12 +215,32 @@ class Session:
|
|
|
146
215
|
SessionStatus: The current status of the session
|
|
147
216
|
|
|
148
217
|
Raises:
|
|
149
|
-
|
|
218
|
+
UserNotFoundError: If the user is not found
|
|
219
|
+
SessionNotFoundError: If the session is not found
|
|
220
|
+
AuthenticationError: If the API key or project ID is invalid
|
|
221
|
+
InternalServerError: If the server encounters an error
|
|
222
|
+
NetworkError: If there are network issues
|
|
223
|
+
TimeoutError: If the request times out
|
|
224
|
+
RecallrAIError: For other API-related errors
|
|
150
225
|
"""
|
|
151
226
|
response = self._http.get(
|
|
152
227
|
f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/status"
|
|
153
228
|
)
|
|
154
|
-
|
|
229
|
+
|
|
230
|
+
if response.status_code == 404:
|
|
231
|
+
# Check if it's a user not found or session not found error
|
|
232
|
+
detail = response.json().get('detail', '')
|
|
233
|
+
if f"User {self.user_id} not found" in detail:
|
|
234
|
+
raise UserNotFoundError(user_id=self.user_id)
|
|
235
|
+
else:
|
|
236
|
+
raise SessionNotFoundError(session_id=self.session_id)
|
|
237
|
+
elif response.status_code != 200:
|
|
238
|
+
raise RecallrAIError(
|
|
239
|
+
message=f"Failed to get session status: {response.json().get('detail', 'Unknown error')}",
|
|
240
|
+
http_status=response.status_code
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
return SessionStatus(response.json()["status"])
|
|
155
244
|
|
|
156
245
|
def get_messages(self) -> List[Message]:
|
|
157
246
|
"""
|
|
@@ -161,9 +250,30 @@ class Session:
|
|
|
161
250
|
List of messages in the session
|
|
162
251
|
|
|
163
252
|
Raises:
|
|
164
|
-
|
|
253
|
+
UserNotFoundError: If the user is not found
|
|
254
|
+
SessionNotFoundError: If the session is not found
|
|
255
|
+
AuthenticationError: If the API key or project ID is invalid
|
|
256
|
+
InternalServerError: If the server encounters an error
|
|
257
|
+
NetworkError: If there are network issues
|
|
258
|
+
TimeoutError: If the request times out
|
|
259
|
+
RecallrAIError: For other API-related errors
|
|
165
260
|
"""
|
|
166
261
|
response = self._http.get(
|
|
167
262
|
f"/api/v1/users/{self.user_id}/sessions/{self.session_id}/messages"
|
|
168
263
|
)
|
|
169
|
-
|
|
264
|
+
|
|
265
|
+
if response.status_code == 404:
|
|
266
|
+
# Check if it's a user not found or session not found error
|
|
267
|
+
detail = response.json().get('detail', '')
|
|
268
|
+
if f"User {self.user_id} not found" in detail:
|
|
269
|
+
raise UserNotFoundError(user_id=self.user_id)
|
|
270
|
+
else:
|
|
271
|
+
raise SessionNotFoundError(session_id=self.session_id)
|
|
272
|
+
elif response.status_code != 200:
|
|
273
|
+
raise RecallrAIError(
|
|
274
|
+
message=f"Failed to get messages: {response.json().get('detail', 'Unknown error')}",
|
|
275
|
+
http_status=response.status_code
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
data = response.json()
|
|
279
|
+
return [Message(**msg) for msg in data["messages"]]
|
recallrai/user.py
CHANGED
|
@@ -6,6 +6,15 @@ from typing import Any, Dict, Optional
|
|
|
6
6
|
from .utils import HTTPClient
|
|
7
7
|
from .models import User as UserModel, SessionList
|
|
8
8
|
from .session import Session
|
|
9
|
+
from .exceptions import (
|
|
10
|
+
UserNotFoundError,
|
|
11
|
+
UserAlreadyExistsError,
|
|
12
|
+
SessionNotFoundError,
|
|
13
|
+
RecallrAIError
|
|
14
|
+
)
|
|
15
|
+
from logging import getLogger
|
|
16
|
+
|
|
17
|
+
logger = getLogger(__name__)
|
|
9
18
|
|
|
10
19
|
class User:
|
|
11
20
|
"""
|
|
@@ -46,18 +55,33 @@ class User:
|
|
|
46
55
|
The updated user object
|
|
47
56
|
|
|
48
57
|
Raises:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
58
|
+
UserNotFoundError: If the user is not found
|
|
59
|
+
UserAlreadyExistsError: If a user with the new_user_id already exists
|
|
60
|
+
AuthenticationError: If the API key or project ID is invalid
|
|
61
|
+
InternalServerError: If the server encounters an error
|
|
62
|
+
NetworkError: If there are network issues
|
|
63
|
+
TimeoutError: If the request times out
|
|
64
|
+
RecallrAIError: For other API-related errors
|
|
52
65
|
"""
|
|
53
66
|
data = {}
|
|
54
67
|
if new_metadata is not None:
|
|
55
|
-
data["
|
|
68
|
+
data["metadata"] = new_metadata
|
|
56
69
|
if new_user_id is not None:
|
|
57
70
|
data["new_user_id"] = new_user_id
|
|
58
71
|
|
|
59
72
|
response = self._http.put(f"/api/v1/users/{self.user_id}", data=data)
|
|
60
|
-
|
|
73
|
+
|
|
74
|
+
if response.status_code == 404:
|
|
75
|
+
raise UserNotFoundError(user_id=self.user_id)
|
|
76
|
+
elif response.status_code == 409:
|
|
77
|
+
raise UserAlreadyExistsError(user_id=new_user_id)
|
|
78
|
+
elif response.status_code != 200:
|
|
79
|
+
raise RecallrAIError(
|
|
80
|
+
message=f"Failed to update user: {response.json().get('detail', 'Unknown error')}",
|
|
81
|
+
http_status=response.status_code
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
updated_data = UserModel.from_api_response(response.json())
|
|
61
85
|
|
|
62
86
|
# Update internal state
|
|
63
87
|
self._user_data = updated_data
|
|
@@ -72,9 +96,22 @@ class User:
|
|
|
72
96
|
Delete this user.
|
|
73
97
|
|
|
74
98
|
Raises:
|
|
75
|
-
|
|
99
|
+
UserNotFoundError: If the user is not found
|
|
100
|
+
AuthenticationError: If the API key or project ID is invalid
|
|
101
|
+
InternalServerError: If the server encounters an error
|
|
102
|
+
NetworkError: If there are network issues
|
|
103
|
+
TimeoutError: If the request times out
|
|
104
|
+
RecallrAIError: For other API-related errors
|
|
76
105
|
"""
|
|
77
|
-
self._http.delete(f"/api/v1/users/{self.user_id}")
|
|
106
|
+
response = self._http.delete(f"/api/v1/users/{self.user_id}")
|
|
107
|
+
|
|
108
|
+
if response.status_code == 404:
|
|
109
|
+
raise UserNotFoundError(user_id=self.user_id)
|
|
110
|
+
elif response.status_code != 204:
|
|
111
|
+
raise RecallrAIError(
|
|
112
|
+
message=f"Failed to delete user: {response.json().get('detail', 'Unknown error')}",
|
|
113
|
+
http_status=response.status_code
|
|
114
|
+
)
|
|
78
115
|
|
|
79
116
|
def create_session(self, auto_process_after_minutes: int = -1) -> Session:
|
|
80
117
|
"""
|
|
@@ -87,14 +124,27 @@ class User:
|
|
|
87
124
|
A Session object to interact with the created session
|
|
88
125
|
|
|
89
126
|
Raises:
|
|
90
|
-
|
|
127
|
+
UserNotFoundError: If the user is not found
|
|
128
|
+
AuthenticationError: If the API key or project ID is invalid
|
|
129
|
+
InternalServerError: If the server encounters an error
|
|
130
|
+
NetworkError: If there are network issues
|
|
131
|
+
TimeoutError: If the request times out
|
|
132
|
+
RecallrAIError: For other API-related errors
|
|
91
133
|
"""
|
|
92
134
|
response = self._http.post(
|
|
93
135
|
f"/api/v1/users/{self.user_id}/sessions",
|
|
94
136
|
data={"auto_process_after_minutes": auto_process_after_minutes},
|
|
95
137
|
)
|
|
96
138
|
|
|
97
|
-
|
|
139
|
+
if response.status_code == 404:
|
|
140
|
+
raise UserNotFoundError(user_id=self.user_id)
|
|
141
|
+
elif response.status_code != 201:
|
|
142
|
+
raise RecallrAIError(
|
|
143
|
+
message=f"Failed to create session: {response.json().get('detail', 'Unknown error')}",
|
|
144
|
+
http_status=response.status_code
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
session_id = response.json()["session_id"]
|
|
98
148
|
return Session(self._http, self.user_id, session_id)
|
|
99
149
|
|
|
100
150
|
def get_session(self, session_id: str) -> Session:
|
|
@@ -108,9 +158,23 @@ class User:
|
|
|
108
158
|
A Session object to interact with the session
|
|
109
159
|
|
|
110
160
|
Raises:
|
|
111
|
-
|
|
161
|
+
UserNotFoundError: If the user is not found
|
|
162
|
+
SessionNotFoundError: If the session is not found
|
|
163
|
+
AuthenticationError: If the API key or project ID is invalid
|
|
164
|
+
InternalServerError: If the server encounters an error
|
|
165
|
+
NetworkError: If there are network issues
|
|
166
|
+
TimeoutError: If the request times out
|
|
167
|
+
RecallrAIError: For other API-related errors
|
|
112
168
|
"""
|
|
113
|
-
|
|
169
|
+
# Verify the session exists by checking its status
|
|
170
|
+
session = Session(self._http, self.user_id, session_id)
|
|
171
|
+
try:
|
|
172
|
+
session.get_status() # This will raise appropriate errors if the session doesn't exist
|
|
173
|
+
return session
|
|
174
|
+
except SessionNotFoundError:
|
|
175
|
+
raise
|
|
176
|
+
except Exception as e:
|
|
177
|
+
raise RecallrAIError(f"Error retrieving session: {str(e)}")
|
|
114
178
|
|
|
115
179
|
def list_sessions(self, offset: int = 0, limit: int = 10) -> SessionList:
|
|
116
180
|
"""
|
|
@@ -122,9 +186,26 @@ class User:
|
|
|
122
186
|
|
|
123
187
|
Returns:
|
|
124
188
|
List of sessions with pagination info
|
|
189
|
+
|
|
190
|
+
Raises:
|
|
191
|
+
UserNotFoundError: If the user is not found
|
|
192
|
+
AuthenticationError: If the API key or project ID is invalid
|
|
193
|
+
InternalServerError: If the server encounters an error
|
|
194
|
+
NetworkError: If there are network issues
|
|
195
|
+
TimeoutError: If the request times out
|
|
196
|
+
RecallrAIError: For other API-related errors
|
|
125
197
|
"""
|
|
126
198
|
response = self._http.get(
|
|
127
199
|
f"/api/v1/users/{self.user_id}/sessions",
|
|
128
200
|
params={"offset": offset, "limit": limit},
|
|
129
201
|
)
|
|
130
|
-
|
|
202
|
+
|
|
203
|
+
if response.status_code == 404:
|
|
204
|
+
raise UserNotFoundError(user_id=self.user_id)
|
|
205
|
+
elif response.status_code != 200:
|
|
206
|
+
raise RecallrAIError(
|
|
207
|
+
message=f"Failed to list sessions: {response.json().get('detail', 'Unknown error')}",
|
|
208
|
+
http_status=response.status_code
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
return SessionList.from_api_response(response.json())
|
recallrai/utils/__init__.py
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# Path: recallrai/utils/__init__.py
|
|
2
2
|
# Description: Package initialization for utilities
|
|
3
3
|
|
|
4
|
-
from .
|
|
5
|
-
from .exceptions import RecallrAIError
|
|
4
|
+
from .http_client import HTTPClient
|
|
6
5
|
|
|
7
6
|
__all__ = [
|
|
8
7
|
"HTTPClient",
|
|
9
|
-
|
|
10
|
-
]
|
|
8
|
+
]
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Path: recallrai/utils/http.py
|
|
2
|
+
# Description: HTTP client utilities for the RecallrAI SDK
|
|
3
|
+
|
|
4
|
+
from httpx import Response, Client, TimeoutException, NetworkError, ConnectError
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
|
+
from ..exceptions import (
|
|
7
|
+
TimeoutError,
|
|
8
|
+
NetworkError as CustomNetworkError,
|
|
9
|
+
ConnectionError,
|
|
10
|
+
ValidationError,
|
|
11
|
+
InternalServerError,
|
|
12
|
+
AuthenticationError,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
class HTTPClient:
|
|
16
|
+
"""HTTP client for making requests to the RecallrAI API."""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
api_key: str,
|
|
21
|
+
project_id: str,
|
|
22
|
+
base_url: str,
|
|
23
|
+
timeout: int = 30,
|
|
24
|
+
):
|
|
25
|
+
"""
|
|
26
|
+
Initialize the HTTP client.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
api_key: Your RecallrAI API key
|
|
30
|
+
project_id: Your project ID
|
|
31
|
+
base_url: The base URL for the RecallrAI API
|
|
32
|
+
timeout: Request timeout in seconds
|
|
33
|
+
"""
|
|
34
|
+
self.api_key = api_key
|
|
35
|
+
self.project_id = project_id
|
|
36
|
+
self.base_url = base_url.rstrip("/")
|
|
37
|
+
self.timeout = timeout
|
|
38
|
+
self.client = Client(
|
|
39
|
+
timeout=self.timeout,
|
|
40
|
+
headers={
|
|
41
|
+
"X-Api-Key": self.api_key,
|
|
42
|
+
"X-Project-Id": self.project_id,
|
|
43
|
+
"Content-Type": "application/json",
|
|
44
|
+
"Accept": "application/json",
|
|
45
|
+
"User-Agent": "RecallrAI-Python-SDK",
|
|
46
|
+
# TODO: "SDK-Version": "0.1.0",
|
|
47
|
+
},
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
def request(
|
|
51
|
+
self,
|
|
52
|
+
method: str,
|
|
53
|
+
path: str,
|
|
54
|
+
params: Optional[Dict[str, Any]] = None,
|
|
55
|
+
data: Optional[Dict[str, Any]] = None,
|
|
56
|
+
) -> Response:
|
|
57
|
+
"""
|
|
58
|
+
Make a request to the RecallrAI API.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
method: HTTP method (GET, POST, PUT, DELETE)
|
|
62
|
+
path: API endpoint path
|
|
63
|
+
params: Query parameters
|
|
64
|
+
data: Request body data
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
The parsed JSON response
|
|
68
|
+
"""
|
|
69
|
+
url = f"{self.base_url}{path}"
|
|
70
|
+
|
|
71
|
+
# Filter out None values in params and data
|
|
72
|
+
if params:
|
|
73
|
+
params = {k: v for k, v in params.items() if v is not None}
|
|
74
|
+
|
|
75
|
+
if data:
|
|
76
|
+
data = {k: v for k, v in data.items() if v is not None}
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
response = self.client.request(
|
|
80
|
+
method=method,
|
|
81
|
+
url=url,
|
|
82
|
+
params=params,
|
|
83
|
+
json=data,
|
|
84
|
+
)
|
|
85
|
+
if response.status_code == 422:
|
|
86
|
+
raise ValidationError(
|
|
87
|
+
details=response.json()["detail"],
|
|
88
|
+
)
|
|
89
|
+
elif response.status_code == 500:
|
|
90
|
+
raise InternalServerError(
|
|
91
|
+
details=response.json()["detail"],
|
|
92
|
+
)
|
|
93
|
+
elif response.status_code == 401:
|
|
94
|
+
raise AuthenticationError(
|
|
95
|
+
details=response.json()["detail"],
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
return response
|
|
99
|
+
except TimeoutException as e:
|
|
100
|
+
raise TimeoutError(f"Request timed out: {e}")
|
|
101
|
+
except NetworkError as e:
|
|
102
|
+
raise CustomNetworkError(f"Network error occurred: {e}")
|
|
103
|
+
except ConnectError as e:
|
|
104
|
+
raise ConnectionError(f"Failed to connect to the API: {e}")
|
|
105
|
+
except Exception as e:
|
|
106
|
+
# Handle other exceptions as needed
|
|
107
|
+
raise e
|
|
108
|
+
|
|
109
|
+
def get(self, path: str, params: Optional[Dict[str, Any]] = None) -> Response:
|
|
110
|
+
"""Make a GET request."""
|
|
111
|
+
return self.request("GET", path, params=params)
|
|
112
|
+
|
|
113
|
+
def post(self, path: str, data: Optional[Dict[str, Any]] = None) -> Response:
|
|
114
|
+
"""Make a POST request."""
|
|
115
|
+
return self.request("POST", path, data=data)
|
|
116
|
+
|
|
117
|
+
def put(self, path: str, data: Optional[Dict[str, Any]] = None) -> Response:
|
|
118
|
+
"""Make a PUT request."""
|
|
119
|
+
return self.request("PUT", path, data=data)
|
|
120
|
+
|
|
121
|
+
def delete(self, path: str) -> Response:
|
|
122
|
+
"""Make a DELETE request."""
|
|
123
|
+
return self.request("DELETE", path)
|