Piyushdash94's picture
Update app.py
3c66e74 verified
raw
history blame
6.91 kB
import os
import gradio as gr
from controller import generate_questions # returns question_list (or a dict containing it)
from controller import generate_answer # returns a dict with question_content, answer_content, reasoning_content
from db import save_in_db # saves parsed dict into mongo
MAX_QUESTIONS = 20
# ---------------- Helpers ---------------- #
def _extract_question_list(result):
"""Safely extract question list from a controller response"""
if not result:
return []
if isinstance(result, dict):
if "success" in result and isinstance(result.get("data"), dict):
return result["data"].get("question_list", [])
if "question_list" in result:
return result["question_list"] or []
if "data" in result and isinstance(result["data"], list):
return result["data"]
if isinstance(result, list):
return result
return []
def _extract_qa(result, original_q):
"""Return a dict with question_content, answer_content, reasoning_content"""
default = {
"question_content": original_q,
"answer_content": "No answer returned",
"reasoning_content": ""
}
if not result:
return default
if isinstance(result, dict):
d = result.get("data") if result.get("success") and isinstance(result.get("data"), dict) else result
return {
"question_content": d.get("question_content", original_q),
"answer_content": d.get("answer_content", d.get("answer", "")) or "",
"reasoning_content": d.get("reasoning_content", d.get("reasoning", "")) or ""
}
return default
# ---------------- Handlers ---------------- #
def generate_questions_ui(topic: str, num_questions: int):
"""Stream Q β†’ A β†’ R one by one"""
result_values = []
for _ in range(MAX_QUESTIONS):
result_values.extend([
"", "", "", # Q, A, R
gr.update(visible=False, interactive=False), # accept
gr.update(visible=False, interactive=False), # reject
gr.update(visible=False) # group hidden
])
yield result_values
try:
qres = generate_questions(topic.strip(), int(num_questions))
except Exception as e:
result_values[0] = f"Error generating questions: {e}"
yield result_values
return
question_list = _extract_question_list(qres)
if not question_list:
result_values[0] = "No questions returned."
yield result_values
return
for i, q in enumerate(question_list[:MAX_QUESTIONS]):
base = i * 6
result_values[base + 0] = q
result_values[base + 1] = "Generating answer..."
result_values[base + 2] = "Generating reasoning..."
result_values[base + 5] = gr.update(visible=True)
yield result_values
try:
ans_res = generate_answer(q)
qa = _extract_qa(ans_res, q)
result_values[base + 1] = qa["answer_content"]
result_values[base + 2] = qa["reasoning_content"]
result_values[base + 3] = gr.update(visible=True, interactive=True)
result_values[base + 4] = gr.update(visible=True, interactive=True)
except Exception as e:
result_values[base + 1] = f"Error: {e}"
result_values[base + 2] = ""
result_values[base + 4] = gr.update(visible=True, interactive=True)
yield result_values
yield result_values
def accept_question(question, answer, reasoning):
"""Save in DB and hide card"""
parsed = {
"question_content": question,
"answer_language": "Odia",
"reasoning_content": reasoning,
"answer_content": answer,
}
try:
save_in_db(parsed)
return (
gr.update(visible=False), # accept_btn
gr.update(visible=False), # reject_btn
gr.update(visible=False) # group hidden
)
except Exception as e:
return (
gr.update(interactive=False, value=f"Error: {e}"),
gr.update(visible=True),
gr.update(visible=True)
)
def reject_card():
"""Hide rejected card"""
return gr.update(visible=False)
# ---------------- UI Layout ---------------- #
custom_css = """
.gradio-container { background-color: #121212 !important; color: #E0E0E0 !important; }
.question-card {
border: 1px solid #333;
box-shadow: 0 4px 12px rgba(0,0,0,0.4);
border-radius: 12px;
padding: 20px !important;
margin-bottom: 20px !important;
background-color: #1E1E1E;
transition: 0.3s ease-in-out;
}
.question-card:hover {
transform: translateY(-3px);
box-shadow: 0 6px 16px rgba(0,0,0,0.6);
}
textarea { background-color: #2A2A2A !important; color: #E0E0E0 !important; border: 1px solid #444 !important; border-radius: 8px !important; }
button { border-radius: 8px !important; padding: 8px 12px !important; }
"""
with gr.Blocks(theme=gr.themes.Base(), css=custom_css) as demo:
gr.Markdown("<h2 style='color:#90CAF9;'>πŸŒ™ Odia Q&A β€” Generate β†’ Answer (streaming)</h2>")
with gr.Row():
topic_input = gr.Textbox(label="πŸ“ Topic", placeholder="Enter a topic, e.g., 'Photosynthesis'")
num_questions_input = gr.Dropdown(label="πŸ”’ Number of Questions", choices=[5, 10, 15, 20], value=5)
generate_btn = gr.Button("⚑ Generate", variant="primary")
output_components = []
for i in range(MAX_QUESTIONS):
with gr.Group(visible=False, elem_classes=["question-card"]) as output_group:
with gr.Row():
with gr.Column(scale=4):
q_text = gr.Textbox(label="❓ Question", interactive=False)
a_text = gr.Textbox(label="βœ… Answer", interactive=False)
r_text = gr.Textbox(label="🧠 Reasoning", interactive=False)
with gr.Column(scale=1, min_width=150):
accept_btn = gr.Button("Accept", variant="primary")
reject_btn = gr.Button("Reject", variant="stop")
# Bind buttons
accept_btn.click(
fn=accept_question,
inputs=[q_text, a_text, r_text], # βœ… only inputs
outputs=[accept_btn, reject_btn, output_group] # βœ… update group visibility
)
reject_btn.click(fn=reject_card, outputs=[output_group])
output_components.extend([q_text, a_text, r_text, accept_btn, reject_btn, output_group])
generate_btn.click(
fn=generate_questions_ui,
inputs=[topic_input, num_questions_input],
outputs=output_components
)
demo.queue()
if __name__ == "__main__":
port = int(os.getenv("UI_PORT", "7860"))
demo.launch(server_name="0.0.0.0", server_port=int(os.getenv("PORT", "7860")), share=False)