diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -1,1424 +1,2302 @@ -import re -import streamlit as st -from datetime import datetime, date, time, timedelta -from pathlib import Path -from utils.sample_data import SAMPLE_COURSES, SAMPLE_SESSIONS -from session_page import display_session_content -from db import ( - courses_collection2, - faculty_collection, - students_collection, - research_assistants_collection, - analysts_collection, -) -from werkzeug.security import generate_password_hash, check_password_hash -import os -from openai import OpenAI -from dotenv import load_dotenv -from create_course2 import create_course, courses_collection, generate_perplexity_response, generate_session_resources, PERPLEXITY_API_KEY, validate_course_plan -import json -from bson import ObjectId -client = OpenAI(api_key=os.getenv("OPENAI_KEY")) -from dotenv import load_dotenv - -load_dotenv() -# PERPLEXITY_API_KEY = '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' - -def get_research_papers(query): - """Get research paper recommendations based on query""" - try: - response = client.chat.completions.create( - model="gpt-3.5-turbo", - messages=[ - { - "role": "system", - "content": "You are a helpful research assistant. Provide 10 relevant research papers with titles, authors, brief descriptions, and DOI/URL links. Format each paper as: \n\n1. **Title**\nAuthors: [names]\nLink: [DOI/URL]\nDescription: [brief summary]", - }, - { - "role": "user", - "content": f"Give me 10 research papers about: {query}. Include valid DOI links or URLs to the papers where available.", - }, - ], - ) - return response.choices[0].message.content - except Exception as e: - return f"Error getting recommendations: {str(e)}" - - -def analyze_research_gaps(papers): - """Analyze gaps in research based on recommended papers""" - try: - response = client.chat.completions.create( - model="gpt-3.5-turbo", - messages=[ - { - "role": "system", - "content": "You are a research analysis expert. Based on the provided papers, identify potential research gaps and future research directions.", - }, - { - "role": "user", - "content": f"Based on these papers, what are the key areas that need more research?\n\nPapers:\n{papers}", - }, - ], - ) - return response.choices[0].message.content - except Exception as e: - return f"Error analyzing research gaps: {str(e)}" - - -def init_session_state(): - """Initialize session state variables""" - if "authenticated" not in st.session_state: - st.session_state.authenticated = False - if "user_id" not in st.session_state: - st.session_state.user_id = None - if "user_type" not in st.session_state: - st.session_state.user_type = None - if "username" not in st.session_state: - st.session_state.username = None - if "selected_course" not in st.session_state: - st.session_state.selected_course = None - if "show_create_course_form" not in st.session_state: - st.session_state.show_create_course_form = False - if "show_create_session_form" not in st.session_state: - st.session_state.show_create_session_form = False - if "show_enroll_course_page" not in st.session_state: - st.session_state.show_enroll_course_page = False - if "course_to_enroll" not in st.session_state: - st.session_state.course_to_enroll = None - -def login_user(username, password, user_type): - """Login user based on credentials""" - if user_type == "student": - # user = students_collection.find_one({"full_name": username}) or students_collection.find_one({"username": username}) - user = students_collection.find_one({"$or": [{"full_name": username}, {"username": username}]}) - elif user_type == "faculty": - user = faculty_collection.find_one({"full_name": username}) - elif user_type == "research_assistant": - user = research_assistants_collection.find_one({"full_name": username}) - elif user_type == "analyst": - user = analysts_collection.find_one({"full_name": username}) - - if user and check_password_hash(user["password"], password): - st.session_state.user_id = user["_id"] - print(st.session_state.user_id) - st.session_state.authenticated = True - st.session_state.user_type = user_type - st.session_state.username = username - return True - return False - -# def login_form(): -# """Display login form""" -# st.title("Welcome to NOVAScholar") - -# with st.form("login_form"): - -# user_type = st.selectbox( -# "Please select your Role", ["student", "faculty", "research_assistant", "analyst"] -# ) -# username = st.text_input("Username") -# password = st.text_input("Password", type="password") -# submit = st.form_submit_button("Login") - -# if submit: -# if login_user(username, password, user_type): -# st.success("Login successful!") -# st.rerun() -# else: -# st.error("Invalid credentials!") -def login_form(): - """Display enhanced login form""" - st.title("Welcome to NOVAScholar") - - with st.form("login_form"): - # Role selection at the top - user_type = st.selectbox( - "Please select your Role", - ["student", "faculty", "research_assistant", "analyst"] - ) - - # Username/email and password stacked vertically - username = st.text_input("Username or Email") - password = st.text_input("Password", type="password") - - # Login button - submit = st.form_submit_button("Login") - - if submit: - # Handle both username and email login - if '@' in username: - username = extract_username(username) - - if login_user(username, password, user_type): - st.success("Login successful!") - st.rerun() - else: - st.error("Invalid credentials!") - -def get_courses(username, user_type): - if user_type == "student": - student = students_collection.find_one({"$or": [{"full_name": username}, {"username": username}]}) - if student: - enrolled_course_ids = [ - course["course_id"] for course in student.get("enrolled_courses", []) - ] - courses = courses_collection.find( - {"course_id": {"$in": enrolled_course_ids}} - ) - # courses += courses_collection2.find( - # {"course_id": {"$in": enrolled_course_ids}} - # ) - # # course_titles = [course['title'] for course in courses] - # return list(courses) - # courses_cursor1 = courses_collection.find( - # {"course_id": {"$in": enrolled_course_ids}} - # ) - # courses_cursor2 = courses_collection2.find( - # {"course_id": {"$in": enrolled_course_ids}} - # ) - # courses = list(courses_cursor1) + list(courses_cursor2) - return list(courses) - elif user_type == "faculty": - faculty = faculty_collection.find_one({"full_name": username}) - if faculty: - course_ids = [ - course["course_id"] for course in faculty.get("courses_taught", []) - ] - # courses_1 = list(courses_collection2.find({"course_id": {"$in": course_ids}})) - courses_2 = list(courses_collection.find({"course_id": {"$in": course_ids}})) - return courses_2 - elif user_type == "research_assistant": - research_assistant = research_assistants_collection.find_one( - {"full_name": username} - ) - if research_assistant: - course_ids = [ - course["course_id"] - for course in research_assistant.get("courses_assisted", []) - ] - courses = courses_collection2.find({"course_id": {"$in": course_ids}}) - return list(courses) - else: - return [] - - -def get_course_ids(): - """Get course IDs for sample courses""" - return [course["course_id"] for course in SAMPLE_COURSES] - - -def get_sessions(course_id, course_title): - """Get sessions for a given course ID""" - course = courses_collection.find_one({"course_id": course_id, "title": course_title}) - if course: - return course.get("sessions", []) - return [] - - -def create_session(new_session, course_id): - """Create a new session for a given course ID""" - course = courses_collection2.find_one({"course_id": course_id}) | courses_collection.find_one({"course_id": course_id}) - if course: - last_session_id = max((session["session_id"] for session in course["sessions"])) - last_session_id = int(last_session_id[1:]) - new_session_id = last_session_id + 1 - new_session["session_id"] = "S" + str(new_session_id) - courses_collection2.update_one( - {"course_id": new_session["course_id"]}, - {"$push": {"sessions": new_session}}, - ) - return True - return False - - -def create_session_form(course_id): - """Display form to create a new session and perform the creation operation""" - st.title("Create New Session") - - if 'session_time' not in st.session_state: - st.session_state.session_time = datetime.now().time() - if 'show_create_session_form' not in st.session_state: - st.session_state.show_create_session_form = False - - with st.form("create_session_form"): - session_title = st.text_input("Session Title") - session_date = st.date_input("Session Date", date.today(), key="session_date") - session_time = st.time_input( - "Session Time", st.session_state.session_time, key="session_time" - ) - - new_session_id = None - # Generate new session ID - course = courses_collection2.find_one({"course_id": course_id}) - if course and "sessions" in course and course["sessions"]: - last_session_id = max( - int(session["session_id"][1:]) for session in course["sessions"] - ) - new_session_id = last_session_id + 1 - else: - new_session_id = 1 - - if st.form_submit_button("Create Session"): - clicked = True - new_session = { - "session_id": f"S{new_session_id}", - "course_id": course_id, - "title": session_title, - "date": datetime.combine(session_date, session_time), - "status": "upcoming", - "created_at": datetime.utcnow(), - "pre_class": { - "resources": [], - "completetion_required": True, - }, - "in_class": { - "topics": [], - "quiz": {"title": "", "questions": 0, "duration": 0}, - "polls": [], - }, - "post_class": { - "assignments": [], - }, - } - courses_collection2.update_one( - {"course_id": course_id}, {"$push": {"sessions": new_session}} - ) - st.success("Session created successfully!") - st.session_state.show_create_session_form = False - - # new_session_id = None - # creation_success = False - # # Generate new session ID - # course = courses_collection2.find_one({"course_id": course_id}) - # if course and 'sessions' in course and course['sessions']: - # last_session_id = max((session['session_id'] for session in course['sessions'])) - # last_session_id = int(last_session_id[1:]) - # new_session_id = last_session_id + 1 - # else: - # new_session_id = 1 - - # new_session = { - # "session_id": 'S' + new_session_id, - # "title": session_title, - # "date": datetime.datetime.combine(session_date, session_time).isoformat(), - # "status": "upcoming", - # "created_at": datetime.datetime.utcnow().isoformat(), - # "pre_class": { - # "resources": [], - # "completetion_required": True, - # }, - # "in_class": { - # "topics": [], - # "quiz": - # { - # "title": '', - # "questions": 0, - # "duration": 0 - # }, - # "polls": [] - # }, - # "post_class": { - # "assignments": [], - # } - # } - # courses_collection2.update_one( - # {"course_id": course_id}, - # {"$push": {"sessions": new_session}} - # ) - # creation_success = True - # st.form_submit_button("Create Session") - # if creation_success == True: - # st.success("Session created successfully!") - # else: - - -def get_new_student_id(): - """Generate a new student ID by incrementing the last student ID""" - last_student = students_collection.find_one(sort=[("SID", -1)]) - if last_student: - last_student_id = int(last_student["SID"][1:]) - new_student_id = f"S{last_student_id + 1}" - else: - new_student_id = "S101" - return new_student_id - - -def get_new_faculty_id(): - """Generate a new faculty ID by incrementing the last faculty ID""" - last_faculty = faculty_collection.find_one(sort=[("TID", -1)]) - if last_faculty: - last_faculty_id = int(last_faculty["TID"][1:]) - new_faculty_id = f"T{last_faculty_id + 1}" - else: - new_faculty_id = "T101" - return new_faculty_id - - -def get_new_course_id(): - """Generate a new course ID by incrementing the last course ID""" - last_course = courses_collection2.find_one(sort=[("course_id", -1)]) - if last_course: - last_course_id = int(last_course["course_id"][2:]) - new_course_id = f"CS{last_course_id + 1}" - else: - new_course_id = "CS101" - return new_course_id - - -# def register_page(): -# st.title("Register") -# if "user_type" not in st.session_state: -# st.session_state.user_type = "student" - -# # Select user type -# st.session_state.user_type = st.selectbox( -# "Select User Type", ["student", "faculty", "research_assistant"] -# ) -# user_type = st.session_state.user_type -# print(user_type) - -# with st.form("register_form"): -# # user_type = st.selectbox("Select User Type", ["student", "faculty", "research_assistant"]) -# # print(user_type) -# full_name = st.text_input("Full Name") -# password = st.text_input("Password", type="password") -# confirm_password = st.text_input("Confirm Password", type="password") - -# if user_type == "student": -# # Fetch courses for students to select from -# courses = list(courses_collection2.find({}, {"course_id": 1, "title": 1})) -# course_options = [ -# f"{course['title']} ({course['course_id']})" for course in courses -# ] -# selected_courses = st.multiselect("Available Courses", course_options) - -# submit = st.form_submit_button("Register") - -# if submit: -# if password == confirm_password: -# hashed_password = generate_password_hash(password) -# if user_type == "student": -# new_student_id = get_new_student_id() -# enrolled_courses = [ -# { -# "course_id": course.split("(")[-1][:-1], -# "title": course.split(" (")[0], -# } -# for course in selected_courses -# ] -# students_collection.insert_one( -# { -# "SID": new_student_id, -# "full_name": full_name, -# "password": hashed_password, -# "enrolled_courses": enrolled_courses, -# "created_at": datetime.utcnow(), -# } -# ) -# st.success( -# f"Student registered successfully with ID: {new_student_id}" -# ) -# elif user_type == "faculty": -# new_faculty_id = get_new_faculty_id() -# faculty_collection.insert_one( -# { -# "TID": new_faculty_id, -# "full_name": full_name, -# "password": hashed_password, -# "courses_taught": [], -# "created_at": datetime.utcnow(), -# } -# ) -# st.success( -# f"Faculty registered successfully with ID: {new_faculty_id}" -# ) -# elif user_type == "research_assistant": -# research_assistants_collection.insert_one( -# { -# "full_name": full_name, -# "password": hashed_password, -# "created_at": datetime.utcnow(), -# } -# ) -# st.success("Research Assistant registered successfully!") -# else: -# st.error("Passwords do not match") - - -def get_new_analyst_id(): - """Generate a new analyst ID by incrementing the last analyst ID""" - last_analyst = analysts_collection.find_one(sort=[("AID", -1)]) - if last_analyst: - last_id = int(last_analyst["AID"][1:]) - new_id = f"A{last_id + 1}" - else: - new_id = "A1" - return new_id - - -# def register_page(): -# st.title("Register") -# if "user_type" not in st.session_state: -# st.session_state.user_type = "student" - -# # Select user type -# st.session_state.user_type = st.selectbox( -# "Please select your Role", ["student", "faculty", "research_assistant", "analyst"] -# ) -# user_type = st.session_state.user_type -# print(user_type) - -# with st.form("register_form"): - -# full_name = st.text_input("Full Name") -# password = st.text_input("Password", type="password") -# confirm_password = st.text_input("Confirm Password", type="password") - -# if user_type == "student": -# # Fetch courses for students to select from -# courses = list(courses_collection.find({}, {"course_id": 1, "title": 1})) -# course_options = [ -# f"{course['title']} ({course['course_id']})" for course in courses -# ] -# selected_courses = st.multiselect("Available Courses", course_options) - -# submit = st.form_submit_button("Register") - -# if submit: -# if password == confirm_password: -# hashed_password = generate_password_hash(password) -# if user_type == "student": -# new_student_id = get_new_student_id() -# enrolled_courses = [ -# { -# "course_id": course.split("(")[-1][:-1], -# "title": course.split(" (")[0], -# } -# for course in selected_courses -# ] -# students_collection.insert_one( -# { -# "SID": new_student_id, -# "full_name": full_name, -# "password": hashed_password, -# "enrolled_courses": enrolled_courses, -# "created_at": datetime.utcnow(), -# } -# ) -# st.success( -# f"Student registered successfully with ID: {new_student_id}" -# ) -# elif user_type == "faculty": -# new_faculty_id = get_new_faculty_id() -# faculty_collection.insert_one( -# { -# "TID": new_faculty_id, -# "full_name": full_name, -# "password": hashed_password, -# "courses_taught": [], -# "created_at": datetime.utcnow(), -# } -# ) -# st.success( -# f"Faculty registered successfully with ID: {new_faculty_id}" -# ) -# elif user_type == "research_assistant": -# research_assistants_collection.insert_one( -# { -# "full_name": full_name, -# "password": hashed_password, -# "created_at": datetime.utcnow(), -# } -# ) -# st.success("Research Assistant registered successfully!") -# elif user_type == "analyst": -# # new_analyst_id = get_new_analyst_id() -# analysts_collection.insert_one( -# { -# # "AID": new_analyst_id, -# "full_name": full_name, -# "password": hashed_password, -# "created_at": datetime.utcnow(), -# } -# ) -# st.success("Analyst registered successfully!") -# else: -# st.error("Passwords do not match") -def register_page(): - st.title("Register for NOVAScholar") - if "user_type" not in st.session_state: - st.session_state.user_type = "student" - - # Select user type - st.session_state.user_type = st.selectbox( - "Please select your Role", - ["student", "faculty", "research_assistant", "analyst"] - ) - user_type = st.session_state.user_type - - with st.form("register_form"): - col1, col2 = st.columns(2) - - with col1: - full_name = st.text_input("Full Name") - email = st.text_input("Institutional Email") - phone = st.text_input("Phone Number") - - with col2: - password = st.text_input("Password", type="password") - confirm_password = st.text_input("Confirm Password", type="password") - - if user_type == "student": - courses = list(courses_collection.find({}, {"course_id": 1, "title": 1})) - course_options = [f"{course['title']} ({course['course_id']})" for course in courses] - selected_courses = st.multiselect("Available Courses", course_options) - - submit = st.form_submit_button("Register") - - if submit: - # Validate email - email_valid, email_msg = validate_email(email) - if not email_valid: - st.error(email_msg) - return - - # Validate phone - phone_valid, phone_msg = validate_phone(phone) - if not phone_valid: - st.error(phone_msg) - return - - # Validate password match - if password != confirm_password: - st.error("Passwords do not match") - return - - # Extract username from email - username = extract_username(email) - - # Check if username already exists - if user_type == "student": - existing_user = students_collection.find_one({"username": username}) - elif user_type == "faculty": - existing_user = faculty_collection.find_one({"username": username}) - elif user_type == "research_assistant": - existing_user = research_assistants_collection.find_one({"username": username}) - elif user_type == "analyst": - existing_user = analysts_collection.find_one({"username": username}) - - if existing_user: - st.error("A user with this email already exists") - return - - # Hash password and create user - hashed_password = generate_password_hash(password) - - user_data = { - "username": username, - "full_name": full_name, - "email": email, - "phone": phone, - "password": hashed_password, - "created_at": datetime.utcnow() - } - - if user_type == "student": - new_student_id = get_new_student_id() - enrolled_courses = [ - { - "course_id": course.split("(")[-1][:-1], - "title": course.split(" (")[0], - } - for course in selected_courses - ] - user_data["SID"] = new_student_id - user_data["enrolled_courses"] = enrolled_courses - students_collection.insert_one(user_data) - st.success(f"Student registered successfully! Your username is: {username}") - - elif user_type == "faculty": - new_faculty_id = get_new_faculty_id() - user_data["TID"] = new_faculty_id - user_data["courses_taught"] = [] - faculty_collection.insert_one(user_data) - st.success(f"Faculty registered successfully! Your username is: {username}") - - elif user_type == "research_assistant": - research_assistants_collection.insert_one(user_data) - st.success(f"Research Assistant registered successfully! Your username is: {username}") - - elif user_type == "analyst": - analysts_collection.insert_one(user_data) - st.success(f"Analyst registered successfully! Your username is: {username}") - -# Create Course feature -# def create_course_form2(faculty_name, faculty_id): -# """Display enhanced form to create a new course with AI-generated content""" -# st.title("Create New Course") - -# if 'course_plan' not in st.session_state: -# st.session_state.course_plan = None -# if 'edit_mode' not in st.session_state: -# st.session_state.edit_mode = False - -# # Initial Course Creation Form -# if not st.session_state.course_plan: -# with st.form("initial_course_form"): -# col1, col2 = st.columns(2) -# with col1: -# course_name = st.text_input("Course Name", placeholder="e.g., Introduction to Computer Science") -# faculty_info = st.text_input("Faculty", value=faculty_name, disabled=True) -# with col2: -# duration_weeks = st.number_input("Duration (weeks)", min_value=1, max_value=16, value=12) -# start_date = st.date_input("Start Date") - -# generate_button = st.form_submit_button("Generate Course Structure", use_container_width=True) - -# if generate_button and course_name: -# with st.spinner("Generating course structure..."): -# try: -# course_plan = generate_perplexity_response(PERPLEXITY_API_KEY, course_name) -# # print(course_plan) -# st.session_state.course_plan = json.loads(course_plan) -# st.session_state.start_date = start_date -# st.session_state.duration_weeks = duration_weeks -# st.rerun() -# except Exception as e: -# st.error(f"Error generating course structure: {e}") - -# # Display and Edit Generated Course Content -# if st.session_state.course_plan: -# with st.expander("Course Overview", expanded=True): -# if not st.session_state.edit_mode: -# st.subheader(st.session_state.course_plan['course_title']) -# st.write(st.session_state.course_plan['course_description']) -# edit_button = st.button("Edit Course Details", use_container_width=True) -# if edit_button: -# st.session_state.edit_mode = True -# st.rerun() -# else: -# with st.form("edit_course_details"): -# st.session_state.course_plan['course_title'] = st.text_input( -# "Course Title", -# value=st.session_state.course_plan['course_title'] -# ) -# st.session_state.course_plan['course_description'] = st.text_area( -# "Course Description", -# value=st.session_state.course_plan['course_description'] -# ) -# if st.form_submit_button("Save Course Details"): -# st.session_state.edit_mode = False -# st.rerun() - -# # Display Modules and Sessions -# st.subheader("Course Modules and Sessions") - -# start_date = st.session_state.start_date -# current_date = start_date - -# all_sessions = [] -# for module_idx, module in enumerate(st.session_state.course_plan['modules']): -# with st.expander(f"📚 Module {module_idx + 1}: {module['module_title']}", expanded=True): -# # Edit module title -# new_module_title = st.text_input( -# f"Module {module_idx + 1} Title", -# value=module['module_title'], -# key=f"module_{module_idx}" -# ) -# module['module_title'] = new_module_title - -# for sub_idx, sub_module in enumerate(module['sub_modules']): -# st.markdown(f"### 📖 {sub_module['title']}") - -# # Create sessions for each topic -# for topic_idx, topic in enumerate(sub_module['topics']): -# session_key = f"session_{module_idx}_{sub_idx}_{topic_idx}" - -# with st.container(): -# col1, col2, col3 = st.columns([3, 2, 1]) -# with col1: -# new_topic = st.text_input( -# "Topic", -# value=topic, -# key=f"{session_key}_topic" -# ) -# sub_module['topics'][topic_idx] = new_topic - -# with col2: -# session_date = st.date_input( -# "Session Date", -# value=current_date, -# key=f"{session_key}_date" -# ) - -# with col3: -# session_status = st.selectbox( -# "Status", -# options=["upcoming", "in-progress", "completed"], -# key=f"{session_key}_status" -# ) - -# # Create session object -# session = { -# "session_id": str(ObjectId()), -# "title": new_topic, -# "date": datetime.combine(session_date, datetime.min.time()), -# "status": session_status, -# "module_name": module['module_title'], -# "created_at": datetime.utcnow(), -# "pre_class": { -# "resources": [], -# "completion_required": True -# }, -# "in_class": { -# "quiz": [], -# "polls": [] -# }, -# "post_class": { -# "assignments": [] -# } -# } -# all_sessions.append(session) -# current_date = session_date + timedelta(days=7) - -# new_course_id = get_new_course_id() -# course_title = st.session_state.course_plan['course_title'] -# # Final Save Button -# if st.button("Save Course", type="primary", use_container_width=True): -# try: -# course_doc = { -# "course_id": new_course_id, -# "title": course_title, -# "description": st.session_state.course_plan['course_description'], -# "faculty": faculty_name, -# "faculty_id": faculty_id, -# "duration": f"{st.session_state.duration_weeks} weeks", -# "start_date": datetime.combine(st.session_state.start_date, datetime.min.time()), -# "created_at": datetime.utcnow(), -# "sessions": all_sessions -# } - -# # Insert into database -# courses_collection.insert_one(course_doc) - -# st.success("Course successfully created!") - -# # Update faculty collection -# faculty_collection.update_one( -# {"_id": st.session_state.user_id}, -# { -# "$push": { -# "courses_taught": { -# "course_id": new_course_id, -# "title": course_title, -# } -# } -# }, -# ) - -# # Clear session state -# st.session_state.course_plan = None -# st.session_state.edit_mode = False - -# # Optional: Add a button to view the created course -# if st.button("View Course"): -# # Add navigation logic here -# pass - -# except Exception as e: -# st.error(f"Error saving course: {e}") - - -def remove_json_backticks(json_string): - """Remove backticks and 'json' from the JSON object string""" - return json_string.replace("```json", "").replace("```", "").strip() - - -def create_course_form(faculty_name, faculty_id): - """Display enhanced form to create a new course with AI-generated content and resources""" - - st.title("Create New Course") - - if 'course_plan' not in st.session_state: - st.session_state.course_plan = None - if 'edit_mode' not in st.session_state: - st.session_state.edit_mode = False - if 'resources_map' not in st.session_state: - st.session_state.resources_map = {} - if 'start_date' not in st.session_state: - st.session_state.start_date = None - if 'duration_weeks' not in st.session_state: - st.session_state.duration_weeks = None - if 'sessions_per_week' not in st.session_state: - st.session_state.sessions_per_week = None - - - # Initial Course Creation Form - if not st.session_state.course_plan: - with st.form("initial_course_form"): - col1, col2 = st.columns(2) - with col1: - course_name = st.text_input("Course Name", placeholder="e.g., Introduction to Computer Science") - faculty_info = st.text_input("Faculty", value=faculty_name, disabled=True) - sessions_per_week = st.number_input("Sessions Per Week", min_value=1, max_value=5, value=2) - with col2: - duration_weeks = st.number_input("Duration (weeks)", min_value=1, max_value=16, value=12) - start_date = st.date_input("Start Date") - - generate_button = st.form_submit_button("Generate Course Structure", use_container_width=True) - - if generate_button and course_name: - with st.spinner("Generating course structure and resources..."): - try: - # Generate course plan with resources - course_plan = generate_perplexity_response( - PERPLEXITY_API_KEY, - course_name, - duration_weeks, - sessions_per_week - ) - try: - course_plan_json = json.loads(course_plan) - validate_course_plan(course_plan_json) - st.session_state.course_plan = course_plan_json - except (json.JSONDecodeError, ValueError) as e: - st.error(f"Error in course plan structure: {e}") - return - st.session_state.start_date = start_date - st.session_state.duration_weeks = duration_weeks - st.session_state.sessions_per_week = sessions_per_week - - # Generate resources for all sessions - session_titles = [] - for module in st.session_state.course_plan['modules']: - for sub_module in module['sub_modules']: - for topic in sub_module['topics']: - # session_titles.append(topic['title']) - # session_titles.append(topic) - if isinstance(topic, dict): - session_titles.append(topic['title']) - else: - session_titles.append(topic) - # In generate_session_resources function, add validation: - if not session_titles: - return json.dumps({"session_resources": []}) - resources_response = generate_session_resources(PERPLEXITY_API_KEY, session_titles) - without_backticks = remove_json_backticks(resources_response) - resources = json.loads(without_backticks) - st.session_state.resources_map = { - resource['session_title']: resource['resources'] - for resource in resources['session_resources'] - } - # Add error handling for the resources map - # if st.session_state.resources_map is None: - # st.session_state.resources_map = {} - - st.rerun() - except Exception as e: - st.error(f"Error generating course structure: {e}") - - # Display and Edit Generated Course Content - if st.session_state.course_plan: - with st.expander("Course Overview", expanded=True): - if not st.session_state.edit_mode: - st.subheader(st.session_state.course_plan['course_title']) - st.write(st.session_state.course_plan['course_description']) - col1, col2, col3 = st.columns(3) - with col1: - st.write(f"**Start Date:** {st.session_state.start_date}") - with col2: - st.write(f"**Duration (weeks):** {st.session_state.duration_weeks}") - with col3: - st.write(f"**Sessions Per Week:** {st.session_state.sessions_per_week}") - - edit_button = st.button("Edit Course Details", use_container_width=True) - if edit_button: - st.session_state.edit_mode = True - st.rerun() - else: - with st.form("edit_course_details"): - st.session_state.course_plan['course_title'] = st.text_input( - "Course Title", - value=st.session_state.course_plan['course_title'] - ) - st.session_state.course_plan['course_description'] = st.text_area( - "Course Description", - value=st.session_state.course_plan['course_description'] - ) - if st.form_submit_button("Save Course Details"): - st.session_state.edit_mode = False - st.rerun() - - # Display Modules and Sessions - st.subheader("Course Modules and Sessions") - - start_date = st.session_state.start_date - current_date = start_date - - all_sessions = [] - for module_idx, module in enumerate(st.session_state.course_plan['modules']): - with st.expander(f"📚 Module {module_idx + 1}: {module['module_title']}", expanded=True): - # Edit module title - new_module_title = st.text_input( - f"Edit Module Title", - value=module['module_title'], - key=f"module_{module_idx}" - ) - module['module_title'] = new_module_title - - for sub_idx, sub_module in enumerate(module['sub_modules']): - st.markdown("
", unsafe_allow_html=True) # Add gap between sessions - # st.markdown(f"### 📖 {sub_module['title']}") - st.markdown(f'

