ai_VirtualShop / main.py
userName3204983204's picture
Initial commit
3b1144b verified
# main.py
import os
import asyncio
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import uvicorn
from serpapi import GoogleSearch
from openai import OpenAI
import json
# --- Securely get API keys from environment variables (provided by Cloud Run) ---
OPENROUTER_API_KEY = os.environ.get('OPENROUTER_API_KEY')
SERPAPI_API_KEY = os.environ.get('SERPAPI_API_KEY')
app = FastAPI(title="AI Shopping Assistant API")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Allows all origins
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
class UserQuery(BaseModel):
product_name: str
description: str
budget: float
# =========================================================================
# === PASTE YOUR 'search_with_serpapi' FUNCTION FROM COLAB HERE ===
# =========================================================================
def search_with_serpapi(search_query: str):
"""Performs a search on Google Shopping (India) using the SerpApi."""
print(f"🕵️‍♂️ Searching Google Shopping with SerpApi for: '{search_query}'")
try:
search = GoogleSearch({
"engine": "google_shopping",
"q": search_query,
"api_key": SERPAPI_API_KEY,
"gl": "in", # Geolocation: India
"hl": "en", # Host Language: English
"currency": "INR" # Currency: Indian Rupee
})
results = search.get_dict()
shopping_results = results.get("shopping_results", [])
if not shopping_results: return []
# Extract the same detailed information your frontend expects
top_results = []
for item in shopping_results[:7]: # Get top 7 results for the AI to choose from
price = item.get('extracted_price') # This field is usually just the number
if not price: continue
top_results.append({
"title": item.get("title"),
"price": price,
"source": item.get("source"), # e.g., "Amazon.in", "Flipkart"
"rating": item.get("rating"),
"reviews_count": item.get("reviews"),
"image_url": item.get("thumbnail"), # Use thumbnail for the image
"link": item.get("link"),
"features": [] # SerpApi doesn't provide feature bullets in the same way
})
print(f"✅ Found {len(top_results)} products from Google Shopping via SerpApi.")
return top_results
except Exception as e:
print(f"❌ Error during SerpApi search: {e}")
return None
# =========================================================================
# === PASTE YOUR 'get_llm_recommendations' FUNCTION FROM COLAB HERE ===
# =========================================================================
def get_llm_recommendations(user_query: UserQuery, product_data: list):
"""Generates a complex JSON object tailored for the React frontend."""
print("🧠 Sending SerpApi data to LLM for analysis...")
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=OPENROUTER_API_KEY,
)
# --- Step 3: Updated Prompt ---
# The prompt is updated to reflect the new, broader data source
prompt = f"""
You are an expert virtual shopping assistant. Your goal is to generate a structured JSON response to power a rich user interface.
My Request:
- Product: "{user_query.product_name}"
- Needs: "{user_query.description}"
- Budget: "Under ₹{user_query.budget} INR"
Detailed Product Data from various online stores in India (via Google Shopping):
{json.dumps(product_data, indent=2)}
Based on my request and this data, return a single JSON object with the following exact keys: "summary", "comparison", "products", and "completeTheLook".
1. "summary": (String) A concise, friendly summary of your findings and top recommendation.
2. "comparison": (Object) A comparison between your top two recommendations. Must have "headers" and "rows" keys.
3. "products": (Array of Objects) A list of your top 2-3 recommended products. Each object must have these exact keys: "id", "name", "brand", "price", "rating", "image", and "link". Infer the brand from the title.
4. "completeTheLook": (Object) A suggestion for a complementary product. Must have "item" and "link" keys.
Do not include any text or markdown outside of the main JSON object.
"""
# -------------------------------
try:
response = client.chat.completions.create(
model="google/gemini-flash-1.5",
response_format={"type": "json_object"},
messages=[{"role": "user", "content": prompt}],
temperature=0.6,
)
print("✅ LLM response for React UI received.")
return json.loads(response.choices[0].message.content)
except Exception as e:
print(f"❌ Error during OpenRouter API call: {e}")
raise HTTPException(status_code=500, detail=f"Error communicating with the AI model: {e}")
# --- API Endpoint (This part is already complete) ---
@app.post("/search")
async def search_products_endpoint(query: UserQuery):
search_query = f"{query.product_name} {query.description}"
product_data = search_with_serpapi(search_query)
if product_data is None: raise HTTPException(status_code=503, detail="The product search service (SerpApi) failed.")
if not product_data: raise HTTPException(status_code=404, detail="Could not find any products matching your query.")
recommendation_json = get_llm_recommendations(query, product_data)
return recommendation_json
@app.get("/")
def read_root(): return {"message": "AI Shopping Assistant Backend is running!"}