aiondtech 2.1.0__py3-none-any.whl → 2.2.0__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.
- aiondtech/__init__.py +1 -1
- aiondtech/client.py +7 -613
- aiondtech/models.py +19 -446
- {aiondtech-2.1.0.dist-info → aiondtech-2.2.0.dist-info}/METADATA +34 -15
- aiondtech-2.2.0.dist-info/RECORD +9 -0
- aiondtech-2.1.0.dist-info/RECORD +0 -9
- {aiondtech-2.1.0.dist-info → aiondtech-2.2.0.dist-info}/WHEEL +0 -0
- {aiondtech-2.1.0.dist-info → aiondtech-2.2.0.dist-info}/licenses/LICENSE +0 -0
- {aiondtech-2.1.0.dist-info → aiondtech-2.2.0.dist-info}/top_level.txt +0 -0
aiondtech/models.py
CHANGED
|
@@ -1,433 +1,3 @@
|
|
|
1
|
-
# """
|
|
2
|
-
# Data models and exceptions for the AiondTech SDK v2.
|
|
3
|
-
# """
|
|
4
|
-
|
|
5
|
-
# from dataclasses import dataclass, field
|
|
6
|
-
# from typing import List, Optional, Dict, Any
|
|
7
|
-
# from datetime import datetime
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# # ============================================================================
|
|
11
|
-
# # EXCEPTIONS
|
|
12
|
-
# # ============================================================================
|
|
13
|
-
|
|
14
|
-
# class APIError(Exception):
|
|
15
|
-
# """Base exception for all API errors."""
|
|
16
|
-
|
|
17
|
-
# def __init__(
|
|
18
|
-
# self,
|
|
19
|
-
# message: str,
|
|
20
|
-
# status_code: Optional[int] = None,
|
|
21
|
-
# response: Optional[Dict[str, Any]] = None
|
|
22
|
-
# ):
|
|
23
|
-
# self.message = message
|
|
24
|
-
# self.status_code = status_code
|
|
25
|
-
# self.response = response or {}
|
|
26
|
-
# super().__init__(self.message)
|
|
27
|
-
|
|
28
|
-
# def __str__(self):
|
|
29
|
-
# if self.status_code:
|
|
30
|
-
# return f"[{self.status_code}] {self.message}"
|
|
31
|
-
# return self.message
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
# class AuthenticationError(APIError):
|
|
35
|
-
# """Raised when API key is invalid or missing."""
|
|
36
|
-
# pass
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
# class RateLimitError(APIError):
|
|
40
|
-
# """Raised when rate limit is exceeded."""
|
|
41
|
-
|
|
42
|
-
# def __init__(
|
|
43
|
-
# self,
|
|
44
|
-
# message: str = "Rate limit exceeded",
|
|
45
|
-
# retry_after: Optional[int] = None,
|
|
46
|
-
# **kwargs
|
|
47
|
-
# ):
|
|
48
|
-
# self.retry_after = retry_after
|
|
49
|
-
# super().__init__(message, **kwargs)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
# class ValidationError(APIError):
|
|
53
|
-
# """Raised when request validation fails."""
|
|
54
|
-
# pass
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
# class NotFoundError(APIError):
|
|
58
|
-
# """Raised when a resource is not found."""
|
|
59
|
-
# pass
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
# class InsufficientCreditsError(APIError):
|
|
63
|
-
# """Raised when user has insufficient API credits."""
|
|
64
|
-
|
|
65
|
-
# def __init__(
|
|
66
|
-
# self,
|
|
67
|
-
# message: str = "Insufficient API credits",
|
|
68
|
-
# credits_remaining: int = 0,
|
|
69
|
-
# credits_required: int = 0,
|
|
70
|
-
# **kwargs
|
|
71
|
-
# ):
|
|
72
|
-
# self.credits_remaining = credits_remaining
|
|
73
|
-
# self.credits_required = credits_required
|
|
74
|
-
# super().__init__(message, **kwargs)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
# # ============================================================================
|
|
78
|
-
# # RESPONSE MODELS
|
|
79
|
-
# # ============================================================================
|
|
80
|
-
|
|
81
|
-
# @dataclass
|
|
82
|
-
# class ResumeUploadResult:
|
|
83
|
-
# """Result from uploading a resume (upload only, no parsing)."""
|
|
84
|
-
# resume_id: int
|
|
85
|
-
# message: str
|
|
86
|
-
# credits_used: int = 1
|
|
87
|
-
# _raw: Dict[str, Any] = field(default_factory=dict, repr=False)
|
|
88
|
-
|
|
89
|
-
# @classmethod
|
|
90
|
-
# def from_response(cls, data: Dict[str, Any]) -> "ResumeUploadResult":
|
|
91
|
-
# return cls(
|
|
92
|
-
# resume_id=data.get("resume_id"),
|
|
93
|
-
# message=data.get("message", "Resume uploaded successfully"),
|
|
94
|
-
# credits_used=data.get("credits_used", 1),
|
|
95
|
-
# _raw=data
|
|
96
|
-
# )
|
|
97
|
-
|
|
98
|
-
# def __repr__(self):
|
|
99
|
-
# return f"<ResumeUploadResult resume_id={self.resume_id}>"
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
# @dataclass
|
|
103
|
-
# class ResumeAnalysisResult:
|
|
104
|
-
# """Result from uploading and analyzing a resume."""
|
|
105
|
-
# resume_id: int
|
|
106
|
-
# parsed_data: Dict[str, Any]
|
|
107
|
-
# credits_used: int = 3
|
|
108
|
-
# _raw: Dict[str, Any] = field(default_factory=dict, repr=False)
|
|
109
|
-
|
|
110
|
-
# @classmethod
|
|
111
|
-
# def from_response(cls, data: Dict[str, Any]) -> "ResumeAnalysisResult":
|
|
112
|
-
# return cls(
|
|
113
|
-
# resume_id=data.get("resume_id"),
|
|
114
|
-
# parsed_data=data.get("parsed_data", {}),
|
|
115
|
-
# credits_used=data.get("credits_used", 3),
|
|
116
|
-
# _raw=data
|
|
117
|
-
# )
|
|
118
|
-
|
|
119
|
-
# @property
|
|
120
|
-
# def full_name(self) -> Optional[str]:
|
|
121
|
-
# return self.parsed_data.get("full_name")
|
|
122
|
-
|
|
123
|
-
# @property
|
|
124
|
-
# def email(self) -> Optional[str]:
|
|
125
|
-
# return self.parsed_data.get("email")
|
|
126
|
-
|
|
127
|
-
# @property
|
|
128
|
-
# def skills(self) -> List[str]:
|
|
129
|
-
# skills = self.parsed_data.get("skills", [])
|
|
130
|
-
# if isinstance(skills, str):
|
|
131
|
-
# return [s.strip() for s in skills.split(",") if s.strip()]
|
|
132
|
-
# return skills or []
|
|
133
|
-
|
|
134
|
-
# @property
|
|
135
|
-
# def job_titles(self) -> List[str]:
|
|
136
|
-
# titles = self.parsed_data.get("job_titles", [])
|
|
137
|
-
# if isinstance(titles, str):
|
|
138
|
-
# return [t.strip() for t in titles.split(",") if t.strip()]
|
|
139
|
-
# return titles or []
|
|
140
|
-
|
|
141
|
-
# @property
|
|
142
|
-
# def total_experience(self) -> Optional[str]:
|
|
143
|
-
# return self.parsed_data.get("total_experience")
|
|
144
|
-
|
|
145
|
-
# def __repr__(self):
|
|
146
|
-
# name = self.full_name or "Unknown"
|
|
147
|
-
# return f"<ResumeAnalysisResult resume_id={self.resume_id} name='{name}'>"
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
# @dataclass
|
|
151
|
-
# class ResumeComparisonResult:
|
|
152
|
-
# """Result from comparing a resume to a job posting."""
|
|
153
|
-
# resume_id: int
|
|
154
|
-
# job_id: int
|
|
155
|
-
# comparison_score: float
|
|
156
|
-
# comparison_reason: str
|
|
157
|
-
# parsed_data: Optional[Dict[str, Any]] = None
|
|
158
|
-
# matched_keywords: List[str] = field(default_factory=list)
|
|
159
|
-
# missing_keywords: List[str] = field(default_factory=list)
|
|
160
|
-
# suggestions: List[str] = field(default_factory=list)
|
|
161
|
-
# credits_used: int = 3
|
|
162
|
-
# _raw: Dict[str, Any] = field(default_factory=dict, repr=False)
|
|
163
|
-
|
|
164
|
-
# @classmethod
|
|
165
|
-
# def from_response(cls, data: Dict[str, Any]) -> "ResumeComparisonResult":
|
|
166
|
-
# return cls(
|
|
167
|
-
# resume_id=data.get("resume_id"),
|
|
168
|
-
# job_id=data.get("job_id"),
|
|
169
|
-
# comparison_score=data.get("comparison_score", 0) or data.get("ats_score", 0),
|
|
170
|
-
# comparison_reason=data.get("comparison_reason", "") or data.get("reason", ""),
|
|
171
|
-
# parsed_data=data.get("parsed_data"),
|
|
172
|
-
# matched_keywords=data.get("matched_keywords", []),
|
|
173
|
-
# missing_keywords=data.get("missing_keywords", []),
|
|
174
|
-
# suggestions=data.get("suggestions", []),
|
|
175
|
-
# credits_used=data.get("credits_used", 3),
|
|
176
|
-
# _raw=data
|
|
177
|
-
# )
|
|
178
|
-
|
|
179
|
-
# @property
|
|
180
|
-
# def is_good_match(self) -> bool:
|
|
181
|
-
# """Returns True if score is 70% or higher."""
|
|
182
|
-
# return self.comparison_score >= 70
|
|
183
|
-
|
|
184
|
-
# @property
|
|
185
|
-
# def match_level(self) -> str:
|
|
186
|
-
# """Returns match level: 'excellent', 'good', 'fair', 'poor'."""
|
|
187
|
-
# if self.comparison_score >= 85:
|
|
188
|
-
# return "excellent"
|
|
189
|
-
# elif self.comparison_score >= 70:
|
|
190
|
-
# return "good"
|
|
191
|
-
# elif self.comparison_score >= 50:
|
|
192
|
-
# return "fair"
|
|
193
|
-
# return "poor"
|
|
194
|
-
|
|
195
|
-
# def __repr__(self):
|
|
196
|
-
# return f"<ResumeComparisonResult resume_id={self.resume_id} score={self.comparison_score}%>"
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
# @dataclass
|
|
200
|
-
# class JobResult:
|
|
201
|
-
# """Result from creating a job posting."""
|
|
202
|
-
# job_id: int
|
|
203
|
-
# title: str
|
|
204
|
-
# description: str
|
|
205
|
-
# created_by: str
|
|
206
|
-
# created_at: Optional[str] = None
|
|
207
|
-
# credits_used: int = 1
|
|
208
|
-
# _raw: Dict[str, Any] = field(default_factory=dict, repr=False)
|
|
209
|
-
|
|
210
|
-
# @classmethod
|
|
211
|
-
# def from_response(cls, data: Dict[str, Any]) -> "JobResult":
|
|
212
|
-
# return cls(
|
|
213
|
-
# job_id=data.get("job_id"),
|
|
214
|
-
# title=data.get("title", ""),
|
|
215
|
-
# description=data.get("description", ""),
|
|
216
|
-
# created_by=data.get("created_by", ""),
|
|
217
|
-
# created_at=data.get("created_at"),
|
|
218
|
-
# credits_used=data.get("credits_used", 1),
|
|
219
|
-
# _raw=data
|
|
220
|
-
# )
|
|
221
|
-
|
|
222
|
-
# def __repr__(self):
|
|
223
|
-
# return f"<JobResult job_id={self.job_id} title='{self.title}'>"
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
# @dataclass
|
|
227
|
-
# class ParsedResumeResult:
|
|
228
|
-
# """Result from parsing/analyzing a resume by ID."""
|
|
229
|
-
# resume_id: int
|
|
230
|
-
# partner: str
|
|
231
|
-
# parsed_data: Dict[str, Any]
|
|
232
|
-
# credits_used: int = 2
|
|
233
|
-
# _raw: Dict[str, Any] = field(default_factory=dict, repr=False)
|
|
234
|
-
|
|
235
|
-
# @classmethod
|
|
236
|
-
# def from_response(cls, data: Dict[str, Any]) -> "ParsedResumeResult":
|
|
237
|
-
# return cls(
|
|
238
|
-
# resume_id=data.get("resume_id"),
|
|
239
|
-
# partner=data.get("partner", ""),
|
|
240
|
-
# parsed_data=data.get("parsed_data", {}),
|
|
241
|
-
# credits_used=data.get("credits_used", 2),
|
|
242
|
-
# _raw=data
|
|
243
|
-
# )
|
|
244
|
-
|
|
245
|
-
# @property
|
|
246
|
-
# def full_name(self) -> Optional[str]:
|
|
247
|
-
# return self.parsed_data.get("full_name")
|
|
248
|
-
|
|
249
|
-
# @property
|
|
250
|
-
# def email(self) -> Optional[str]:
|
|
251
|
-
# return self.parsed_data.get("email")
|
|
252
|
-
|
|
253
|
-
# @property
|
|
254
|
-
# def phone(self) -> Optional[str]:
|
|
255
|
-
# return self.parsed_data.get("contact_number")
|
|
256
|
-
|
|
257
|
-
# @property
|
|
258
|
-
# def linkedin(self) -> Optional[str]:
|
|
259
|
-
# return self.parsed_data.get("linkedin")
|
|
260
|
-
|
|
261
|
-
# @property
|
|
262
|
-
# def location(self) -> Optional[str]:
|
|
263
|
-
# return self.parsed_data.get("location")
|
|
264
|
-
|
|
265
|
-
# @property
|
|
266
|
-
# def skills(self) -> List[str]:
|
|
267
|
-
# skills = self.parsed_data.get("skills", [])
|
|
268
|
-
# if isinstance(skills, str):
|
|
269
|
-
# return [s.strip() for s in skills.split(",") if s.strip()]
|
|
270
|
-
# return skills or []
|
|
271
|
-
|
|
272
|
-
# @property
|
|
273
|
-
# def job_titles(self) -> List[str]:
|
|
274
|
-
# titles = self.parsed_data.get("job_titles", [])
|
|
275
|
-
# if isinstance(titles, str):
|
|
276
|
-
# return [t.strip() for t in titles.split(",") if t.strip()]
|
|
277
|
-
# return titles or []
|
|
278
|
-
|
|
279
|
-
# @property
|
|
280
|
-
# def companies(self) -> List[str]:
|
|
281
|
-
# companies = self.parsed_data.get("companies", [])
|
|
282
|
-
# if isinstance(companies, str):
|
|
283
|
-
# return [c.strip() for c in companies.split(",") if c.strip()]
|
|
284
|
-
# return companies or []
|
|
285
|
-
|
|
286
|
-
# @property
|
|
287
|
-
# def education(self) -> List[str]:
|
|
288
|
-
# edu = self.parsed_data.get("education", [])
|
|
289
|
-
# if isinstance(edu, str):
|
|
290
|
-
# return [e.strip() for e in edu.split(",") if e.strip()]
|
|
291
|
-
# return edu or []
|
|
292
|
-
|
|
293
|
-
# @property
|
|
294
|
-
# def total_experience(self) -> Optional[str]:
|
|
295
|
-
# return self.parsed_data.get("total_experience")
|
|
296
|
-
|
|
297
|
-
# @property
|
|
298
|
-
# def certifications(self) -> List[str]:
|
|
299
|
-
# certs = self.parsed_data.get("certifications", [])
|
|
300
|
-
# if isinstance(certs, str):
|
|
301
|
-
# return [c.strip() for c in certs.split(",") if c.strip()]
|
|
302
|
-
# return certs or []
|
|
303
|
-
|
|
304
|
-
# def __repr__(self):
|
|
305
|
-
# name = self.full_name or "Unknown"
|
|
306
|
-
# return f"<ParsedResumeResult resume_id={self.resume_id} name='{name}'>"
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
# @dataclass
|
|
310
|
-
# class ResumeListItem:
|
|
311
|
-
# """Single resume in a list."""
|
|
312
|
-
# id: int
|
|
313
|
-
# filename: str
|
|
314
|
-
# full_name: Optional[str] = None
|
|
315
|
-
# email: Optional[str] = None
|
|
316
|
-
# uploaded_at: Optional[str] = None
|
|
317
|
-
# is_parsed: bool = False
|
|
318
|
-
|
|
319
|
-
# @classmethod
|
|
320
|
-
# def from_dict(cls, data: Dict[str, Any]) -> "ResumeListItem":
|
|
321
|
-
# return cls(
|
|
322
|
-
# id=data.get("id"),
|
|
323
|
-
# filename=data.get("filename", ""),
|
|
324
|
-
# full_name=data.get("full_name"),
|
|
325
|
-
# email=data.get("email"),
|
|
326
|
-
# uploaded_at=data.get("uploaded_at"),
|
|
327
|
-
# is_parsed=data.get("is_parsed", False)
|
|
328
|
-
# )
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
# @dataclass
|
|
332
|
-
# class ResumeListResult:
|
|
333
|
-
# """Result from listing resumes."""
|
|
334
|
-
# resumes: List[Dict[str, Any]]
|
|
335
|
-
# total: int
|
|
336
|
-
# page: int
|
|
337
|
-
# limit: int
|
|
338
|
-
# has_more: bool
|
|
339
|
-
# _raw: Dict[str, Any] = field(default_factory=dict, repr=False)
|
|
340
|
-
|
|
341
|
-
# @classmethod
|
|
342
|
-
# def from_response(cls, data: Dict[str, Any]) -> "ResumeListResult":
|
|
343
|
-
# return cls(
|
|
344
|
-
# resumes=data.get("resumes", []),
|
|
345
|
-
# total=data.get("total", 0),
|
|
346
|
-
# page=data.get("page", 1),
|
|
347
|
-
# limit=data.get("limit", 50),
|
|
348
|
-
# has_more=data.get("has_more", False),
|
|
349
|
-
# _raw=data
|
|
350
|
-
# )
|
|
351
|
-
|
|
352
|
-
# def __len__(self):
|
|
353
|
-
# return len(self.resumes)
|
|
354
|
-
|
|
355
|
-
# def __iter__(self):
|
|
356
|
-
# return iter(self.resumes)
|
|
357
|
-
|
|
358
|
-
# def __repr__(self):
|
|
359
|
-
# return f"<ResumeListResult count={len(self.resumes)} total={self.total}>"
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
# @dataclass
|
|
363
|
-
# class JobListItem:
|
|
364
|
-
# """Single job in a list."""
|
|
365
|
-
# id: int
|
|
366
|
-
# title: str
|
|
367
|
-
# description: str
|
|
368
|
-
# created_at: Optional[str] = None
|
|
369
|
-
|
|
370
|
-
# @classmethod
|
|
371
|
-
# def from_dict(cls, data: Dict[str, Any]) -> "JobListItem":
|
|
372
|
-
# return cls(
|
|
373
|
-
# id=data.get("id"),
|
|
374
|
-
# title=data.get("title", ""),
|
|
375
|
-
# description=data.get("description", ""),
|
|
376
|
-
# created_at=data.get("created_at")
|
|
377
|
-
# )
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
# @dataclass
|
|
381
|
-
# class JobListResult:
|
|
382
|
-
# """Result from listing jobs."""
|
|
383
|
-
# jobs: List[Dict[str, Any]]
|
|
384
|
-
# total: int
|
|
385
|
-
# page: int
|
|
386
|
-
# limit: int
|
|
387
|
-
# has_more: bool
|
|
388
|
-
# _raw: Dict[str, Any] = field(default_factory=dict, repr=False)
|
|
389
|
-
|
|
390
|
-
# @classmethod
|
|
391
|
-
# def from_response(cls, data: Dict[str, Any]) -> "JobListResult":
|
|
392
|
-
# return cls(
|
|
393
|
-
# jobs=data.get("jobs", []),
|
|
394
|
-
# total=data.get("total", 0),
|
|
395
|
-
# page=data.get("page", 1),
|
|
396
|
-
# limit=data.get("limit", 50),
|
|
397
|
-
# has_more=data.get("has_more", False),
|
|
398
|
-
# _raw=data
|
|
399
|
-
# )
|
|
400
|
-
|
|
401
|
-
# def __len__(self):
|
|
402
|
-
# return len(self.jobs)
|
|
403
|
-
|
|
404
|
-
# def __iter__(self):
|
|
405
|
-
# return iter(self.jobs)
|
|
406
|
-
|
|
407
|
-
# def __repr__(self):
|
|
408
|
-
# return f"<JobListResult count={len(self.jobs)} total={self.total}>"
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
# @dataclass
|
|
412
|
-
# class CreditBalance:
|
|
413
|
-
# """Credit balance information."""
|
|
414
|
-
# total: int
|
|
415
|
-
# used_mtd: int
|
|
416
|
-
# remaining: int
|
|
417
|
-
# plan_name: str
|
|
418
|
-
# resets_at: Optional[str] = None
|
|
419
|
-
|
|
420
|
-
# @classmethod
|
|
421
|
-
# def from_response(cls, data: Dict[str, Any]) -> "CreditBalance":
|
|
422
|
-
# return cls(
|
|
423
|
-
# total=data.get("total", 0),
|
|
424
|
-
# used_mtd=data.get("used_mtd", 0),
|
|
425
|
-
# remaining=data.get("remaining", 0),
|
|
426
|
-
# plan_name=data.get("plan_name", ""),
|
|
427
|
-
# resets_at=data.get("resets_at")
|
|
428
|
-
# )
|
|
429
|
-
|
|
430
|
-
|
|
431
1
|
"""
|
|
432
2
|
Data models and exceptions for the AiondTech SDK v2.
|
|
433
3
|
"""
|
|
@@ -513,7 +83,7 @@ class ResumeUploadResult:
|
|
|
513
83
|
"""Result from uploading a resume (upload only, no parsing)."""
|
|
514
84
|
resume_id: int
|
|
515
85
|
message: str
|
|
516
|
-
credits_used: int =
|
|
86
|
+
credits_used: int = 0
|
|
517
87
|
_raw: Dict[str, Any] = field(default_factory=dict, repr=False)
|
|
518
88
|
|
|
519
89
|
@classmethod
|
|
@@ -521,7 +91,7 @@ class ResumeUploadResult:
|
|
|
521
91
|
return cls(
|
|
522
92
|
resume_id=data.get("resume_id"),
|
|
523
93
|
message=data.get("message", "Resume uploaded successfully"),
|
|
524
|
-
credits_used=data.get("credits_used",
|
|
94
|
+
credits_used=data.get("credits_used", 0),
|
|
525
95
|
_raw=data
|
|
526
96
|
)
|
|
527
97
|
|
|
@@ -534,7 +104,7 @@ class ResumeAnalysisResult:
|
|
|
534
104
|
"""Result from uploading and analyzing a resume."""
|
|
535
105
|
resume_id: int
|
|
536
106
|
parsed_data: Dict[str, Any]
|
|
537
|
-
credits_used: int =
|
|
107
|
+
credits_used: int = 0
|
|
538
108
|
_raw: Dict[str, Any] = field(default_factory=dict, repr=False)
|
|
539
109
|
|
|
540
110
|
@classmethod
|
|
@@ -542,7 +112,7 @@ class ResumeAnalysisResult:
|
|
|
542
112
|
return cls(
|
|
543
113
|
resume_id=data.get("resume_id"),
|
|
544
114
|
parsed_data=data.get("parsed_data", {}),
|
|
545
|
-
credits_used=data.get("credits_used",
|
|
115
|
+
credits_used=data.get("credits_used", 0),
|
|
546
116
|
_raw=data
|
|
547
117
|
)
|
|
548
118
|
|
|
@@ -589,19 +159,22 @@ class ResumeComparisonResult:
|
|
|
589
159
|
matched_keywords: List[str] = field(default_factory=list)
|
|
590
160
|
missing_keywords: List[str] = field(default_factory=list)
|
|
591
161
|
suggestions: List[str] = field(default_factory=list)
|
|
592
|
-
credits_used: int =
|
|
162
|
+
credits_used: int = 0
|
|
593
163
|
_raw: Dict[str, Any] = field(default_factory=dict, repr=False)
|
|
594
164
|
|
|
595
165
|
@classmethod
|
|
596
166
|
def from_response(cls, data: Dict[str, Any]) -> "ResumeComparisonResult":
|
|
597
167
|
# Score field: API returns "score", fallback to legacy field names
|
|
598
|
-
score = (
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
168
|
+
score = data.get("score")
|
|
169
|
+
if score is None:
|
|
170
|
+
score = data.get("comparison_score")
|
|
171
|
+
if score is None:
|
|
172
|
+
score = data.get("ats_score", 0)
|
|
173
|
+
|
|
603
174
|
# Reason field: API returns "reason", fallback to legacy field name
|
|
604
|
-
reason = data.get("reason"
|
|
175
|
+
reason = data.get("reason")
|
|
176
|
+
if reason is None:
|
|
177
|
+
reason = data.get("comparison_reason", "")
|
|
605
178
|
|
|
606
179
|
return cls(
|
|
607
180
|
resume_id=data.get("resume_id"),
|
|
@@ -613,7 +186,7 @@ class ResumeComparisonResult:
|
|
|
613
186
|
matched_keywords=data.get("matched_keywords", []),
|
|
614
187
|
missing_keywords=data.get("missing_keywords", []),
|
|
615
188
|
suggestions=data.get("suggestions", []),
|
|
616
|
-
credits_used=data.get("credits_used",
|
|
189
|
+
credits_used=data.get("credits_used", 0),
|
|
617
190
|
_raw=data
|
|
618
191
|
)
|
|
619
192
|
|
|
@@ -629,7 +202,7 @@ class JobResult:
|
|
|
629
202
|
description: str
|
|
630
203
|
created_by: str
|
|
631
204
|
created_at: Optional[str] = None
|
|
632
|
-
credits_used: int =
|
|
205
|
+
credits_used: int = 0
|
|
633
206
|
_raw: Dict[str, Any] = field(default_factory=dict, repr=False)
|
|
634
207
|
|
|
635
208
|
@classmethod
|
|
@@ -640,7 +213,7 @@ class JobResult:
|
|
|
640
213
|
description=data.get("description", ""),
|
|
641
214
|
created_by=data.get("created_by", ""),
|
|
642
215
|
created_at=data.get("created_at"),
|
|
643
|
-
credits_used=data.get("credits_used",
|
|
216
|
+
credits_used=data.get("credits_used", 0),
|
|
644
217
|
_raw=data
|
|
645
218
|
)
|
|
646
219
|
|
|
@@ -654,7 +227,7 @@ class ParsedResumeResult:
|
|
|
654
227
|
resume_id: int
|
|
655
228
|
partner: str
|
|
656
229
|
parsed_data: Dict[str, Any]
|
|
657
|
-
credits_used: int =
|
|
230
|
+
credits_used: int = 0
|
|
658
231
|
_raw: Dict[str, Any] = field(default_factory=dict, repr=False)
|
|
659
232
|
|
|
660
233
|
@classmethod
|
|
@@ -663,7 +236,7 @@ class ParsedResumeResult:
|
|
|
663
236
|
resume_id=data.get("resume_id"),
|
|
664
237
|
partner=data.get("partner", ""),
|
|
665
238
|
parsed_data=data.get("parsed_data", {}),
|
|
666
|
-
credits_used=data.get("credits_used",
|
|
239
|
+
credits_used=data.get("credits_used", 0),
|
|
667
240
|
_raw=data
|
|
668
241
|
)
|
|
669
242
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aiondtech
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Official Python SDK for AiondTech Resume Analyser API
|
|
5
5
|
Author-email: AiondTech <support@aiondtech.com>
|
|
6
6
|
Maintainer-email: AiondTech <support@aiondtech.com>
|
|
@@ -77,19 +77,31 @@ client = ResumeAnalyser(api_key="your-api-key", production=True)
|
|
|
77
77
|
|
|
78
78
|
## API Endpoints
|
|
79
79
|
|
|
80
|
+
Credit usage varies depending on resume size and complexity. Every response includes the actual `credits_used` — always check it for accurate tracking.
|
|
81
|
+
|
|
80
82
|
| Method | Credits | Description |
|
|
81
83
|
|--------|---------|-------------|
|
|
82
|
-
| `resumes.upload()` |
|
|
83
|
-
| `resumes.upload_and_analyze()` |
|
|
84
|
-
| `resumes.upload_analyze_compare()` |
|
|
85
|
-
| `resumes.analyze()` |
|
|
86
|
-
| `resumes.compare_resumes()` |
|
|
84
|
+
| `resumes.upload()` | Varies | Upload PDF resume |
|
|
85
|
+
| `resumes.upload_and_analyze()` | Varies | Upload + AI parsing |
|
|
86
|
+
| `resumes.upload_analyze_compare()` | Varies | Upload + parse + compare to job |
|
|
87
|
+
| `resumes.analyze()` | Varies | Parse existing resume by ID |
|
|
88
|
+
| `resumes.compare_resumes()` | Varies | Compare resume to job |
|
|
87
89
|
| `resumes.list()` | 0 | List all resumes |
|
|
88
|
-
| `jobs.create()` |
|
|
90
|
+
| `jobs.create()` | Varies | Create job posting |
|
|
89
91
|
| `jobs.list()` | 0 | List all jobs |
|
|
90
92
|
| `credits.balance()` | 0 | Check credit balance |
|
|
91
93
|
| `credits.usage()` | 0 | View usage history |
|
|
92
94
|
|
|
95
|
+
**Tracking credits:**
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
result = client.resumes.upload_and_analyze("resume.pdf")
|
|
99
|
+
print(f"This call used {result.credits_used} credits")
|
|
100
|
+
|
|
101
|
+
balance = client.credits.balance()
|
|
102
|
+
print(f"Remaining: {balance['remaining']}")
|
|
103
|
+
```
|
|
104
|
+
|
|
93
105
|
---
|
|
94
106
|
|
|
95
107
|
## Detailed Usage
|
|
@@ -107,7 +119,7 @@ result = client.resumes.upload("path/to/resume.pdf")
|
|
|
107
119
|
```python
|
|
108
120
|
result.resume_id # int — Unique resume ID
|
|
109
121
|
result.message # str — "Resume uploaded successfully"
|
|
110
|
-
result.credits_used # int —
|
|
122
|
+
result.credits_used # int — Credits consumed by this call
|
|
111
123
|
result._raw # dict — Full raw API response
|
|
112
124
|
```
|
|
113
125
|
|
|
@@ -126,7 +138,7 @@ result = client.resumes.upload_and_analyze("path/to/resume.pdf")
|
|
|
126
138
|
```python
|
|
127
139
|
result.resume_id # int — Unique resume ID
|
|
128
140
|
result.parsed_data # dict — Full parsed data (see structure below)
|
|
129
|
-
result.credits_used # int —
|
|
141
|
+
result.credits_used # int — Credits consumed by this call
|
|
130
142
|
result._raw # dict — Full raw API response
|
|
131
143
|
|
|
132
144
|
# Convenience properties
|
|
@@ -175,7 +187,7 @@ result.comparison_score # float — Match score (0-100)
|
|
|
175
187
|
result.comparison_reason # str — Detailed reasoning
|
|
176
188
|
result.language # str | None — Detected language (e.g. "en", "ar")
|
|
177
189
|
result.parsed_data # dict | None — Parsed resume data
|
|
178
|
-
result.credits_used # int —
|
|
190
|
+
result.credits_used # int — Credits consumed by this call
|
|
179
191
|
result._raw # dict — Full raw API response
|
|
180
192
|
```
|
|
181
193
|
|
|
@@ -195,7 +207,7 @@ result = client.resumes.analyze(resume_id=123)
|
|
|
195
207
|
result.resume_id # int — Resume ID
|
|
196
208
|
result.partner # str — Partner identifier
|
|
197
209
|
result.parsed_data # dict — Full parsed data
|
|
198
|
-
result.credits_used # int —
|
|
210
|
+
result.credits_used # int — Credits consumed by this call
|
|
199
211
|
result._raw # dict — Full raw API response
|
|
200
212
|
|
|
201
213
|
# Convenience properties
|
|
@@ -233,7 +245,7 @@ job.title # str — Job title
|
|
|
233
245
|
job.description # str — Job description
|
|
234
246
|
job.created_by # str — Creator identifier
|
|
235
247
|
job.created_at # str | None — Creation timestamp
|
|
236
|
-
job.credits_used # int —
|
|
248
|
+
job.credits_used # int — Credits consumed by this call
|
|
237
249
|
job._raw # dict — Full raw API response
|
|
238
250
|
```
|
|
239
251
|
|
|
@@ -254,8 +266,7 @@ result.resume_id # int — Resume ID
|
|
|
254
266
|
result.job_id # int — Job ID
|
|
255
267
|
result.comparison_score # float — Match score (0-100)
|
|
256
268
|
result.comparison_reason # str — Detailed reasoning
|
|
257
|
-
result.
|
|
258
|
-
result.credits_used # int — 3
|
|
269
|
+
result.credits_used # int — Credits consumed by this call
|
|
259
270
|
result._raw # dict — Full raw API response
|
|
260
271
|
```
|
|
261
272
|
|
|
@@ -391,12 +402,14 @@ job = client.jobs.create(
|
|
|
391
402
|
description="5+ years Python, Django, AWS, PostgreSQL required..."
|
|
392
403
|
)
|
|
393
404
|
print(f"Created job #{job.job_id}: {job.title}")
|
|
405
|
+
print(f"Credits used: {job.credits_used}")
|
|
394
406
|
|
|
395
407
|
# Step 2: Upload and analyze a resume
|
|
396
408
|
analysis = client.resumes.upload_and_analyze("candidate_resume.pdf")
|
|
397
409
|
print(f"Candidate: {analysis.full_name}")
|
|
398
410
|
print(f"Skills: {', '.join(analysis.skills)}")
|
|
399
411
|
print(f"Experience: {analysis.total_experience}")
|
|
412
|
+
print(f"Credits used: {analysis.credits_used}")
|
|
400
413
|
|
|
401
414
|
# Step 3: Compare resume to job
|
|
402
415
|
comparison = client.resumes.compare_resumes(
|
|
@@ -406,6 +419,7 @@ comparison = client.resumes.compare_resumes(
|
|
|
406
419
|
print(f"Score: {comparison.comparison_score}%")
|
|
407
420
|
print(f"Language: {comparison.language}")
|
|
408
421
|
print(f"Reasoning: {comparison.comparison_reason}")
|
|
422
|
+
print(f"Credits used: {comparison.credits_used}")
|
|
409
423
|
|
|
410
424
|
# Step 4: Check remaining credits
|
|
411
425
|
balance = client.credits.balance()
|
|
@@ -417,6 +431,7 @@ print(f"Credits remaining: {balance['remaining']}")
|
|
|
417
431
|
```python
|
|
418
432
|
result = client.resumes.upload_analyze_compare("resume.pdf", job_id=job.job_id)
|
|
419
433
|
print(f"Score: {result.comparison_score}% — {result.comparison_reason}")
|
|
434
|
+
print(f"Credits used: {result.credits_used}")
|
|
420
435
|
```
|
|
421
436
|
|
|
422
437
|
### Batch Processing
|
|
@@ -426,18 +441,22 @@ import os
|
|
|
426
441
|
|
|
427
442
|
job = client.jobs.create("Data Scientist", "ML, Python, statistics...")
|
|
428
443
|
|
|
444
|
+
total_credits = job.credits_used
|
|
429
445
|
results = []
|
|
446
|
+
|
|
430
447
|
for pdf in os.listdir("resumes/"):
|
|
431
448
|
if pdf.endswith(".pdf"):
|
|
432
449
|
r = client.resumes.upload_analyze_compare(
|
|
433
450
|
f"resumes/{pdf}", job_id=job.job_id
|
|
434
451
|
)
|
|
435
452
|
results.append(r)
|
|
436
|
-
|
|
453
|
+
total_credits += r.credits_used
|
|
454
|
+
print(f"{r.comparison_score:5.1f}% — {pdf} ({r.credits_used} credits)")
|
|
437
455
|
|
|
438
456
|
# Sort by score
|
|
439
457
|
results.sort(key=lambda x: x.comparison_score, reverse=True)
|
|
440
458
|
print(f"\nTop candidate: resume_id={results[0].resume_id} ({results[0].comparison_score}%)")
|
|
459
|
+
print(f"Total credits used: {total_credits}")
|
|
441
460
|
```
|
|
442
461
|
|
|
443
462
|
---
|