kontext_pro_task.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import logging
  2. import time
  3. from app.config import settings
  4. from app.service.task.base_task import BaseTask
  5. from app.service.task.task_param import TaskParam
  6. from app.service.task.task_result import TaskResult
  7. from app.util.http_util import logged_client
  8. logger = logging.getLogger(__name__)
  9. class KontextProTask(BaseTask):
  10. def get_type(self) -> str:
  11. return "kontext_pro"
  12. @property
  13. def execute_url(self) -> str:
  14. return settings.kontext_pro_url
  15. def _headers(self) -> dict[str, str]:
  16. return {
  17. "Content-Type": "application/json",
  18. "x-key": settings.kontext_api_key,
  19. }
  20. def execute(self, param: TaskParam) -> TaskResult:
  21. logger.info("[%s] Submitting task: POST %s", self.get_type(), self.execute_url)
  22. t0 = time.time()
  23. try:
  24. with logged_client(timeout=settings.http_timeout) as client:
  25. resp = client.post(self.execute_url, headers=self._headers(), json=param.inputs)
  26. elapsed = time.time() - t0
  27. logger.info("[%s] Submit response: status=%d, elapsed=%.2fs",
  28. self.get_type(), resp.status_code, elapsed)
  29. resp.raise_for_status()
  30. bean = resp.json()
  31. except Exception as e:
  32. elapsed = time.time() - t0
  33. logger.error("[%s] Submit failed in %.2fs: %s", self.get_type(), elapsed, e)
  34. return TaskResult.failure(f"submit task fail: {e}")
  35. if not bean:
  36. return TaskResult.failure("submit task fail !")
  37. task_id = bean.get("id")
  38. polling_url = bean.get("polling_url")
  39. logger.info("[%s] Task submitted, remote_id=%s, polling_url=%s",
  40. self.get_type(), task_id, polling_url)
  41. poll_count = 0
  42. poll_t0 = time.time()
  43. while True:
  44. poll_count += 1
  45. poll = self._poll(polling_url)
  46. status = poll.get("status")
  47. logger.info("[%s] Poll #%d: remote_id=%s, status=%s, elapsed=%.1fs",
  48. self.get_type(), poll_count, task_id, status, time.time() - poll_t0)
  49. if status == "Pending":
  50. time.sleep(3)
  51. elif status == "Ready":
  52. result = poll.get("result", {})
  53. break
  54. else:
  55. logger.warning("[%s] Unexpected status '%s', treating as failure", self.get_type(), status)
  56. time.sleep(3)
  57. return TaskResult.failure(str(poll))
  58. if not result:
  59. return TaskResult.failure("No result found")
  60. images: list[str] = []
  61. sample = result.get("sample")
  62. if sample and sample.strip():
  63. images.append(sample)
  64. logger.info("[%s] Completed: %d images, total_elapsed=%.2fs",
  65. self.get_type(), len(images), time.time() - t0)
  66. return TaskResult.success({"images": images})
  67. def _poll(self, polling_url: str) -> dict:
  68. with logged_client(timeout=settings.http_timeout) as client:
  69. resp = client.get(polling_url, headers=self._headers())
  70. return resp.json()