import json from typing import Dict, Optional import openai from fastapi import HTTPException, status from app.core.config import settings from app.schemas.preference import Preference class AIRecommendationService: def __init__(self): self.api_key = settings.OPENAI_API_KEY self.model = settings.OPENAI_MODEL if not self.api_key: print("Warning: OPENAI_API_KEY not set. AI recommendations will not work.") async def generate_recommendations( self, recipient_name: str, occasion: Optional[str] = None, preferences: Optional[Preference] = None, budget_min: Optional[float] = None, budget_max: Optional[float] = None, additional_info: Optional[str] = None, ) -> Dict: """Generate gift recommendations based on preferences and constraints.""" if not self.api_key: raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="AI service not available. OPENAI_API_KEY not configured.", ) # Construct the prompt budget_text = "" if budget_min is not None and budget_max is not None: budget_text = f"Budget range: ${budget_min} - ${budget_max}" elif budget_min is not None: budget_text = f"Minimum budget: ${budget_min}" elif budget_max is not None: budget_text = f"Maximum budget: ${budget_max}" preferences_text = "" if preferences: preferences_text = f""" Recipient interests: {preferences.interests if preferences.interests else 'Not specified'} Recipient hobbies: {preferences.hobbies if preferences.hobbies else 'Not specified'} Favorite colors: {preferences.favorite_colors if preferences.favorite_colors else 'Not specified'} Clothing size: {preferences.clothing_size if preferences.clothing_size else 'Not specified'} Dislikes: {preferences.dislikes if preferences.dislikes else 'Not specified'} """ occasion_text = f"Occasion: {occasion}" if occasion else "Occasion: Not specified" additional_text = f"Additional information: {additional_info}" if additional_info else "" prompt = f""" You are a gift recommendation expert. Please suggest a thoughtful gift for {recipient_name}. {occasion_text} {budget_text} {preferences_text} {additional_text} Please provide your gift recommendation in JSON format with the following fields: 1. recommendation_text: A thoughtful explanation of your recommendation 2. item_name: The name of the recommended gift 3. description: A detailed description of the gift 4. price_estimate: Estimated price (as a number only, no currency symbol) 5. purchase_url: A suggested place to purchase the gift (can be a generic store name if specific URL not available) """ try: openai.api_key = self.api_key response = openai.ChatCompletion.create( model=self.model, messages=[ {"role": "system", "content": "You are a helpful gift recommendation assistant."}, {"role": "user", "content": prompt} ], temperature=0.7, max_tokens=800, ) # Extract the recommendation from the response recommendation_text = response.choices[0].message.content.strip() # Try to parse the JSON response try: # Find the JSON part in the response json_start = recommendation_text.find('{') json_end = recommendation_text.rfind('}') + 1 if json_start >= 0 and json_end > json_start: json_content = recommendation_text[json_start:json_end] recommendation_dict = json.loads(json_content) else: # If we can't find proper JSON, create a basic response recommendation_dict = { "recommendation_text": recommendation_text, "item_name": "Custom Gift", "description": "Based on the preferences provided", "price_estimate": budget_min if budget_min else 50.0, "purchase_url": "https://www.amazon.com" } # Ensure all required fields are present required_fields = ["recommendation_text", "item_name", "description", "price_estimate", "purchase_url"] for field in required_fields: if field not in recommendation_dict: recommendation_dict[field] = "Not specified" # Convert price to float if it's a string if isinstance(recommendation_dict["price_estimate"], str): price_str = recommendation_dict["price_estimate"].replace("$", "").replace(",", "") try: recommendation_dict["price_estimate"] = float(price_str) except ValueError: recommendation_dict["price_estimate"] = budget_min if budget_min else 50.0 return recommendation_dict except json.JSONDecodeError: # If JSON parsing fails, create a structured response from the text return { "recommendation_text": recommendation_text, "item_name": "Custom Gift", "description": "Based on the preferences provided", "price_estimate": budget_min if budget_min else 50.0, "purchase_url": "https://www.amazon.com" } except Exception as e: raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail=f"Error generating recommendation: {str(e)}", )