data-extract / app /services /file_service.py
validops-east-1's picture
feat: optimize code + add json key extractor
c5638b0
Raw
History Blame Contribute Delete
3.32 kB
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,
)