📖 Chapter {sub_idx + 1}: {sub_module["title"]}

', unsafe_allow_html=True) - # Possible fix: - # Inside the loop where topics are being processed: - - for topic_idx, topic in enumerate(sub_module['topics']): - st.markdown("
", unsafe_allow_html=True) # Add gap between sessions - session_key = f"session_{module_idx}_{sub_idx}_{topic_idx}" - - # Get topic title based on type - if isinstance(topic, dict): - current_topic_title = topic.get('title', '') - current_topic_display = current_topic_title - else: - current_topic_title = str(topic) - current_topic_display = current_topic_title - - with st.container(): - # Session Details - col1, col2, col3 = st.columns([3, 2, 1]) - with col1: - new_topic = st.text_input( - f"Session {topic_idx + 1} Title", - value=current_topic_display, - key=f"{session_key}_topic" - ) - # Update the topic in the data structure - if isinstance(topic, dict): - topic['title'] = new_topic - else: - sub_module['topics'][topic_idx] = new_topic - - with col2: - session_date = st.date_input( - "Session Date", - value=current_date, - key=f"{session_key}_date" - ) - - with col3: - session_status = st.selectbox( - "Status", - options=["upcoming", "in-progress", "completed"], - key=f"{session_key}_status" - ) - - # Display Resources - if st.session_state.resources_map: - # Try both the full topic title and the display title - resources = None - if isinstance(topic, dict) and topic.get('title') in st.session_state.resources_map: - resources = st.session_state.resources_map[topic['title']] - elif current_topic_title in st.session_state.resources_map: - resources = st.session_state.resources_map[current_topic_title] - - if resources: - with st.container(): - # st.markdown("#### 📚 Session Resources") - st.markdown(f'

