import gradio as gr import utils from app import question_graph, MemorySaver from translation import LANGUAGES import uuid import os from dotenv import load_dotenv import tempfile load_dotenv() service_account_json = os.environ.get("GOOGLE_SERVICE_ACCOUNT_JSON") PROJECT_ID = os.environ.get("GOOGLE_CLOUD_PROJECT") if service_account_json: # Write the JSON content to a temporary file temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".json") temp_file.write(service_account_json.encode("utf-8")) temp_file.close() # Set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the temp file path os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = temp_file.name # ----------------------------- # In-Memory Storage for Feedback Flow # ----------------------------- session_data = {} session_data["en_topics"] = utils.get_topic_names("en") session_data["az_topics"] = utils.get_topic_names("az") session_data["ru_topics"] = utils.get_topic_names("ru") # ----------------------------- # Graph Invocation Function # ----------------------------- def run_graph(topic, subtopic, difficulty, lang): session_id = str(uuid.uuid4()) # Unique session per question memory = MemorySaver() if lang == "az" or lang == "ru": topic, subtopic, difficulty = utils.get_eng_names( topic, subtopic, difficulty, lang ) print("Topic:", topic, "Subtopic:", subtopic, "Difficulty:", difficulty) inputs = { "topic": topic, "subtopic": subtopic, "difficulty": difficulty, "description": "", "num_questions": 3, "messages": [], "context": [], "relevant_questions": [], "question": "", "steps": [], "tool_requests": [], "tool_results": [], "verified": False, "solution": "", "answer": "", "error": "", "human_feedback": "", } # Run up to feedback node (interrupt point) partial_result = question_graph.invoke( inputs, config={"configurable": {"thread_id": session_id}} ) session_data[session_id] = { "memory": memory, "inputs": partial_result, # Store intermediate state } generated_question = partial_result.get("question", "No question generated.") # Translate Question if English is not selected if lang != "en": generated_question = utils.translate_text( generated_question, PROJECT_ID, target_lang=lang, source_lang="en" ) return session_id, generated_question, LANGUAGES[lang]["feedback_placeholder"] # ----------------------------- # Handle Feedback and Rerun Graph # ----------------------------- def handle_feedback(session_id, feedback_text, lang): data = session_data.get(session_id) if not data: return session_id, "Session expired or invalid.", "" memory = data["memory"] feedback_text = feedback_text.strip() thread = {"configurable": {"thread_id": session_id}} if feedback_text: # Update state with feedback at node 'feedback' feedback_text = utils.translate_text( feedback_text, PROJECT_ID, target_lang="en" ) question_graph.update_state( thread, {"human_feedback": feedback_text}, as_node="feedback" ) # Continue from feedback final_result = question_graph.invoke( None, config={"configurable": {"thread_id": session_id}} ) new_question = final_result.get("question", "No question generated.") session_data[session_id]["inputs"] = final_result if final_result.get("steps"): return session_id, new_question, "Proceeding to solve question..." else: return ( session_id, new_question, "Feedback applied. Refine again or click 'Solve Question'.", ) else: # No feedback provided, proceed immediately question_graph.update_state( thread, {"human_feedback": None}, as_node="feedback", ) final_result = question_graph.invoke( None, config={"configurable": {"thread_id": session_id}} ) solution_md = final_result.get("solution", "No solution generated.") answer = final_result.get("answer", "No answer.") # Translate solution and answer if lang is not English if lang != "en": solution_md = utils.translate_text( solution_md, PROJECT_ID, target_lang=lang, source_lang="en" ) answer = utils.translate_text( answer, PROJECT_ID, target_lang=lang, source_lang="en" ) return session_id, solution_md, answer # ----------------------------- # Solve Question – Full Graph Run # ----------------------------- def solve_question(session_id, lang): data = session_data.get(session_id) thread = {"configurable": {"thread_id": session_id}} if not data: return "Session expired or invalid.", "", "" state = data["inputs"] memory = data["memory"] question_graph.update_state( thread, {"human_feedback": None}, as_node="feedback", ) final_result = question_graph.invoke( None, config={"configurable": {"thread_id": session_id}} ) print("Final Result", final_result) solution_md = final_result.get("solution", "No solution generated.") answer = final_result.get("answer", "No answer.") # Translate solution and answer if lang is not English if lang != "en": solution_md = utils.translate_text( solution_md, PROJECT_ID, target_lang=lang, source_lang="en" ) answer = utils.translate_text( answer, PROJECT_ID, target_lang=lang, source_lang="en" ) return solution_md # Language toggle updates UI def update_ui(lang): return ( LANGUAGES[lang]["title"], # Markdown title gr.update(visible=(lang == "az")), # Show Azerbaijani UI gr.update(visible=(lang == "en")), # Show English UI gr.update(visible=(lang == "ru")), # Show Russian UI ) def update_subtopics(selected_topic, lang): subtopics_list = utils.get_subtopics(selected_topic, lang) return gr.update( choices=subtopics_list, value=subtopics_list[0] if subtopics_list else "" ) # ----------------------------- # Gradio UI Layout # ----------------------------- with gr.Blocks(title="LangGraph Math Solver") as demo: lang_toggle = gr.Dropdown( label="🌍 Select Language", choices=["en", "az", "ru"], value="en" ) title = gr.Markdown(LANGUAGES["en"]["title"]) # English UI Components with gr.Column(visible=True) as english_ui: with gr.Row(): topic_input_en = gr.Dropdown( label=LANGUAGES["en"]["topic_label"], choices=session_data["en_topics"], value=None, ) subtopic_input_en = gr.Dropdown( label=LANGUAGES["en"]["subtopic_label"], choices=[], value=None ) difficulty_input_en = gr.Dropdown( label=LANGUAGES["en"]["difficulty_label"], choices=["easy", "medium", "hard"], value="medium", ) generate_btn_en = gr.Button(LANGUAGES["en"]["generate_btn"]) question_output_en = gr.Markdown( label=LANGUAGES["en"]["question_output"], render=True, latex_delimiters=[ {"left": "$$", "right": "$$", "display": True}, {"left": "$", "right": "$", "display": False}, ], ) feedback_note_en = gr.Textbox( label=LANGUAGES["en"]["feedback_label"], placeholder=LANGUAGES["en"]["feedback_placeholder"], ) with gr.Row(): feedback_btn_en = gr.Button(LANGUAGES["en"]["feedback_btn"]) solve_btn_en = gr.Button(LANGUAGES["en"]["solve_btn"]) solution_output_en = gr.Markdown( label=LANGUAGES["en"]["solution_output"], render=True, latex_delimiters=[ {"left": "$$", "right": "$$", "display": True}, {"left": "$", "right": "$", "display": False}, {"left": "[", "right": "]", "display": False}, ], ) # final_answer_en = gr.Markdown( # label=LANGUAGES["en"]["final_answer"], render=True # ) # Azerbaijani UI Components (Initially Hidden) with gr.Column(visible=False) as azeri_ui: with gr.Row(): topic_input_az = gr.Dropdown( label=LANGUAGES["az"]["topic_label"], choices=session_data["az_topics"], value=None, ) subtopic_input_az = gr.Dropdown( label=LANGUAGES["az"]["subtopic_label"], choices=[], value=None ) difficulty_input_az = gr.Dropdown( label=LANGUAGES["az"]["difficulty_label"], choices=["asan", "orta", "çətin"], value="orta", ) generate_btn_az = gr.Button(LANGUAGES["az"]["generate_btn"]) question_output_az = gr.Markdown( label=LANGUAGES["az"]["question_output"], render=True, latex_delimiters=[ {"left": "$$", "right": "$$", "display": True}, {"left": "$", "right": "$", "display": False}, ], ) feedback_note_az = gr.Textbox( label=LANGUAGES["az"]["feedback_label"], placeholder=LANGUAGES["az"]["feedback_placeholder"], ) with gr.Row(): feedback_btn_az = gr.Button(LANGUAGES["az"]["feedback_btn"]) solve_btn_az = gr.Button(LANGUAGES["az"]["solve_btn"]) solution_output_az = gr.Markdown( label=LANGUAGES["az"]["solution_output"], render=True, latex_delimiters=[ {"left": "$$", "right": "$$", "display": True}, {"left": "$", "right": "$", "display": False}, {"left": "[", "right": "]", "display": False}, ], ) # final_answer_az = gr.Markdown( # label=LANGUAGES["az"]["final_answer"], render=True # ) # Russian UI Components (Initially Hidden) with gr.Column(visible=False) as russian_ui: with gr.Row(): topic_input_ru = gr.Dropdown( label=LANGUAGES["ru"]["topic_label"], choices=session_data["ru_topics"], value=None, ) subtopic_input_ru = gr.Dropdown( label=LANGUAGES["ru"]["subtopic_label"], choices=[], value=None ) difficulty_input_ru = gr.Dropdown( label=LANGUAGES["ru"]["difficulty_label"], choices=["легкий", "средний", "сложный"], value="средний", ) generate_btn_ru = gr.Button(LANGUAGES["ru"]["generate_btn"]) question_output_ru = gr.Markdown( label=LANGUAGES["ru"]["question_output"], render=True, latex_delimiters=[ {"left": "$$", "right": "$$", "display": True}, {"left": "$", "right": "$", "display": False}, ], ) feedback_note_ru = gr.Textbox( label=LANGUAGES["ru"]["feedback_label"], placeholder=LANGUAGES["ru"]["feedback_placeholder"], ) with gr.Row(): feedback_btn_ru = gr.Button(LANGUAGES["ru"]["feedback_btn"]) solve_btn_ru = gr.Button(LANGUAGES["ru"]["solve_btn"]) solution_output_ru = gr.Markdown( label=LANGUAGES["ru"]["solution_output"], render=True, latex_delimiters=[ {"left": "$$", "right": "$$", "display": True}, {"left": "$", "right": "$", "display": False}, {"left": "[", "right": "]", "display": False}, ], ) # final_answer_ru = gr.Markdown( # label=LANGUAGES["ru"]["final_answer"], render=True # ) # Language Toggle lang_toggle.change( update_ui, inputs=[lang_toggle], outputs=[ title, azeri_ui, english_ui, russian_ui, ], # Using .update() to toggle visibility ) # Topic Selection Events topic_input_en.change( update_subtopics, inputs=[topic_input_en, lang_toggle], outputs=[subtopic_input_en], ) topic_input_az.change( update_subtopics, inputs=[topic_input_az, lang_toggle], outputs=[subtopic_input_az], ) topic_input_ru.change( update_subtopics, inputs=[topic_input_ru, lang_toggle], outputs=[subtopic_input_ru], ) # Hidden session ID session_state = gr.State() # Events for English UI generate_btn_en.click( run_graph, inputs=[topic_input_en, subtopic_input_en, difficulty_input_en, lang_toggle], outputs=[session_state, question_output_en, feedback_note_en], ) feedback_btn_en.click( handle_feedback, inputs=[session_state, feedback_note_en, lang_toggle], outputs=[session_state, question_output_en, feedback_note_en], ) solve_btn_en.click( solve_question, inputs=[session_state, lang_toggle], outputs=[solution_output_en], ) # Events for Azerbaijani UI generate_btn_az.click( run_graph, inputs=[topic_input_az, subtopic_input_az, difficulty_input_az, lang_toggle], outputs=[session_state, question_output_az, feedback_note_az], ) feedback_btn_az.click( handle_feedback, inputs=[session_state, feedback_note_az, lang_toggle], outputs=[session_state, question_output_az, feedback_note_az], ) solve_btn_az.click( solve_question, inputs=[session_state, lang_toggle], outputs=[solution_output_az], ) # Events for Russian UI generate_btn_ru.click( run_graph, inputs=[topic_input_ru, subtopic_input_ru, difficulty_input_ru, lang_toggle], outputs=[session_state, question_output_ru, feedback_note_ru], ) feedback_btn_ru.click( handle_feedback, inputs=[session_state, feedback_note_ru, lang_toggle], outputs=[session_state, question_output_ru, feedback_note_ru], ) solve_btn_ru.click( solve_question, inputs=[session_state, lang_toggle], outputs=[solution_output_ru], ) # ----------------------------- # Launch App # ----------------------------- if __name__ == "__main__": demo.launch()