GiziMeal API
System Online

GiziMeal API Documentation

A deep learning RESTful API for food ingredient image classification and comprehensive nutritional analysis. Explore the available endpoints below.

Base URL:
Prediction
POST /predict

Uploads a food ingredient image to classify the subject and retrieves the corresponding nutritional data.

ParameterTypeDescription
filesrequiredformData (image[])One or more food ingredient image files to be detected (JPG/PNG). Upload multiple files to get menu recommendations based on all detected ingredients.
curl -X POST "http://localhost:8000/predict" \ -F "files=@./image1.jpg" \ -F "files=@./image2.jpg"
import requests files = [ ("files", open("image1.jpg", "rb")), ("files", open("image2.jpg", "rb")), ] response = requests.post("http://localhost:8000/predict", files=files) print(response.json())
const axios = require("axios"); const FormData = require("form-data"); const fs = require("fs"); const form = new FormData(); form.append("files", fs.createReadStream("./image1.jpg")); form.append("files", fs.createReadStream("./image2.jpg")); const { data } = await axios.post("http://localhost:8000/predict", form, { headers: form.getHeaders(), }); console.log(data);
import { useState } from "react"; export default function PredictForm() { const [result, setResult] = useState(null); const [loading, setLoading] = useState(false); const handleSubmit = async (e) => { e.preventDefault(); setLoading(true); const formData = new FormData(); for (const file of e.target.files.files) { formData.append("files", file); } const res = await fetch("/predict", { method: "POST", body: formData }); setResult(await res.json()); setLoading(false); }; return ( <form onSubmit={handleSubmit}> <input type="file" name="files" accept="image/*" multiple /> <button disabled={loading}>{loading ? "Loading..." : "Predict"}</button> {result && <pre>{JSON.stringify(result, null, 2)}</pre>} </form> ); }
// app/actions/predict.ts "use server"; export async function predictFood(formData: FormData) { const res = await fetch("http://localhost:8000/predict", { method: "POST", body: formData, }); if (!res.ok) throw new Error("Prediction failed"); return res.json(); }
use Illuminate\Support\Facades\Http; $response = Http::attach('files', file_get_contents('image1.jpg'), 'image1.jpg') ->attach('files', file_get_contents('image2.jpg'), 'image2.jpg') ->post('http://localhost:8000/predict'); return $response->json();
body := &bytes.Buffer{} writer := multipart.NewWriter(body) for _, path := range []string{"image1.jpg", "image2.jpg"} { file, _ := os.Open(path) part, _ := writer.CreateFormFile("files", path) io.Copy(part, file) file.Close() } writer.Close() req, _ := http.NewRequest("POST", "http://localhost:8000/predict", body) req.Header.Set("Content-Type", writer.FormDataContentType()) resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() result, _ := io.ReadAll(resp.Body) fmt.Println(string(result))
import * as ImagePicker from "expo-image-picker"; const result = await ImagePicker.launchImageLibraryAsync({ allowsMultipleSelection: true, quality: 0.8, }); if (!result.canceled) { const formData = new FormData(); result.assets.forEach((asset, i) => { formData.append("files", { uri: asset.uri, name: `image_${i}.jpg`, type: "image/jpeg", }); }); const res = await fetch("http://localhost:8000/predict", { method: "POST", body: formData, headers: { "Content-Type": "multipart/form-data" }, }); console.log(await res.json()); }
import 'dart:convert'; import 'package:http/http.dart' as http; final request = http.MultipartRequest( 'POST', Uri.parse('http://localhost:8000/predict'), ); request.files.add(await http.MultipartFile.fromPath('files', 'image1.jpg')); request.files.add(await http.MultipartFile.fromPath('files', 'image2.jpg')); final response = await request.send(); final body = await response.stream.bytesToString(); print(jsonDecode(body));
val client = OkHttpClient() val body = MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("files", "image1.jpg", File("image1.jpg").asRequestBody("image/jpeg".toMediaType())) .addFormDataPart("files", "image2.jpg", File("image2.jpg").asRequestBody("image/jpeg".toMediaType())) .build() val request = Request.Builder() .url("http://localhost:8000/predict") .post(body) .build() val response = client.newCall(request).execute() println(response.body?.string())
var request = URLRequest(url: URL(string: "http://localhost:8000/predict")!) request.httpMethod = "POST" let boundary = UUID().uuidString request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") var body = Data() for url in imageURLs { let imageData = try Data(contentsOf: url) body.append("--\(boundary)\r\n") body.append("Content-Disposition: form-data; name=\"files\"; filename=\"\(url.lastPathComponent)\"\r\n") body.append("Content-Type: image/jpeg\r\n\r\n") body.append(imageData) body.append("\r\n") } body.append("--\(boundary)--\r\n") request.httpBody = body let (data, _) = try await URLSession.shared.data(for: request) let json = try JSONSerialization.jsonObject(with: data)
Try it