📚 Session Resources

', unsafe_allow_html=True) - # Readings Tab - if resources.get('readings'): - st.markdown(f'
📖 External Resources
', unsafe_allow_html=True) - col1, col2 = st.columns(2) - for idx, reading in enumerate(resources['readings']): - with col1 if idx % 2 == 0 else col2: - st.markdown(f""" - - **{reading['title']}** - - Type: {reading['type']} - - Estimated reading time: {reading['estimated_read_time']} - - [Access Resource]({reading['url']}) - """) - - # Books Tab and Additional Resources Tab side-by-side - col1, col2 = st.columns(2) - - with col1: - if resources.get('books'): - st.markdown(f'
📚 Reference Books
', unsafe_allow_html=True) - for book in resources['books']: - with st.container(): - st.markdown(f""" - - **{book['title']}** - - Author: {book['author']} - - ISBN: {book['isbn']} - - Chapters: {book['chapters']} - """) - - with col2: - if resources.get('additional_resources'): - st.markdown(f'
🔗 Additional Study Resources
', unsafe_allow_html=True) - for resource in resources['additional_resources']: - with st.container(): - st.markdown(f""" - - **{resource['title']}** - - Type: {resource['type']} - - Description: {resource['description']} - - [Access Resource]({resource['url']}) - """) - - # Create session object - session = { - "session_id": str(ObjectId()), - "title": new_topic, - "date": datetime.combine(session_date, datetime.min.time()), - "status": session_status, - "module_name": module['module_title'], - "created_at": datetime.utcnow(), - "pre_class": { - "resources": [], - "completion_required": True - }, - "in_class": { - "quiz": [], - "polls": [] - }, - "post_class": { - "assignments": [] - }, - "external_resources": st.session_state.resources_map.get(current_topic_title, {}) - } - all_sessions.append(session) - current_date = session_date + timedelta(days=7) - - - new_course_id = get_new_course_id() - course_title = st.session_state.course_plan['course_title'] - - # Final Save Button - if st.button("Save Course", type="primary", use_container_width=True): - try: - course_doc = { - "course_id": new_course_id, - "title": course_title, - "description": st.session_state.course_plan['course_description'], - "faculty": faculty_name, - "faculty_id": faculty_id, - "duration": f"{st.session_state.duration_weeks} weeks", - "sessions_per_week": st.session_state.sessions_per_week, - "start_date": datetime.combine(st.session_state.start_date, datetime.min.time()), - "created_at": datetime.utcnow(), - "sessions": all_sessions - } - - # Insert into database - courses_collection.insert_one(course_doc) - st.success("Course successfully created!") - - # Update faculty collection - faculty_collection.update_one( - {"_id": st.session_state.user_id}, - { - "$push": { - "courses_taught": { - "course_id": new_course_id, - "title": course_title, - } - } - } - ) - - # Clear session state - st.session_state.course_plan = None - st.session_state.edit_mode = False - st.session_state.resources_map = {} - - # Optional: Add a button to view the created course - if st.button("View Course"): - # Add navigation logic here - pass - - except Exception as e: - st.error(f"Error saving course: {e}") - - - -from research_assistant_dashboard import display_research_assistant_dashboard -from goals2 import display_analyst_dashboard -def enroll_in_course(course_id, course_title, student): - """Enroll a student in a course""" - if student: - courses = student.get("enrolled_courses", []) - if course_id not in [course["course_id"] for course in courses]: - course = courses_collection.find_one({"course_id": course_id}) - if course: - courses.append( - { - "course_id": course["course_id"], - "title": course["title"], - } - ) - students_collection.update_one( - {"_id": st.session_state.user_id}, - {"$set": {"enrolled_courses": courses}}, - ) - st.success(f"Enrolled in course {course_title}") - # st.experimental_rerun() - else: - st.error("Course not found") - else: - st.warning("Already enrolled in this course") - -# def enroll_in_course_page(course_id): -# """Enroll a student in a course""" -# student = students_collection.find_one({"_id": st.session_state.user_id}) -# course_title = courses_collection.find_one({"course_id": course_id})["title"] - -# course = courses_collection.find_one({"course_id": course_id}) -# if course: -# st.title(course["title"]) -# st.subheader("Course Description:") -# st.write(course["description"]) -# st.write(f"Faculty: {course['faculty']}") -# st.write(f"Duration: {course['duration']}") - -# st.title("Course Sessions") -# for session in course["sessions"]: -# st.write(f"Session: {session['title']}") -# st.write(f"Date: {session['date']}") -# st.write(f"Status: {session['status']}") -# st.write("----") -# else: -# st.error("Course not found") - -# enroll_button = st.button("Enroll in Course", key="enroll_button", use_container_width=True) -# if enroll_button: -# enroll_in_course(course_id, course_title, student) -def enroll_in_course_page(course_id): - """Display an aesthetically pleasing course enrollment page""" - student = students_collection.find_one({"_id": st.session_state.user_id}) - course = courses_collection.find_one({"course_id": course_id}) - - if not course: - st.error("Course not found") - return - - # Create two columns for layout - col1, col2 = st.columns([2, 1]) - - with col1: - # Course header section - st.title(course["title"]) - st.markdown(f"*{course['description']}*") - - # Course details in an expander - with st.expander("Course Details", expanded=True): - st.markdown(f"👨‍🏫 **Faculty:** {course['faculty']}") - st.markdown(f"⏱️ **Duration:** {course['duration']}") - - # Sessions in a clean card-like format - st.subheader("📚 Course Sessions") - for idx, session in enumerate(course["sessions"], 1): - with st.container(): - st.markdown(f""" - --- - ### Session {idx}: {session['title']} - 🗓️ **Date:** {session['date']} - 📌 **Status:** {session['status']} - """) - - with col2: - with st.container(): - st.markdown("### Ready to Learn?") - st.markdown("Click below to enroll in this course") - - # Check if already enrolled - courses = student.get("enrolled_courses", []) - is_enrolled = course_id in [c["course_id"] for c in courses] - - if is_enrolled: - st.info("✅ You are already enrolled in this course") - else: - enroll_button = st.button( - "🎓 Enroll Now", - key="enroll_button", - use_container_width=True - ) - if enroll_button: - enroll_in_course(course_id, course["title"], student) - -def show_available_courses(username, user_type, user_id): - """Display available courses for enrollment""" - st.title("Available Courses") - - courses = list(courses_collection.find({}, {"course_id": 1, "title": 1})) - course_options = [ - f"{course['title']} ({course['course_id']})" for course in courses - ] - - selected_course = st.selectbox("Select a Course to Enroll", course_options) - # if selected_courses: - # for course in selected_courses: - # course_id = course.split("(")[-1][:-1] - # course_title = course.split(" (")[0] - # enroll_in_course(course_id, course_title, user_id) - # st.success("Courses enrolled successfully!") - if selected_course: - course_id = selected_course.split("(")[-1][:-1] - enroll_in_course_page(course_id) - -def validate_email(email): - """Validate email format and domain""" - # Basic email pattern - pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' - if not re.match(pattern, email): - return False, "Invalid email format" - - # You can add additional institution-specific validation here - # For example, checking if the domain is from your institution - # allowed_domains = ["spit.ac.in"] # Add more domains as needed - # domain = email.split('@')[1] - # if domain not in allowed_domains: - # return False, "Please use your institutional email address" - - return True, "Valid email" - -def validate_phone(phone): - """Validate phone number format""" - # Assuming Indian phone numbers - pattern = r'^[6-9]\d{9}$' - if not re.match(pattern, phone): - return False, "Invalid phone number format. Please enter a 10-digit Indian mobile number" - return True, "Valid phone number" - -def extract_username(email): - """Extract username from email""" - return email.split('@')[0] - - - - -def main_dashboard(): - if st.session_state.user_type == "research_assistant": - display_research_assistant_dashboard() - elif st.session_state.user_type == "analyst": - display_analyst_dashboard() - else: - selected_course_id = None - create_session = False - with st.sidebar: - st.title(f"Welcome, {st.session_state.username}") - if st.session_state.user_type == "student": - st.title("Enrolled Courses") - else: - st.title("Your Courses") - - # Course selection - enrolled_courses = get_courses( - st.session_state.username, st.session_state.user_type - ) - - # Enroll in Courses - if st.session_state.user_type == "student": - if st.button( - "Enroll in a New Course", key="enroll_course", use_container_width=True - ): - st.session_state.show_enroll_course_page = True - - # if st.session_state.show_enroll_course_form: - # courses = list(courses_collection.find({}, {"course_id": 1, "title": 1})) - # courses += list(courses_collection2.find({}, {"course_id": 1, "title": 1})) - # course_options = [f"{course['title']} ({course['course_id']})" for course in courses] - # course_to_enroll = st.selectbox("Available Courses", course_options) - # st.session_state.course_to_enroll = course_to_enroll - - if st.session_state.user_type == "faculty": - if st.button( - "Create New Course", key="create_course", use_container_width=True - ): - st.session_state.show_create_course_form = True - - if not enrolled_courses: - st.warning("No courses found") - else: - course_titles = [course["title"] for course in enrolled_courses] - course_ids = [course["course_id"] for course in enrolled_courses] - - selected_course = st.selectbox("Select Course", course_titles) - selected_course_id = course_ids[course_titles.index(selected_course)] - print("Selected Course ID: ", selected_course_id) - - st.session_state.selected_course = selected_course - st.session_state.selected_course_id = selected_course_id - - # Display course sessions - sessions = get_sessions(selected_course_id, selected_course) - - st.title("Course Sessions") - for i, session in enumerate(sessions, start=1): - if st.button( - f"Session {i}", key=f"session_{i}", use_container_width=True - ): - st.session_state.selected_session = session - - if st.session_state.user_type == "faculty": - # Create new session - # create_session = st.button("Create New Session Button", key="create_session", use_container_width=True) - if st.button( - "Create New Session", - key="create_session", - use_container_width=True, - ): - st.session_state.show_create_session_form = True - - if st.button("Logout", use_container_width=True): - for key in st.session_state.keys(): - del st.session_state[key] - st.rerun() - - # if create_session: - # create_session_form(selected_course_id) - if st.session_state.get("show_create_course_form"): - create_course_form(st.session_state.username, st.session_state.user_id) - elif st.session_state.get("show_create_session_form"): - create_session_form(selected_course_id) - elif st.session_state.get("show_enroll_course_page"): - show_available_courses(st.session_state.username, st.session_state.user_type, st.session_state.user_id) - else: - # Main content - if "selected_session" in st.session_state: - display_session_content( - st.session_state.user_id, - selected_course_id, - st.session_state.selected_session, - st.session_state.username, - st.session_state.user_type, - ) - else: - st.info("Select a session to view details") - # # Main content - # if 'selected_session' in st.session_state: - # display_session_content(st.session_state.user_id, selected_course_id, st.session_state.selected_session, st.session_state.username, st.session_state.user_type) - # if create_session: - # create_session_form(selected_course_id) - - -def main(): - st.set_page_config(page_title="NOVAScholar", page_icon="📚", layout="wide") - init_session_state() - # modify_courses_collection_schema() - - if not st.session_state.authenticated: - login_tab, register_tab = st.tabs(["Login", "Register"]) - - with register_tab: - register_page() - with login_tab: - login_form() - else: - main_dashboard() - - -if __name__ == "__main__": - main() +import re +import streamlit as st +from datetime import datetime, date, time, timedelta +from pathlib import Path +# from utils.sample_data import SAMPLE_COURSES, SAMPLE_SESSIONS +from session_page import display_session_content +from db import ( + courses_collection2, + faculty_collection, + students_collection, + research_assistants_collection, + analysts_collection, +) +from werkzeug.security import generate_password_hash, check_password_hash +import os +from openai import OpenAI +from dotenv import load_dotenv +from create_course2 import create_course, courses_collection, generate_perplexity_response, generate_session_resources, PERPLEXITY_API_KEY, validate_course_plan +import json +from bson import ObjectId +client = OpenAI(api_key=os.getenv("OPENAI_KEY")) +from dotenv import load_dotenv +from create_course3 import generate_course_outcomes, generate_resources_by_titles_chunking, generate_session_outcomes, generate_module_outcomes, generate_submodule_outcomes, generate_session_resources, GEMINI_API_KEY, PERPLEXITY_API_KEY, merge_course_structure +load_dotenv() +# PERPLEXITY_API_KEY = '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' + +def get_research_papers(query): + """Get research paper recommendations based on query""" + try: + response = client.chat.completions.create( + model="gpt-3.5-turbo", + messages=[ + { + "role": "system", + "content": "You are a helpful research assistant. Provide 10 relevant research papers with titles, authors, brief descriptions, and DOI/URL links. Format each paper as: \n\n1. **Title**\nAuthors: [names]\nLink: [DOI/URL]\nDescription: [brief summary]", + }, + { + "role": "user", + "content": f"Give me 10 research papers about: {query}. Include valid DOI links or URLs to the papers where available.", + }, + ], + ) + return response.choices[0].message.content + except Exception as e: + return f"Error getting recommendations: {str(e)}" + + +def analyze_research_gaps(papers): + """Analyze gaps in research based on recommended papers""" + try: + response = client.chat.completions.create( + model="gpt-3.5-turbo", + messages=[ + { + "role": "system", + "content": "You are a research analysis expert. Based on the provided papers, identify potential research gaps and future research directions.", + }, + { + "role": "user", + "content": f"Based on these papers, what are the key areas that need more research?\n\nPapers:\n{papers}", + }, + ], + ) + return response.choices[0].message.content + except Exception as e: + return f"Error analyzing research gaps: {str(e)}" + + +def init_session_state(): + """Initialize session state variables""" + if "authenticated" not in st.session_state: + st.session_state.authenticated = False + if "user_id" not in st.session_state: + st.session_state.user_id = None + if "user_type" not in st.session_state: + st.session_state.user_type = None + if "username" not in st.session_state: + st.session_state.username = None + if "selected_course" not in st.session_state: + st.session_state.selected_course = None + if "show_create_course_form" not in st.session_state: + st.session_state.show_create_course_form = False + if "show_create_session_form" not in st.session_state: + st.session_state.show_create_session_form = False + if "show_enroll_course_page" not in st.session_state: + st.session_state.show_enroll_course_page = False + if "course_to_enroll" not in st.session_state: + st.session_state.course_to_enroll = None + +def login_user(username, password, user_type): + """Login user based on credentials""" + if user_type == "student": + # user = students_collection.find_one({"full_name": username}) or students_collection.find_one({"username": username}) + user = students_collection.find_one({"$or": [{"full_name": username}, {"username": username}]}) + elif user_type == "faculty": + user = faculty_collection.find_one({"full_name": username}) + elif user_type == "research_assistant": + user = research_assistants_collection.find_one({"full_name": username}) + elif user_type == "analyst": + user = analysts_collection.find_one({"full_name": username}) + + if user and check_password_hash(user["password"], password): + st.session_state.user_id = user["_id"] + print(st.session_state.user_id) + st.session_state.authenticated = True + st.session_state.user_type = user_type + st.session_state.username = username + return True + return False + +# def login_form(): +# """Display login form""" +# st.title("Welcome to NOVAScholar") + +# with st.form("login_form"): + +# user_type = st.selectbox( +# "Please select your Role", ["student", "faculty", "research_assistant", "analyst"] +# ) +# username = st.text_input("Username") +# password = st.text_input("Password", type="password") +# submit = st.form_submit_button("Login") + +# if submit: +# if login_user(username, password, user_type): +# st.success("Login successful!") +# st.rerun() +# else: +# st.error("Invalid credentials!") +def login_form(): + """Display enhanced login form""" + st.title("Welcome to NOVAScholar") + + with st.form("login_form"): + # Role selection at the top + user_type = st.selectbox( + "Please select your Role", + ["student", "faculty", "research_assistant", "analyst"] + ) + + # Username/email and password stacked vertically + username = st.text_input("Username or Email") + password = st.text_input("Password", type="password") + + # Login button + submit = st.form_submit_button("Login") + + if submit: + # Handle both username and email login + if '@' in username: + username = extract_username(username) + + if login_user(username, password, user_type): + st.success("Login successful!") + st.rerun() + else: + st.error("Invalid credentials!") + +def get_courses(username, user_type): + if user_type == "student": + student = students_collection.find_one({"$or": [{"full_name": username}, {"username": username}]}) + if student: + enrolled_course_ids = [ + course["course_id"] for course in student.get("enrolled_courses", []) + ] + courses = courses_collection.find( + {"course_id": {"$in": enrolled_course_ids}} + ) + # courses += courses_collection2.find( + # {"course_id": {"$in": enrolled_course_ids}} + # ) + # # course_titles = [course['title'] for course in courses] + # return list(courses) + # courses_cursor1 = courses_collection.find( + # {"course_id": {"$in": enrolled_course_ids}} + # ) + # courses_cursor2 = courses_collection2.find( + # {"course_id": {"$in": enrolled_course_ids}} + # ) + # courses = list(courses_cursor1) + list(courses_cursor2) + return list(courses) + elif user_type == "faculty": + faculty = faculty_collection.find_one({"full_name": username}) + if faculty: + course_ids = [ + course["course_id"] for course in faculty.get("courses_taught", []) + ] + # courses_1 = list(courses_collection2.find({"course_id": {"$in": course_ids}})) + courses_2 = list(courses_collection.find({"course_id": {"$in": course_ids}})) + return courses_2 + elif user_type == "research_assistant": + research_assistant = research_assistants_collection.find_one( + {"full_name": username} + ) + if research_assistant: + course_ids = [ + course["course_id"] + for course in research_assistant.get("courses_assisted", []) + ] + courses = courses_collection2.find({"course_id": {"$in": course_ids}}) + return list(courses) + else: + return [] + + +def get_course_ids(): + """Get course IDs for sample courses""" + return [course["course_id"] for course in SAMPLE_COURSES] + + +def get_sessions(course_id, course_title): + """Get sessions for a given course ID""" + course = courses_collection.find_one({"course_id": course_id, "title": course_title}) + if course: + return course.get("sessions", []) + return [] + + +def create_session(new_session, course_id): + """Create a new session for a given course ID""" + course = courses_collection2.find_one({"course_id": course_id}) | courses_collection.find_one({"course_id": course_id}) + if course: + last_session_id = max((session["session_id"] for session in course["sessions"])) + last_session_id = int(last_session_id[1:]) + new_session_id = last_session_id + 1 + new_session["session_id"] = "S" + str(new_session_id) + courses_collection2.update_one( + {"course_id": new_session["course_id"]}, + {"$push": {"sessions": new_session}}, + ) + return True + return False + + +def create_session_form(course_id): + """Display form to create a new session and perform the creation operation""" + st.title("Create New Session") + + if 'session_time' not in st.session_state: + st.session_state.session_time = datetime.now().time() + if 'show_create_session_form' not in st.session_state: + st.session_state.show_create_session_form = False + + with st.form("create_session_form"): + session_title = st.text_input("Session Title") + session_date = st.date_input("Session Date", date.today(), key="session_date") + session_time = st.time_input( + "Session Time", st.session_state.session_time, key="session_time" + ) + + new_session_id = None + # Generate new session ID + course = courses_collection2.find_one({"course_id": course_id}) + if course and "sessions" in course and course["sessions"]: + last_session_id = max( + int(session["session_id"][1:]) for session in course["sessions"] + ) + new_session_id = last_session_id + 1 + else: + new_session_id = 1 + + if st.form_submit_button("Create Session"): + clicked = True + new_session = { + "session_id": f"S{new_session_id}", + "course_id": course_id, + "title": session_title, + "date": datetime.combine(session_date, session_time), + "status": "upcoming", + "created_at": datetime.utcnow(), + "pre_class": { + "resources": [], + "completetion_required": True, + }, + "in_class": { + "topics": [], + "quiz": {"title": "", "questions": 0, "duration": 0}, + "polls": [], + }, + "post_class": { + "assignments": [], + }, + } + courses_collection2.update_one( + {"course_id": course_id}, {"$push": {"sessions": new_session}} + ) + st.success("Session created successfully!") + st.session_state.show_create_session_form = False + + # new_session_id = None + # creation_success = False + # # Generate new session ID + # course = courses_collection2.find_one({"course_id": course_id}) + # if course and 'sessions' in course and course['sessions']: + # last_session_id = max((session['session_id'] for session in course['sessions'])) + # last_session_id = int(last_session_id[1:]) + # new_session_id = last_session_id + 1 + # else: + # new_session_id = 1 + + # new_session = { + # "session_id": 'S' + new_session_id, + # "title": session_title, + # "date": datetime.datetime.combine(session_date, session_time).isoformat(), + # "status": "upcoming", + # "created_at": datetime.datetime.utcnow().isoformat(), + # "pre_class": { + # "resources": [], + # "completetion_required": True, + # }, + # "in_class": { + # "topics": [], + # "quiz": + # { + # "title": '', + # "questions": 0, + # "duration": 0 + # }, + # "polls": [] + # }, + # "post_class": { + # "assignments": [], + # } + # } + # courses_collection2.update_one( + # {"course_id": course_id}, + # {"$push": {"sessions": new_session}} + # ) + # creation_success = True + # st.form_submit_button("Create Session") + # if creation_success == True: + # st.success("Session created successfully!") + # else: + + +def get_new_student_id(): + """Generate a new student ID by incrementing the last student ID""" + last_student = students_collection.find_one(sort=[("SID", -1)]) + if last_student: + last_student_id = int(last_student["SID"][1:]) + new_student_id = f"S{last_student_id + 1}" + else: + new_student_id = "S101" + return new_student_id + + +def get_new_faculty_id(): + """Generate a new faculty ID by incrementing the last faculty ID""" + last_faculty = faculty_collection.find_one(sort=[("TID", -1)]) + if last_faculty: + last_faculty_id = int(last_faculty["TID"][1:]) + new_faculty_id = f"T{last_faculty_id + 1}" + else: + new_faculty_id = "T101" + return new_faculty_id + + +def get_new_course_id(): + """Generate a new course ID by incrementing the last course ID""" + last_course = courses_collection2.find_one(sort=[("course_id", -1)]) + if last_course: + last_course_id = int(last_course["course_id"][2:]) + new_course_id = f"CS{last_course_id + 1}" + else: + new_course_id = "CS101" + return new_course_id + + +# def register_page(): +# st.title("Register") +# if "user_type" not in st.session_state: +# st.session_state.user_type = "student" + +# # Select user type +# st.session_state.user_type = st.selectbox( +# "Select User Type", ["student", "faculty", "research_assistant"] +# ) +# user_type = st.session_state.user_type +# print(user_type) + +# with st.form("register_form"): +# # user_type = st.selectbox("Select User Type", ["student", "faculty", "research_assistant"]) +# # print(user_type) +# full_name = st.text_input("Full Name") +# password = st.text_input("Password", type="password") +# confirm_password = st.text_input("Confirm Password", type="password") + +# if user_type == "student": +# # Fetch courses for students to select from +# courses = list(courses_collection2.find({}, {"course_id": 1, "title": 1})) +# course_options = [ +# f"{course['title']} ({course['course_id']})" for course in courses +# ] +# selected_courses = st.multiselect("Available Courses", course_options) + +# submit = st.form_submit_button("Register") + +# if submit: +# if password == confirm_password: +# hashed_password = generate_password_hash(password) +# if user_type == "student": +# new_student_id = get_new_student_id() +# enrolled_courses = [ +# { +# "course_id": course.split("(")[-1][:-1], +# "title": course.split(" (")[0], +# } +# for course in selected_courses +# ] +# students_collection.insert_one( +# { +# "SID": new_student_id, +# "full_name": full_name, +# "password": hashed_password, +# "enrolled_courses": enrolled_courses, +# "created_at": datetime.utcnow(), +# } +# ) +# st.success( +# f"Student registered successfully with ID: {new_student_id}" +# ) +# elif user_type == "faculty": +# new_faculty_id = get_new_faculty_id() +# faculty_collection.insert_one( +# { +# "TID": new_faculty_id, +# "full_name": full_name, +# "password": hashed_password, +# "courses_taught": [], +# "created_at": datetime.utcnow(), +# } +# ) +# st.success( +# f"Faculty registered successfully with ID: {new_faculty_id}" +# ) +# elif user_type == "research_assistant": +# research_assistants_collection.insert_one( +# { +# "full_name": full_name, +# "password": hashed_password, +# "created_at": datetime.utcnow(), +# } +# ) +# st.success("Research Assistant registered successfully!") +# else: +# st.error("Passwords do not match") + + +def get_new_analyst_id(): + """Generate a new analyst ID by incrementing the last analyst ID""" + last_analyst = analysts_collection.find_one(sort=[("AID", -1)]) + if last_analyst: + last_id = int(last_analyst["AID"][1:]) + new_id = f"A{last_id + 1}" + else: + new_id = "A1" + return new_id + + +# def register_page(): +# st.title("Register") +# if "user_type" not in st.session_state: +# st.session_state.user_type = "student" + +# # Select user type +# st.session_state.user_type = st.selectbox( +# "Please select your Role", ["student", "faculty", "research_assistant", "analyst"] +# ) +# user_type = st.session_state.user_type +# print(user_type) + +# with st.form("register_form"): + +# full_name = st.text_input("Full Name") +# password = st.text_input("Password", type="password") +# confirm_password = st.text_input("Confirm Password", type="password") + +# if user_type == "student": +# # Fetch courses for students to select from +# courses = list(courses_collection.find({}, {"course_id": 1, "title": 1})) +# course_options = [ +# f"{course['title']} ({course['course_id']})" for course in courses +# ] +# selected_courses = st.multiselect("Available Courses", course_options) + +# submit = st.form_submit_button("Register") + +# if submit: +# if password == confirm_password: +# hashed_password = generate_password_hash(password) +# if user_type == "student": +# new_student_id = get_new_student_id() +# enrolled_courses = [ +# { +# "course_id": course.split("(")[-1][:-1], +# "title": course.split(" (")[0], +# } +# for course in selected_courses +# ] +# students_collection.insert_one( +# { +# "SID": new_student_id, +# "full_name": full_name, +# "password": hashed_password, +# "enrolled_courses": enrolled_courses, +# "created_at": datetime.utcnow(), +# } +# ) +# st.success( +# f"Student registered successfully with ID: {new_student_id}" +# ) +# elif user_type == "faculty": +# new_faculty_id = get_new_faculty_id() +# faculty_collection.insert_one( +# { +# "TID": new_faculty_id, +# "full_name": full_name, +# "password": hashed_password, +# "courses_taught": [], +# "created_at": datetime.utcnow(), +# } +# ) +# st.success( +# f"Faculty registered successfully with ID: {new_faculty_id}" +# ) +# elif user_type == "research_assistant": +# research_assistants_collection.insert_one( +# { +# "full_name": full_name, +# "password": hashed_password, +# "created_at": datetime.utcnow(), +# } +# ) +# st.success("Research Assistant registered successfully!") +# elif user_type == "analyst": +# # new_analyst_id = get_new_analyst_id() +# analysts_collection.insert_one( +# { +# # "AID": new_analyst_id, +# "full_name": full_name, +# "password": hashed_password, +# "created_at": datetime.utcnow(), +# } +# ) +# st.success("Analyst registered successfully!") +# else: +# st.error("Passwords do not match") +def register_page(): + st.title("Register for NOVAScholar") + if "user_type" not in st.session_state: + st.session_state.user_type = "student" + + # Select user type + st.session_state.user_type = st.selectbox( + "Please select your Role", + ["student", "faculty", "research_assistant", "analyst"] + ) + user_type = st.session_state.user_type + + with st.form("register_form"): + col1, col2 = st.columns(2) + + with col1: + full_name = st.text_input("Full Name") + email = st.text_input("Institutional Email") + phone = st.text_input("Phone Number") + + with col2: + password = st.text_input("Password", type="password") + confirm_password = st.text_input("Confirm Password", type="password") + + if user_type == "student": + courses = list(courses_collection.find({}, {"course_id": 1, "title": 1})) + course_options = [f"{course['title']} ({course['course_id']})" for course in courses] + selected_courses = st.multiselect("Available Courses", course_options) + + submit = st.form_submit_button("Register") + + if submit: + # Validate email + email_valid, email_msg = validate_email(email) + if not email_valid: + st.error(email_msg) + return + + # Validate phone + phone_valid, phone_msg = validate_phone(phone) + if not phone_valid: + st.error(phone_msg) + return + + # Validate password match + if password != confirm_password: + st.error("Passwords do not match") + return + + # Extract username from email + username = extract_username(email) + + # Check if username already exists + if user_type == "student": + existing_user = students_collection.find_one({"username": username}) + elif user_type == "faculty": + existing_user = faculty_collection.find_one({"username": username}) + elif user_type == "research_assistant": + existing_user = research_assistants_collection.find_one({"username": username}) + elif user_type == "analyst": + existing_user = analysts_collection.find_one({"username": username}) + + if existing_user: + st.error("A user with this email already exists") + return + + # Hash password and create user + hashed_password = generate_password_hash(password) + + user_data = { + "username": username, + "full_name": full_name, + "email": email, + "phone": phone, + "password": hashed_password, + "created_at": datetime.utcnow() + } + + if user_type == "student": + new_student_id = get_new_student_id() + enrolled_courses = [ + { + "course_id": course.split("(")[-1][:-1], + "title": course.split(" (")[0], + } + for course in selected_courses + ] + user_data["SID"] = new_student_id + user_data["enrolled_courses"] = enrolled_courses + students_collection.insert_one(user_data) + st.success(f"Student registered successfully! Your username is: {username}") + + elif user_type == "faculty": + new_faculty_id = get_new_faculty_id() + user_data["TID"] = new_faculty_id + user_data["courses_taught"] = [] + faculty_collection.insert_one(user_data) + st.success(f"Faculty registered successfully! Your username is: {username}") + + elif user_type == "research_assistant": + research_assistants_collection.insert_one(user_data) + st.success(f"Research Assistant registered successfully! Your username is: {username}") + + elif user_type == "analyst": + analysts_collection.insert_one(user_data) + st.success(f"Analyst registered successfully! Your username is: {username}") + +# Create Course feature +# def create_course_form2(faculty_name, faculty_id): +# """Display enhanced form to create a new course with AI-generated content""" +# st.title("Create New Course") + +# if 'course_plan' not in st.session_state: +# st.session_state.course_plan = None +# if 'edit_mode' not in st.session_state: +# st.session_state.edit_mode = False + +# # Initial Course Creation Form +# if not st.session_state.course_plan: +# with st.form("initial_course_form"): +# col1, col2 = st.columns(2) +# with col1: +# course_name = st.text_input("Course Name", placeholder="e.g., Introduction to Computer Science") +# faculty_info = st.text_input("Faculty", value=faculty_name, disabled=True) +# with col2: +# duration_weeks = st.number_input("Duration (weeks)", min_value=1, max_value=16, value=12) +# start_date = st.date_input("Start Date") + +# generate_button = st.form_submit_button("Generate Course Structure", use_container_width=True) + +# if generate_button and course_name: +# with st.spinner("Generating course structure..."): +# try: +# course_plan = generate_perplexity_response(PERPLEXITY_API_KEY, course_name) +# # print(course_plan) +# st.session_state.course_plan = json.loads(course_plan) +# st.session_state.start_date = start_date +# st.session_state.duration_weeks = duration_weeks +# st.rerun() +# except Exception as e: +# st.error(f"Error generating course structure: {e}") + +# # Display and Edit Generated Course Content +# if st.session_state.course_plan: +# with st.expander("Course Overview", expanded=True): +# if not st.session_state.edit_mode: +# st.subheader(st.session_state.course_plan['course_title']) +# st.write(st.session_state.course_plan['course_description']) +# edit_button = st.button("Edit Course Details", use_container_width=True) +# if edit_button: +# st.session_state.edit_mode = True +# st.rerun() +# else: +# with st.form("edit_course_details"): +# st.session_state.course_plan['course_title'] = st.text_input( +# "Course Title", +# value=st.session_state.course_plan['course_title'] +# ) +# st.session_state.course_plan['course_description'] = st.text_area( +# "Course Description", +# value=st.session_state.course_plan['course_description'] +# ) +# if st.form_submit_button("Save Course Details"): +# st.session_state.edit_mode = False +# st.rerun() + +# # Display Modules and Sessions +# st.subheader("Course Modules and Sessions") + +# start_date = st.session_state.start_date +# current_date = start_date + +# all_sessions = [] +# for module_idx, module in enumerate(st.session_state.course_plan['modules']): +# with st.expander(f"📚 Module {module_idx + 1}: {module['module_title']}", expanded=True): +# # Edit module title +# new_module_title = st.text_input( +# f"Module {module_idx + 1} Title", +# value=module['module_title'], +# key=f"module_{module_idx}" +# ) +# module['module_title'] = new_module_title + +# for sub_idx, sub_module in enumerate(module['sub_modules']): +# st.markdown(f"### 📖 {sub_module['title']}") + +# # Create sessions for each topic +# for topic_idx, topic in enumerate(sub_module['topics']): +# session_key = f"session_{module_idx}_{sub_idx}_{topic_idx}" + +# with st.container(): +# col1, col2, col3 = st.columns([3, 2, 1]) +# with col1: +# new_topic = st.text_input( +# "Topic", +# value=topic, +# key=f"{session_key}_topic" +# ) +# sub_module['topics'][topic_idx] = new_topic + +# with col2: +# session_date = st.date_input( +# "Session Date", +# value=current_date, +# key=f"{session_key}_date" +# ) + +# with col3: +# session_status = st.selectbox( +# "Status", +# options=["upcoming", "in-progress", "completed"], +# key=f"{session_key}_status" +# ) + +# # Create session object +# session = { +# "session_id": str(ObjectId()), +# "title": new_topic, +# "date": datetime.combine(session_date, datetime.min.time()), +# "status": session_status, +# "module_name": module['module_title'], +# "created_at": datetime.utcnow(), +# "pre_class": { +# "resources": [], +# "completion_required": True +# }, +# "in_class": { +# "quiz": [], +# "polls": [] +# }, +# "post_class": { +# "assignments": [] +# } +# } +# all_sessions.append(session) +# current_date = session_date + timedelta(days=7) + +# new_course_id = get_new_course_id() +# course_title = st.session_state.course_plan['course_title'] +# # Final Save Button +# if st.button("Save Course", type="primary", use_container_width=True): +# try: +# course_doc = { +# "course_id": new_course_id, +# "title": course_title, +# "description": st.session_state.course_plan['course_description'], +# "faculty": faculty_name, +# "faculty_id": faculty_id, +# "duration": f"{st.session_state.duration_weeks} weeks", +# "start_date": datetime.combine(st.session_state.start_date, datetime.min.time()), +# "created_at": datetime.utcnow(), +# "sessions": all_sessions +# } + +# # Insert into database +# courses_collection.insert_one(course_doc) + +# st.success("Course successfully created!") + +# # Update faculty collection +# faculty_collection.update_one( +# {"_id": st.session_state.user_id}, +# { +# "$push": { +# "courses_taught": { +# "course_id": new_course_id, +# "title": course_title, +# } +# } +# }, +# ) + +# # Clear session state +# st.session_state.course_plan = None +# st.session_state.edit_mode = False + +# # Optional: Add a button to view the created course +# if st.button("View Course"): +# # Add navigation logic here +# pass + +# except Exception as e: +# st.error(f"Error saving course: {e}") + + +def remove_json_backticks(json_string): + """Remove backticks and 'json' from the JSON object string""" + return json_string.replace("```json", "").replace("```", "").strip() + + +# def create_course_form(faculty_name, faculty_id): +# """Display enhanced form to create a new course with AI-generated content and resources""" + +# st.title("Create New Course") + +# if 'course_plan' not in st.session_state: +# st.session_state.course_plan = None +# if 'edit_mode' not in st.session_state: +# st.session_state.edit_mode = False +# if 'resources_map' not in st.session_state: +# st.session_state.resources_map = {} +# if 'start_date' not in st.session_state: +# st.session_state.start_date = None +# if 'duration_weeks' not in st.session_state: +# st.session_state.duration_weeks = None +# if 'sessions_per_week' not in st.session_state: +# st.session_state.sessions_per_week = None + + +# # Initial Course Creation Form +# if not st.session_state.course_plan: +# with st.form("initial_course_form"): +# col1, col2 = st.columns(2) +# with col1: +# course_name = st.text_input("Course Name", placeholder="e.g., Introduction to Computer Science") +# faculty_info = st.text_input("Faculty", value=faculty_name, disabled=True) +# sessions_per_week = st.number_input("Sessions Per Week", min_value=1, max_value=5, value=2) +# with col2: +# duration_weeks = st.number_input("Duration (weeks)", min_value=1, max_value=16, value=12) +# start_date = st.date_input("Start Date") + +# generate_button = st.form_submit_button("Generate Course Structure", use_container_width=True) + +# if generate_button and course_name: +# with st.spinner("Generating course structure and resources..."): +# try: +# # Generate course plan with resources +# course_plan = generate_perplexity_response( +# PERPLEXITY_API_KEY, +# course_name, +# duration_weeks, +# sessions_per_week +# ) +# try: +# course_plan_json = json.loads(course_plan) +# validate_course_plan(course_plan_json) +# st.session_state.course_plan = course_plan_json +# except (json.JSONDecodeError, ValueError) as e: +# st.error(f"Error in course plan structure: {e}") +# return +# st.session_state.start_date = start_date +# st.session_state.duration_weeks = duration_weeks +# st.session_state.sessions_per_week = sessions_per_week + +# # Generate resources for all sessions +# session_titles = [] +# for module in st.session_state.course_plan['modules']: +# for sub_module in module['sub_modules']: +# for topic in sub_module['topics']: +# # session_titles.append(topic['title']) +# # session_titles.append(topic) +# if isinstance(topic, dict): +# session_titles.append(topic['title']) +# else: +# session_titles.append(topic) +# # In generate_session_resources function, add validation: +# if not session_titles: +# return json.dumps({"session_resources": []}) +# resources_response = generate_session_resources(PERPLEXITY_API_KEY, session_titles) +# without_backticks = remove_json_backticks(resources_response) +# resources = json.loads(without_backticks) +# st.session_state.resources_map = { +# resource['session_title']: resource['resources'] +# for resource in resources['session_resources'] +# } +# # Add error handling for the resources map +# # if st.session_state.resources_map is None: +# # st.session_state.resources_map = {} + +# st.rerun() +# except Exception as e: +# st.error(f"Error generating course structure: {e}") + +# # Display and Edit Generated Course Content +# if st.session_state.course_plan: +# with st.expander("Course Overview", expanded=True): +# if not st.session_state.edit_mode: +# st.subheader(st.session_state.course_plan['course_title']) +# st.write(st.session_state.course_plan['course_description']) +# col1, col2, col3 = st.columns(3) +# with col1: +# st.write(f"**Start Date:** {st.session_state.start_date}") +# with col2: +# st.write(f"**Duration (weeks):** {st.session_state.duration_weeks}") +# with col3: +# st.write(f"**Sessions Per Week:** {st.session_state.sessions_per_week}") + +# edit_button = st.button("Edit Course Details", use_container_width=True) +# if edit_button: +# st.session_state.edit_mode = True +# st.rerun() +# else: +# with st.form("edit_course_details"): +# st.session_state.course_plan['course_title'] = st.text_input( +# "Course Title", +# value=st.session_state.course_plan['course_title'] +# ) +# st.session_state.course_plan['course_description'] = st.text_area( +# "Course Description", +# value=st.session_state.course_plan['course_description'] +# ) +# if st.form_submit_button("Save Course Details"): +# st.session_state.edit_mode = False +# st.rerun() + +# # Display Modules and Sessions +# st.subheader("Course Modules and Sessions") + +# start_date = st.session_state.start_date +# current_date = start_date + +# all_sessions = [] +# for module_idx, module in enumerate(st.session_state.course_plan['modules']): +# with st.expander(f"📚 Module {module_idx + 1}: {module['module_title']}", expanded=True): +# # Edit module title +# new_module_title = st.text_input( +# f"Edit Module Title", +# value=module['module_title'], +# key=f"module_{module_idx}" +# ) +# module['module_title'] = new_module_title + +# for sub_idx, sub_module in enumerate(module['sub_modules']): +# st.markdown("
", unsafe_allow_html=True) # Add gap between sessions +# # st.markdown(f"### 📖 {sub_module['title']}") +# st.markdown(f'

