BlasterBlade65's picture
Update app.py
8634f2e verified
import streamlit as st
import numpy as np
import pickle
import tensorflow as tf
import os
import pandas as pd
from datetime import datetime
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.applications.mobilenet_v2 import MobileNetV2, preprocess_input
from tensorflow.keras.preprocessing.image import img_to_array
from PIL import Image
# ==========================================
# 1. KONFIGURASI PATH
# ==========================================
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
MODEL_DIR = os.path.join(BASE_DIR, 'models')
PATH_MODEL_CAPTION = os.path.join(MODEL_DIR, 'fruit_caption_model.h5')
PATH_TOKENIZER = os.path.join(MODEL_DIR, 'tokenizer.pkl')
PATH_LOG = os.path.join(MODEL_DIR, 'riwayat_penggunaan.csv')
PATH_GRAFIK = os.path.join(MODEL_DIR, '1_grafik_akurasi.png')
# ==========================================
# 2. TAMPILAN UI UTAMA
# ==========================================
st.set_page_config(page_title="AI Fruit Captioning", page_icon="๐Ÿฅญ", layout="wide")
st.title("๐ŸŽ Identifikasi Citra Buah Digital")
st.write("Sistem otomatis yang mendeskripsikan jenis buah dan manfaatnya menggunakan Deep Learning.")
# ==========================================
# 3. FUNGSI LOGIKA
# ==========================================
def save_to_log(nama, vitamin, deskripsi):
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
new_data = {'Waktu': [now], 'Nama Buah': [nama], 'Vitamin': [vitamin], 'Deskripsi': [deskripsi]}
df_new = pd.DataFrame(new_data)
if not os.path.exists(MODEL_DIR):
os.makedirs(MODEL_DIR)
if not os.path.isfile(PATH_LOG):
df_new.to_csv(PATH_LOG, index=False)
else:
df_new.to_csv(PATH_LOG, mode='a', header=False, index=False)
@st.cache_resource
def load_assets():
if not os.path.exists(PATH_MODEL_CAPTION) or not os.path.exists(PATH_TOKENIZER):
raise FileNotFoundError("File model atau tokenizer tidak ditemukan!")
model = load_model(PATH_MODEL_CAPTION)
with open(PATH_TOKENIZER, 'rb') as f:
tokenizer = pickle.load(f)
base_model = MobileNetV2(weights='imagenet')
fe_model = tf.keras.Model(inputs=base_model.inputs, outputs=base_model.layers[-2].output)
return model, tokenizer, fe_model
def generate_caption(image, model, tokenizer, fe_model):
img = image.convert('RGB').resize((224, 224))
img = img_to_array(img)
img = np.expand_dims(img, axis=0)
img = preprocess_input(img)
feature = fe_model.predict(img, verbose=0)
max_length = 21
in_text = 'startseq'
for i in range(max_length):
sequence = tokenizer.texts_to_sequences([in_text])[0]
sequence = pad_sequences([sequence], maxlen=max_length)
yhat = model.predict([feature, sequence], verbose=0)
idx = np.argmax(yhat)
word = tokenizer.index_word.get(idx)
if word is None or word == 'endseq':
break
in_text += ' ' + word
return in_text.replace('startseq', '').strip()
# ==========================================
# 4. ALUR PROSES APLIKASI
# ==========================================
try:
model, tokenizer, fe_model = load_assets()
except Exception as e:
st.error(f"โš ๏ธ Gagal memuat sistem: {e}")
st.stop()
uploaded_file = st.file_uploader("Unggah foto buah...", type=["jpg", "png", "jpeg"])
if uploaded_file is not None:
img_display = Image.open(uploaded_file).convert('RGB')
col1, col2 = st.columns([1, 1])
with col1:
st.subheader("๐Ÿ–ผ๏ธ Citra Input")
st.image(img_display, use_column_width=True)
with col2:
st.subheader("๐Ÿค– Hasil Analisis AI")
with st.spinner('Menganalisis citra...'):
try:
caption = generate_caption(img_display, model, tokenizer, fe_model)
if "b9" in caption or len(caption.split()) < 2:
st.warning("Model belum mengenali gambar ini. Pastikan file tokenizer sudah sesuai.")
st.write(f"Output mentah: `{caption}`")
elif ' deskripsi ' in caption and ' mengandung vitamin ' in caption:
parts = caption.split(' deskripsi ')
nama_buah = parts[0].replace('buah ', '').title()
detail = parts[1].split(' mengandung vitamin ')
deskripsi_clean = detail[0].capitalize()
vitamin_clean = detail[1].upper()
st.success(f"**Jenis Buah:** {nama_buah}")
st.metric(label="Kandungan Utama", value=f"Vitamin {vitamin_clean}")
st.info(f"**Keterangan:**\n{deskripsi_clean}")
save_to_log(nama_buah, vitamin_clean, deskripsi_clean)
else:
st.success("Analisis Selesai")
st.write(f"**Hasil Prediksi:** {caption}")
except Exception as e:
st.error(f"Terjadi kesalahan: {e}")
# ==========================================
# 5. SIDEBAR
# ==========================================
with st.sidebar:
st.header("๐Ÿ“Š Informasi & Riwayat")
if os.path.exists(PATH_GRAFIK):
st.image(PATH_GRAFIK, caption="Grafik Performa Model", use_column_width=True)
st.markdown("---")
if os.path.exists(PATH_LOG):
df_log = pd.read_csv(PATH_LOG)
csv_data = df_log.to_csv(index=False).encode('utf-8')
# PERBAIKAN: Menghapus use_column_width dari download_button
st.download_button(
label="Download Riwayat (CSV)",
data=csv_data,
file_name=f"riwayat_buah_{datetime.now().strftime('%Y%m%d')}.csv",
mime="text/csv"
)