Stores an API request's inputs, outputs, and other metadata. Contains a method to make an API call.
| 272 | |
| 273 | @dataclass |
| 274 | class APIRequest: |
| 275 | """Stores an API request's inputs, outputs, and other metadata. Contains a method to make an API call.""" |
| 276 | |
| 277 | task_id: int |
| 278 | request_json: dict |
| 279 | token_consumption: int |
| 280 | attempts_left: int |
| 281 | metadata: dict |
| 282 | result: list = field(default_factory=list) |
| 283 | |
| 284 | async def call_api( |
| 285 | self, |
| 286 | session: aiohttp.ClientSession, |
| 287 | request_url: str, |
| 288 | request_header: dict, |
| 289 | retry_queue: asyncio.Queue, |
| 290 | save_filepath: str, |
| 291 | status_tracker: StatusTracker, |
| 292 | ): |
| 293 | """Calls the OpenAI API and saves results.""" |
| 294 | # logging.info(f"Starting request #{self.task_id}") |
| 295 | error = None |
| 296 | try: |
| 297 | async with session.post( |
| 298 | url=request_url, headers=request_header, json=self.request_json |
| 299 | ) as response: |
| 300 | response = await response.json() |
| 301 | if "error" in response: |
| 302 | logging.warning( |
| 303 | f"Request {self.task_id} failed with error {response['error']}" |
| 304 | ) |
| 305 | status_tracker.num_api_errors += 1 |
| 306 | error = response |
| 307 | if "rate limit" in response["error"].get("message", "").lower(): |
| 308 | status_tracker.time_of_last_rate_limit_error = time.time() |
| 309 | status_tracker.num_rate_limit_errors += 1 |
| 310 | status_tracker.num_api_errors -= ( |
| 311 | 1 # rate limit errors are counted separately |
| 312 | ) |
| 313 | |
| 314 | except ( |
| 315 | Exception |
| 316 | ) as e: # catching naked exceptions is bad practice, but in this case we'll log & save them |
| 317 | logging.warning(f"Request {self.task_id} failed with Exception {e}") |
| 318 | status_tracker.num_other_errors += 1 |
| 319 | error = e |
| 320 | if error: |
| 321 | self.result.append(error) |
| 322 | if self.attempts_left: |
| 323 | retry_queue.put_nowait(self) |
| 324 | else: |
| 325 | logging.error( |
| 326 | f"Request {self.request_json} failed after all attempts. Saving errors: {self.result}" |
| 327 | ) |
| 328 | data = ( |
| 329 | [self.request_json, [str(e) for e in self.result], self.metadata] |
| 330 | if self.metadata |
| 331 | else [self.request_json, [str(e) for e in self.result]] |
no outgoing calls
no test coverage detected