Drop images here or browse

Formats: JPG, PNG • Max 15 files • 1 MB per file

Nutrition
GET /classes

Retrieves the exhaustive list of food classes the machine learning model is trained to recognize. Accesses the core nutritional dataset and supported classifications.

curl -X GET "http://localhost:8000/classes"
import requests response = requests.get("http://localhost:8000/classes") print(response.json())
const { data } = await axios.get("http://localhost:8000/classes"); console.log(data);
import { useState, useEffect } from "react"; export default function ClassList() { const [classes, setClasses] = useState([]); useEffect(() => { fetch("/classes") .then((res) => res.json()) .then(setClasses); }, []); return ( <ul> {classes.map((cls, i) => <li key={i}>{cls}</li>)} </ul> ); }
// app/classes/page.tsx export default async function ClassesPage() { const res = await fetch("http://localhost:8000/classes", { next: { revalidate: 3600 }, }); const classes: string[] = await res.json(); return ( <ul> {classes.map((cls, i) => <li key={i}>{cls}</li>)} </ul> ); }
use Illuminate\Support\Facades\Http; $response = Http::get('http://localhost:8000/classes'); return $response->json();
resp, _ := http.Get("http://localhost:8000/classes") defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))
const res = await fetch("http://localhost:8000/classes"); const classes = await res.json(); console.log(classes);
import 'dart:convert'; import 'package:http/http.dart' as http; final response = await http.get(Uri.parse('http://localhost:8000/classes')); final List<dynamic> classes = jsonDecode(response.body); print(classes);
val response = client.get("http://localhost:8000/classes") val classes: List<String> = Json.decodeFromString(response.bodyAsText())
let url = URL(string: "http://localhost:8000/classes")! let (data, _) = try await URLSession.shared.data(from: url) let classes = try JSONDecoder().decode([String].self, from: data)
Try it
GET /foods

Retrieves all food items from the internal dataset. Optionally pass a limit parameter to cap the number of results.

ParameterTypeDescription
limitoptionalinteger ≥ 1Max number of items to return. Omit to get all items.
# All items curl -X GET "http://localhost:8000/foods" # With limit curl -X GET "http://localhost:8000/foods?limit=10"
import requests response = requests.get("http://localhost:8000/foods", params={"limit": 10}) print(response.json())
const { data } = await axios.get("http://localhost:8000/foods", { params: { limit: 10 }, }); console.log(data);
import { useState, useEffect } from "react"; export default function FoodList({ limit }) { const [foods, setFoods] = useState([]); useEffect(() => { const params = limit ? `?limit=${limit}` : ""; fetch(`/foods${params}`) .then((res) => res.json()) .then(setFoods); }, [limit]); return ( <ul> {foods.map((food, i) => <li key={i}>{food.name}</li>)} </ul> ); }
// app/foods/page.tsx export default async function FoodsPage({ searchParams }) { const limit = searchParams.limit ?? ""; const params = limit ? `?limit=${limit}` : ""; const res = await fetch(`http://localhost:8000/foods${params}`); const foods = await res.json(); return ( <ul> {foods.map((food, i) => <li key={i}>{food.name}</li>)} </ul> ); }
use Illuminate\Support\Facades\Http; $response = Http::get('http://localhost:8000/foods', [ 'limit' => 10, ]); return $response->json();
resp, _ := http.Get("http://localhost:8000/foods?limit=10") defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))
const res = await fetch("http://localhost:8000/foods?limit=10"); const foods = await res.json(); console.log(foods);
import 'dart:convert'; import 'package:http/http.dart' as http; final response = await http.get(Uri.parse('http://localhost:8000/foods?limit=10')); final foods = jsonDecode(response.body); print(foods);
val response = client.get("http://localhost:8000/foods") { parameter("limit", 10) } println(response.bodyAsText())
var components = URLComponents(string: "http://localhost:8000/foods")! components.queryItems = [URLQueryItem(name: "limit", value: "10")] let (data, _) = try await URLSession.shared.data(from: components.url!) let foods = try JSONSerialization.jsonObject(with: data)
Try it
Calculator
POST /calculator/bmr