📖 Chapter {sub_idx + 1}: {sub_module["title"]}

', unsafe_allow_html=True) +# # Possible fix: +# # Inside the loop where topics are being processed: + +# for topic_idx, topic in enumerate(sub_module['topics']): +# st.markdown("
", unsafe_allow_html=True) # Add gap between sessions +# session_key = f"session_{module_idx}_{sub_idx}_{topic_idx}" + +# # Get topic title based on type +# if isinstance(topic, dict): +# current_topic_title = topic.get('title', '') +# current_topic_display = current_topic_title +# else: +# current_topic_title = str(topic) +# current_topic_display = current_topic_title + +# with st.container(): +# # Session Details +# col1, col2, col3 = st.columns([3, 2, 1]) +# with col1: +# new_topic = st.text_input( +# f"Session {topic_idx + 1} Title", +# value=current_topic_display, +# key=f"{session_key}_topic" +# ) +# # Update the topic in the data structure +# if isinstance(topic, dict): +# topic['title'] = new_topic +# else: +# sub_module['topics'][topic_idx] = new_topic + +# with col2: +# session_date = st.date_input( +# "Session Date", +# value=current_date, +# key=f"{session_key}_date" +# ) + +# with col3: +# session_status = st.selectbox( +# "Status", +# options=["upcoming", "in-progress", "completed"], +# key=f"{session_key}_status" +# ) + +# # Display Resources +# if st.session_state.resources_map: +# # Try both the full topic title and the display title +# resources = None +# if isinstance(topic, dict) and topic.get('title') in st.session_state.resources_map: +# resources = st.session_state.resources_map[topic['title']] +# elif current_topic_title in st.session_state.resources_map: +# resources = st.session_state.resources_map[current_topic_title] + +# if resources: +# with st.container(): +# # st.markdown("#### 📚 Session Resources") +# st.markdown(f'

