|
|
import uvicorn |
|
|
import numpy as np |
|
|
import pandas as pd |
|
|
import pickle |
|
|
from fastapi import FastAPI, File, UploadFile |
|
|
from fastapi.responses import JSONResponse |
|
|
from PIL import Image |
|
|
from io import BytesIO |
|
|
from model.feature_extractor import FeatureExtractor |
|
|
from utils.faiss_index import FaissIndex |
|
|
|
|
|
import os |
|
|
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" |
|
|
|
|
|
app = FastAPI() |
|
|
|
|
|
|
|
|
embeddings = np.load("data/embeddings.npy") |
|
|
with open("data/image_urls.pkl", "rb") as f: |
|
|
image_urls = pickle.load(f) |
|
|
product_data = pd.read_csv("data/product_data.csv") |
|
|
|
|
|
fe = FeatureExtractor() |
|
|
index = FaissIndex(dim=embeddings.shape[1]) |
|
|
index.build(embeddings, image_urls) |
|
|
|
|
|
@app.post("/recommend") |
|
|
async def recommend(file: UploadFile = File(...), threshold: float = 0.8, k: int = 100): |
|
|
try: |
|
|
image = Image.open(BytesIO(await file.read())).convert("RGB") |
|
|
user_emb = fe.extract(image) |
|
|
results = index.search(user_emb, threshold=threshold, k=k) |
|
|
|
|
|
if not results: |
|
|
return JSONResponse({"message": "No similar products found"}, status_code=404) |
|
|
|
|
|
input_url = results[0][0] |
|
|
input_row = product_data[product_data['IMAGE'] == input_url] |
|
|
|
|
|
input_group_id = input_row['GROUP_ID'].values[0] if not input_row.empty else None |
|
|
input_product_name = input_row['PRODUCT_NAME'].values[0] if not input_row.empty else None |
|
|
|
|
|
|
|
|
filtered = [] |
|
|
for url, sim in results: |
|
|
row = product_data[product_data['IMAGE'] == url] |
|
|
group_id = row['GROUP_ID'].values[0] if not row.empty else None |
|
|
product_name = row['PRODUCT_NAME'].values[0] if not row.empty else None |
|
|
|
|
|
if (input_group_id is None or input_group_id == 0): |
|
|
if product_name != input_product_name: |
|
|
filtered.append((url, sim)) |
|
|
else: |
|
|
if group_id != input_group_id: |
|
|
filtered.append((url, sim)) |
|
|
|
|
|
|
|
|
seen = set() |
|
|
final = [] |
|
|
for url, sim in filtered: |
|
|
row = product_data[product_data['IMAGE'] == url] |
|
|
product_name = row['PRODUCT_NAME'].values[0] if not row.empty else None |
|
|
if product_name and product_name not in seen: |
|
|
seen.add(product_name) |
|
|
brand_name = row['BRAND_NAME'].values[0] if 'BRAND_NAME' in row else "Unknown" |
|
|
final.append({ |
|
|
"brand_name": brand_name, |
|
|
"product_name": product_name, |
|
|
"image_url": url, |
|
|
"similarity_score": float(f"{sim:.4f}") |
|
|
}) |
|
|
|
|
|
return {"recommendations": final[:15]} |
|
|
|
|
|
except Exception as e: |
|
|
return JSONResponse({"error": str(e)}, status_code=500) |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) |