InfoJury / app.py
Abrar-Ahmad's picture
Update app.py
27baac5 verified
Raw
History Blame Contribute Delete
6.17 kB
# app.py
import os
import uuid
import gradio as gr
from PIL import Image
from datetime import datetime
from supabase import create_client
from sentence_transformers import SentenceTransformer
# =======================
# SUPABASE CONFIG
# =======================
SUPABASE_URL = os.environ["https://pjrzisurkyeunhgbmvco.supabase.co"] # suprabase url
SUPABASE_KEY = os.environ["sb_publishable_mYlT4zRks_3BF-Lqqw35og_wzvLnMg2"] # suprabase service key
supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
# Table names
CONTEXT_TABLE = "context_memory"
CHAT_TABLE = "conversation_history"
# =======================
# USER SESSION MANAGEMENT
# =======================
def get_or_create_user_id(user_id_state):
if user_id_state is None:
return str(uuid.uuid4())
return user_id_state
# =======================
# EMBEDDINGS SETUP
# =======================
embedding_model = SentenceTransformer(
"jinaai/jina-embeddings-v3",
trust_remote_code=True
)
TRUNCATE_DIM = 256 # matches your Supabase vector column
def embed_query(text: str):
return embedding_model.encode([text], task="retrieval.query", truncate_dim=TRUNCATE_DIM)[0]
# =======================
# RAG RETRIEVAL
# =======================
TOP_K = 3
def get_top_k_chunks(user_id: str, query: str, k: int = TOP_K):
q_emb = embed_query(query)
# call Supabase RPC or SQL for vector similarity search
# assuming you have a match_context_memory RPC defined in Supabase
result = supabase.rpc(
"match_context_memory",
{
"query_embedding": q_emb,
"match_count": k,
"user_id": user_id
}
).execute()
if result.data:
return [row["semantic_chunk"] for row in result.data]
return []
# =======================
# LOAD RECENT CHAT
# =======================
MAX_HISTORY = 10
def get_recent_history(user_id: str, limit: int = MAX_HISTORY):
res = supabase.table(CHAT_TABLE) \
.select("query_input,llm_output") \
.eq("unique_user_id", user_id) \
.order("convo_num", desc=True) \
.limit(limit) \
.execute()
history = []
for row in reversed(res.data):
history.append(f"User: {row['query_input']}")
if row["llm_output"]:
history.append(f"Assistant: {row['llm_output']}")
return "\n".join(history)
# =======================
# SAVE / UPDATE CHAT
# =======================
def insert_user_query(user_id, user_name, region, query):
supabase.table(CHAT_TABLE).insert({
"unique_user_id": user_id,
"user_name": user_name,
"region": region,
"query_input": query
}).execute()
def update_llm_output(user_id, llm_output):
supabase.table(CHAT_TABLE) \
.update({"llm_output": llm_output}) \
.eq("unique_user_id", user_id) \
.is_("llm_output", None) \
.order("convo_num", desc=True) \
.limit(1) \
.execute()
# =======================
# VISION + LLM HANDLER (Bangla LLaMA 3.2)
# =======================
import requests
HF_LLM_KEY = os.environ.get("HF_API_KEY")
MODEL_ID = "hishab/titulm-llama-3.2-3b-v2.0"
HEADERS = {"Authorization": f"Bearer {HF_LLM_KEY}"}
def vision_llm(image: Image.Image | None, text: str, top_chunks: list, chat_history: str):
"""
Calls Bangla LLaMA 3.2 via Hugging Face API with:
- top-k RAG chunks
- recent chat history
- user input
- optional image info
"""
prompt_parts = [
"You are a helpful assistant that can analyze images and text.",
"Follow these rules: answer concisely, prefer facts from context.",
"\n--- Context chunks ---\n" + "\n".join(top_chunks) if top_chunks else "",
"\n--- Chat History ---\n" + chat_history if chat_history else "",
"\n--- User Input ---\n" + text
]
if image:
prompt_parts.append(f"\nUser uploaded an image of size {image.width}x{image.height}.")
prompt = "\n".join(prompt_parts)
# Call Hugging Face Inference API
payload = {"inputs": prompt, "parameters": {"max_new_tokens": 512}}
try:
response = requests.post(
f"https://api-inference.huggingface.co/models/{MODEL_ID}",
headers=HEADERS,
json=payload,
timeout=60
)
response.raise_for_status()
data = response.json()
# HF API returns a list of dicts with "generated_text"
if isinstance(data, list) and "generated_text" in data[0]:
return data[0]["generated_text"]
elif isinstance(data, dict) and "generated_text" in data:
return data["generated_text"]
else:
return str(data)
except Exception as e:
return f"Error calling Bangla LLaMA 3.2: {e}"
# =======================
# GRADIO HANDLER
# =======================
def analyze_input(message, history, user_id_state):
user_id = get_or_create_user_id(user_id_state)
text = (message.get("text") or "").strip()
files = message.get("files") or []
image = None
if files:
image_path = files[0]["path"]
image = Image.open(image_path)
else:
image_path = None
# Save user query in Supabase
insert_user_query(user_id, "Anonymous", "Unknown", text)
# Retrieve top-k chunks for RAG
top_chunks = get_top_k_chunks(user_id, text, k=TOP_K)
# Load recent chat
recent_history = get_recent_history(user_id, limit=MAX_HISTORY)
# Call LLM
llm_reply = vision_llm(image, text, top_chunks, recent_history)
# Update chat with LLM reply
update_llm_output(user_id, llm_reply)
return llm_reply, user_id
# =======================
# GRADIO UI
# =======================
with gr.Blocks() as demo:
user_id_state = gr.State(None)
chatbot = gr.ChatInterface(
fn=analyze_input,
multimodal=True,
additional_inputs=[user_id_state],
additional_outputs=[user_id_state],
title="InfoJury – Vision + RAG + Chat",
description="Upload an image, ask a question, and the system will reason using your personal knowledge base plus vision."
)
if __name__ == "__main__":
demo.launch()