from fastapi import FastAPI, File, UploadFile, Form from pydantic import BaseModel import numpy as np from tensorflow.keras.models import load_model import PIL.Image import io import pandas as pd import os app = FastAPI() model = load_model("foodnutrition.keras", compile=False) CLASS_NAMES = [ 'Ayam Bakar', 'Ayam Geprek', 'Ayam Goreng', 'Ayam Tepung', 'Bakso', 'Bakwan', 'Batagor', 'Bolu Kukus', 'Burger', 'Cap Cay', 'Chicken Katsu', 'Cilok', 'Dimsum', 'Donat', 'Es Teh', 'Gado-Gado', 'Ikan Goreng', 'Jasuke', 'Jus Jeruk', 'Kikil', 'Kopi', 'Krepes', 'Lemper', 'Mie Ayam', 'Mie Instan', 'Nasi Goreng', 'Nasi Padang', 'Pecel Lele', 'Pizza', 'Random Image', 'Rendang', 'Risoles', 'Sate Ayam', 'Seblak', 'Siomay', 'Sop', 'Soto', 'Tahu', 'Tangkil', 'Telur Balado', 'Telur Dadar', 'Tempe', 'Thai Tea' ] # Muat file CSV nutrisi_csv = pd.read_csv('nutrisi_origin.csv') KOLOM_NAMA = nutrisi_csv.columns[1] class FoodRequest(BaseModel): nama_makanan: str def get_nutrition_data(food_name: str): pencarian = nutrisi_csv[nutrisi_csv[KOLOM_NAMA].str.lower() == food_name.lower()] kalori, protein, lemak, karbo = 0.0, 0.0, 0.0, 0.0 kategori = "Tidak Diketahui" if not pencarian.empty: detail_nutrisi = pencarian.iloc[0] kal_teks = str(detail_nutrisi.get('Kalori', '0')).lower().replace(',', '.').replace('g', '').strip() pro_teks = str(detail_nutrisi.get('Protein', '0')).lower().replace(',', '.').replace('g', '').strip() lem_teks = str(detail_nutrisi.get('Lemak', '0')).lower().replace(',', '.').replace('g', '').strip() karbo_teks = str(detail_nutrisi.get('Karbohidrat', '0')).lower().replace(',', '.').replace('g', '').strip() if 'Kategori' in detail_nutrisi: kategori = str(detail_nutrisi['Kategori']) try: kalori = float(kal_teks) except: kalori = 0.0 try: protein = float(pro_teks) except: protein = 0.0 try: lemak = float(lem_teks) except: lemak = 0.0 try: karbo = float(karbo_teks) except: karbo = 0.0 return { "kalori": kalori, "protein": protein, "lemak": lemak, "karbohidrat": karbo, "kategori": kategori } @app.get('/') async def hello(): return {"message": "Food Nutrition API Ready"} @app.post('/predict') async def predict(file: UploadFile = File(...)): img_bytes = await file.read() img = PIL.Image.open(io.BytesIO(img_bytes)).convert('RGB') img = img.resize((244, 244)) img_array = np.array(img).astype("float32") / 255.0 img_array = np.expand_dims(img_array, axis=0) preds = model.predict(img_array, verbose=0) index = np.argmax(preds[0]) confidence = round(float(np.max(preds[0])) * 100, 2) if confidence >= 90.0: predicted_label = CLASS_NAMES[index] else: predicted_label = "Tidak diketahui" probability = [] for i, prob in enumerate(preds[0]): probability.append({ "label": CLASS_NAMES[i], "score": round(float(prob) * 100, 2) }) probability = sorted(probability, key=lambda x: x["score"], reverse=True) data_nutrisi = get_nutrition_data(predicted_label) return { "prediction": predicted_label, "confidence": confidence, "probability": probability, "nutrisi": data_nutrisi }