Computes the Basal Metabolic Rate (BMR) and Total Daily Energy Expenditure (TDEE). Provides dietary utility metrics based on user anthropometric data.

ParameterTypeDescription
agerequiredintegerUser's age (years).
weightrequiredfloatBody weight (kg).
heightrequiredfloatBody height (cm).
genderrequiredstringEither male or female.
activity_leveloptionalstringsedentary, light, moderate, active, very_active.
curl -X POST "http://localhost:8000/calculator/bmr" \ -H "Content-Type: application/json" \ -d '{"age":25,"weight":70,"height":175,"gender":"male","activity_level":"moderate"}'
import requests payload = { "age": 25, "weight": 70, "height": 175, "gender": "male", "activity_level": "moderate", } response = requests.post("http://localhost:8000/calculator/bmr", json=payload) print(response.json())
const { data } = await axios.post("http://localhost:8000/calculator/bmr", { age: 25, weight: 70, height: 175, gender: "male", activity_level: "moderate", }); console.log(data);
import { useState } from "react"; export default function BMRCalculator() { const [result, setResult] = useState(null); const handleSubmit = async (e) => { e.preventDefault(); const form = Object.fromEntries(new FormData(e.target)); const res = await fetch("/calculator/bmr", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(form), }); setResult(await res.json()); }; return ( <form onSubmit={handleSubmit}> <input name="age" type="number" defaultValue={25} /> <input name="weight" type="number" defaultValue={70} /> <input name="height" type="number" defaultValue={175} /> <select name="gender"> <option value="male">Male</option> <option value="female">Female</option> </select> <button type="submit">Calculate</button> {result && <pre>{JSON.stringify(result, null, 2)}</pre>} </form> ); }
// app/actions/bmr.ts "use server"; export async function calculateBMR(payload: Record<string, unknown>) { const res = await fetch("http://localhost:8000/calculator/bmr", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); if (!res.ok) throw new Error("Calculation failed"); return res.json(); }
use Illuminate\Support\Facades\Http; $response = Http::post('http://localhost:8000/calculator/bmr', [ 'age' => 25, 'weight' => 70, 'height' => 175, 'gender' => 'male', 'activity_level' => 'moderate', ]); return $response->json();
payload := []byte(`{"age":25,"weight":70,"height":175,"gender":"male","activity_level":"moderate"}`) resp, _ := http.Post("http://localhost:8000/calculator/bmr", "application/json", bytes.NewBuffer(payload)) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))
const payload = { age: 25, weight: 70, height: 175, gender: "male", activity_level: "moderate", }; const res = await fetch("http://localhost:8000/calculator/bmr", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); const result = await res.json(); console.log(result);
import 'dart:convert'; import 'package:http/http.dart' as http; final response = await http.post( Uri.parse('http://localhost:8000/calculator/bmr'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({ 'age': 25, 'weight': 70, 'height': 175, 'gender': 'male', 'activity_level': 'moderate', }), ); print(jsonDecode(response.body));
val payload = """{"age":25,"weight":70,"height":175,"gender":"male","activity_level":"moderate"}""" val request = Request.Builder() .url("http://localhost:8000/calculator/bmr") .post(payload.toRequestBody("application/json".toMediaType())) .build() val response = client.newCall(request).execute() println(response.body?.string())
var request = URLRequest(url: URL(string: "http://localhost:8000/calculator/bmr")!) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = try JSONSerialization.data(withJSONObject: [ "age": 25, "weight": 70, "height": 175, "gender": "male", "activity_level": "moderate" ]) let (data, _) = try await URLSession.shared.data(for: request) let result = try JSONSerialization.jsonObject(with: data)
Try it
Model
GET /model/list

Retrieves all model files and directories present in the API path. Manages the underlying machine learning infrastructure.

curl -X GET "http://localhost:8000/model/list"
import requests response = requests.get("http://localhost:8000/model/list") print(response.json())
const { data } = await axios.get("http://localhost:8000/model/list"); console.log(data);
import { useState, useEffect } from "react"; export default function ModelList() { const [models, setModels] = useState([]); useEffect(() => { fetch("/model/list") .then((res) => res.json()) .then(setModels); }, []); return ( <ul> {models.map((m, i) => <li key={i}>{m}</li>)} </ul> ); }
// app/models/page.tsx export default async function ModelsPage() { const res = await fetch("http://localhost:8000/model/list", { cache: "no-store", }); const models: string[] = await res.json(); return ( <ul> {models.map((m, i) => <li key={i}>{m}</li>)} </ul> ); }
use Illuminate\Support\Facades\Http; $response = Http::get('http://localhost:8000/model/list'); return $response->json();
resp, _ := http.Get("http://localhost:8000/model/list") defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))
const res = await fetch("http://localhost:8000/model/list"); const models = await res.json(); console.log(models);
import 'dart:convert'; import 'package:http/http.dart' as http; final response = await http.get(Uri.parse('http://localhost:8000/model/list')); final models = jsonDecode(response.body); print(models);
val response = client.get("http://localhost:8000/model/list") println(response.bodyAsText())
let url = URL(string: "http://localhost:8000/model/list")! let (data, _) = try await URLSession.shared.data(from: url) let models = try JSONDecoder().decode([String].self, from: data)
Try it
POST /model/switch

