Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import httpx | |
| import structlog | |
| from app.core.config import settings | |
| from app.core.exceptions import FileServiceError | |
| from app.models.schemas import UploadedFileInfo | |
| logger = structlog.get_logger(__name__) | |
| async def upload_file_to_service( | |
| file_bytes: bytes, | |
| filename: str, | |
| content_type: str = "application/octet-stream", | |
| ) -> UploadedFileInfo: | |
| timeout = httpx.Timeout(settings.FILE_SERVICE_TIMEOUT, connect=settings.FILE_SERVICE_CONNECT_TIMEOUT) | |
| headers = { | |
| "X-API-Key": settings.FILE_SERVICE_API_KEY, | |
| "Authorization": f"Bearer {settings.FILE_SERVICE_BEARER_TOKEN}", | |
| } | |
| async with httpx.AsyncClient(timeout=timeout) as client: | |
| try: | |
| response = await client.post( | |
| settings.FILE_SERVICE_URL, | |
| headers=headers, | |
| files={"files": (filename, file_bytes, content_type)}, | |
| ) | |
| response.raise_for_status() | |
| except httpx.HTTPStatusError as exc: | |
| logger.error( | |
| "file_service_http_error", | |
| status_code=exc.response.status_code, | |
| body=exc.response.text, | |
| ) | |
| raise FileServiceError( | |
| f"File service returned HTTP {exc.response.status_code}" | |
| ) from exc | |
| except httpx.RequestError as exc: | |
| logger.error("file_service_request_error", error=str(exc)) | |
| raise FileServiceError(f"File service unreachable: {exc}") from exc | |
| uploaded = _extract_uploaded_file(response.json(), filename, len(file_bytes)) | |
| logger.info("file_uploaded", file_id=uploaded.file_id, filename=filename) | |
| return uploaded | |
| def _extract_uploaded_file( | |
| payload: object, | |
| filename: str, | |
| size_bytes: int, | |
| ) -> UploadedFileInfo: | |
| """Pick the first file entry out of the (variably-shaped) service response.""" | |
| if isinstance(payload, list): | |
| if not payload or not isinstance(payload[0], dict): | |
| raise FileServiceError("File service returned an empty or malformed list") | |
| entry = payload[0].get("data") or payload[0] | |
| return _entry_to_info(entry, filename, size_bytes) | |
| if isinstance(payload, dict): | |
| nested = payload.get("files") or payload.get("data") | |
| if isinstance(nested, list) and nested and isinstance(nested[0], dict): | |
| entry = nested[0].get("data") or nested[0] | |
| return _entry_to_info(entry, filename, size_bytes) | |
| return _entry_to_info(payload, filename, size_bytes) | |
| raise FileServiceError(f"Unrecognised file service response type: {type(payload)}") | |
| def _entry_to_info(entry: dict, filename: str, size_bytes: int) -> UploadedFileInfo: | |
| file_id = str( | |
| entry.get("fileid") | |
| or entry.get("file_id") | |
| or entry.get("id") | |
| or entry.get("_id") | |
| or "" | |
| ) | |
| file_url = str( | |
| entry.get("file_url") | |
| or entry.get("url") | |
| or entry.get("path") | |
| or "" | |
| ) | |
| resolved_filename = str(entry.get("filename") or entry.get("name") or filename) | |
| resolved_size = int(entry.get("size") or entry.get("size_bytes") or size_bytes) | |
| return UploadedFileInfo( | |
| file_id=file_id, | |
| file_url=file_url, | |
| filename=resolved_filename, | |
| size_bytes=resolved_size, | |
| ) | |