|
import gradio as gr |
|
from typing import List, Optional |
|
from services.llm_factory import get_default_model |
|
|
|
|
|
def create_provider_dropdown(providers: List[str], default_value: str = "mistral") -> gr.Dropdown: |
|
"""Creates a standardized LLM provider dropdown.""" |
|
return gr.Dropdown(providers, value=default_value, label="AI Provider") |
|
|
|
|
|
def create_llm_config_inputs(providers: List[str], default_provider: str = "mistral", initial_api_key: str = "") -> dict: |
|
"""Creates a 3-column AI provider configuration with Provider, Model Name, and API Key.""" |
|
with gr.Row(): |
|
provider_dropdown = gr.Dropdown( |
|
choices=providers, |
|
value=default_provider, |
|
label="AI Provider", |
|
interactive=True |
|
) |
|
|
|
model_textbox = gr.Textbox( |
|
label="Model Name", |
|
placeholder=f"Default: {get_default_model(default_provider)}", |
|
value="", |
|
interactive=True, |
|
) |
|
|
|
api_key_textbox = gr.Textbox( |
|
label="API Key", |
|
placeholder="Default: from .env file (if ran locally)", |
|
value=initial_api_key, |
|
type="password", |
|
interactive=True, |
|
) |
|
|
|
|
|
def update_model_placeholder(provider): |
|
default_model = get_default_model(provider) |
|
return gr.update(placeholder=f"Default: {default_model}") |
|
|
|
provider_dropdown.change( |
|
fn=update_model_placeholder, |
|
inputs=[provider_dropdown], |
|
outputs=[model_textbox] |
|
) |
|
|
|
return { |
|
"provider": provider_dropdown, |
|
"model": model_textbox, |
|
"api_key": api_key_textbox, |
|
"provider_dropdown_component": provider_dropdown, |
|
"api_key_textbox_component": api_key_textbox |
|
} |
|
|
|
|
|
def create_unit_dropdown(default_label: str = "Select Generated Unit") -> gr.Dropdown: |
|
"""Creates a standardized unit selection dropdown.""" |
|
return gr.Dropdown( |
|
choices=["Select Generated Unit"], |
|
value="Select Generated Unit", |
|
label=default_label, |
|
interactive=True |
|
) |
|
|
|
|
|
def create_file_upload() -> gr.File: |
|
"""Creates a standardized file upload component.""" |
|
return gr.File( |
|
label="", |
|
file_types=[".pdf", ".doc", ".txt", ".pptx", ".md"], |
|
height=200 |
|
) |
|
|
|
|
|
def create_text_input(label: str = "Text Input", lines: int = 4) -> gr.Textbox: |
|
"""Creates a standardized text input component.""" |
|
return gr.Textbox( |
|
placeholder="Paste your learning content here...", |
|
lines=lines, |
|
label="" |
|
) |
|
|
|
|
|
def create_status_markdown(initial_text: str = "Ready") -> gr.Markdown: |
|
"""Creates a standardized status display.""" |
|
return gr.Markdown(initial_text) |
|
|
|
|
|
def create_primary_button(text: str, size: str = "lg") -> gr.Button: |
|
"""Creates a standardized primary button.""" |
|
return gr.Button(text, variant="primary", size=size, elem_classes="learnflow-button-large learnflow-button-rounded") |
|
|
|
|
|
def create_secondary_button(text: str, size: str = "lg", elem_classes: Optional[str] = None) -> gr.Button: |
|
"""Creates a standardized secondary button.""" |
|
classes = "learnflow-button-large learnflow-button-rounded" |
|
if elem_classes: |
|
classes += f" {elem_classes}" |
|
return gr.Button(text, variant="secondary", size=size, elem_classes=classes) |
|
|
|
|
|
def create_quiz_components(): |
|
"""Creates standardized quiz UI components.""" |
|
mcq_section = gr.Column(visible=False, elem_classes="quiz-section") |
|
with mcq_section: |
|
mcq_question = gr.Markdown("### Multiple Choice Questions") |
|
mcq_choices = gr.Radio(choices=[], label="Select your answer") |
|
mcq_submit = gr.Button("Submit MCQ Answer", elem_classes="learnflow-button-large learnflow-button-rounded") |
|
mcq_feedback = gr.Markdown("", elem_classes="correct-feedback") |
|
mcq_next = gr.Button("Next Question", visible=False, elem_classes="learnflow-button-large learnflow-button-rounded") |
|
|
|
open_ended_section = gr.Column(visible=False, elem_classes="quiz-section") |
|
with open_ended_section: |
|
open_question = gr.Markdown("### Open-Ended Questions") |
|
open_answer = gr.Textbox(label="Your answer", lines=4, placeholder="Type your answer here...") |
|
open_submit = gr.Button("Submit Open Answer", elem_classes="learnflow-button-large learnflow-button-rounded") |
|
open_feedback = gr.Markdown("", elem_classes="correct-feedback") |
|
open_next = gr.Button("Next Open-Ended Question", visible=False, elem_classes="learnflow-button-large learnflow-button-rounded") |
|
|
|
tf_section = gr.Column(visible=False, elem_classes="quiz-section") |
|
with tf_section: |
|
tf_question = gr.Markdown("### True/False Questions") |
|
tf_choices = gr.Radio(choices=["True", "False"], label="Your Answer") |
|
tf_submit = gr.Button("Submit True/False Answer", elem_classes="learnflow-button-large learnflow-button-rounded") |
|
tf_feedback = gr.Markdown("", elem_classes="correct-feedback") |
|
tf_next = gr.Button("Next True/False Question", visible=False, elem_classes="learnflow-button-large learnflow-button-rounded") |
|
|
|
fitb_section = gr.Column(visible=False, elem_classes="quiz-section") |
|
with fitb_section: |
|
fitb_question = gr.Markdown("### Fill in the Blank Questions") |
|
fitb_answer = gr.Textbox(label="Your Answer", placeholder="Type your answer here...") |
|
fitb_submit = gr.Button("Submit Fill in the Blank Answer", elem_classes="learnflow-button-large learnflow-button-rounded") |
|
fitb_feedback = gr.Markdown("", elem_classes="correct-feedback") |
|
fitb_next = gr.Button("Next Fill in the Blank Question", visible=False, elem_classes="learnflow-button-large learnflow-button-rounded") |
|
|
|
return { |
|
"mcq_section": mcq_section, |
|
"mcq_question": mcq_question, |
|
"mcq_choices": mcq_choices, |
|
"mcq_submit": mcq_submit, |
|
"mcq_feedback": mcq_feedback, |
|
"mcq_next": mcq_next, |
|
"open_ended_section": open_ended_section, |
|
"open_question": open_question, |
|
"open_answer": open_answer, |
|
"open_submit": open_submit, |
|
"open_feedback": open_feedback, |
|
"open_next": open_next, |
|
"tf_section": tf_section, |
|
"tf_question": tf_question, |
|
"tf_choices": tf_choices, |
|
"tf_submit": tf_submit, |
|
"tf_feedback": tf_feedback, |
|
"tf_next": tf_next, |
|
"fitb_section": fitb_section, |
|
"fitb_question": fitb_question, |
|
"fitb_answer": fitb_answer, |
|
"fitb_submit": fitb_submit, |
|
"fitb_feedback": fitb_feedback, |
|
"fitb_next": fitb_next |
|
} |
|
|
|
|
|
def create_progress_components(): |
|
"""Creates standardized progress display components.""" |
|
return { |
|
"overall_stats": gr.Markdown("No session data available."), |
|
"progress_bar": gr.HTML(""), |
|
"unit_details": gr.Dataframe( |
|
headers=["Unit", "Status", "Quiz Score", "Completion"], |
|
datatype=["str", "str", "str", "str"], |
|
interactive=False |
|
) |
|
} |
|
|
|
|
|
def create_session_management_components(): |
|
"""Creates standardized session management components.""" |
|
return { |
|
"session_name_input": gr.Textbox(placeholder="Enter session name to save or load...", label="Session Name"), |
|
"save_session_btn": gr.Button("πΎ Save Current Session", elem_classes="learnflow-button-large learnflow-button-rounded"), |
|
"load_session_btn": gr.Button("π Load Session", elem_classes="learnflow-button-large learnflow-button-rounded"), |
|
"saved_sessions_dropdown": gr.Dropdown(choices=["Choose from saved sessions..."], value="Choose from saved sessions...", label="Previous Sessions", interactive=True), |
|
"session_status": gr.Markdown("") |
|
} |
|
|
|
|
|
def create_export_components(): |
|
"""Creates standardized export components.""" |
|
return { |
|
"export_markdown_btn": gr.Button("π Export Markdown", elem_classes="learnflow-button-large learnflow-button-rounded"), |
|
"export_html_btn": gr.Button("π Export HTML", elem_classes="learnflow-button-large learnflow-button-rounded"), |
|
"export_pdf_btn": gr.Button("π Export PDF", elem_classes="learnflow-button-large learnflow-button-rounded"), |
|
"export_file": gr.File(label="Download Exported File", visible=False), |
|
"export_status": gr.Markdown("") |
|
} |
|
|
|
def create_difficulty_radio() -> gr.Radio: |
|
"""Creates a radio group for difficulty level.""" |
|
return gr.Radio( |
|
choices=["Easy", "Medium", "Hard"], |
|
value="Medium", |
|
label="Difficulty Level", |
|
interactive=True, |
|
container=False, |
|
elem_classes="difficulty-radio-group" |
|
) |
|
|
|
def create_question_number_slider(min_val: int = 3, max_val: int = 30, default_val: int = 8) -> gr.Slider: |
|
"""Creates a slider for number of questions.""" |
|
return gr.Slider( |
|
minimum=min_val, |
|
maximum=max_val, |
|
value=default_val, |
|
step=1, |
|
label="Questions Count", |
|
interactive=True |
|
) |
|
|
|
def create_question_types_checkboxgroup() -> gr.CheckboxGroup: |
|
"""Creates a checkbox group for question types.""" |
|
return gr.CheckboxGroup( |
|
choices=["Multiple Choice", "Open-Ended", "True/False", "Fill in the Blank"], |
|
value=["Multiple Choice", "Open-Ended", "True/False"], |
|
label="Question Types", |
|
interactive=True, |
|
elem_classes="question-types-checkbox-group" |
|
) |
|
|
|
def create_ai_provider_dropdown(providers: List[str], default_value: str = "mistral") -> gr.Dropdown: |
|
"""Creates a dropdown for AI provider.""" |
|
return gr.Dropdown( |
|
choices=providers, |
|
value=default_value, |
|
label="AI Provider", |
|
interactive=True |
|
) |
|
|
|
def create_stats_card(title: str, value: str, description: str, icon: str, color: str) -> gr.Markdown: |
|
"""Creates a standardized statistics card.""" |
|
return gr.Markdown(f""" |
|
<div style="background: rgba(51, 65, 85, 0.6); padding: 20px; border-radius: 12px; text-align: center;"> |
|
<h3 style="color: {color}; margin-top: 0; font-size: 1.5em;">{icon} {title}</h3> |
|
<p style="color: white; font-size: 2.5em; font-weight: 700; margin: 5px 0;">{value}</p> |
|
<p style="color: #94a3b8; margin-bottom: 0;">{description}</p> |
|
</div> |
|
""") |
|
|
|
def create_overall_progress_html(progress_percentage: int = 53) -> gr.HTML: |
|
"""Creates the HTML for the overall learning progress bar.""" |
|
return gr.HTML(f""" |
|
<div style="background: rgba(51, 65, 85, 0.6); padding: 20px; border-radius: 12px; margin: 10px 0;"> |
|
<h3 style="color: #10b981; margin-top: 0;">Total Course Progress: {progress_percentage}%</h3> |
|
<div style="background: rgba(30, 41, 59, 0.8); border-radius: 8px; height: 20px; overflow: hidden;"> |
|
<div style="background: linear-gradient(135deg, #10b981, #059669); height: 100%; width: {progress_percentage}%; transition: width 0.5s ease;"></div> |
|
</div> |
|
<p style="color: #94a3b8; margin-bottom: 0;">Keep going! You're making great progress.</p> |
|
</div> |
|
""") |
|
|