Switches the active machine learning model during runtime without requiring a server restart.

ParameterTypeDescription
model_namerequiredstringTarget model filename (e.g., model_name.keras).
curl -X POST "http://localhost:8000/model/switch" \ -H "Content-Type: application/json" \ -d '{"model_name": "gizimeal_1.1.keras"}'
import requests payload = {"model_name": "gizimeal_1.1.keras"} response = requests.post("http://localhost:8000/model/switch", json=payload) print(response.json())
const { data } = await axios.post("http://localhost:8000/model/switch", { model_name: "gizimeal_1.1.keras", }); console.log(data);
import { useState } from "react"; export default function ModelSwitcher({ models }) { const [selected, setSelected] = useState(""); const [result, setResult] = useState(null); const handleSwitch = async () => { if (!selected) return; const res = await fetch("/model/switch", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ model_name: selected }), }); setResult(await res.json()); }; return ( <div> <select value={selected} onChange={(e) => setSelected(e.target.value)}> <option value="">Select model</option> {models.map((m) => <option key={m} value={m}>{m}</option>)} </select> <button onClick={handleSwitch}>Switch</button> {result && <pre>{JSON.stringify(result, null, 2)}</pre>} </div> ); }
// app/actions/model.ts "use server"; export async function switchModel(modelName: string) { const res = await fetch("http://localhost:8000/model/switch", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ model_name: modelName }), }); if (!res.ok) throw new Error("Switch failed"); return res.json(); }
use Illuminate\Support\Facades\Http; $response = Http::post('http://localhost:8000/model/switch', [ 'model_name' => 'gizimeal_1.1.keras', ]); return $response->json();
payload := []byte(`{"model_name":"gizimeal_1.1.keras"}`) resp, _ := http.Post("http://localhost:8000/model/switch", "application/json", bytes.NewBuffer(payload)) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))
const res = await fetch("http://localhost:8000/model/switch", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ model_name: "gizimeal_1.1.keras" }), }); const result = await res.json(); console.log(result);
import 'dart:convert'; import 'package:http/http.dart' as http; final response = await http.post( Uri.parse('http://localhost:8000/model/switch'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({'model_name': 'gizimeal_1.1.keras'}), ); print(jsonDecode(response.body));
val payload = """{"model_name": "gizimeal_1.1.keras"}""" val request = Request.Builder() .url("http://localhost:8000/model/switch") .post(payload.toRequestBody("application/json".toMediaType())) .build() val response = client.newCall(request).execute() println(response.body?.string())
var request = URLRequest(url: URL(string: "http://localhost:8000/model/switch")!) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = try JSONSerialization.data( withJSONObject: ["model_name": "gizimeal_1.1.keras"] ) let (data, _) = try await URLSession.shared.data(for: request) let result = try JSONSerialization.jsonObject(with: data)
Try it
Chatbot
POST /chatbot/ask

Send a message to the GiziMeal nutrition chatbot. Currently returns a dummy response — will be integrated with Google AI Studio (Gemini Flash Lite) in the future.

ParameterTypeDescription
messagerequiredstringUser message to the chatbot (1–2000 characters).
historyoptionalarrayPrevious conversation history for context. Each item: { role, content }.
curl -X POST "http://localhost:8000/chatbot/ask" \ -H "Content-Type: application/json" \ -d '{"message": "Jelaskan tentang kalori"}'
import requests response = requests.post("http://localhost:8000/chatbot/ask", json={ "message": "Jelaskan tentang kalori", "history": [] }) data = response.json() print(data["reply"])
const axios = require("axios"); const { data } = await axios.post("http://localhost:8000/chatbot/ask", { message: "Jelaskan tentang kalori", history: [] }); console.log(data.reply);
import { useState } from "react"; export default function Chatbot() { const [messages, setMessages] = useState([]); const [input, setInput] = useState(""); const sendMessage = async () => { const res = await fetch("/chatbot/ask", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: input, history: messages }), }); const data = await res.json(); setMessages([...messages, { role: "user", content: input }, { role: "assistant", content: data.reply }, ]); setInput(""); }; return ( <div> {messages.map((m, i) => <p key={i}>{m.content}</p>)} <input value={input} onChange={(e) => setInput(e.target.value)} /> <button onClick={sendMessage}>Send</button> </div> ); }
// app/actions/chat.ts "use server"; export async function sendChatMessage(message: string, history: any[]) { const res = await fetch("http://localhost:8000/chatbot/ask", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message, history }), }); if (!res.ok) throw new Error("Chat request failed"); return res.json(); }
use Illuminate\Support\Facades\Http; $response = Http::post('http://localhost:8000/chatbot/ask', [ 'message' => 'Jelaskan tentang kalori', 'history' => [], ]); return $response->json();
payload := map[string]interface{}{ "message": "Jelaskan tentang kalori", "history": []interface{}{}, } jsonData, _ := json.Marshal(payload) resp, _ := http.Post( "http://localhost:8000/chatbot/ask", "application/json", bytes.NewBuffer(jsonData), ) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))
const sendMessage = async (message) => { const res = await fetch("http://localhost:8000/chatbot/ask", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message, history: [] }), }); const data = await res.json(); console.log(data.reply); // data.suggestions contains follow-up actions };
import 'dart:convert'; import 'package:http/http.dart' as http; final response = await http.post( Uri.parse('http://localhost:8000/chatbot/ask'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({ 'message': 'Jelaskan tentang kalori', 'history': [], }), ); final data = jsonDecode(response.body); print(data['reply']);
val client = OkHttpClient() val json = """{"message":"Jelaskan tentang kalori","history":[]}""" val body = json.toRequestBody("application/json".toMediaType()) val request = Request.Builder() .url("http://localhost:8000/chatbot/ask") .post(body) .build() val response = client.newCall(request).execute() println(response.body?.string())
var request = URLRequest(url: URL(string: "http://localhost:8000/chatbot/ask")!) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") let payload: [String: Any] = ["message": "Jelaskan tentang kalori", "history": []] request.httpBody = try JSONSerialization.data(withJSONObject: payload) let (data, _) = try await URLSession.shared.data(for: request) let result = try JSONSerialization.jsonObject(with: data)
Try it
Halo! Saya GiziMeal Bot, asisten nutrisi virtualmu. Tanyakan apa saja seputar gizi dan makanan.
System
GET /health

Retrieves the server status, active model load state, and dataset availability metrics.

curl -X GET "http://localhost:8000/health"
import requests response = requests.get("http://localhost:8000/health") print(response.json())
const { data } = await axios.get("http://localhost:8000/health"); console.log(data);
import { useState, useEffect } from "react"; export default function HealthStatus() { const [health, setHealth] = useState(null); useEffect(() => { fetch("/health") .then((res) => res.json()) .then(setHealth); }, []); if (!health) return <span>Checking...</span>; return <span>Status: {health.status}</span>; }
// app/api/health/route.ts import { NextResponse } from "next/server"; export async function GET() { const res = await fetch("http://localhost:8000/health", { cache: "no-store", }); return NextResponse.json(await res.json()); }
use Illuminate\Support\Facades\Http; $response = Http::get('http://localhost:8000/health'); return $response->json();
resp, _ := http.Get("http://localhost:8000/health") defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))
const res = await fetch("http://localhost:8000/health"); const health = await res.json(); console.log(health.status);
import 'dart:convert'; import 'package:http/http.dart' as http; final response = await http.get(Uri.parse('http://localhost:8000/health')); final health = jsonDecode(response.body); print(health['status']);
val response = client.get("http://localhost:8000/health") println(response.bodyAsText())
let url = URL(string: "http://localhost:8000/health")! let (data, _) = try await URLSession.shared.data(from: url) let health = try JSONSerialization.jsonObject(with: data)
Try it