负责请求兼容图片上游、退避重试和响应解析。
| 13 | |
| 14 | |
| 15 | class ImageApiClient: |
| 16 | """负责请求兼容图片上游、退避重试和响应解析。""" |
| 17 | |
| 18 | def __init__( |
| 19 | self, |
| 20 | policy: ImageProviderPolicy, |
| 21 | session: Optional[requests.Session] = None, |
| 22 | timeout: int = 300, |
| 23 | ): |
| 24 | self.policy = policy |
| 25 | self.session = session or requests.Session() |
| 26 | self.timeout = timeout |
| 27 | self.extractor = ImageResponseExtractor(self.download_image) |
| 28 | |
| 29 | def generate_via_images(self, payload: Dict[str, Any]) -> bytes: |
| 30 | result = self._post_json(payload, label="Image API") |
| 31 | return self.extractor.extract_from_images_response(result) |
| 32 | |
| 33 | def generate_via_chat(self, payload: Dict[str, Any]) -> bytes: |
| 34 | result = self._post_json(payload, label="Chat API") |
| 35 | return self.extractor.extract_from_chat_response(result) |
| 36 | |
| 37 | def download_image(self, url: str) -> bytes: |
| 38 | logger.info(f"下载图片: {url[:100]}...") |
| 39 | try: |
| 40 | response = self.session.get(url, timeout=60) |
| 41 | except requests.exceptions.Timeout as exc: |
| 42 | raise Exception("下载图片超时,请重试") from exc |
| 43 | except requests.RequestException as exc: |
| 44 | raise Exception(f"下载图片失败: {str(exc)}") from exc |
| 45 | |
| 46 | if response.status_code != 200: |
| 47 | raise Exception(f"下载图片失败: HTTP {response.status_code}") |
| 48 | |
| 49 | logger.info(f"图片下载成功: {len(response.content)} bytes") |
| 50 | return response.content |
| 51 | |
| 52 | def _post_json(self, payload: Dict[str, Any], label: str) -> Dict[str, Any]: |
| 53 | url = f"{self.policy.base_url}{self.policy.endpoint_type}" |
| 54 | request_payload = dict(payload) |
| 55 | if self.policy.response_format and "response_format" not in request_payload: |
| 56 | request_payload["response_format"] = self.policy.response_format |
| 57 | |
| 58 | downgraded_response_format = False |
| 59 | transient_attempt = 0 |
| 60 | |
| 61 | while True: |
| 62 | try: |
| 63 | logger.debug(f"{label} 请求: {url}") |
| 64 | response = self.session.post( |
| 65 | url, |
| 66 | headers=self._headers(), |
| 67 | json=request_payload, |
| 68 | timeout=self.timeout, |
| 69 | ) |
| 70 | except ( |
| 71 | requests.exceptions.SSLError, |
| 72 | requests.exceptions.ConnectionError, |
no outgoing calls