📚 Session Resources

', unsafe_allow_html=True) +# # Readings Tab +# if resources.get('readings'): +# st.markdown(f'
📖 External Resources
', unsafe_allow_html=True) +# col1, col2 = st.columns(2) +# for idx, reading in enumerate(resources['readings']): +# with col1 if idx % 2 == 0 else col2: +# st.markdown(f""" +# - **{reading['title']}** +# - Type: {reading['type']} +# - Estimated reading time: {reading['estimated_read_time']} +# - [Access Resource]({reading['url']}) +# """) + +# # Books Tab and Additional Resources Tab side-by-side +# col1, col2 = st.columns(2) + +# with col1: +# if resources.get('books'): +# st.markdown(f'
📚 Reference Books
', unsafe_allow_html=True) +# for book in resources['books']: +# with st.container(): +# st.markdown(f""" +# - **{book['title']}** +# - Author: {book['author']} +# - ISBN: {book['isbn']} +# - Chapters: {book['chapters']} +# """) + +# with col2: +# if resources.get('additional_resources'): +# st.markdown(f'
🔗 Additional Study Resources
', unsafe_allow_html=True) +# for resource in resources['additional_resources']: +# with st.container(): +# st.markdown(f""" +# - **{resource['title']}** +# - Type: {resource['type']} +# - Description: {resource['description']} +# - [Access Resource]({resource['url']}) +# """) + +# # Create session object +# session = { +# "session_id": str(ObjectId()), +# "title": new_topic, +# "date": datetime.combine(session_date, datetime.min.time()), +# "status": session_status, +# "module_name": module['module_title'], +# "created_at": datetime.utcnow(), +# "pre_class": { +# "resources": [], +# "completion_required": True +# }, +# "in_class": { +# "quiz": [], +# "polls": [] +# }, +# "post_class": { +# "assignments": [] +# }, +# "external_resources": st.session_state.resources_map.get(current_topic_title, {}) +# } +# all_sessions.append(session) +# current_date = session_date + timedelta(days=7) + + +# new_course_id = get_new_course_id() +# course_title = st.session_state.course_plan['course_title'] + +# # Final Save Button +# if st.button("Save Course", type="primary", use_container_width=True): +# try: +# course_doc = { +# "course_id": new_course_id, +# "title": course_title, +# "description": st.session_state.course_plan['course_description'], +# "faculty": faculty_name, +# "faculty_id": faculty_id, +# "duration": f"{st.session_state.duration_weeks} weeks", +# "sessions_per_week": st.session_state.sessions_per_week, +# "start_date": datetime.combine(st.session_state.start_date, datetime.min.time()), +# "created_at": datetime.utcnow(), +# "sessions": all_sessions +# } + +# # Insert into database +# courses_collection.insert_one(course_doc) +# st.success("Course successfully created!") + +# # Update faculty collection +# faculty_collection.update_one( +# {"_id": st.session_state.user_id}, +# { +# "$push": { +# "courses_taught": { +# "course_id": new_course_id, +# "title": course_title, +# } +# } +# } +# ) + +# # Clear session state +# st.session_state.course_plan = None +# st.session_state.edit_mode = False +# st.session_state.resources_map = {} + +# # Optional: Add a button to view the created course +# if st.button("View Course"): +# # Add navigation logic here +# pass + +# except Exception as e: +# st.error(f"Error saving course: {e}") + + +def create_course_form(faculty_name, faculty_id): + """Display enhanced form to create a new course with AI-generated content and faculty validation""" + + st.title("Create New Course - Outcome Based Approach") + + # Initialize session states + if 'current_step' not in st.session_state: + st.session_state.current_step = 1 + if 'course_details' not in st.session_state: + st.session_state.course_details = None + if 'course_outcomes' not in st.session_state: + st.session_state.course_outcomes = None + if 'module_outcomes' not in st.session_state: + st.session_state.module_outcomes = None + if 'submodule_outcomes' not in st.session_state: + st.session_state.submodule_outcomes = None + + # Step 1: Initial Course Details + if st.session_state.current_step == 1: + st.subheader("Step 1: Course Details") + with st.form("initial_course_form"): + col1, col2 = st.columns(2) + with col1: + course_name = st.text_input("Course Name", placeholder="e.g., Introduction to Computer Science") + faculty_info = st.text_input("Faculty", value=faculty_name, disabled=True) + sessions_per_week = st.number_input("Sessions Per Week", min_value=1, max_value=5, value=2) + with col2: + duration_weeks = st.number_input("Duration (weeks)", min_value=1, max_value=16, value=12) + start_date = st.date_input("Start Date") + + if st.form_submit_button("Generate Course Outcomes", use_container_width=True): + if course_name: + with st.spinner("Generating course outcomes..."): + try: + # Store course details + st.session_state.course_details = { + "name": course_name, + "faculty": faculty_name, + "duration": duration_weeks, + "sessions_per_week": sessions_per_week, + "start_date": start_date + } + + # Generate course outcomes + outcomes = generate_course_outcomes( + GEMINI_API_KEY, + course_name, + duration_weeks, + sessions_per_week + ) + st.session_state.course_outcomes = json.loads(outcomes) + st.session_state.current_step = 2 + st.rerun() + except Exception as e: + st.error(f"Error generating course outcomes: {e}") + else: + st.error("Please enter a course name") + + # Step 2: Course Outcomes Validation + elif st.session_state.current_step == 2: + st.subheader("Step 2: Course Learning Outcomes (CLOs)") + + with st.expander("Course Details", expanded=True): + col1, col2, col3 = st.columns(3) + with col1: + st.write(f"**Course:** {st.session_state.course_details['name']}") + with col2: + st.write(f"**Duration:** {st.session_state.course_details['duration']} weeks") + with col3: + st.write(f"**Sessions/Week:** {st.session_state.course_details['sessions_per_week']}") + + st.write("Please review and validate the generated course outcomes:") + + # Display and edit course description + st.text_area( + "Course Description", + value=st.session_state.course_outcomes['course_description'], + key="course_description", + height=100 + ) + + st.markdown("### Course Learning Outcomes") + + # Display existing outcomes with edit/delete capabilities + outcomes = st.session_state.course_outcomes['learning_outcomes'] + for i, outcome in enumerate(outcomes): + col1, col2, col3 = st.columns([6, 2, 1]) + with col1: + outcomes[i]['outcome_description'] = st.text_area( + f"CO{i+1}", + value=outcome['outcome_description'], + key=f"co_{i}", + height=100 + ) + with col2: + outcomes[i]['aligned_blooms_taxonomy_level'] = st.selectbox( + "Bloom's Level", + ["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"], + index=["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"].index(outcome['aligned_blooms_taxonomy_level']), + key=f"bloom_{i}" + ) + with col3: + if st.button("🗑️", key=f"delete_co_{i}"): + outcomes.pop(i) + st.rerun() + + # Add new outcome + st.markdown("### Add New Outcome") + with st.form("add_outcome"): + new_outcome = st.text_area("Outcome Description", placeholder="Enter new course outcome...") + col1, col2 = st.columns([2, 1]) + with col1: + bloom_level = st.selectbox( + "Bloom's Taxonomy Level", + ["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"] + ) + with col2: + if st.form_submit_button("Add Outcome", use_container_width=True): + if new_outcome: + outcomes.append({ + "outcome_number": f"CO{len(outcomes)+1}", + "outcome_description": new_outcome, + "aligned_blooms_taxonomy_level": bloom_level + }) + st.rerun() + + col1, col2 = st.columns(2) + with col1: + if st.button("⬅️ Back to Course Details", use_container_width=True): + st.session_state.current_step = 1 + st.rerun() + with col2: + if st.button("Generate Module Outcomes ➡️", use_container_width=True): + with st.spinner("Generating module outcomes..."): + try: + module_outcomes = generate_module_outcomes( + st.session_state.course_details['name'], + json.dumps(st.session_state.course_outcomes), + st.session_state.course_details['duration'], + st.session_state.course_details['sessions_per_week'] + ) + st.session_state.module_outcomes = json.loads(module_outcomes) + st.session_state.current_step = 3 + st.rerun() + except Exception as e: + st.error(f"Error generating module outcomes: {e}") + + # Step 3: Module Outcomes Validation + elif st.session_state.current_step == 3: + st.subheader("Step 3: Module Learning Outcomes (MLOs)") + + modules = st.session_state.module_outcomes['modules'] + + for module_idx, module in enumerate(modules): + with st.expander(f"Module {module_idx + 1}: {module['module_title']}", expanded=True): + # Edit module title and duration + col1, col2 = st.columns([3, 1]) + with col1: + module['module_title'] = st.text_input( + "Module Title", + value=module['module_title'], + key=f"module_title_{module_idx}" + ) + with col2: + module['module_duration_sessions'] = st.number_input( + "Sessions", + min_value=1, + value=module['module_duration_sessions'], + key=f"module_duration_{module_idx}" + ) + + # Display and edit module outcomes + st.markdown("#### Module Learning Outcomes") + for outcome_idx, outcome in enumerate(module['module_learning_outcomes']): + col1, col2, col3 = st.columns([6, 2, 1]) + with col1: + outcome['outcome_description'] = st.text_area( + f"MLO{module_idx+1}.{outcome_idx+1}", + value=outcome['outcome_description'], + key=f"mlo_{module_idx}_{outcome_idx}", + height=100 + ) + with col2: + outcome['aligned_blooms_taxonomy_level'] = st.selectbox( + "Bloom's Level", + ["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"], + index=["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"].index(outcome['aligned_blooms_taxonomy_level']), + key=f"module_bloom_{module_idx}_{outcome_idx}" + ) + with col3: + if st.button("🗑️", key=f"delete_mlo_{module_idx}_{outcome_idx}"): + module['module_learning_outcomes'].pop(outcome_idx) + st.rerun() + + # Add new module outcome + with st.form(f"add_module_outcome_{module_idx}"): + new_outcome = st.text_area("New Module Outcome", placeholder="Enter new module outcome...") + col1, col2 = st.columns([2, 1]) + with col1: + bloom_level = st.selectbox( + "Bloom's Taxonomy Level", + ["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"], + key=f"new_module_bloom_{module_idx}" + ) + with col2: + if st.form_submit_button("Add Outcome", use_container_width=True): + if new_outcome: + module['module_learning_outcomes'].append({ + "outcome_number": f"MLO{module_idx+1}.{len(module['module_learning_outcomes'])+1}", + "outcome_description": new_outcome, + "aligned_blooms_taxonomy_level": bloom_level + }) + st.rerun() + + col1, col2 = st.columns(2) + with col1: + if st.button("⬅️ Back to Course Outcomes", use_container_width=True): + st.session_state.current_step = 2 + st.rerun() + with col2: + if st.button("Generate Submodule Outcomes ➡️", use_container_width=True): + with st.spinner("Generating submodule outcomes..."): + try: + submodule_outcomes = generate_submodule_outcomes( + st.session_state.course_details['name'], + json.dumps(st.session_state.course_outcomes), + json.dumps(st.session_state.module_outcomes), + st.session_state.course_details['duration'], + st.session_state.course_details['sessions_per_week'] + ) + st.session_state.submodule_outcomes = json.loads(submodule_outcomes) + st.session_state.current_step = 4 + st.rerun() + except Exception as e: + st.error(f"Error generating submodule outcomes: {e}") + + # Step 4: Submodule Outcomes Validation + elif st.session_state.current_step == 4: + st.subheader("Step 4: Submodule Learning Outcomes (SMLOs)") + + try: + submodule_outcomes = st.session_state.get('submodule_outcomes', None) + if submodule_outcomes is None: + st.error("Submodule outcomes are not set in the session state.") + elif 'modules' not in submodule_outcomes: + st.error("The 'modules' key is missing in submodule outcomes.") + else: + print("No problem here") + except Exception as e: + st.error(f"Error accessing submodule outcomes: {e}") + + for module_idx, module in enumerate(st.session_state.module_outcomes['modules']): + st.markdown(f"### Module {module_idx + 1}: {module['module_title']}") + + if module_idx < len(st.session_state.submodule_outcomes['modules']): + for submodule_idx, submodule in enumerate(st.session_state.submodule_outcomes['modules'][module_idx]['submodules']): + with st.expander(f"Submodule {module_idx + 1}.{submodule_idx + 1}: {submodule['submodule_title']}", expanded=True): + # Edit submodule title and duration + col1, col2 = st.columns([3, 1]) + with col1: + submodule['submodule_title'] = st.text_input( + "Submodule Title", + value=submodule['submodule_title'], + key=f"submodule_title_{module_idx}_{submodule_idx}" + ) + with col2: + submodule['submodule_duration_sessions'] = st.number_input( + "Sessions", + min_value=1, + value=submodule['submodule_duration_sessions'], + key=f"submodule_duration_{module_idx}_{submodule_idx}" + ) + + # Display and edit submodule outcomes + st.markdown("#### Submodule Learning Outcomes") + for outcome_idx, outcome in enumerate(submodule['submodule_learning_outcomes']): + col1, col2, col3 = st.columns([6, 2, 1]) + with col1: + outcome['outcome_description'] = st.text_area( + f"SMLO{module_idx+1}.{submodule_idx+1}.{outcome_idx+1}", + value=outcome['outcome_description'], + key=f"smlo_{module_idx}_{submodule_idx}_{outcome_idx}", + height=100 + ) + with col2: + outcome['aligned_blooms_taxonomy_level'] = st.selectbox( + "Bloom's Level", + ["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"], + index=["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"].index(outcome['aligned_blooms_taxonomy_level']), + key=f"submodule_bloom_{module_idx}_{submodule_idx}_{outcome_idx}" + ) + with col3: + if st.button("🗑️", key=f"delete_smlo_{module_idx}_{submodule_idx}_{outcome_idx}"): + submodule['submodule_learning_outcomes'].pop(outcome_idx) + st.rerun() + + # Add new submodule outcome + with st.form(f"add_submodule_outcome_{module_idx}_{submodule_idx}"): + new_outcome = st.text_area("New Submodule Outcome", placeholder="Enter new submodule outcome...") + col1, col2 = st.columns([2, 1]) + with col1: + bloom_level = st.selectbox( + "Bloom's Taxonomy Level", + ["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"], + key=f"new_submodule_bloom_{module_idx}_{submodule_idx}" + ) + with col2: + if st.form_submit_button("Add Outcome", use_container_width=True): + if new_outcome: + submodule['submodule_learning_outcomes'].append({ + "outcome_number": f"SMLO{module_idx+1}.{submodule_idx+1}.{len(submodule['submodule_learning_outcomes'])+1}", + "outcome_description": new_outcome, + "aligned_blooms_taxonomy_level": bloom_level + }) + st.rerun() + + # Navigation buttons + col1, col2 = st.columns(2) + with col1: + if st.button("⬅️ Back to Module Outcomes", use_container_width=True): + st.session_state.current_step = 3 + st.rerun() + with col2: + if st.button("Proceed to Sessions Generation ➡️", use_container_width=True): + # Validate total sessions distribution + total_sessions = st.session_state.course_details['duration'] * st.session_state.course_details['sessions_per_week'] + # current_sessions = sum( + # sum(submodule['submodule_duration_sessions'] + # for submodule in module['submodules']) + # for module in st.session_state.module_outcomes['modules'] + # ) + current_sessions = sum( + sum(submodule['submodule_duration_sessions'] + for submodule in st.session_state.submodule_outcomes['modules'][module_idx]['submodules']) + for module_idx in range(len(st.session_state.submodule_outcomes['modules']))) + + if current_sessions != total_sessions: + st.error(f""" + Session distribution mismatch! + Total available sessions: {total_sessions} + Currently allocated sessions: {current_sessions} + Please adjust the session distribution in modules and submodules. + """) + else: + try: + # Merge all outcomes into final structure + final_course_structure = { + "course_title": st.session_state.course_outcomes['course_title'], + "course_description": st.session_state.course_outcomes['course_description'], + "learning_outcomes": st.session_state.course_outcomes['learning_outcomes'], + "modules": st.session_state.module_outcomes['modules'] + } + + # Store in session state for next step + st.session_state.final_course_structure = final_course_structure + st.session_state.current_step = 5 # Move to resources generation + st.rerun() + except Exception as e: + st.error(f"Error finalizing course structure: {e}") + + # Add helper text about session distribution + total_sessions = st.session_state.course_details['duration'] * st.session_state.course_details['sessions_per_week'] + # current_sessions = sum( + # sum(submodule['submodule_duration_sessions'] + # for submodule in module['submodules']) + # for module in st.session_state.module_outcomes['modules'] + # ) + current_sessions = sum( + sum(submodule['submodule_duration_sessions'] + for submodule in st.session_state.submodule_outcomes['modules'][module_idx]['submodules']) + for module_idx in range(len(st.session_state.submodule_outcomes['modules']))) + + st.info(f""" + Session Distribution: + - Total available sessions: {total_sessions} + - Currently allocated sessions: {current_sessions} + - Remaining sessions: {total_sessions - current_sessions} + """) + + # Step 4: Session Outcomes Generation + elif st.session_state.current_step == 5: + st.subheader("Step 5: Session Learning Outcomes (SLOs)") + + # Calculate total sessions for validation + total_sessions = st.session_state.course_details['duration'] * st.session_state.course_details['sessions_per_week'] + + try: + # Generate session outcomes if not already generated + if 'session_outcomes' not in st.session_state: + with st.spinner("Generating session outcomes..."): + session_outcomes = generate_session_outcomes( + st.session_state.course_details['name'], + json.dumps(st.session_state.course_outcomes), + json.dumps(st.session_state.module_outcomes), + json.dumps(st.session_state.submodule_outcomes), + st.session_state.course_details['duration'], + st.session_state.course_details['sessions_per_week'] + ) + st.session_state.session_outcomes = json.loads(session_outcomes) + + # Warning about final edits + st.warning(""" + ⚠️ **Important Notice**: You cannot edit the Session Details after this step. Please ensure all the Session Details are correct. + """) + + # Display and edit session outcomes for each submodule + # for module_idx, module in enumerate(st.session_state.submodule_outcomes['modules']): + # st.markdown(f"### Module {module_idx + 1}: {module['module_title']}") + + # for submodule_idx, submodule in enumerate(module['submodules']): + # with st.expander(f"Submodule {module_idx + 1}.{submodule_idx + 1}: {submodule['submodule_title']}", expanded=True): + # st.markdown(f"#### Sessions ({submodule['submodule_duration_sessions']} allocated)") + + # # Get sessions for this submodule + # sessions = st.session_state.session_outcomes['submodules'][submodule_idx]['sessions'] + + # for session_idx, session in enumerate(sessions): + # with st.expander(f"Session {session_idx + 1}: {session['session_title']}", expanded=True): + # # Edit session details + # session['session_title'] = st.text_input( + # "Session Title", + # value=session['session_title'], + # key=f"session_title_{module_idx}_{submodule_idx}_{session_idx}" + # ) + + # # Prerequisites + # st.markdown("##### Prerequisites") + # prereq_container = st.container() + # for prereq_idx, prereq in enumerate(session['prerequisites']): + # col1, col2 = prereq_container.columns([5, 1]) + # with col1: + # session['prerequisites'][prereq_idx] = st.text_input( + # f"Prerequisite {prereq_idx + 1}", + # value=prereq, + # key=f"prereq_{module_idx}_{submodule_idx}_{session_idx}_{prereq_idx}" + # ) + # with col2: + # if st.button("🗑️", key=f"del_prereq_{module_idx}_{submodule_idx}_{session_idx}_{prereq_idx}"): + # session['prerequisites'].pop(prereq_idx) + # st.rerun() + + # if st.button("Add Prerequisite", key=f"add_prereq_{module_idx}_{submodule_idx}_{session_idx}"): + # session['prerequisites'].append("") + # st.rerun() + + # # Key Concepts + # st.markdown("##### Key Concepts") + # concept_container = st.container() + # for concept_idx, concept in enumerate(session['key_concepts']): + # col1, col2 = concept_container.columns([5, 1]) + # with col1: + # session['key_concepts'][concept_idx] = st.text_input( + # f"Concept {concept_idx + 1}", + # value=concept, + # key=f"concept_{module_idx}_{submodule_idx}_{session_idx}_{concept_idx}" + # ) + # with col2: + # if st.button("🗑️", key=f"del_concept_{module_idx}_{submodule_idx}_{session_idx}_{concept_idx}"): + # session['key_concepts'].pop(concept_idx) + # st.rerun() + + # if st.button("Add Concept", key=f"add_concept_{module_idx}_{submodule_idx}_{session_idx}"): + # session['key_concepts'].append("") + # st.rerun() + + # # Session Learning Outcomes + # st.markdown("##### Session Learning Outcomes") + # for outcome_idx, outcome in enumerate(session['session_learning_outcomes']): + # col1, col2, col3, col4 = st.columns([4, 2, 2, 1]) + # with col1: + # outcome['outcome_description'] = st.text_area( + # f"SLO{session_idx+1}.{outcome_idx+1}", + # value=outcome['outcome_description'], + # key=f"slo_{module_idx}_{submodule_idx}_{session_idx}_{outcome_idx}", + # height=100 + # ) + # with col2: + # outcome['bloom_taxonomy_level'] = st.selectbox( + # "Bloom's Level", + # ["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"], + # index=["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"].index(outcome['bloom_taxonomy_level']), + # key=f"slo_bloom_{module_idx}_{submodule_idx}_{session_idx}_{outcome_idx}" + # ) + # with col3: + # outcome['aligned_smlo'] = st.selectbox( + # "Aligned SMLO", + # [f"SMLO{module_idx+1}.{submodule_idx+1}.{i+1}" for i in range(len(submodule['submodule_learning_outcomes']))], + # index=0, + # key=f"slo_align_{module_idx}_{submodule_idx}_{session_idx}_{outcome_idx}" + # ) + # with col4: + # if st.button("🗑️", key=f"del_slo_{module_idx}_{submodule_idx}_{session_idx}_{outcome_idx}"): + # session['session_learning_outcomes'].pop(outcome_idx) + # st.rerun() + + # # Add new session outcome + # with st.form(f"add_session_outcome_{module_idx}_{submodule_idx}_{session_idx}"): + # new_outcome = st.text_area("New Session Outcome", placeholder="Enter new session outcome...") + # col1, col2, col3 = st.columns([2, 2, 1]) + # with col1: + # bloom_level = st.selectbox( + # "Bloom's Level", + # ["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"], + # key=f"new_slo_bloom_{module_idx}_{submodule_idx}_{session_idx}" + # ) + # with col2: + # aligned_smlo = st.selectbox( + # "Aligned SMLO", + # [f"SMLO{module_idx+1}.{submodule_idx+1}.{i+1}" for i in range(len(submodule['submodule_learning_outcomes']))], + # key=f"new_slo_align_{module_idx}_{submodule_idx}_{session_idx}" + # ) + # with col3: + # if st.form_submit_button("Add Outcome"): + # if new_outcome: + # session['session_learning_outcomes'].append({ + # "outcome_number": f"SLO{session_idx+1}.{len(session['session_learning_outcomes'])+1}", + # "outcome_description": new_outcome, + # "bloom_taxonomy_level": bloom_level, + # "aligned_smlo": aligned_smlo + # }) + # st.rerun() + + for module_idx, module in enumerate(st.session_state.module_outcomes['modules']): + st.markdown(f"### Module {module_idx + 1}: {module['module_title']}") + + # Ensure the module index exists in submodule_outcomes + if module_idx < len(st.session_state.submodule_outcomes['modules']): + for submodule_idx, submodule in enumerate(st.session_state.submodule_outcomes['modules'][module_idx]['submodules']): + with st.container(): + st.markdown(f"#### Submodule {module_idx + 1}.{submodule_idx + 1}: {submodule['submodule_title']}") + st.markdown(f"**Sessions ({submodule['submodule_duration_sessions']} allocated)**") + + # Get sessions for this submodule + sessions = st.session_state.session_outcomes['submodules'][submodule_idx]['sessions'] + + for session_idx, session in enumerate(sessions): + with st.container(): + st.markdown(f"**Session {session_idx + 1}: {session['session_title']}**") + + # Edit session details + session['session_title'] = st.text_input( + "Session Title", + value=session['session_title'], + key=f"session_title_{module_idx}_{submodule_idx}_{session_idx}" + ) + + # Prerequisites + st.markdown("##### Prerequisites") + prereq_container = st.container() + for prereq_idx, prereq in enumerate(session['prerequisites']): + col1, col2 = prereq_container.columns([5, 1]) + with col1: + session['prerequisites'][prereq_idx] = st.text_input( + f"Prerequisite {prereq_idx + 1}", + value=prereq, + key=f"prereq_{module_idx}_{submodule_idx}_{session_idx}_{prereq_idx}" + ) + with col2: + if st.button("🗑️", key=f"del_prereq_{module_idx}_{submodule_idx}_{session_idx}_{prereq_idx}"): + session['prerequisites'].pop(prereq_idx) + st.rerun() + + if st.button("Add Prerequisite", key=f"add_prereq_{module_idx}_{submodule_idx}_{session_idx}"): + session['prerequisites'].append("") + st.rerun() + + # Key Concepts + st.markdown("##### Key Concepts") + concept_container = st.container() + for concept_idx, concept in enumerate(session['key_concepts']): + col1, col2 = concept_container.columns([5, 1]) + with col1: + session['key_concepts'][concept_idx] = st.text_input( + f"Concept {concept_idx + 1}", + value=concept, + key=f"concept_{module_idx}_{submodule_idx}_{session_idx}_{concept_idx}" + ) + with col2: + if st.button("🗑️", key=f"del_concept_{module_idx}_{submodule_idx}_{session_idx}_{concept_idx}"): + session['key_concepts'].pop(concept_idx) + st.rerun() + + if st.button("Add Concept", key=f"add_concept_{module_idx}_{submodule_idx}_{session_idx}"): + session['key_concepts'].append("") + st.rerun() + + # Session Learning Outcomes + st.markdown("##### Session Learning Outcomes") + for outcome_idx, outcome in enumerate(session['session_learning_outcomes']): + col1, col2, col3, col4 = st.columns([4, 2, 2, 1]) + with col1: + outcome['outcome_description'] = st.text_area( + f"SLO{session_idx+1}.{outcome_idx+1}", + value=outcome['outcome_description'], + key=f"slo_{module_idx}_{submodule_idx}_{session_idx}_{outcome_idx}", + height=100 + ) + with col2: + outcome['bloom_taxonomy_level'] = st.selectbox( + "Bloom's Level", + ["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"], + index=["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"].index(outcome['bloom_taxonomy_level']), + key=f"slo_bloom_{module_idx}_{submodule_idx}_{session_idx}_{outcome_idx}" + ) + with col3: + outcome['aligned_smlo'] = st.selectbox( + "Aligned SMLO", + [f"SMLO{module_idx+1}.{submodule_idx+1}.{i+1}" for i in range(len(submodule['submodule_learning_outcomes']))], + index=0, + key=f"slo_align_{module_idx}_{submodule_idx}_{session_idx}_{outcome_idx}" + ) + with col4: + if st.button("🗑️", key=f"del_slo_{module_idx}_{submodule_idx}_{session_idx}_{outcome_idx}"): + session['session_learning_outcomes'].pop(outcome_idx) + st.rerun() + + # Add new session outcome + with st.form(f"add_session_outcome_{module_idx}_{submodule_idx}_{session_idx}"): + new_outcome = st.text_area("New Session Outcome", placeholder="Enter new session outcome...") + col1, col2, col3 = st.columns([2, 2, 1]) + with col1: + bloom_level = st.selectbox( + "Bloom's Level", + ["Remember", "Understand", "Apply", "Analyze", "Evaluate", "Create"], + key=f"new_slo_bloom_{module_idx}_{submodule_idx}_{session_idx}" + ) + with col2: + aligned_smlo = st.selectbox( + "Aligned SMLO", + [f"SMLO{module_idx+1}.{submodule_idx+1}.{i+1}" for i in range(len(submodule['submodule_learning_outcomes']))], + key=f"new_slo_align_{module_idx}_{submodule_idx}_{session_idx}" + ) + with col3: + if st.form_submit_button("Add Outcome"): + if new_outcome: + session['session_learning_outcomes'].append({ + "outcome_number": f"SLO{session_idx+1}.{len(session['session_learning_outcomes'])+1}", + "outcome_description": new_outcome, + "bloom_taxonomy_level": bloom_level, + "aligned_smlo": aligned_smlo + }) + st.rerun() + + # Navigation buttons + col1, col2 = st.columns(2) + with col1: + if st.button("⬅️ Back to Submodule Outcomes", use_container_width=True): + st.session_state.current_step = 3 + st.rerun() + with col2: + if st.button("Generate Session Resources ➡️", use_container_width=True): + # Merge all structures before moving to resources + final_structure = merge_course_structure( + st.session_state.course_outcomes, + st.session_state.module_outcomes, + st.session_state.submodule_outcomes, + st.session_state.session_outcomes + ) + st.session_state.final_structure = final_structure + st.session_state.current_step = 6 + st.rerun() + + except Exception as e: + st.error(f"Error accessing session outcomes: {e}") + # Step 5: Resources Generation and Final Save + elif st.session_state.current_step == 6: + st.subheader("Step 5: Course Resources") + + try: + if 'generated_resources' not in st.session_state: + with st.spinner("Generating course resources..."): + # Extract all session titles + session_titles = [] + for module in st.session_state.final_structure['modules']: + for submodule in module['submodules']: + for session in submodule['sessions']: + session_titles.append(session['session_title']) + + resources = generate_resources_by_titles_chunking(session_titles, st.session_state.final_structure['course_title']) + # Load sample resources from JSON file: + # with open("sample_files/session_resources.json", "r") as file: + # resources = json.load(file) + + # Debug print + st.write("Type of resources:", type(resources)) + st.write("Resources content:", resources) + + st.session_state.generated_resources = resources + + # Display Course Reference Books + st.markdown("### 📚 Course Reference Books") + for book in st.session_state.generated_resources['course_reference_books']: + with st.container(): + st.markdown(f""" + **{book['title']}** + *by {book['author']}* + Publisher: {book['publisher']}, {book['year']} + {book['description']} + """) + + # Display Session Resources + st.markdown("### 📖 Session Resources") + for session_resource in st.session_state.generated_resources['session_resources']: + with st.expander(f"Session: {session_resource['session_title']}", expanded=False): + # Readings + readings = session_resource['resources'].get('readings', []) + videos = session_resource['resources'].get('videos', []) + + # Separate readings and videos + filtered_readings = [] + for reading in readings: + if reading['type'].lower() == 'video': + videos.append(reading) + else: + filtered_readings.append(reading) + + # Display filtered readings + if filtered_readings: + st.markdown("#### 📚 Required Readings") + for reading in filtered_readings: + st.markdown(f""" + - **{reading['title']}** + - Type: {reading['type']} + - Estimated reading time: {reading['estimated_read_time']} + - [Access Resource]({reading['url']}) + """) + + # Display videos + if videos: + st.markdown("#### 🎥 Video Resources") + for video in videos: + st.markdown(f""" + - **{video['title']}** + - Type: {video['type']} + - Duration: {video.get('duration', 'N/A')} + - [Watch Video]({video['url']}) + """) + + all_sessions = [] + start_date = st.session_state.course_details['start_date'] + sessions_per_week = st.session_state.course_details['sessions_per_week'] + for module in st.session_state.final_structure['modules']: + for submodule in module['submodules']: + for session_idx, session in enumerate(submodule['sessions']): + days_per_session = 7 / sessions_per_week + print(days_per_session) + session_date = start_date + timedelta(days=session_idx * days_per_session) + # get external resources for this session + external_resources = st.session_state.generated_resources['session_resources'][session_idx]['resources'] + session_datetime = datetime.combine(session_date, datetime.min.time()) + session_doc = { + "session_id": str(ObjectId()), + "title": session['session_title'], + "session_learning_outcomes": session['session_learning_outcomes'], + "date": session_datetime, + "status": "Scheduled", + "module_name": module['module_title'], + "submodule_name": submodule['submodule_title'], + "created_at": datetime.utcnow(), + "pre_class": { + "resources": [], + "completion_required": True + }, + "in_class": { + "quiz": [], + "polls": [] + }, + "post_class": { + "assignments": [] + }, + "external_resources": external_resources + } + all_sessions.append(session_doc) + + # Display 1st two sessions + print(all_sessions[:2]) + + new_course_id = get_new_course_id() + course_title = st.session_state.final_structure['course_title'] + + # if st.button("Save Course", type="primary", use_container_width=True): +# try: +# course_doc = { +# "course_id": new_course_id, +# "title": course_title, +# "description": st.session_state.course_plan['course_description'], +# "faculty": faculty_name, +# "faculty_id": faculty_id, +# "duration": f"{st.session_state.duration_weeks} weeks", +# "sessions_per_week": st.session_state.sessions_per_week, +# "start_date": datetime.combine(st.session_state.start_date, datetime.min.time()), +# "created_at": datetime.utcnow(), +# "sessions": all_sessions +# } + +# # Insert into database +# courses_collection.insert_one(course_doc) +# st.success("Course successfully created!") + +# # Update faculty collection +# faculty_collection.update_one( +# {"_id": st.session_state.user_id}, +# { +# "$push": { +# "courses_taught": { +# "course_id": new_course_id, +# "title": course_title, +# } +# } +# } +# ) + +# # Clear session state +# st.session_state.course_plan = None +# st.session_state.edit_mode = False +# st.session_state.resources_map = {} + +# # Optional: Add a button to view the created course +# if st.button("View Course"): +# # Add navigation logic here +# pass + +# except Exception as e: +# st.error(f"Error saving course: {e}") + + + # Final Save Button + if st.button("Save Course", type="primary", use_container_width=True): + try: + # Create final course document + course_doc = { + "course_id": new_course_id, + "title": st.session_state.final_structure['course_title'], + "description": st.session_state.final_structure['course_description'], + "course_outcomes": st.session_state.final_structure['learning_outcomes'], + "faculty": st.session_state.course_details['faculty'], + "faculty_id": faculty_id, + "duration": f"{st.session_state.course_details['duration']} weeks", + "sessions_per_week": st.session_state.course_details['sessions_per_week'], + "start_date": datetime.combine(st.session_state.course_details['start_date'], datetime.min.time()), + "created_at": datetime.utcnow(), + "sessions": all_sessions, + "full_course_structure": st.session_state.final_structure + } + + # Insert into database + courses_collection.insert_one(course_doc) + + # Update faculty collection + faculty_collection.update_one( + {"_id": st.session_state.user_id}, + { + "$push": { + "courses_taught": { + "course_id": new_course_id, + "title": course_title, + } + } + } + ) + + # Show success message + st.success("🎉 Course successfully created! You can now access it from your dashboard.") + + # Clear session state + for key in ['course_details', 'course_outcomes', 'module_outcomes', + 'submodule_outcomes', 'session_outcomes', 'final_structure', + 'generated_resources', 'current_step']: + if key in st.session_state: + del st.session_state[key] + + except Exception as e: + st.error(f"Error saving course: {e}") + + # Back button + if st.button("⬅️ Back to Session Outcomes", use_container_width=True): + st.session_state.current_step = 4 + st.rerun() + + except Exception as e: + st.error(f"Error in resource generation: {e}") + + + +from research_assistant_dashboard import display_research_assistant_dashboard +from goals2 import display_analyst_dashboard +def enroll_in_course(course_id, course_title, student): + """Enroll a student in a course""" + if student: + courses = student.get("enrolled_courses", []) + if course_id not in [course["course_id"] for course in courses]: + course = courses_collection.find_one({"course_id": course_id}) + if course: + courses.append( + { + "course_id": course["course_id"], + "title": course["title"], + } + ) + students_collection.update_one( + {"_id": st.session_state.user_id}, + {"$set": {"enrolled_courses": courses}}, + ) + st.success(f"Enrolled in course {course_title}") + # st.experimental_rerun() + else: + st.error("Course not found") + else: + st.warning("Already enrolled in this course") + +# def enroll_in_course_page(course_id): +# """Enroll a student in a course""" +# student = students_collection.find_one({"_id": st.session_state.user_id}) +# course_title = courses_collection.find_one({"course_id": course_id})["title"] + +# course = courses_collection.find_one({"course_id": course_id}) +# if course: +# st.title(course["title"]) +# st.subheader("Course Description:") +# st.write(course["description"]) +# st.write(f"Faculty: {course['faculty']}") +# st.write(f"Duration: {course['duration']}") + +# st.title("Course Sessions") +# for session in course["sessions"]: +# st.write(f"Session: {session['title']}") +# st.write(f"Date: {session['date']}") +# st.write(f"Status: {session['status']}") +# st.write("----") +# else: +# st.error("Course not found") + +# enroll_button = st.button("Enroll in Course", key="enroll_button", use_container_width=True) +# if enroll_button: +# enroll_in_course(course_id, course_title, student) +def enroll_in_course_page(course_id): + """Display an aesthetically pleasing course enrollment page""" + student = students_collection.find_one({"_id": st.session_state.user_id}) + course = courses_collection.find_one({"course_id": course_id}) + + if not course: + st.error("Course not found") + return + + # Create two columns for layout + col1, col2 = st.columns([2, 1]) + + with col1: + # Course header section + st.title(course["title"]) + st.markdown(f"*{course['description']}*") + + # Course details in an expander + with st.expander("Course Details", expanded=True): + st.markdown(f"👨‍🏫 **Faculty:** {course['faculty']}") + st.markdown(f"⏱️ **Duration:** {course['duration']}") + + # Sessions in a clean card-like format + st.subheader("📚 Course Sessions") + for idx, session in enumerate(course["sessions"], 1): + with st.container(): + st.markdown(f""" + --- + ### Session {idx}: {session['title']} + 🗓️ **Date:** {session['date']} + 📌 **Status:** {session['status']} + """) + + with col2: + with st.container(): + st.markdown("### Ready to Learn?") + st.markdown("Click below to enroll in this course") + + # Check if already enrolled + courses = student.get("enrolled_courses", []) + is_enrolled = course_id in [c["course_id"] for c in courses] + + if is_enrolled: + st.info("✅ You are already enrolled in this course") + else: + enroll_button = st.button( + "🎓 Enroll Now", + key="enroll_button", + use_container_width=True + ) + if enroll_button: + enroll_in_course(course_id, course["title"], student) + +def show_available_courses(username, user_type, user_id): + """Display available courses for enrollment""" + st.title("Available Courses") + + courses = list(courses_collection.find({}, {"course_id": 1, "title": 1})) + course_options = [ + f"{course['title']} ({course['course_id']})" for course in courses + ] + + selected_course = st.selectbox("Select a Course to Enroll", course_options) + # if selected_courses: + # for course in selected_courses: + # course_id = course.split("(")[-1][:-1] + # course_title = course.split(" (")[0] + # enroll_in_course(course_id, course_title, user_id) + # st.success("Courses enrolled successfully!") + if selected_course: + course_id = selected_course.split("(")[-1][:-1] + enroll_in_course_page(course_id) + +def validate_email(email): + """Validate email format and domain""" + # Basic email pattern + pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' + if not re.match(pattern, email): + return False, "Invalid email format" + + # You can add additional institution-specific validation here + # For example, checking if the domain is from your institution + # allowed_domains = ["spit.ac.in"] # Add more domains as needed + # domain = email.split('@')[1] + # if domain not in allowed_domains: + # return False, "Please use your institutional email address" + + return True, "Valid email" + +def validate_phone(phone): + """Validate phone number format""" + # Assuming Indian phone numbers + pattern = r'^[6-9]\d{9}$' + if not re.match(pattern, phone): + return False, "Invalid phone number format. Please enter a 10-digit Indian mobile number" + return True, "Valid phone number" + +def extract_username(email): + """Extract username from email""" + return email.split('@')[0] + +def main_dashboard(): + if st.session_state.user_type == "research_assistant": + display_research_assistant_dashboard() + elif st.session_state.user_type == "analyst": + display_analyst_dashboard() + else: + selected_course_id = None + create_session = False + with st.sidebar: + st.title(f"Welcome, {st.session_state.username}") + if st.session_state.user_type == "student": + st.title("Enrolled Courses") + else: + st.title("Your Courses") + + # Course selection + enrolled_courses = get_courses( + st.session_state.username, st.session_state.user_type + ) + + # Enroll in Courses + if st.session_state.user_type == "student": + if st.button( + "Enroll in a New Course", key="enroll_course", use_container_width=True + ): + st.session_state.show_enroll_course_page = True + + # if st.session_state.show_enroll_course_form: + # courses = list(courses_collection.find({}, {"course_id": 1, "title": 1})) + # course_options = [f"{course['title']} ({course['course_id']})" for course in courses] + # course_to_enroll = st.selectbox("Available Courses", course_options) + # st.session_state.course_to_enroll = course_to_enroll + + if st.session_state.user_type == "faculty": + if st.button( + "Create New Course", key="create_course", use_container_width=True + ): + st.session_state.show_create_course_form = True + + if not enrolled_courses: + st.warning("No courses found") + else: + course_titles = [course["title"] for course in enrolled_courses] + course_ids = [course["course_id"] for course in enrolled_courses] + + selected_course = st.selectbox("Select Course", course_titles) + selected_course_id = course_ids[course_titles.index(selected_course)] + print("Selected Course ID: ", selected_course_id) + + st.session_state.selected_course = selected_course + st.session_state.selected_course_id = selected_course_id + + # Display course sessions + sessions = get_sessions(selected_course_id, selected_course) + + st.title("Course Sessions") + for i, session in enumerate(sessions, start=1): + if st.button( + f"Session {i}", key=f"session_{i}", use_container_width=True + ): + st.session_state.selected_session = session + + if st.session_state.user_type == "faculty": + # Create new session + # create_session = st.button("Create New Session Button", key="create_session", use_container_width=True) + if st.button( + "Create New Session", + key="create_session", + use_container_width=True, + ): + st.session_state.show_create_session_form = True + + if st.button("Logout", use_container_width=True): + for key in st.session_state.keys(): + del st.session_state[key] + st.rerun() + + # if create_session: + # create_session_form(selected_course_id) + if st.session_state.get("show_create_course_form"): + create_course_form(st.session_state.username, st.session_state.user_id) + elif st.session_state.get("show_create_session_form"): + create_session_form(selected_course_id) + elif st.session_state.get("show_enroll_course_page"): + show_available_courses(st.session_state.username, st.session_state.user_type, st.session_state.user_id) + else: + # Main content + if "selected_session" in st.session_state: + display_session_content( + st.session_state.user_id, + selected_course_id, + st.session_state.selected_session, + st.session_state.username, + st.session_state.user_type, + ) + else: + st.info("Select a session to view details") + # # Main content + # if 'selected_session' in st.session_state: + # display_session_content(st.session_state.user_id, selected_course_id, st.session_state.selected_session, st.session_state.username, st.session_state.user_type) + # if create_session: + # create_session_form(selected_course_id) + +def main(): + st.set_page_config(page_title="NOVAScholar", page_icon="📚", layout="wide") + init_session_state() + # modify_courses_collection_schema() + + if not st.session_state.authenticated: + login_tab, register_tab = st.tabs(["Login", "Register"]) + + with register_tab: + register_page() + with login_tab: + login_form() + else: + main_dashboard() + + +if __name__ == "__main__": + main()