Brook-api / api.py
Punnawat01's picture
Update api.py
79b91ac
Raw History Blame Contribute Delete
6.37 kB
#uvicorn bytext:app --reload
from pydantic import BaseModel
from fastapi import FastAPI,Query
from typing import List
import difflib
import csv
from fastapi.middleware.cors import CORSMiddleware
import random
from fooddata import csv_data
from io import StringIO
app = FastAPI()
@app.get("/")
async def read_main():
return {"msg": "Hello World"}
# Enable CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Parse CSV data (assuming 'csv_data' is defined somewhere)
csv_lines = csv_data.strip().split('\n')
csv_reader = csv.DictReader(csv_lines)
foods = list(csv_reader)
def calculate_similarity(user_input, food):
# Compare user input directly with the "foodname" field
food_name_lower = food['foodname'].lower()
similarity_score = difflib.SequenceMatcher(None, user_input, food_name_lower).ratio()
return similarity_score
@app.post("/recommend")
async def find_food(
keyword: str = Query(None, title="General Search Keyword", min_length=1),
avoid_preference: str = Query(None, title="Avoid Preference"),
):
# Split avoid_preference into a list of individual preferences
avoid_preferences_list = avoid_preference.lower().split(",") if avoid_preference else []
# If there's no input for keyword, return 5 random foods without the specified avoid preferences
if not keyword and avoid_preferences_list:
foods_without_avoid = [food for food in foods if not any(avoid_pref in food['avoid'].lower() for avoid_pref in avoid_preferences_list)]
random_foods = random.sample(foods_without_avoid, min(5, len(foods_without_avoid)))
result = [{"foodname": food['foodname'], "type": food['type'], "price": food['price'], "country": food['country'], "images": food['images']} for food in random_foods]
return result
# Filter out foods to avoid
foods_to_consider = [food for food in foods if not any(avoid_pref in food['avoid'].lower() for avoid_pref in avoid_preferences_list)] if avoid_preference else foods
# If there's no input for both keyword and avoid_preference, return random 5 foods
if not keyword and not avoid_preference:
random_foods = random.sample(foods, 5)
result = [{"foodname": food['foodname'], "type": food['type'], "price": food['price'], "country": food['country'], "images": food['images']} for food in random_foods]
return result
# Convert user input to lowercase
user_input = keyword.lower()
# Calculate similarity using a more flexible approach
similarity_scores = [
(
food['foodname'],
food['type'],
food['price'],
food['country'],
food['images'], # Add 'images' here
calculate_similarity(user_input, food)
)
for food in foods_to_consider
]
# Find the top 5 foods with the highest similarity scores
top_matches = sorted(similarity_scores, key=lambda x: x[5], reverse=True)[:5]
# Format the results
result = [{"foodname": foodname, "type": foodtype, "price": foodprice, "country": foodcountry, "images": images}
for foodname, foodtype, foodprice, foodcountry, images, _ in top_matches]
return result
def filter_food_by_criteria(data, criteria, header_mapping):
filtered_food = [food for i, food in enumerate(csv.reader(data.strip().split("\n"))) if i > 0]
for criterion, value in criteria.items():
if value and criterion != 'price':
if criterion == 'avoid':
avoid_values = [av.lower() for av in value.split(',')]
filtered_food = [food for food in filtered_food if not any(any(av.lower() in tag.lower() for tag in food[header_mapping['avoid']].split(',')) for av in avoid_values)]
elif criterion == 'country':
# Improved handling of 'country' criterion (case-insensitive and stripping whitespace)
filtered_food = [food for food in filtered_food if isinstance(food, list) and value.lower().strip() in food[header_mapping[criterion]].lower().strip()]
else:
filtered_food = [food for food in filtered_food if isinstance(food, list) and any(val.lower() in food[header_mapping[criterion]].lower() for val in value.split(','))]
if value and criterion == 'price':
min_price, max_price = map(int, value.split('-'))
if isinstance(filtered_food[0][header_mapping[criterion]], list):
# Case when it's a list
filtered_food = [food for food in filtered_food if min_price < int(food[header_mapping[criterion]][0].split('-')[0]) < max_price]
else:
# Case when it's not a list
filtered_food = [food for food in filtered_food if min_price < int(food[header_mapping[criterion]].split('-')[0]) < max_price]
return filtered_food
# รหัสหัวข้อ
header_mapping = {
'foodname': 0,
'country': 1,
'taste': 2,
'type': 3,
'price': 4,
'avoid': 5,
'images': 6,
}
@app.post("/all")
def recommend_food(
avoid: str = Query(None, description="Foods to avoid, use comma as separator"),
country: str = Query(None, description="Preferred country"),
taste: str = Query(None, description="Preferred taste"),
price: str = Query(None, description="Preferred price range"),
food_type: str = Query(None, description="Preferred food type")
):
try:
user_criteria = {
'avoid': avoid,
'country': country,
'taste': taste,
'price': price,
'type': food_type,
}
# Filter food based on user criteria
recommended_food = filter_food_by_criteria(csv_data, user_criteria, header_mapping)
# Extract relevant information for the response
response_data = [
{
"foodname": food[header_mapping['foodname']],
"price": food[header_mapping['price']],
"type": food[header_mapping['type']],
"country": food[header_mapping['country']],
"images": food[header_mapping['images']],
} for food in recommended_food
]
return response_data
except Exception as e:
return {"error": str(e)}