LearnFlow-AI / components /ui_components.py
Kyo-Kai's picture
Public Release
7bd8010
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,
)
# Update model placeholder when provider changes
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>
""")