Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import os | |
| from learning_platform import EnhancedCourseBuilder | |
| import asyncio | |
| import nest_asyncio | |
| from datetime import datetime | |
| from sqlalchemy.orm import sessionmaker | |
| from models import create_engine | |
| nest_asyncio.apply() | |
| # Database setup | |
| db_url = os.getenv('DATABASE_URL', 'sqlite:///learning_platform.db') | |
| engine = create_engine(db_url) | |
| Session = sessionmaker(bind=engine) | |
| db_session = Session() | |
| # Page config | |
| st.set_page_config(page_title="MicroGuru", page_icon="π", layout="wide") | |
| # Custom CSS | |
| st.markdown(""" | |
| <style> | |
| .agent-log { | |
| padding: 8px; | |
| margin: 4px 0; | |
| border-radius: 4px; | |
| background: #f0f7ff; | |
| border-left: 3px solid #1e88e5; | |
| } | |
| .module-card { | |
| padding: 20px; | |
| background: white; | |
| border-radius: 8px; | |
| border-left: 4px solid #4caf50; | |
| margin: 10px 0; | |
| cursor: pointer; | |
| transition: background 0.3s ease; | |
| } | |
| .module-card:hover { | |
| background: #f5f5f5; | |
| } | |
| .loading-icon { | |
| font-size: 1.5em; | |
| color: #1e88e5; | |
| margin-right: 10px; | |
| } | |
| .completed-icon { | |
| font-size: 1.5em; | |
| color: #4caf50; | |
| margin-right: 10px; | |
| } | |
| .progress-bar { | |
| height: 20px; | |
| background: #e0e0e0; | |
| border-radius: 10px; | |
| overflow: hidden; | |
| } | |
| .progress-value { | |
| height: 100%; | |
| background: #4caf50; | |
| transition: width 0.5s ease-in-out; | |
| } | |
| .alert { | |
| position: relative; | |
| padding: 20px; | |
| margin-bottom: 20px; | |
| border-radius: 8px; | |
| border: 1px solid #4caf50; | |
| background-color: #dff0d8; | |
| } | |
| .alert .close { | |
| position: absolute; | |
| top: 10px; | |
| right: 10px; | |
| cursor: pointer; | |
| font-size: 1.5em; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # Initialize session state | |
| if 'learning_path' not in st.session_state: | |
| st.session_state.learning_path = None | |
| if 'current_module' not in st.session_state: | |
| st.session_state.current_module = 0 | |
| if 'agent_logs' not in st.session_state: | |
| st.session_state.agent_logs = [] | |
| if 'completed_courses' not in st.session_state: | |
| st.session_state.completed_courses = [] | |
| # Initialize platform | |
| api_key = os.environ.get('OPENAI_API_KEY') | |
| if not api_key: | |
| st.error("β οΈ OpenAI API key not found.") | |
| st.stop() | |
| platform = EnhancedCourseBuilder(api_key, db_session) | |
| def display_agent_logs(): | |
| """Display agent activity logs in sidebar""" | |
| with st.sidebar: | |
| st.markdown("### π€ Agent Activity") | |
| for log in st.session_state.agent_logs[-5:]: # Show last 5 logs | |
| st.markdown(f'<div class="agent-log">{log}</div>', unsafe_allow_html=True) | |
| def display_progress_bar(): | |
| """Display course progress bar""" | |
| if st.session_state.learning_path: | |
| path = st.session_state.learning_path | |
| total_modules = len(path.modules) | |
| if total_modules == 0: | |
| st.warning("No modules available in the course.") | |
| return | |
| current = st.session_state.current_module + 1 | |
| progress = (current / total_modules) * 100 | |
| st.markdown(f""" | |
| <div class="progress-bar"> | |
| <div class="progress-value" style="width: {progress}%"></div> | |
| </div> | |
| <p style="text-align: center">Module {current}/{total_modules}</p> | |
| """, unsafe_allow_html=True) | |
| def display_learning_roadmap(): | |
| """Display the learning roadmap with module cards""" | |
| st.markdown("### π£οΈ Learning Roadmap") | |
| path = st.session_state.learning_path | |
| for i, module in enumerate(path.modules): | |
| status_icon = "" if module.is_complete else "<i class='loading-icon'>⌛</i>" | |
| is_clickable = "true" if module.is_complete else "false" | |
| st.markdown(f""" | |
| <div class="module-card" onclick="if({is_clickable}) {{ location.href='#module-{i}'; }}"> | |
| {status_icon}<h4 id="module-{i}">{module.title}</h4> | |
| <p>{module.description}</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| def display_module_content(module): | |
| """Display module content and quiz""" | |
| st.markdown(f""" | |
| <div class="module-card"> | |
| <h3>{module.title}</h3> | |
| """, unsafe_allow_html=True) | |
| # Display objectives | |
| st.markdown("#### π― Learning Objectives") | |
| for obj in module.objectives: | |
| st.markdown(f"- {obj}") | |
| # Display prerequisites if any | |
| if module.prerequisites: | |
| st.markdown("#### π Prerequisites") | |
| for prereq in module.prerequisites: | |
| st.markdown(f"- {prereq}") | |
| if not module.is_complete: | |
| st.info("π Content is being generated... Please wait.") | |
| return | |
| # Display sections | |
| for section in module.sections: | |
| with st.expander(f"π {section.title}", expanded=True): | |
| st.markdown(section.content) | |
| st.markdown("#### Key Points") | |
| for point in section.key_points: | |
| st.markdown(f"- {point}") | |
| if section.examples: | |
| st.markdown("#### Examples") | |
| for example in section.examples: | |
| st.code(example) | |
| # Quiz section | |
| st.markdown(""" | |
| <div class="quiz-card"> | |
| <h4>π Knowledge Check</h4> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| for i, question in enumerate(section.quiz_questions): | |
| st.markdown(f"**Q{i+1}: {question['question']}**") | |
| answer = st.radio( | |
| "Choose your answer:", | |
| question['options'], | |
| key=f"quiz_{section.title}_{i}" | |
| ) | |
| if st.button("Check Answer", key=f"check_{section.title}_{i}"): | |
| if answer == question['correct_answer']: | |
| st.success(f"β Correct! {question['explanation']}") | |
| else: | |
| st.error(f"β Incorrect. {question['explanation']}") | |
| def create_new_course(): | |
| """Handle new course creation""" | |
| st.markdown("### π Start Your Learning Journey") | |
| with st.form("course_generator"): | |
| topic = st.text_input("What would you like to learn?") | |
| difficulty = st.select_slider( | |
| "Choose difficulty level:", | |
| options=["beginner", "intermediate", "advanced"], | |
| value="intermediate" | |
| ) | |
| if st.form_submit_button("Create Course π―"): | |
| with st.spinner('Our AI agents are crafting your personalized course...'): | |
| try: | |
| async def create_course(): | |
| return await platform.create_course(topic, difficulty, user_id=1) | |
| path = asyncio.run(create_course()) | |
| st.session_state.learning_path = path | |
| st.markdown(""" | |
| <div class="alert"> | |
| π Your course is ready! Modules are being generated. | |
| <span class="close" onclick="this.parentElement.style.display='none';">×</span> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| except Exception as e: | |
| st.error(f"Error: {str(e)}") | |
| def main(): | |
| st.title("π MicroGuru") | |
| display_agent_logs() | |
| # Navigation | |
| pages = { | |
| "π Home": create_new_course, | |
| "π Current Course": lambda: display_current_course(), | |
| "π Completed Courses": lambda: display_completed_courses() | |
| } | |
| page = st.sidebar.radio("Navigation", list(pages.keys())) | |
| if page == "π Current Course" and not st.session_state.learning_path: | |
| st.info("π Welcome! Start by creating a new course from the Home page.") | |
| page = "π Home" | |
| pages[page]() | |
| def display_current_course(): | |
| """Display current course content""" | |
| path = st.session_state.learning_path | |
| if not path or len(path.modules) == 0: | |
| st.warning("No modules are available yet. Please wait for the course generation to complete.") | |
| return | |
| display_learning_roadmap() | |
| display_progress_bar() | |
| col1, col2 = st.columns([7, 3]) | |
| with col1: | |
| current_module = path.modules[st.session_state.current_module] | |
| display_module_content(current_module) | |
| with col2: | |
| st.markdown("### π Navigation") | |
| # Previous module button | |
| if st.session_state.current_module > 0: | |
| if st.button("β¬ οΈ Previous Module"): | |
| st.session_state.current_module -= 1 | |
| st.rerun() | |
| # Next module button | |
| next_idx = st.session_state.current_module + 1 | |
| if next_idx < len(path.modules): | |
| if path.modules[next_idx].is_complete: | |
| if st.button("Next Module β‘οΈ"): | |
| st.session_state.current_module = next_idx | |
| st.rerun() | |
| else: | |
| with st.spinner("Generating next module..."): | |
| asyncio.run( | |
| platform.generate_module_content(module_id=path.modules[next_idx].id) | |
| ) | |
| st.rerun() | |
| def display_completed_courses(): | |
| """Display completed courses""" | |
| st.markdown("### π Completed Courses") | |
| if not st.session_state.completed_courses: | |
| st.info("Complete your first course to see it here!") | |
| return | |
| for course in st.session_state.completed_courses: | |
| st.markdown(f""" | |
| <div class="module-card"> | |
| <h4>{course.topic}</h4> | |
| <p>{course.description}</p> | |
| <p><small>Completed on: {course.completion_date}</small></p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| if __name__ == "__main__": | |
| main() | |