File size: 5,457 Bytes
004faab
0dd2dc1
004faab
0dd2dc1
 
 
 
1e384db
 
 
 
 
0dd2dc1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import streamlit as st
import requests
from PIL import Image
import io
import base64

# URL untuk kedua endpoint FastAPI
# API_DETECT_URL = "http://localhost:8000/detect"
# API_ASK_URL = "http://localhost:8000/ask"

API_DETECT_URL = "http://backend:8000/detect"
API_ASK_URL = "http://backend:8000/ask"

st.set_page_config(page_title="ChiliCare AI", page_icon="🌶️", layout="centered")

# === MEMBUAT SIDEBAR NAVIGASI ===
st.sidebar.title("🌶️ Menu ChiliCare")
st.sidebar.markdown("Pilih fitur yang ingin Anda gunakan:")
menu = st.sidebar.radio(
    "====",
    ["📷 Deteksi Penyakit (Gambar)", "🤖 Chatbot (Teks)"]
)

# === HALAMAN 1: DETEKSI PENYAKIT (GAMBAR) ===
if menu == "📷 Deteksi Penyakit (Gambar)":
    st.title("🌶️🌿 Deteksi Penyakit Daun Cabai")
    st.write("Unggah foto daun cabai yang sakit untuk mendapatkan diagnosis dan solusinya.")
    
    uploaded_file = st.file_uploader("Unggah gambar daun cabai anda", type=["jpg", "jpeg", "png"])

    if uploaded_file is not None:
        original_image = Image.open(uploaded_file)
       # st.image(original_image, caption="Gambar yang Diupload", use_container_width=True)

        files = {"file": (uploaded_file.name, uploaded_file.getvalue(), uploaded_file.type)}
            
        try:
            with st.spinner("Memproses gambar dengan YOLOv11..."):
                response = requests.post(API_DETECT_URL, files=files)
                
            if response.status_code == 200:
                data = response.json()
                    
                if "image_base64" in data:
                    image_bytes = base64.b64decode(data["image_base64"])
                    annotated_image = Image.open(io.BytesIO(image_bytes))
                    st.image(annotated_image, caption="Hasil Analisis YOLO", use_container_width=True)

                st.subheader("📋 Hasil Diagnosis: ")
                if data.get("total_detections", 0) > 0:
                    for item in data["results"]:
                        st.markdown(f"### 🦠 {item['class']} (Keyakinan: {item['confidence']:.0%})")
                        st.info(f"**Saran Penanganan:**\n\n{item['narrative']}")
                else:
                    st.success("Tidak ada penyakit yang terdeteksi. Daun tampak sehat!")
            else:
                st.error(f"Gagal memproses gambar. Error: {response.status_code}")
        except requests.exceptions.ConnectionError:
            st.error("Gagal terhubung ke server FastAPI. Pastikan backend sudah berjalan.")

# === HALAMAN 2: TANYA AHLI (TEKS) ===
elif menu == "🤖 Chatbot (Teks)":
    st.title("🤖 Chatbot Ahli Cabai")
    st.write("Tanyakan seputar perawatan, penyakit, atau pupuk cabai. Saya siap membantu!")
    
    # 1. Inisialisasi memori obrolan (session state)
    if "messages" not in st.session_state:
        st.session_state.messages = []

    # 2. Tampilkan riwayat chat sebelumnya agar tidak hilang saat halaman direfresh
    for message in st.session_state.messages:
        with st.chat_message(message["role"]):
            st.markdown(message["content"])

    # 3. Kolom input untuk user menggunakan gaya chat
    if prompt := st.chat_input("Tulis pertanyaan Anda di sini... (misal: Kapan waktu panen cabai?)"):
        
        # Tampilkan pesan user di layar
        with st.chat_message("user"):
            st.markdown(prompt)
        
        # Simpan pesan user ke memori
        st.session_state.messages.append({"role": "user", "content": prompt})

        # Siapkan tempat untuk jawaban AI
        with st.chat_message("assistant"):
            with st.spinner("Berpikir dan mencari referensi..."):
                try:
                    # KITA KIRIM REQUEST KE FASTAPI (Bukan panggil chain lokal)
                    payload = {"question": prompt}
                    response = requests.post(API_ASK_URL, json=payload)
                    
                    if response.status_code == 200:
                        data = response.json()
                        jawaban = data["answer"]
                        
                        # Tampilkan jawaban dari FastAPI/LLM
                        st.markdown(jawaban)
                        
                        # Simpan jawaban ke memori
                        st.session_state.messages.append({"role": "assistant", "content": jawaban})
                    else:
                        error_msg = f"Gagal mendapatkan jawaban. Error: {response.status_code}"
                        st.error(error_msg)
                        st.session_state.messages.append({"role": "assistant", "content": error_msg})
                        
                except requests.exceptions.ConnectionError:
                    error_msg = "Gagal terhubung ke server FastAPI. Pastikan backend sudah berjalan."
                    st.error(error_msg)
                    st.session_state.messages.append({"role": "assistant", "content": error_msg})

st.sidebar.markdown("---")

st.sidebar.markdown("""
    # Spesifikasi Model AI
    **1. Vision (Deteksi Penyakit)**
    * Model: `YOLOv11s` (Small)
    * Framework: `Ultralytics`
    
    **2. Retrieval-Augmented Generation (RAG)**
    * Vector Database: `ChromaDB`
    * Embedding: `Qwen3-Embedding-0.6B`
    
    **3. Large Language Model (LLM)**
    * Model: `Nvidia Nemotron-3 120B`
    * Provider: `OpenRouter`
    """)

st.sidebar.markdown("---")

st.sidebar.caption("© 2026 ChiliCare AI Engineer Portfolio")