|
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 code_playground import display_code_playground |
|
load_dotenv() |
|
|
|
|
|
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({"$or": [{"full_name": username}, {"username": username}]}) |
|
elif user_type == "faculty": |
|
user = faculty_collection.find_one({"$or": [{"full_name": username}, {"username": 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 enhanced 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"] |
|
) |
|
user_type = user_type.lower().replace(" ", "_") |
|
|
|
username = st.text_input("Username or Email") |
|
password = st.text_input("Password", type="password") |
|
|
|
|
|
submit = st.form_submit_button("Login") |
|
|
|
if submit: |
|
|
|
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}} |
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return list(courses) |
|
elif user_type == "faculty": |
|
faculty = faculty_collection.find_one({"$or": [{"full_name": username}, {"username": username}]}) |
|
if faculty: |
|
course_ids = [ |
|
course["course_id"] for course in faculty.get("courses_taught", []) |
|
] |
|
|
|
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_collection.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 |
|
|
|
course = courses_collection.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_collection.update_one( |
|
{"course_id": course_id}, {"$push": {"sessions": new_session}} |
|
) |
|
st.success("Session created successfully!") |
|
st.session_state.show_create_session_form = False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 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 for NOVAScholar") |
|
if "user_type" not in st.session_state: |
|
st.session_state.user_type = "student" |
|
|
|
|
|
st.session_state.user_type = st.selectbox( |
|
"Please select your Role", |
|
["Student", "Faculty", "Research Assistant", "Analyst"] |
|
) |
|
user_type = st.session_state.user_type.lower().replace(" ", "_") |
|
|
|
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: |
|
|
|
email_valid, email_msg = validate_email(email) |
|
if not email_valid: |
|
st.error(email_msg) |
|
return |
|
|
|
|
|
phone_valid, phone_msg = validate_phone(phone) |
|
if not phone_valid: |
|
st.error(phone_msg) |
|
return |
|
|
|
|
|
if password != confirm_password: |
|
st.error("Passwords do not match") |
|
return |
|
|
|
|
|
username = extract_username(email) |
|
|
|
|
|
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 |
|
|
|
|
|
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}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
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: |
|
|
|
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 |
|
|
|
|
|
session_titles = [] |
|
for module in st.session_state.course_plan['modules']: |
|
for sub_module in module['sub_modules']: |
|
for topic in sub_module['topics']: |
|
|
|
|
|
if isinstance(topic, dict): |
|
session_titles.append(topic['title']) |
|
else: |
|
session_titles.append(topic) |
|
|
|
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'] |
|
} |
|
|
|
|
|
|
|
|
|
st.rerun() |
|
except Exception as e: |
|
st.error(f"Error generating course structure: {e}") |
|
|
|
|
|
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() |
|
|
|
|
|
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): |
|
|
|
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("<br>", unsafe_allow_html=True) |
|
|
|
st.markdown(f'<h3 style="font-size: 1.25rem;">📖 Chapter {sub_idx + 1}: {sub_module["title"]}</h3>', unsafe_allow_html=True) |
|
|
|
|
|
|
|
for topic_idx, topic in enumerate(sub_module['topics']): |
|
st.markdown("<br>", unsafe_allow_html=True) |
|
session_key = f"session_{module_idx}_{sub_idx}_{topic_idx}" |
|
|
|
|
|
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(): |
|
|
|
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" |
|
) |
|
|
|
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" |
|
) |
|
|
|
|
|
if st.session_state.resources_map: |
|
|
|
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(f'<h4 style="font-size: 1.25rem;">📚 Session Resources</h4>', unsafe_allow_html=True) |
|
|
|
if resources.get('readings'): |
|
st.markdown(f'<h5 style="font-size: 1.1rem; margin-top: 1rem;">📖 External Resources</h5>', 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']}) |
|
""") |
|
|
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
if resources.get('books'): |
|
st.markdown(f'<h5 style="font-size: 1.1rem; margin-top: 1rem;">📚 Reference Books</h5>', 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'<h5 style="font-size: 1.1rem; margin-top: 1rem;">🔗 Additional Study Resources</h5>', 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']}) |
|
""") |
|
|
|
|
|
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'] |
|
|
|
|
|
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 |
|
} |
|
|
|
|
|
courses_collection.insert_one(course_doc) |
|
st.success("Course successfully created!") |
|
|
|
|
|
faculty_collection.update_one( |
|
{"_id": st.session_state.user_id}, |
|
{ |
|
"$push": { |
|
"courses_taught": { |
|
"course_id": new_course_id, |
|
"title": course_title, |
|
} |
|
} |
|
} |
|
) |
|
|
|
|
|
st.session_state.course_plan = None |
|
st.session_state.edit_mode = False |
|
st.session_state.resources_map = {} |
|
|
|
|
|
if st.button("View Course"): |
|
|
|
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}") |
|
|
|
else: |
|
st.error("Course not found") |
|
else: |
|
st.warning("Already enrolled in this course") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
col1, col2 = st.columns([2, 1]) |
|
|
|
with col1: |
|
|
|
st.title(course["title"]) |
|
st.markdown(f"*{course['description']}*") |
|
|
|
|
|
with st.expander("Course Details", expanded=True): |
|
st.markdown(f"👨🏫 **Faculty:** {course['faculty']}") |
|
st.markdown(f"⏱️ **Duration:** {course['duration']}") |
|
|
|
|
|
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") |
|
|
|
|
|
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_course: |
|
course_id = selected_course.split("(")[-1][:-1] |
|
enroll_in_course_page(course_id) |
|
|
|
def validate_email(email): |
|
"""Validate email format and domain""" |
|
|
|
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" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return True, "Valid email" |
|
|
|
def validate_phone(phone): |
|
"""Validate phone number format""" |
|
|
|
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") |
|
|
|
|
|
enrolled_courses = get_courses( |
|
st.session_state.username, st.session_state.user_type |
|
) |
|
|
|
|
|
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.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 |
|
|
|
|
|
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": |
|
|
|
|
|
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 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: |
|
|
|
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") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(): |
|
st.set_page_config(page_title="NOVAScholar", page_icon="📚", layout="wide") |
|
init_session_state() |
|
|
|
|
|
if not st.session_state.authenticated: |
|
login_tab, register_tab = st.tabs(["Login", "Register"]) |
|
|
|
with register_tab: |
|
|
|
st.info("Registrations are closed.") |
|
with login_tab: |
|
login_form() |
|
else: |
|
main_dashboard() |
|
|
|
if __name__ == "__main__": |
|
main() |
|
|