Spaces:
Sleeping
Sleeping
| 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) | |