Spaces:
Running on Zero
Running on Zero
| from __future__ import annotations | |
| from typing import Any | |
| import gradio as gr | |
| from gradio.themes import Soft | |
| from core.analyzer import analyze_homework_ui, reset_outputs | |
| from env.config import APP_DESCRIPTION, APP_TITLE, GITHUB_URL, SPACE_URL | |
| from ui.examples import render_examples | |
| def get_theme() -> Any: | |
| """Returns the custom soft theme configured for a blackboard tutoring palette.""" | |
| # Pair the CSS with a teal classroom palette. | |
| return Soft(primary_hue="teal", secondary_hue="amber", neutral_hue="zinc") | |
| def create_app() -> gr.Blocks: | |
| """Creates and lays out the Gradio interface for Pocket Tutor.""" | |
| with gr.Blocks(title=APP_TITLE) as demo: | |
| # Header gives the product promise without a marketing page. | |
| gr.Markdown(f"# {APP_TITLE}\n{APP_DESCRIPTION}", elem_id="pt-header") | |
| gr.Markdown( | |
| "Point at the problem. Ask naturally. Learn the next step.", | |
| elem_id="pt-kicker", | |
| ) | |
| with gr.Row(elem_classes=["pt-main-grid"]): | |
| with gr.Column(scale=1, elem_classes=["pt-input-panel"]): | |
| gr.Markdown("## Question and Inputs") | |
| question_input = gr.Textbox( | |
| label="What should we work on?", | |
| lines=8, | |
| placeholder="Type the problem, paste the confusing line, or explain what you already tried.", | |
| elem_id="pt-question-input", | |
| ) | |
| image_input = gr.Image( | |
| label="Upload or capture a worksheet/photo", | |
| type="filepath", | |
| sources=["upload", "webcam", "clipboard"], | |
| elem_classes=["pt-image-input"], | |
| ) | |
| audio_input = gr.Audio( | |
| label="Ask with your microphone", | |
| sources=["microphone", "upload"], | |
| type="filepath", | |
| elem_classes=["pt-audio-input"], | |
| ) | |
| with gr.Column(scale=1, elem_classes=["pt-capture-panel"]): | |
| gr.Markdown("## Teaching Controls") | |
| with gr.Column(elem_classes=["pt-control-stack"]): | |
| with gr.Column(elem_classes=["pt-control-card"]): | |
| gr.Markdown("### Grade band") | |
| grade_input = gr.Radio( | |
| ["Elementary", "Middle school", "High school", "College"], | |
| value="Middle school", | |
| label="Pick the learner level", | |
| elem_id="pt-grade-control", | |
| elem_classes=["pt-grade-input"], | |
| ) | |
| with gr.Column(elem_classes=["pt-control-card"]): | |
| gr.Markdown("### Help mode") | |
| mode_input = gr.Radio( | |
| ["Coach me", "Hint only", "Step-by-step"], | |
| value="Coach me", | |
| label="Choose the help style", | |
| elem_id="pt-mode-control", | |
| elem_classes=["pt-mode-input"], | |
| ) | |
| run_button = gr.Button( | |
| "Teach Me", | |
| variant="primary", | |
| min_width=0, | |
| elem_classes=["pt-run-btn", "pt-teach-btn"], | |
| ) | |
| with gr.Column(elem_classes=["pt-results-section"]): | |
| with gr.Column(elem_classes=["pt-analysis-section"]): | |
| gr.Markdown("## Tutoring Plan") | |
| with gr.Row(elem_classes=["pt-plan-grid"]): | |
| problem_output = gr.Textbox( | |
| label="Problem Read", | |
| interactive=False, | |
| elem_classes=["pt-output-card", "pt-problem-card"], | |
| ) | |
| knowns_output = gr.Textbox( | |
| label="Knowns", | |
| interactive=False, | |
| elem_classes=["pt-output-card", "pt-knowns-card"], | |
| ) | |
| strategy_output = gr.Textbox( | |
| label="Strategy", | |
| interactive=False, | |
| elem_classes=["pt-output-card", "pt-strategy-card"], | |
| ) | |
| gr.Markdown("## Workbench") | |
| with gr.Row(elem_classes=["pt-workbench-grid"]): | |
| steps_output = gr.Textbox( | |
| label="Worked Steps", | |
| interactive=False, | |
| elem_classes=["pt-output-card", "pt-steps-card"], | |
| ) | |
| check_output = gr.Textbox( | |
| label="Check", | |
| interactive=False, | |
| elem_classes=["pt-output-card", "pt-check-card"], | |
| ) | |
| with gr.Row(elem_classes=["pt-workbench-grid"]): | |
| hint_output = gr.Textbox( | |
| label="Next Hint", | |
| interactive=False, | |
| elem_classes=["pt-output-card", "pt-hint-card"], | |
| ) | |
| parent_output = gr.Textbox( | |
| label="Parent Note", | |
| interactive=False, | |
| elem_classes=["pt-output-card", "pt-parent-card"], | |
| ) | |
| render_examples( | |
| image_input, | |
| question_input, | |
| audio_input, | |
| grade_input, | |
| mode_input, | |
| ) | |
| gr.Markdown( | |
| f"[GitHub repo]({GITHUB_URL}) | [Hugging Face Space]({SPACE_URL})", | |
| elem_id="pt-links", | |
| ) | |
| with gr.Accordion( | |
| "Diagnostics & Local Execution Logs", | |
| open=False, | |
| elem_classes=["pt-diagnostics-section"], | |
| ): | |
| context_output = gr.Textbox( | |
| label="Student context", | |
| lines=4, | |
| interactive=False, | |
| elem_classes=["pt-log-box"], | |
| ) | |
| model_output = gr.Textbox( | |
| label="System execution logs", | |
| lines=5, | |
| interactive=False, | |
| elem_classes=["pt-log-box"], | |
| ) | |
| # Reset outputs immediately, then run the GPU-backed tutoring function. | |
| reset_event = run_button.click( | |
| fn=reset_outputs, | |
| inputs=[], | |
| outputs=[ | |
| context_output, | |
| model_output, | |
| problem_output, | |
| knowns_output, | |
| strategy_output, | |
| steps_output, | |
| check_output, | |
| hint_output, | |
| parent_output, | |
| ], | |
| queue=False, | |
| ) | |
| reset_event.then( | |
| fn=analyze_homework_ui, | |
| inputs=[ | |
| image_input, | |
| question_input, | |
| audio_input, | |
| grade_input, | |
| mode_input, | |
| ], | |
| outputs=[ | |
| context_output, | |
| model_output, | |
| problem_output, | |
| knowns_output, | |
| strategy_output, | |
| steps_output, | |
| check_output, | |
| hint_output, | |
| parent_output, | |
| ], | |
| api_name="analyze_homework_ui", | |
| ) | |
| return demo | |