Harshal Vhatkar
add new features
9987aed
raw
history blame
64.1 kB
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_alt import display_session_content
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()
# 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({"$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 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"]
)
user_type = user_type.lower().replace(" ", "_")
# 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({"$or": [{"full_name": username}, {"username": 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_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
# Generate new session ID
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
# 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.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:
# 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("<br>", unsafe_allow_html=True) # Add gap between sessions
# st.markdown(f"### 📖 {sub_module['title']}")
st.markdown(f'<h3 style="font-size: 1.25rem;">📖 Chapter {sub_idx + 1}: {sub_module["title"]}</h3>', 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("<br>", 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'<h4 style="font-size: 1.25rem;">📚 Session Resources</h4>', unsafe_allow_html=True)
# Readings Tab
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']})
""")
# Books Tab and Additional Resources Tab side-by-side
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']})
""")
# 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()
st.info("Registrations are closed.")
with login_tab:
login_form()
else:
main_dashboard()
if __name__ == "__main__":
main()