Tomichan / streamlit_app.py
TOMICHANZ's picture
Update streamlit_app.py
fc0f328 verified
Raw
History Blame Contribute Delete
6.36 kB
import streamlit as st
import pandas as pd
import os
import torch
from huggingface_hub import InferenceClient
from deep_translator import GoogleTranslator
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document
# --- CONFIG ---
MODEL_NAME = "mistralai/Mixtral-8x7B-Instruct-v0.1"
# --- Language Support ---
language_map = {
"English": "en",
"Malayalam": "ml",
"Kannada": "kn",
"Urdu": "ur"
}
# --- Hugging Face Token ---
try:
hf_token = st.secrets["unicorn"]
except:
hf_token = os.getenv("unicorn")
client = InferenceClient(
provider="together",
api_key=hf_token,
)
# --- Crop Images ---
crop_images = {
"FAB Cabbage": "https://via.placeholder.com/300?text=Cabbage",
"FAB Mint": "https://via.placeholder.com/300?text=Mint",
"FAB Spinach": "https://via.placeholder.com/300?text=Spinach",
"FAB Mustard": "https://via.placeholder.com/300?text=Mustard",
"FAB Coriander leaves": "https://via.placeholder.com/300?text=Coriander",
"FAB Spring onion": "https://via.placeholder.com/300?text=Spring+Onion",
"FAB Lettuce": "https://via.placeholder.com/300?text=Lettuce",
"FAB Celery": "https://via.placeholder.com/300?text=Celery",
"FAB Mushroom": "https://via.placeholder.com/300?text=Mushroom"
}
# --- Translator ---
def translate(text, lang):
try:
return GoogleTranslator(source='auto', target=lang).translate(text)
except:
return text
# --- Load Dataset ---
@st.cache_data(show_spinner="πŸ“… Loading crop dataset...")
def load_csv(crop):
folder = os.path.join(os.path.dirname(__file__), "datasets")
for filename in os.listdir(folder):
if crop.replace(" ", "").lower() in filename.replace(" ", "").lower():
return pd.read_csv(os.path.join(folder, filename))
return None
# --- Ontology Reasoning ---
def apply_ontology(question, crop):
if "insect" in question or "pest" in question:
return f"{crop} is often affected by pests like aphids."
return ""
# --- Knowledge Graph Retrieval ---
def from_knowledge_graph(question, crop):
if "aphids" in question:
return "Neem oil is effective against aphids."
if "fungus" in question:
return "Try a mix of baking soda and water."
return ""
# --- FAISS Store ---
@st.cache_resource(show_spinner="πŸ”Ž Building vector store...")
def build_store(df):
docs = [Document(page_content=f"Q: {row['Question']}\nA: {row['Answer']}") for _, row in df.iterrows()]
device = "cuda" if torch.cuda.is_available() else "cpu"
emb = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2", model_kwargs={"device": device})
return FAISS.from_documents(docs, embedding=emb)
# --- LLM Answer with Step-by-Step Instructions ---
def get_llm_answer(context, question, crop):
user_background = "I am building a crop question-answering chatbot."
response_style = "Respond in a clear, step-by-step bullet point format. Only answer about the selected crop. Be concise and skip unrelated questions."
messages = [
{"role": "system", "content": f"You are a helpful, honest, and intelligent assistant.\n\nThe user has provided the following instructions:\n1. What the assistant should know about the user:\n{user_background}\n2. How the assistant should respond:\n{response_style}\n\nAlways follow these instructions.\n\nCrop: {crop}\n\nContext:\n{context}"},
{"role": "user", "content": f"Question: {question}\nAnswer:"}
]
try:
completion = client.chat.completions.create(
model=MODEL_NAME,
messages=messages,
)
return f"[{crop}] {completion.choices[0].message.content.strip()}"
except Exception as e:
return f"LLM Error: {e}"
# --- Question Handler ---
def handle_question(df, vectorstore, crop, question):
question_lower = question.lower()
selected_crop_clean = crop.lower().replace("fab", "").strip()
for other_crop in crop_images:
other_clean = other_crop.lower().replace("fab", "").strip()
if other_clean in question_lower and other_clean != selected_crop_clean:
return f"This question is unrelated to {crop} and will not be addressed.\nPlease ask specifically about {crop} for tailored guidance.", "🚫 Unrelated"
logic_reason = apply_ontology(question_lower, crop)
kg_reason = from_knowledge_graph(question_lower, crop)
retriever = vectorstore.as_retriever(search_type="similarity", k=1)
doc = retriever.get_relevant_documents(question)[0]
context = doc.page_content
if logic_reason or kg_reason:
context += f"\n\n{logic_reason}\n{kg_reason}"
return get_llm_answer(context, question, crop), "βœ… Combined (Hybrid + Ontology + KG)"
# --- Streamlit App ---
def main():
st.set_page_config("Crop QA Chatbot", layout="wide")
st.title("🌾 Crop QA with Hybrid Search + Ontology + Knowledge Graph")
lang = st.selectbox("🌐 Language", list(language_map.keys()))
lang_code = language_map[lang]
translated_crop_names = {translate(c, lang_code): c for c in crop_images}
cols = st.columns(3)
for i, (label, orig) in enumerate(translated_crop_names.items()):
with cols[i % 3]:
st.image(crop_images[orig], caption=label, use_container_width=True)
if st.button(label):
st.session_state["selected_crop"] = orig
st.session_state["lang_code"] = lang_code
if "selected_crop" in st.session_state:
crop = st.session_state["selected_crop"]
lang_code = st.session_state["lang_code"]
st.subheader(f"πŸ“ Ask about: {translate(crop, lang_code)}")
df = load_csv(crop)
if df is None:
st.error("❌ Dataset not found.")
return
vectorstore = build_store(df)
user_q = st.text_input(translate("❓ Ask your question", lang_code))
if user_q:
with st.spinner("🧐 Thinking..."):
translated_q = translate(user_q, "en")
answer, source = handle_question(df, vectorstore, crop, translated_q)
st.markdown(f"{translate(source, lang_code)}")
st.write(translate(answer, lang_code))
if __name__ == "__main__":
main()