Spaces:
Sleeping
Sleeping
File size: 6,368 Bytes
ead8552 c5137a6 ead8552 79b91ac ead8552 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | #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)} |