rxresume-python 0.3.0__tar.gz → 0.4.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.
- {rxresume_python-0.3.0/rxresume_python.egg-info → rxresume_python-0.4.0}/PKG-INFO +67 -28
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/README.md +66 -27
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/pyproject.toml +1 -1
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/reactive_resume/api/__init__.py +9 -6
- rxresume_python-0.4.0/reactive_resume/api/agent.py +243 -0
- rxresume_python-0.4.0/reactive_resume/api/ai.py +89 -0
- rxresume_python-0.4.0/reactive_resume/api/ai_providers.py +89 -0
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/reactive_resume/api/applications.py +36 -14
- rxresume_python-0.4.0/reactive_resume/api/auth.py +45 -0
- rxresume_python-0.4.0/reactive_resume/api/flags.py +27 -0
- rxresume_python-0.4.0/reactive_resume/api/resumes.py +251 -0
- rxresume_python-0.4.0/reactive_resume/api/statistics.py +41 -0
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/reactive_resume/core/async_client.py +6 -5
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/reactive_resume/core/client.py +6 -5
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/reactive_resume/models/__init__.py +2 -7
- {rxresume_python-0.3.0 → rxresume_python-0.4.0/rxresume_python.egg-info}/PKG-INFO +67 -28
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/rxresume_python.egg-info/SOURCES.txt +2 -3
- rxresume_python-0.3.0/reactive_resume/api/agent.py +0 -37
- rxresume_python-0.3.0/reactive_resume/api/ai_providers.py +0 -31
- rxresume_python-0.3.0/reactive_resume/api/auth.py +0 -66
- rxresume_python-0.3.0/reactive_resume/api/resumes.py +0 -169
- rxresume_python-0.3.0/reactive_resume/api/statistics.py +0 -27
- rxresume_python-0.3.0/reactive_resume/api/storage.py +0 -53
- rxresume_python-0.3.0/reactive_resume/models/agent.py +0 -15
- rxresume_python-0.3.0/reactive_resume/models/storage.py +0 -14
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/LICENSE +0 -0
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/reactive_resume/__init__.py +0 -0
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/reactive_resume/core/__init__.py +0 -0
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/reactive_resume/core/exceptions.py +0 -0
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/reactive_resume/models/application.py +0 -0
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/reactive_resume/models/resume.py +0 -0
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/reactive_resume/models/statistics.py +0 -0
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/reactive_resume/models/user.py +0 -0
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/rxresume_python.egg-info/dependency_links.txt +0 -0
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/rxresume_python.egg-info/requires.txt +0 -0
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/rxresume_python.egg-info/top_level.txt +0 -0
- {rxresume_python-0.3.0 → rxresume_python-0.4.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rxresume-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Unofficial Python API client (SDK) for Reactive Resume v4
|
|
5
5
|
Author: Ata Can Yaymacı
|
|
6
6
|
License: MIT
|
|
@@ -42,14 +42,57 @@ It supports both synchronous (`httpx.Client`) and asynchronous (`httpx.AsyncClie
|
|
|
42
42
|
## Features
|
|
43
43
|
|
|
44
44
|
- **Dual client modes**: Support for both sync and async APIs.
|
|
45
|
-
- **Full API coverage**: Integrated modules for Resume management,
|
|
45
|
+
- **Full API coverage**: Integrated modules for Resume management, Job Applications tracking, AI Agent, AI Providers configurations, Global Statistics, and Feature Flags.
|
|
46
46
|
- **Type safety**: Fully typed models for all entities using Pydantic V2.
|
|
47
47
|
- **Robust error handling**: Raw API status errors are automatically parsed into specific exceptions (`AuthenticationError`, `NotFoundError`, etc.).
|
|
48
48
|
- **Developer Experience (DX)**: Code-completion ready with clear typing and docstrings.
|
|
49
49
|
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Architecture
|
|
53
|
+
|
|
54
|
+
```mermaid
|
|
55
|
+
graph TD
|
|
56
|
+
UserApp[User Application / Script] -->|Instantiates| SyncClient[RxResumeClient]
|
|
57
|
+
UserApp -->|Instantiates| AsyncClient[AsyncRxResumeClient]
|
|
58
|
+
|
|
59
|
+
subgraph "Service Modules (Sync & Async)"
|
|
60
|
+
SyncClient --> Auth[auth]
|
|
61
|
+
SyncClient --> Resumes[resumes]
|
|
62
|
+
SyncClient --> Stats[statistics]
|
|
63
|
+
SyncClient --> Agent[agent]
|
|
64
|
+
SyncClient --> AIProviders[ai_providers]
|
|
65
|
+
SyncClient --> Flags[flags]
|
|
66
|
+
SyncClient --> AI[ai]
|
|
67
|
+
SyncClient --> Applications[applications]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
Auth -->|HTTP/REST Calls| Backend[Reactive Resume v4 API Backend]
|
|
71
|
+
Resumes -->|HTTP/REST Calls| Backend
|
|
72
|
+
Stats -->|HTTP/REST Calls| Backend
|
|
73
|
+
Agent -->|HTTP/REST Calls| Backend
|
|
74
|
+
AIProviders -->|HTTP/REST Calls| Backend
|
|
75
|
+
Flags -->|HTTP/REST Calls| Backend
|
|
76
|
+
AI -->|HTTP/REST Calls| Backend
|
|
77
|
+
Applications -->|HTTP/REST Calls| Backend
|
|
78
|
+
```
|
|
50
79
|
|
|
51
80
|
---
|
|
52
81
|
|
|
82
|
+
## Capability Matrix
|
|
83
|
+
|
|
84
|
+
| Service Module | Sync | Async | Key Mapped Endpoints (Postman Collection) |
|
|
85
|
+
| :--- | :---: | :---: | :--- |
|
|
86
|
+
| **Resumes** (`client.resumes`) | Yes | Yes | List, Get, Create, Update, Delete, Import, Download PDF, Set/Verify/Remove Password, Duplicate, Lock, Version History, Public Resume, Statistics |
|
|
87
|
+
| **Applications** (`client.applications`) | Yes | Yes | List, Get, Create, Delete, List Tags, Pipeline Stats, Bulk Import |
|
|
88
|
+
| **Auth** (`client.auth`) | Yes | Yes | List Providers, Export Account, Delete Account |
|
|
89
|
+
| **Statistics** (`client.statistics`) | Yes | Yes | Users Count, GitHub Stars, Resumes Count (Global Stats) |
|
|
90
|
+
| **Agent** (`client.agent`) | Yes | Yes | List Threads, Create/Get/Delete Threads, Send Message, Stop Active Run, Resume Message Stream, Create/Delete Attachment, Revert Action |
|
|
91
|
+
| **AI Providers** (`client.ai_providers`) | Yes | Yes | List, Create, Update, Delete, Test saved AI providers |
|
|
92
|
+
| **AI Functions** (`client.ai`) | Yes | Yes | Parse PDF, Parse DOCX, Chat, Analyze Resume |
|
|
93
|
+
| **Feature Flags** (`client.flags`) | Yes | Yes | List Server-side Feature Flags |
|
|
94
|
+
|
|
95
|
+
|
|
53
96
|
## Installation
|
|
54
97
|
|
|
55
98
|
Install the package via `pip` or your favorite package manager:
|
|
@@ -90,9 +133,9 @@ async def main():
|
|
|
90
133
|
new_resume = await client.resumes.import_resume(import_data)
|
|
91
134
|
print(f"Created resume: {new_resume.name} (ID: {new_resume.id})")
|
|
92
135
|
|
|
93
|
-
#
|
|
94
|
-
|
|
95
|
-
print(f"PDF
|
|
136
|
+
# Download the compiled PDF bytes
|
|
137
|
+
pdf_bytes = await client.resumes.download_pdf(new_resume.id)
|
|
138
|
+
print(f"Downloaded PDF: {len(pdf_bytes)} bytes")
|
|
96
139
|
|
|
97
140
|
except Exception as e:
|
|
98
141
|
print(f"An error occurred: {e}")
|
|
@@ -105,7 +148,6 @@ if __name__ == "__main__":
|
|
|
105
148
|
|
|
106
149
|
```python
|
|
107
150
|
from reactive_resume import RxResumeClient
|
|
108
|
-
from reactive_resume.models import ResumeImportData
|
|
109
151
|
|
|
110
152
|
with RxResumeClient(base_url="https://rxresu.me", api_key="your_api_key") as client:
|
|
111
153
|
resumes = client.resumes.list()
|
|
@@ -113,33 +155,30 @@ with RxResumeClient(base_url="https://rxresu.me", api_key="your_api_key") as cli
|
|
|
113
155
|
print(f"Resume: {resume.name} (Slug: {resume.slug})")
|
|
114
156
|
```
|
|
115
157
|
|
|
116
|
-
### 3. Advanced Features (AI Agent,
|
|
158
|
+
### 3. Advanced Features (AI Agent, Statistics, Applications)
|
|
117
159
|
|
|
118
160
|
```python
|
|
119
161
|
with RxResumeClient(base_url="https://rxresu.me", api_key="your_api_key") as client:
|
|
120
|
-
# 1.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
print(f"
|
|
128
|
-
|
|
129
|
-
# 3.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
position="Senior Backend Engineer",
|
|
138
|
-
stage="Interviewing"
|
|
139
|
-
))
|
|
140
|
-
print(f"Logged Application ID: {app.id}")
|
|
162
|
+
# 1. Start a new AI Agent thread and send a message
|
|
163
|
+
thread = client.agent.create_thread()
|
|
164
|
+
response = client.agent.send_message(thread["id"], "Suggest a professional summary for a software developer.")
|
|
165
|
+
print(f"AI Suggestion: {response}")
|
|
166
|
+
|
|
167
|
+
# 2. Retrieve global resume platform metrics
|
|
168
|
+
users_count = client.statistics.get_users_count()
|
|
169
|
+
print(f"Platform Users: {users_count}")
|
|
170
|
+
|
|
171
|
+
# 3. List job applications
|
|
172
|
+
apps = client.applications.list()
|
|
173
|
+
for app in apps:
|
|
174
|
+
print(f"Job application: {app.company} - {app.position} ({app.stage})")
|
|
175
|
+
|
|
176
|
+
# 4. Check server-side feature flags
|
|
177
|
+
flags = client.flags.list()
|
|
178
|
+
print(f"Signups disabled: {flags.get('isSignupsDisabled')}")
|
|
141
179
|
```
|
|
142
180
|
|
|
181
|
+
|
|
143
182
|
---
|
|
144
183
|
|
|
145
184
|
|
|
@@ -13,14 +13,57 @@ It supports both synchronous (`httpx.Client`) and asynchronous (`httpx.AsyncClie
|
|
|
13
13
|
## Features
|
|
14
14
|
|
|
15
15
|
- **Dual client modes**: Support for both sync and async APIs.
|
|
16
|
-
- **Full API coverage**: Integrated modules for Resume management,
|
|
16
|
+
- **Full API coverage**: Integrated modules for Resume management, Job Applications tracking, AI Agent, AI Providers configurations, Global Statistics, and Feature Flags.
|
|
17
17
|
- **Type safety**: Fully typed models for all entities using Pydantic V2.
|
|
18
18
|
- **Robust error handling**: Raw API status errors are automatically parsed into specific exceptions (`AuthenticationError`, `NotFoundError`, etc.).
|
|
19
19
|
- **Developer Experience (DX)**: Code-completion ready with clear typing and docstrings.
|
|
20
20
|
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Architecture
|
|
24
|
+
|
|
25
|
+
```mermaid
|
|
26
|
+
graph TD
|
|
27
|
+
UserApp[User Application / Script] -->|Instantiates| SyncClient[RxResumeClient]
|
|
28
|
+
UserApp -->|Instantiates| AsyncClient[AsyncRxResumeClient]
|
|
29
|
+
|
|
30
|
+
subgraph "Service Modules (Sync & Async)"
|
|
31
|
+
SyncClient --> Auth[auth]
|
|
32
|
+
SyncClient --> Resumes[resumes]
|
|
33
|
+
SyncClient --> Stats[statistics]
|
|
34
|
+
SyncClient --> Agent[agent]
|
|
35
|
+
SyncClient --> AIProviders[ai_providers]
|
|
36
|
+
SyncClient --> Flags[flags]
|
|
37
|
+
SyncClient --> AI[ai]
|
|
38
|
+
SyncClient --> Applications[applications]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
Auth -->|HTTP/REST Calls| Backend[Reactive Resume v4 API Backend]
|
|
42
|
+
Resumes -->|HTTP/REST Calls| Backend
|
|
43
|
+
Stats -->|HTTP/REST Calls| Backend
|
|
44
|
+
Agent -->|HTTP/REST Calls| Backend
|
|
45
|
+
AIProviders -->|HTTP/REST Calls| Backend
|
|
46
|
+
Flags -->|HTTP/REST Calls| Backend
|
|
47
|
+
AI -->|HTTP/REST Calls| Backend
|
|
48
|
+
Applications -->|HTTP/REST Calls| Backend
|
|
49
|
+
```
|
|
21
50
|
|
|
22
51
|
---
|
|
23
52
|
|
|
53
|
+
## Capability Matrix
|
|
54
|
+
|
|
55
|
+
| Service Module | Sync | Async | Key Mapped Endpoints (Postman Collection) |
|
|
56
|
+
| :--- | :---: | :---: | :--- |
|
|
57
|
+
| **Resumes** (`client.resumes`) | Yes | Yes | List, Get, Create, Update, Delete, Import, Download PDF, Set/Verify/Remove Password, Duplicate, Lock, Version History, Public Resume, Statistics |
|
|
58
|
+
| **Applications** (`client.applications`) | Yes | Yes | List, Get, Create, Delete, List Tags, Pipeline Stats, Bulk Import |
|
|
59
|
+
| **Auth** (`client.auth`) | Yes | Yes | List Providers, Export Account, Delete Account |
|
|
60
|
+
| **Statistics** (`client.statistics`) | Yes | Yes | Users Count, GitHub Stars, Resumes Count (Global Stats) |
|
|
61
|
+
| **Agent** (`client.agent`) | Yes | Yes | List Threads, Create/Get/Delete Threads, Send Message, Stop Active Run, Resume Message Stream, Create/Delete Attachment, Revert Action |
|
|
62
|
+
| **AI Providers** (`client.ai_providers`) | Yes | Yes | List, Create, Update, Delete, Test saved AI providers |
|
|
63
|
+
| **AI Functions** (`client.ai`) | Yes | Yes | Parse PDF, Parse DOCX, Chat, Analyze Resume |
|
|
64
|
+
| **Feature Flags** (`client.flags`) | Yes | Yes | List Server-side Feature Flags |
|
|
65
|
+
|
|
66
|
+
|
|
24
67
|
## Installation
|
|
25
68
|
|
|
26
69
|
Install the package via `pip` or your favorite package manager:
|
|
@@ -61,9 +104,9 @@ async def main():
|
|
|
61
104
|
new_resume = await client.resumes.import_resume(import_data)
|
|
62
105
|
print(f"Created resume: {new_resume.name} (ID: {new_resume.id})")
|
|
63
106
|
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
print(f"PDF
|
|
107
|
+
# Download the compiled PDF bytes
|
|
108
|
+
pdf_bytes = await client.resumes.download_pdf(new_resume.id)
|
|
109
|
+
print(f"Downloaded PDF: {len(pdf_bytes)} bytes")
|
|
67
110
|
|
|
68
111
|
except Exception as e:
|
|
69
112
|
print(f"An error occurred: {e}")
|
|
@@ -76,7 +119,6 @@ if __name__ == "__main__":
|
|
|
76
119
|
|
|
77
120
|
```python
|
|
78
121
|
from reactive_resume import RxResumeClient
|
|
79
|
-
from reactive_resume.models import ResumeImportData
|
|
80
122
|
|
|
81
123
|
with RxResumeClient(base_url="https://rxresu.me", api_key="your_api_key") as client:
|
|
82
124
|
resumes = client.resumes.list()
|
|
@@ -84,33 +126,30 @@ with RxResumeClient(base_url="https://rxresu.me", api_key="your_api_key") as cli
|
|
|
84
126
|
print(f"Resume: {resume.name} (Slug: {resume.slug})")
|
|
85
127
|
```
|
|
86
128
|
|
|
87
|
-
### 3. Advanced Features (AI Agent,
|
|
129
|
+
### 3. Advanced Features (AI Agent, Statistics, Applications)
|
|
88
130
|
|
|
89
131
|
```python
|
|
90
132
|
with RxResumeClient(base_url="https://rxresu.me", api_key="your_api_key") as client:
|
|
91
|
-
# 1.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
print(f"
|
|
99
|
-
|
|
100
|
-
# 3.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
position="Senior Backend Engineer",
|
|
109
|
-
stage="Interviewing"
|
|
110
|
-
))
|
|
111
|
-
print(f"Logged Application ID: {app.id}")
|
|
133
|
+
# 1. Start a new AI Agent thread and send a message
|
|
134
|
+
thread = client.agent.create_thread()
|
|
135
|
+
response = client.agent.send_message(thread["id"], "Suggest a professional summary for a software developer.")
|
|
136
|
+
print(f"AI Suggestion: {response}")
|
|
137
|
+
|
|
138
|
+
# 2. Retrieve global resume platform metrics
|
|
139
|
+
users_count = client.statistics.get_users_count()
|
|
140
|
+
print(f"Platform Users: {users_count}")
|
|
141
|
+
|
|
142
|
+
# 3. List job applications
|
|
143
|
+
apps = client.applications.list()
|
|
144
|
+
for app in apps:
|
|
145
|
+
print(f"Job application: {app.company} - {app.position} ({app.stage})")
|
|
146
|
+
|
|
147
|
+
# 4. Check server-side feature flags
|
|
148
|
+
flags = client.flags.list()
|
|
149
|
+
print(f"Signups disabled: {flags.get('isSignupsDisabled')}")
|
|
112
150
|
```
|
|
113
151
|
|
|
152
|
+
|
|
114
153
|
---
|
|
115
154
|
|
|
116
155
|
|
|
@@ -2,25 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
from .auth import AuthAPI, AsyncAuthAPI
|
|
4
4
|
from .resumes import ResumesAPI, AsyncResumesAPI
|
|
5
|
-
from .applications import ApplicationsAPI, AsyncApplicationsAPI
|
|
6
5
|
from .statistics import StatisticsAPI, AsyncStatisticsAPI
|
|
7
|
-
from .storage import StorageAPI, AsyncStorageAPI
|
|
8
6
|
from .agent import AgentAPI, AsyncAgentAPI
|
|
9
7
|
from .ai_providers import AiProvidersAPI, AsyncAiProvidersAPI
|
|
8
|
+
from .flags import FlagsAPI, AsyncFlagsAPI
|
|
9
|
+
from .ai import AIAPI, AsyncAIAPI
|
|
10
|
+
from .applications import ApplicationsAPI, AsyncApplicationsAPI
|
|
10
11
|
|
|
11
12
|
__all__ = [
|
|
12
13
|
"AuthAPI",
|
|
13
14
|
"AsyncAuthAPI",
|
|
14
15
|
"ResumesAPI",
|
|
15
16
|
"AsyncResumesAPI",
|
|
16
|
-
"ApplicationsAPI",
|
|
17
|
-
"AsyncApplicationsAPI",
|
|
18
17
|
"StatisticsAPI",
|
|
19
18
|
"AsyncStatisticsAPI",
|
|
20
|
-
"StorageAPI",
|
|
21
|
-
"AsyncStorageAPI",
|
|
22
19
|
"AgentAPI",
|
|
23
20
|
"AsyncAgentAPI",
|
|
24
21
|
"AiProvidersAPI",
|
|
25
22
|
"AsyncAiProvidersAPI",
|
|
23
|
+
"FlagsAPI",
|
|
24
|
+
"AsyncFlagsAPI",
|
|
25
|
+
"AIAPI",
|
|
26
|
+
"AsyncAIAPI",
|
|
27
|
+
"ApplicationsAPI",
|
|
28
|
+
"AsyncApplicationsAPI",
|
|
26
29
|
]
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"""Agent API endpoints implementation."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Dict, Any, Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AgentAPI:
|
|
7
|
+
"""Synchronous AI Agent operations."""
|
|
8
|
+
|
|
9
|
+
def __init__(self, client) -> None:
|
|
10
|
+
self._client = client
|
|
11
|
+
|
|
12
|
+
def list_threads(self) -> List[Dict[str, Any]]:
|
|
13
|
+
"""List all active agent threads."""
|
|
14
|
+
response = self._client._request("GET", "/api/openapi/agent/threads")
|
|
15
|
+
return list(response)
|
|
16
|
+
|
|
17
|
+
def get_thread(self, thread_id: str) -> Dict[str, Any]:
|
|
18
|
+
"""Get details of a specific agent thread by ID."""
|
|
19
|
+
response = self._client._request("GET", f"/api/openapi/agent/threads/{thread_id}")
|
|
20
|
+
return dict(response)
|
|
21
|
+
|
|
22
|
+
def delete_thread(self, thread_id: str) -> None:
|
|
23
|
+
"""Delete an agent thread by ID."""
|
|
24
|
+
self._client._request("DELETE", f"/api/openapi/agent/threads/{thread_id}")
|
|
25
|
+
|
|
26
|
+
def create_thread(
|
|
27
|
+
self, ai_provider_id: Optional[str] = None, source_resume_id: Optional[str] = None
|
|
28
|
+
) -> Dict[str, Any]:
|
|
29
|
+
"""Create a new agent thread."""
|
|
30
|
+
payload = {}
|
|
31
|
+
if ai_provider_id is not None:
|
|
32
|
+
payload["aiProviderId"] = ai_provider_id
|
|
33
|
+
if source_resume_id is not None:
|
|
34
|
+
payload["sourceResumeId"] = source_resume_id
|
|
35
|
+
response = self._client._request("POST", "/api/openapi/agent/threads", json=payload)
|
|
36
|
+
return dict(response)
|
|
37
|
+
|
|
38
|
+
def get_or_create_thread_for_resume(
|
|
39
|
+
self, ai_provider_id: Optional[str] = None, source_resume_id: Optional[str] = None
|
|
40
|
+
) -> Dict[str, Any]:
|
|
41
|
+
"""Get or create an in-resume agent thread."""
|
|
42
|
+
payload = {}
|
|
43
|
+
if ai_provider_id is not None:
|
|
44
|
+
payload["aiProviderId"] = ai_provider_id
|
|
45
|
+
if source_resume_id is not None:
|
|
46
|
+
payload["sourceResumeId"] = source_resume_id
|
|
47
|
+
response = self._client._request(
|
|
48
|
+
"POST", "/api/openapi/agent/threads/for-resume", json=payload
|
|
49
|
+
)
|
|
50
|
+
return dict(response)
|
|
51
|
+
|
|
52
|
+
def send_message(
|
|
53
|
+
self, thread_id: str, message: Any, attachment_ids: Optional[List[str]] = None
|
|
54
|
+
) -> Dict[str, Any]:
|
|
55
|
+
"""Send an agent message."""
|
|
56
|
+
payload = {
|
|
57
|
+
"threadId": thread_id,
|
|
58
|
+
"message": message,
|
|
59
|
+
}
|
|
60
|
+
if attachment_ids is not None:
|
|
61
|
+
payload["attachmentIds"] = attachment_ids
|
|
62
|
+
response = self._client._request("POST", "/api/openapi/agent/messages/send", json=payload)
|
|
63
|
+
return dict(response)
|
|
64
|
+
|
|
65
|
+
def archive_thread(
|
|
66
|
+
self,
|
|
67
|
+
thread_id: str,
|
|
68
|
+
ai_provider_id: Optional[str] = None,
|
|
69
|
+
source_resume_id: Optional[str] = None,
|
|
70
|
+
) -> Dict[str, Any]:
|
|
71
|
+
"""Archive an agent thread."""
|
|
72
|
+
payload = {}
|
|
73
|
+
if ai_provider_id is not None:
|
|
74
|
+
payload["aiProviderId"] = ai_provider_id
|
|
75
|
+
if source_resume_id is not None:
|
|
76
|
+
payload["sourceResumeId"] = source_resume_id
|
|
77
|
+
response = self._client._request(
|
|
78
|
+
"POST", f"/api/openapi/agent/threads/{thread_id}/archive", json=payload
|
|
79
|
+
)
|
|
80
|
+
return dict(response)
|
|
81
|
+
|
|
82
|
+
def stop_run(self, thread_id: str, partial_message: Optional[Any] = None) -> Dict[str, Any]:
|
|
83
|
+
"""Stop active agent run."""
|
|
84
|
+
payload = {
|
|
85
|
+
"threadId": thread_id,
|
|
86
|
+
}
|
|
87
|
+
if partial_message is not None:
|
|
88
|
+
payload["partialMessage"] = partial_message
|
|
89
|
+
response = self._client._request("POST", "/api/openapi/agent/messages/stop", json=payload)
|
|
90
|
+
return dict(response)
|
|
91
|
+
|
|
92
|
+
def resume_message_stream(self, thread_id: str) -> Any:
|
|
93
|
+
"""Resume agent message stream."""
|
|
94
|
+
return self._client._request(
|
|
95
|
+
"GET", f"/api/openapi/agent/messages/resume?threadId={thread_id}"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def create_attachment(
|
|
99
|
+
self, thread_id: str, filename: str, media_type: str, data: str
|
|
100
|
+
) -> Dict[str, Any]:
|
|
101
|
+
"""Create agent attachment."""
|
|
102
|
+
payload = {
|
|
103
|
+
"threadId": thread_id,
|
|
104
|
+
"filename": filename,
|
|
105
|
+
"mediaType": media_type,
|
|
106
|
+
"data": data,
|
|
107
|
+
}
|
|
108
|
+
response = self._client._request("POST", "/api/openapi/agent/attachments", json=payload)
|
|
109
|
+
return dict(response)
|
|
110
|
+
|
|
111
|
+
def delete_attachment(self, attachment_id: str) -> None:
|
|
112
|
+
"""Delete agent attachment."""
|
|
113
|
+
self._client._request("DELETE", f"/api/openapi/agent/attachments/{attachment_id}")
|
|
114
|
+
|
|
115
|
+
def revert_action(self, action_id: str) -> Dict[str, Any]:
|
|
116
|
+
"""Restore agent action snapshot."""
|
|
117
|
+
response = self._client._request("POST", f"/api/openapi/agent/actions/{action_id}/revert")
|
|
118
|
+
return dict(response)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class AsyncAgentAPI:
|
|
122
|
+
"""Asynchronous AI Agent operations."""
|
|
123
|
+
|
|
124
|
+
def __init__(self, client) -> None:
|
|
125
|
+
self._client = client
|
|
126
|
+
|
|
127
|
+
async def list_threads(self) -> List[Dict[str, Any]]:
|
|
128
|
+
"""List all active agent threads asynchronously."""
|
|
129
|
+
response = await self._client._request("GET", "/api/openapi/agent/threads")
|
|
130
|
+
return list(response)
|
|
131
|
+
|
|
132
|
+
async def get_thread(self, thread_id: str) -> Dict[str, Any]:
|
|
133
|
+
"""Get details of a specific agent thread by ID asynchronously."""
|
|
134
|
+
response = await self._client._request("GET", f"/api/openapi/agent/threads/{thread_id}")
|
|
135
|
+
return dict(response)
|
|
136
|
+
|
|
137
|
+
async def delete_thread(self, thread_id: str) -> None:
|
|
138
|
+
"""Delete an agent thread by ID asynchronously."""
|
|
139
|
+
await self._client._request("DELETE", f"/api/openapi/agent/threads/{thread_id}")
|
|
140
|
+
|
|
141
|
+
async def create_thread(
|
|
142
|
+
self, ai_provider_id: Optional[str] = None, source_resume_id: Optional[str] = None
|
|
143
|
+
) -> Dict[str, Any]:
|
|
144
|
+
"""Create a new agent thread asynchronously."""
|
|
145
|
+
payload = {}
|
|
146
|
+
if ai_provider_id is not None:
|
|
147
|
+
payload["aiProviderId"] = ai_provider_id
|
|
148
|
+
if source_resume_id is not None:
|
|
149
|
+
payload["sourceResumeId"] = source_resume_id
|
|
150
|
+
response = await self._client._request("POST", "/api/openapi/agent/threads", json=payload)
|
|
151
|
+
return dict(response)
|
|
152
|
+
|
|
153
|
+
async def get_or_create_thread_for_resume(
|
|
154
|
+
self, ai_provider_id: Optional[str] = None, source_resume_id: Optional[str] = None
|
|
155
|
+
) -> Dict[str, Any]:
|
|
156
|
+
"""Get or create an in-resume agent thread asynchronously."""
|
|
157
|
+
payload = {}
|
|
158
|
+
if ai_provider_id is not None:
|
|
159
|
+
payload["aiProviderId"] = ai_provider_id
|
|
160
|
+
if source_resume_id is not None:
|
|
161
|
+
payload["sourceResumeId"] = source_resume_id
|
|
162
|
+
response = await self._client._request(
|
|
163
|
+
"POST", "/api/openapi/agent/threads/for-resume", json=payload
|
|
164
|
+
)
|
|
165
|
+
return dict(response)
|
|
166
|
+
|
|
167
|
+
async def send_message(
|
|
168
|
+
self, thread_id: str, message: Any, attachment_ids: Optional[List[str]] = None
|
|
169
|
+
) -> Dict[str, Any]:
|
|
170
|
+
"""Send an agent message asynchronously."""
|
|
171
|
+
payload = {
|
|
172
|
+
"threadId": thread_id,
|
|
173
|
+
"message": message,
|
|
174
|
+
}
|
|
175
|
+
if attachment_ids is not None:
|
|
176
|
+
payload["attachmentIds"] = attachment_ids
|
|
177
|
+
response = await self._client._request(
|
|
178
|
+
"POST", "/api/openapi/agent/messages/send", json=payload
|
|
179
|
+
)
|
|
180
|
+
return dict(response)
|
|
181
|
+
|
|
182
|
+
async def archive_thread(
|
|
183
|
+
self,
|
|
184
|
+
thread_id: str,
|
|
185
|
+
ai_provider_id: Optional[str] = None,
|
|
186
|
+
source_resume_id: Optional[str] = None,
|
|
187
|
+
) -> Dict[str, Any]:
|
|
188
|
+
"""Archive an agent thread asynchronously."""
|
|
189
|
+
payload = {}
|
|
190
|
+
if ai_provider_id is not None:
|
|
191
|
+
payload["aiProviderId"] = ai_provider_id
|
|
192
|
+
if source_resume_id is not None:
|
|
193
|
+
payload["sourceResumeId"] = source_resume_id
|
|
194
|
+
response = await self._client._request(
|
|
195
|
+
"POST", f"/api/openapi/agent/threads/{thread_id}/archive", json=payload
|
|
196
|
+
)
|
|
197
|
+
return dict(response)
|
|
198
|
+
|
|
199
|
+
async def stop_run(
|
|
200
|
+
self, thread_id: str, partial_message: Optional[Any] = None
|
|
201
|
+
) -> Dict[str, Any]:
|
|
202
|
+
"""Stop active agent run asynchronously."""
|
|
203
|
+
payload = {
|
|
204
|
+
"threadId": thread_id,
|
|
205
|
+
}
|
|
206
|
+
if partial_message is not None:
|
|
207
|
+
payload["partialMessage"] = partial_message
|
|
208
|
+
response = await self._client._request(
|
|
209
|
+
"POST", "/api/openapi/agent/messages/stop", json=payload
|
|
210
|
+
)
|
|
211
|
+
return dict(response)
|
|
212
|
+
|
|
213
|
+
async def resume_message_stream(self, thread_id: str) -> Any:
|
|
214
|
+
"""Resume agent message stream asynchronously."""
|
|
215
|
+
return await self._client._request(
|
|
216
|
+
"GET", f"/api/openapi/agent/messages/resume?threadId={thread_id}"
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
async def create_attachment(
|
|
220
|
+
self, thread_id: str, filename: str, media_type: str, data: str
|
|
221
|
+
) -> Dict[str, Any]:
|
|
222
|
+
"""Create agent attachment asynchronously."""
|
|
223
|
+
payload = {
|
|
224
|
+
"threadId": thread_id,
|
|
225
|
+
"filename": filename,
|
|
226
|
+
"mediaType": media_type,
|
|
227
|
+
"data": data,
|
|
228
|
+
}
|
|
229
|
+
response = await self._client._request(
|
|
230
|
+
"POST", "/api/openapi/agent/attachments", json=payload
|
|
231
|
+
)
|
|
232
|
+
return dict(response)
|
|
233
|
+
|
|
234
|
+
async def delete_attachment(self, attachment_id: str) -> None:
|
|
235
|
+
"""Delete agent attachment asynchronously."""
|
|
236
|
+
await self._client._request("DELETE", f"/api/openapi/agent/attachments/{attachment_id}")
|
|
237
|
+
|
|
238
|
+
async def revert_action(self, action_id: str) -> Dict[str, Any]:
|
|
239
|
+
"""Restore agent action snapshot asynchronously."""
|
|
240
|
+
response = await self._client._request(
|
|
241
|
+
"POST", f"/api/openapi/agent/actions/{action_id}/revert"
|
|
242
|
+
)
|
|
243
|
+
return dict(response)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""AI API endpoints implementation."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AIAPI:
|
|
7
|
+
"""Synchronous AI operations."""
|
|
8
|
+
|
|
9
|
+
def __init__(self, client) -> None:
|
|
10
|
+
self._client = client
|
|
11
|
+
|
|
12
|
+
def parse_pdf(self, file_name: str, file_data: str, provider_id: str) -> Dict[str, Any]:
|
|
13
|
+
"""Parse a PDF file into resume data.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
file_name: Name of the file.
|
|
17
|
+
file_data: Base64 or binary data representation.
|
|
18
|
+
provider_id: The ID of the configured AI provider.
|
|
19
|
+
"""
|
|
20
|
+
payload = {
|
|
21
|
+
"file": {"name": file_name, "data": file_data},
|
|
22
|
+
"aiProviderId": provider_id,
|
|
23
|
+
}
|
|
24
|
+
response = self._client._request("POST", "/api/openapi/ai/parse-pdf", json=payload)
|
|
25
|
+
return dict(response)
|
|
26
|
+
|
|
27
|
+
def parse_docx(self, file_name: str, file_data: str, provider_id: str) -> Dict[str, Any]:
|
|
28
|
+
"""Parse a DOCX file into resume data."""
|
|
29
|
+
payload = {
|
|
30
|
+
"file": {"name": file_name, "data": file_data},
|
|
31
|
+
"aiProviderId": provider_id,
|
|
32
|
+
}
|
|
33
|
+
response = self._client._request("POST", "/api/openapi/ai/parse-docx", json=payload)
|
|
34
|
+
return dict(response)
|
|
35
|
+
|
|
36
|
+
def chat(self, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
37
|
+
"""Chat with AI to modify resume."""
|
|
38
|
+
response = self._client._request("POST", "/api/openapi/ai/chat", json=payload)
|
|
39
|
+
return dict(response)
|
|
40
|
+
|
|
41
|
+
def analyze_resume(self, resume_id: str, provider_id: str) -> Dict[str, Any]:
|
|
42
|
+
"""Analyze a resume and persist the latest analysis."""
|
|
43
|
+
payload = {
|
|
44
|
+
"resumeId": resume_id,
|
|
45
|
+
"aiProviderId": provider_id,
|
|
46
|
+
}
|
|
47
|
+
response = self._client._request("POST", "/api/openapi/ai/analyze-resume", json=payload)
|
|
48
|
+
return dict(response)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class AsyncAIAPI:
|
|
52
|
+
"""Asynchronous AI operations."""
|
|
53
|
+
|
|
54
|
+
def __init__(self, client) -> None:
|
|
55
|
+
self._client = client
|
|
56
|
+
|
|
57
|
+
async def parse_pdf(self, file_name: str, file_data: str, provider_id: str) -> Dict[str, Any]:
|
|
58
|
+
"""Parse a PDF file into resume data asynchronously."""
|
|
59
|
+
payload = {
|
|
60
|
+
"file": {"name": file_name, "data": file_data},
|
|
61
|
+
"aiProviderId": provider_id,
|
|
62
|
+
}
|
|
63
|
+
response = await self._client._request("POST", "/api/openapi/ai/parse-pdf", json=payload)
|
|
64
|
+
return dict(response)
|
|
65
|
+
|
|
66
|
+
async def parse_docx(self, file_name: str, file_data: str, provider_id: str) -> Dict[str, Any]:
|
|
67
|
+
"""Parse a DOCX file into resume data asynchronously."""
|
|
68
|
+
payload = {
|
|
69
|
+
"file": {"name": file_name, "data": file_data},
|
|
70
|
+
"aiProviderId": provider_id,
|
|
71
|
+
}
|
|
72
|
+
response = await self._client._request("POST", "/api/openapi/ai/parse-docx", json=payload)
|
|
73
|
+
return dict(response)
|
|
74
|
+
|
|
75
|
+
async def chat(self, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
76
|
+
"""Chat with AI asynchronously to modify resume."""
|
|
77
|
+
response = await self._client._request("POST", "/api/openapi/ai/chat", json=payload)
|
|
78
|
+
return dict(response)
|
|
79
|
+
|
|
80
|
+
async def analyze_resume(self, resume_id: str, provider_id: str) -> Dict[str, Any]:
|
|
81
|
+
"""Analyze a resume asynchronously and persist the latest analysis."""
|
|
82
|
+
payload = {
|
|
83
|
+
"resumeId": resume_id,
|
|
84
|
+
"aiProviderId": provider_id,
|
|
85
|
+
}
|
|
86
|
+
response = await self._client._request(
|
|
87
|
+
"POST", "/api/openapi/ai/analyze-resume", json=payload
|
|
88
|
+
)
|
|
89
|
+
return dict(response)
|