Spaces:
Sleeping
Sleeping
| from io import BytesIO | |
| import requests | |
| from fastapi import HTTPException | |
| from PIL import Image | |
| from app.config import get_settings | |
| from app.core.errors import BadRequestError, VendorError | |
| from app.schemas.requests import ExtractionRequest | |
| from app.schemas.responses import APIResponse | |
| from app.services.factory import AIServiceFactory | |
| from app.utils.logger import exception_to_str, setup_logger | |
| logger = setup_logger(__name__) | |
| settings = get_settings() | |
| async def handle_extract(request: ExtractionRequest): | |
| request.max_attempts = max(request.max_attempts, 1) | |
| request.max_attempts = min(request.max_attempts, 5) | |
| for attempt in range(1, request.max_attempts + 1): | |
| try: | |
| logger.info(f"Attempt: {attempt}") | |
| if request.ai_model in settings.OPENAI_MODELS: | |
| ai_vendor = "openai" | |
| elif request.ai_model in settings.ANTHROPIC_MODELS: | |
| ai_vendor = "anthropic" | |
| elif request.ai_model in settings.GEMINI_MODELS_MODELS: | |
| ai_vendor = "gemini" | |
| else: | |
| raise ValueError( | |
| f"Invalid AI model: {request.ai_model}, only support {settings.SUPPORTED_MODELS}" | |
| ) | |
| service = AIServiceFactory.get_service(ai_vendor) | |
| # pil_images = [] | |
| pil_images = None # temporarily removed to save cost | |
| for url in request.img_urls: | |
| try: | |
| # response = requests.get(url) | |
| # response.raise_for_status() | |
| # image = Image.open(BytesIO(response.content)) | |
| # pil_images.append(image) | |
| pass | |
| except Exception as e: | |
| # logger.error(f"Failed to download or process image from {url}: {exception_to_str(e)}") | |
| raise HTTPException( | |
| status_code=400, | |
| detail=f"Failed to process image from {url}", | |
| headers={"attempt": attempt}, | |
| ) | |
| json_attributes = await service.extract_attributes_with_validation( | |
| request.attributes, | |
| request.ai_model, | |
| request.img_urls, | |
| request.product_taxonomy, | |
| request.product_data, | |
| pil_images=pil_images, | |
| ) | |
| break | |
| except BadRequestError as e: | |
| logger.error( | |
| f"Bad request error: {exception_to_str(e)}", | |
| ) | |
| raise HTTPException( | |
| status_code=400, | |
| detail=exception_to_str(e), | |
| headers={"attempt": attempt}, | |
| ) | |
| except ValueError as e: | |
| logger.error(f"Value error: {exception_to_str(e)}") | |
| raise HTTPException( | |
| status_code=400, | |
| detail=exception_to_str(e), | |
| headers={"attempt": attempt}, | |
| ) | |
| except VendorError as e: | |
| logger.error(f"Vendor error: {exception_to_str(e)}") | |
| if attempt == request.max_attempts: | |
| raise HTTPException( | |
| status_code=500, | |
| detail=exception_to_str(e), | |
| headers={"attempt": attempt}, | |
| ) | |
| else: | |
| if request.ai_model in settings.ANTHROPIC_MODELS: | |
| request.ai_model = settings.OPENAI_MODELS[ | |
| 0 | |
| ] # switch to OpenAI, and try again if max_attempts not reached | |
| logger.info( | |
| f"Switching from anthropic to {request.ai_model} for attempt {attempt + 1}" | |
| ) | |
| elif request.ai_model in settings.OPENAI_MODELS: | |
| request.ai_model = settings.ANTHROPIC_MODELS[ | |
| 0 | |
| ] # switch to anthropic, and try again if max_attempts not reached | |
| logger.info( | |
| f"Switching from OpenAI to {request.ai_model} for attempt {attempt + 1}" | |
| ) | |
| except HTTPException as e: | |
| logger.error(f"HTTP exception: {exception_to_str(e)}") | |
| raise e | |
| except Exception as e: | |
| logger.error("Exception: ", exception_to_str(e)) | |
| if ( | |
| "overload" in str(e).lower() | |
| and request.ai_model in settings.ANTHROPIC_MODELS | |
| ): | |
| request.ai_model = settings.OPENAI_MODELS[ | |
| 0 | |
| ] # switch to OpenAI, and try again if max_attempts not reached | |
| if attempt == request.max_attempts: | |
| raise HTTPException( | |
| status_code=500, | |
| detail="Internal server error", | |
| headers={"attempt": attempt}, | |
| ) | |
| return json_attributes, attempt | |