Harshal V commited on
Commit
5097cc9
·
1 Parent(s): 9630b25

Build in-session features

Browse files
Files changed (8) hide show
  1. chatbot.py +45 -0
  2. db.py +55 -1
  3. file_upload_vectorize.py +24 -0
  4. live_polls.py +115 -0
  5. main.py +4 -1
  6. poll_db_operations.py +70 -0
  7. poll_db_setup.py +35 -0
  8. session_page.py +230 -91
chatbot.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import datetime
3
+ from db import courses_collection2, faculty_collection, students_collection, vectors_collection, chat_history_collection
4
+ from PIL import Image
5
+ from dotenv import load_dotenv
6
+ import os
7
+ from datetime import datetime
8
+ from bson import ObjectId
9
+ from file_upload_vectorize import model
10
+
11
+ load_dotenv()
12
+ MONGO_URI = os.getenv('MONGO_URI')
13
+ OPENAI_KEY = os.getenv('OPENAI_KEY')
14
+ GEMINI_KEY = os.getenv('GEMINI_KEY')
15
+
16
+ def insert_chat_message(user_id, session_id, role, content):
17
+ message = {
18
+ "role": role,
19
+ "content": content,
20
+ "timestamp": datetime.utcnow()
21
+ }
22
+
23
+ chat_history_collection.update_one(
24
+ {"user_id": ObjectId(user_id), "session_id": session_id},
25
+ {"$push": {"messages": message}, "$set": {"timestamp": datetime.utcnow()}},
26
+ upsert=True
27
+ )
28
+
29
+
30
+ def give_chat_response(user_id, session_id, question, context, prompt):
31
+ st.title("Chat with NOVA")
32
+ st.write("Ask any question and NOVA will provide an answer.")
33
+
34
+ with st.form("chat_form"):
35
+ message = st.text_input("Message")
36
+ submit = st.form_submit_button("Send")
37
+
38
+ if submit:
39
+ insert_chat_message(user_id, session_id, "user", message)
40
+ st.write(f"You: {message}")
41
+
42
+ # Get response from NOVA
43
+ response = get_nova_response(question, context, prompt, message)
44
+ insert_chat_message(user_id, session_id, "nova", response)
45
+ st.write(f"NOVA: {response}")
db.py CHANGED
@@ -532,4 +532,58 @@ vector_schema = {
532
  }
533
  # Creating the Vector Collection
534
  # db.create_collection("vectors", validator={"$jsonSchema": vector_schema})
535
- vectors_collection = db['vectors']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
532
  }
533
  # Creating the Vector Collection
534
  # db.create_collection("vectors", validator={"$jsonSchema": vector_schema})
535
+ vectors_collection = db['vectors']
536
+
537
+
538
+ # Creating a Chat-History Collection
539
+ # Creating a Chat-History Collection
540
+ chat_history_schema = {
541
+ "bsonType": "object",
542
+ "required": ["user_id", "session_id", "messages", "timestamp"],
543
+ "properties": {
544
+ "user_id": {
545
+ "bsonType": "objectId",
546
+ "description": "Unique identifier for the user"
547
+ },
548
+ "session_id": {
549
+ "bsonType": "string",
550
+ "description": "Identifier for the session"
551
+ },
552
+ "timestamp": {
553
+ "bsonType": "date",
554
+ "description": "Timestamp when the chat session started"
555
+ },
556
+ "messages": {
557
+ "bsonType": "array",
558
+ "description": "List of chat messages",
559
+ "items": {
560
+ "bsonType": "object",
561
+ "properties": {
562
+ "prompt": {
563
+ "bsonType": "string",
564
+ "description": "User's question or prompt"
565
+ },
566
+ "response": {
567
+ "bsonType": "string",
568
+ "description": "Assistant's response"
569
+ },
570
+ "timestamp": {
571
+ "bsonType": "date",
572
+ "description": "Timestamp of the message"
573
+ }
574
+ }
575
+ }
576
+ }
577
+ }
578
+ }
579
+
580
+ # Create the collection with the schema
581
+ # db.create_collection("chat_history", validator={"$jsonSchema": chat_history_schema})
582
+ chat_history_collection = db['chat_history']
583
+
584
+ # Create the collection with the schema
585
+ # db.create_collection("chat_history", validator={"$jsonSchema": chat_history_schema})
586
+ # chat_history_collection = db['chat_history']
587
+
588
+
589
+ # database_setup for live polls
file_upload_vectorize.py CHANGED
@@ -61,6 +61,30 @@ def upload_resource(course_id, session_id, file_name, file_content, material_typ
61
  resources_collection.insert_one(resource_data)
62
  return resource_id
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  def extract_text_from_file(uploaded_file):
65
  text = ""
66
  file_type = uploaded_file.type
 
61
  resources_collection.insert_one(resource_data)
62
  return resource_id
63
 
64
+ def assignment_submit(student_id, course_id, session_id, file_name, file_content, material_type):
65
+ # Extract text content from the file
66
+ text_content = extract_text_from_file(file_content)
67
+
68
+ # Read the file content
69
+ file_content.seek(0) # Reset the file pointer to the beginning
70
+ original_file_content = file_content.read()
71
+
72
+ assignment_data = {
73
+ "student_id": student_id,
74
+ "course_id": course_id,
75
+ "session_id": session_id,
76
+ "file_name": file_name,
77
+ "file_type": file_content.type,
78
+ "text_content": text_content,
79
+ "file_content": original_file_content, # Store the original file content
80
+ "material_type": material_type,
81
+ "uploaded_at": datetime.utcnow()
82
+ }
83
+ courses_collection2.update_one(
84
+ {"course_id": course_id, "sessions.session_id": session_id},
85
+ {"$push": {"sessions.$.post_class.assignments": assignment_data}}
86
+ )
87
+
88
  def extract_text_from_file(uploaded_file):
89
  text = ""
90
  file_type = uploaded_file.type
live_polls.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # live_poll_feature.py
2
+
3
+ import streamlit as st
4
+ import pandas as pd
5
+ from datetime import datetime
6
+ from poll_db_operations import PollDatabase
7
+
8
+ class LivePollFeature:
9
+ def __init__(self):
10
+ self.db = PollDatabase()
11
+
12
+ def display_faculty_interface(self, session_id):
13
+ """Display the faculty interface for managing polls"""
14
+ st.subheader("Live Polls Management")
15
+
16
+ # Create new poll
17
+ with st.expander("Create New Poll", expanded=False):
18
+ question = st.text_input("Poll Question")
19
+
20
+ num_options = st.number_input("Number of Options",
21
+ min_value=2,
22
+ max_value=6,
23
+ value=4)
24
+
25
+ options = []
26
+ for i in range(num_options):
27
+ option = st.text_input(f"Option {i+1}",
28
+ key=f"option_{i}")
29
+ if option:
30
+ options.append(option)
31
+
32
+ if st.button("Create Poll") and question and len(options) >= 2:
33
+ self.db.create_poll(
34
+ st.session_state.selected_course,
35
+ session_id,
36
+ question,
37
+ options,
38
+ st.session_state.user_id
39
+ )
40
+ st.success("Poll created successfully!")
41
+ st.rerun()
42
+
43
+ # Display active polls
44
+ active_polls = self.db.get_active_polls(session_id)
45
+ if active_polls:
46
+ st.subheader("Active Polls")
47
+ for poll in active_polls:
48
+ with st.expander(f"Poll: {poll['question']}", expanded=True):
49
+ # Display results
50
+ self._display_poll_results(poll)
51
+
52
+ if st.button("Close Poll",
53
+ key=f"close_{str(poll['_id'])}"):
54
+ self.db.close_poll(poll['_id'])
55
+ st.success("Poll closed successfully!")
56
+ st.rerun()
57
+
58
+ def display_student_interface(self, session_id):
59
+ """Display the student interface for participating in polls"""
60
+ st.subheader("Live Polls")
61
+
62
+ active_polls = self.db.get_active_polls(session_id)
63
+ if not active_polls:
64
+ st.info("No active polls at the moment.")
65
+ return
66
+
67
+ for poll in active_polls:
68
+ with st.expander(f"Poll: {poll['question']}", expanded=True):
69
+ selected_option = st.radio(
70
+ "Your response:",
71
+ options=poll['options'],
72
+ key=f"poll_{str(poll['_id'])}"
73
+ )
74
+
75
+ if st.button("Submit Response",
76
+ key=f"submit_{str(poll['_id'])}"):
77
+ success, message = self.db.submit_response(
78
+ poll['_id'],
79
+ st.session_state.user_id,
80
+ selected_option
81
+ )
82
+ if success:
83
+ st.success(message)
84
+ else:
85
+ st.warning(message)
86
+ st.rerun()
87
+
88
+ self._display_poll_results(poll)
89
+
90
+ def _display_poll_results(self, poll):
91
+ """Helper method to display poll results"""
92
+ responses_df = pd.DataFrame(
93
+ list(poll['responses'].items()),
94
+ columns=['Option', 'Votes']
95
+ )
96
+
97
+ total_votes = responses_df['Votes'].sum()
98
+
99
+ # Calculate percentages
100
+ if total_votes > 0:
101
+ responses_df['Percentage'] = (
102
+ responses_df['Votes'] / total_votes * 100
103
+ ).round(1)
104
+ else:
105
+ responses_df['Percentage'] = 0
106
+
107
+ # Display metrics
108
+ st.metric("Total Responses", total_votes)
109
+
110
+ # Display charts
111
+ st.bar_chart(responses_df.set_index('Option')['Votes'])
112
+
113
+ # Display detailed statistics
114
+ if st.session_state.user_type == 'faculty':
115
+ st.dataframe(responses_df)
main.py CHANGED
@@ -11,6 +11,8 @@ def init_session_state():
11
  """Initialize session state variables"""
12
  if 'authenticated' not in st.session_state:
13
  st.session_state.authenticated = False
 
 
14
  if 'user_type' not in st.session_state:
15
  st.session_state.user_type = None
16
  if 'username' not in st.session_state:
@@ -26,6 +28,7 @@ def login_user(username, password, user_type):
26
  user = faculty_collection.find_one({"full_name": username})
27
 
28
  if user and check_password_hash(user['password'], password):
 
29
  st.session_state.authenticated = True
30
  st.session_state.user_type = user_type
31
  st.session_state.username = username
@@ -113,7 +116,7 @@ def main_dashboard():
113
 
114
  # Main content
115
  if 'selected_session' in st.session_state:
116
- display_session_content(selected_course_id, st.session_state.selected_session, st.session_state.username)
117
 
118
 
119
  def main():
 
11
  """Initialize session state variables"""
12
  if 'authenticated' not in st.session_state:
13
  st.session_state.authenticated = False
14
+ if 'user_id' not in st.session_state:
15
+ st.session_state.user_id = None
16
  if 'user_type' not in st.session_state:
17
  st.session_state.user_type = None
18
  if 'username' not in st.session_state:
 
28
  user = faculty_collection.find_one({"full_name": username})
29
 
30
  if user and check_password_hash(user['password'], password):
31
+ st.session_state.user_id = user['_id']
32
  st.session_state.authenticated = True
33
  st.session_state.user_type = user_type
34
  st.session_state.username = username
 
116
 
117
  # Main content
118
  if 'selected_session' in st.session_state:
119
+ 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)
120
 
121
 
122
  def main():
poll_db_operations.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pymongo import MongoClient
2
+ from datetime import datetime
3
+ from bson import ObjectId
4
+ from dotenv import load_dotenv
5
+ import os
6
+
7
+ load_dotenv()
8
+ MONGO_URI = os.getenv('MONGO_URI')
9
+ class PollDatabase:
10
+ def __init__(self):
11
+ self.client = MongoClient(MONGO_URI)
12
+ self.db = self.client["novascholar_db"]
13
+
14
+ def create_poll(self, course_id, session_id, question, options, faculty_id):
15
+ """Create a new poll"""
16
+ poll = {
17
+ "course_id": course_id,
18
+ "session_id": session_id,
19
+ "faculty_id": faculty_id,
20
+ "question": question,
21
+ "options": options,
22
+ "status": "active",
23
+ "created_at": datetime.now(),
24
+ "responses": {option: 0 for option in options}
25
+ }
26
+ return self.db.polls.insert_one(poll)
27
+
28
+ def get_active_polls(self, session_id):
29
+ """Get all active polls for a session"""
30
+ return list(self.db.polls.find({
31
+ "session_id": session_id,
32
+ "status": "active"
33
+ }))
34
+
35
+ def submit_response(self, poll_id, student_id, selected_option):
36
+ """Submit a student's response to a poll"""
37
+ try:
38
+ # Record individual response
39
+ response = {
40
+ "poll_id": poll_id,
41
+ "student_id": student_id,
42
+ "selected_option": selected_option,
43
+ "submitted_at": datetime.now()
44
+ }
45
+ self.db.poll_responses.insert_one(response)
46
+
47
+ # Update aggregated results
48
+ self.db.polls.update_one(
49
+ {"_id": ObjectId(poll_id)},
50
+ {"$inc": {f"responses.{selected_option}": 1}}
51
+ )
52
+ return True, "Vote recorded successfully"
53
+
54
+ except Exception as e:
55
+ if "duplicate key error" in str(e):
56
+ return False, "You have already voted in this poll"
57
+ return False, f"Error recording vote: {str(e)}"
58
+
59
+ def close_poll(self, poll_id):
60
+ """Close a poll"""
61
+ return self.db.polls.update_one(
62
+ {"_id": ObjectId(poll_id)},
63
+ {"$set": {"status": "closed"}}
64
+ )
65
+
66
+ def get_poll_analytics(self, poll_id):
67
+ """Get detailed analytics for a poll"""
68
+ poll = self.db.polls.find_one({"_id": ObjectId(poll_id)})
69
+ responses = self.db.poll_responses.find({"poll_id": ObjectId(poll_id)})
70
+ return poll, list(responses)
poll_db_setup.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pymongo import MongoClient
2
+ from datetime import datetime
3
+ from dotenv import load_dotenv
4
+ import os
5
+
6
+ load_dotenv()
7
+ MONGO_URI = os.getenv('MONGO_URI')
8
+ def setup_mongodb():
9
+ """Initialize MongoDB connection and create collections with indexes"""
10
+ client = MongoClient(MONGO_URI)
11
+ db = client["novascholar_db"]
12
+
13
+ # Create indexes for polls collection
14
+ db.polls.create_index([("session_id", 1), ("status", 1)])
15
+ db.polls.create_index([("course_id", 1)])
16
+
17
+ # Create unique index for poll_responses to prevent duplicate votes
18
+ db.poll_responses.create_index(
19
+ [("poll_id", 1), ("student_id", 1)],
20
+ unique=True
21
+ )
22
+
23
+ return "Database setup completed successfully"
24
+
25
+ def print_all_polls():
26
+ """Print all polls in the database"""
27
+ client = MongoClient(MONGO_URI)
28
+ db = client["novascholar_db"]
29
+
30
+ polls = db.polls.find()
31
+ for poll in polls:
32
+ print(poll)
33
+
34
+ if __name__ == "__main__":
35
+ print(print_all_polls())
session_page.py CHANGED
@@ -3,9 +3,18 @@ from datetime import datetime
3
  from utils.sample_data import SAMPLE_CHAT_HISTORY, SAMPLE_STUDENT_PROGRESS
4
  from utils.helpers import display_progress_bar, create_notification, format_datetime
5
  from utils.sample_data import SAMPLE_SESSIONS, SAMPLE_COURSES
6
- from file_upload_vectorize import upload_resource, extract_text_from_file, create_vector_store, resources_collection
7
- from db import courses_collection2
8
- def display_preclass_content(session, username):
 
 
 
 
 
 
 
 
 
9
  """Display pre-class materials for a session"""
10
  st.subheader("Pre-class Materials")
11
 
@@ -41,13 +50,12 @@ def display_preclass_content(session, username):
41
  # create_notification("Notes saved successfully!", "success")
42
 
43
  # Display pre-class materials
 
 
44
  materials = resources_collection.find({"session_id": session['session_id']})
 
45
  for material in materials:
46
- # with st.expander(f"{material['file_name']} ({material['material_type'].upper()})"):
47
- # if material['material_type'] == 'pdf':
48
- # # st.markdown(f"📑 [Open PDF Document]({material['url']})")
49
- # if st.button("Mark PDF as Read", key=f"pdf_{material['file_name']}"):
50
- # create_notification("PDF marked as read!", "success")
51
  with st.expander(f"{material['file_name']} ({material['material_type'].upper()})"):
52
  file_type = material.get('file_type', 'unknown')
53
  if file_type == 'application/pdf':
@@ -64,91 +72,218 @@ def display_preclass_content(session, username):
64
  if st.button("Mark PDF as Read", key=f"pdf_{material['file_name']}"):
65
  create_notification("PDF marked as read!", "success")
66
 
67
- def display_in_class_content(session):
68
- """Display in-class activities and interactions"""
69
- st.header("In-class Activities")
 
70
 
71
- # Topics covered
72
- with st.expander("Topics Covered", expanded=True):
73
- for topic in session['in_class']['topics']:
74
- st.markdown(f"- {topic}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
- # Live Quiz section
77
- st.subheader("Session Quiz")
78
- quiz = session['in_class']['quiz']
79
- with st.expander(f"Quiz: {quiz['title']}"):
80
- st.markdown(f"- Number of questions: {quiz['questions']}")
81
- st.markdown(f"- Time allowed: {quiz['duration']} minutes")
82
- if session['status'] == 'in_progress':
83
- if st.button("Start Quiz"):
84
- create_notification("Quiz will begin shortly!", "info")
85
  else:
86
- st.info("Quiz not available at this time")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
 
88
- # Live Polls
89
- st.subheader("Interactive Polls")
90
- for idx, poll in enumerate(session['in_class']['polls']):
91
- with st.expander(f"Poll {idx + 1}: {poll['question']}"):
92
- selected_option = st.radio(
93
- "Your response:",
94
- options=poll['options'],
95
- key=f"poll_{session['session_id']}_{idx}"
96
- )
97
- if st.button("Submit Response", key=f"submit_poll_{idx}"):
98
- create_notification("Poll response recorded!", "success")
99
 
100
- # Chat Interface
101
- st.subheader("Class Discussion")
102
- chat_container = st.container()
103
- with chat_container:
104
- # Display existing messages
105
- messages = SAMPLE_CHAT_HISTORY.get(session['session_id'], [])
106
- for msg in messages:
107
- with st.chat_message(msg['user']):
108
- st.write(msg['message'])
109
-
110
- # New message input
111
- if session['status'] == 'in_progress':
112
- if prompt := st.chat_input("Ask a question..."):
113
- if len(messages) < 20:
114
- with st.chat_message("user"):
115
- st.write(prompt)
116
- with st.chat_message("assistant"):
117
- st.write("This is a sample response to your question.")
118
- else:
119
- create_notification("Message limit (20) reached for this session.", "warning")
120
 
121
- def display_post_class_content(session):
122
  """Display post-class assignments and submissions"""
123
  st.header("Post-class Work")
124
 
125
- # Display assignments
126
- for assignment in session['post_class']['assignments']:
127
- with st.expander(f"Assignment: {assignment['title']}", expanded=True):
128
- st.markdown(f"**Due Date:** {format_datetime(assignment['due_date'])}")
129
- st.markdown(f"**Status:** {assignment['status'].replace('_', ' ').title()}")
130
-
131
- # Assignment details
132
- st.markdown("### Instructions")
133
- st.markdown("Complete the assignment according to the provided guidelines.")
134
-
135
- # File submission
136
- st.markdown("### Submission")
137
- uploaded_file = st.file_uploader(
138
- "Upload your work",
139
- type=['pdf', 'py', 'ipynb'],
140
- key=f"upload_{assignment['id']}"
141
- )
142
-
143
- if uploaded_file is not None:
144
- st.success("File uploaded successfully!")
145
- if st.button("Submit Assignment", key=f"submit_{assignment['id']}"):
146
- create_notification("Assignment submitted successfully!", "success")
147
 
148
- # Feedback section (if assignment is completed)
149
- if assignment['status'] == 'completed':
150
- st.markdown("### Feedback")
151
- st.info("Feedback will be provided here once the assignment is graded.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
153
  def display_preclass_analytics(session):
154
  """Display pre-class analytics for faculty"""
@@ -185,10 +320,10 @@ def display_postclass_analytics(session):
185
  """Display post-class analytics for faculty"""
186
  st.subheader("Post-class Analytics")
187
 
188
- # Display assignment completion rates
189
- for assignment in session['post_class']['assignments']:
190
- progress = SAMPLE_STUDENT_PROGRESS.get(assignment['id'], 0)
191
- display_progress_bar(progress, 100, assignment['title'])
192
 
193
 
194
  def upload_preclass_materials(session_id, course_id):
@@ -222,7 +357,7 @@ def upload_preclass_materials(session_id, course_id):
222
 
223
 
224
 
225
- def display_session_content(course_id, session, username):
226
  st.title(f"Session {session['session_id']}: {session['title']}")
227
  st.markdown(f"**Date:** {format_datetime(session['date'])}")
228
  st.markdown(f"**Status:** {session['status'].replace('_', ' ').title()}")
@@ -250,18 +385,22 @@ def display_session_content(course_id, session, username):
250
  # Display pre-class materials
251
  if st.session_state.user_type == 'student':
252
  with pre_class_tab:
253
- display_preclass_content(session, username)
254
 
255
  with in_class_tab:
256
- display_in_class_content(session)
257
 
258
  # Post-class Content
259
  with post_class_tab:
260
- display_post_class_content(session)
261
 
262
  if st.session_state.user_type == 'faculty':
263
  with pre_class_work:
264
  upload_preclass_materials(session['session_id'], course_id)
 
 
 
 
265
  with preclass_analytics:
266
  display_preclass_analytics(session)
267
  with inclass_analytics:
 
3
  from utils.sample_data import SAMPLE_CHAT_HISTORY, SAMPLE_STUDENT_PROGRESS
4
  from utils.helpers import display_progress_bar, create_notification, format_datetime
5
  from utils.sample_data import SAMPLE_SESSIONS, SAMPLE_COURSES
6
+ from file_upload_vectorize import upload_resource, extract_text_from_file, create_vector_store, resources_collection, model, assignment_submit
7
+ from db import courses_collection2, chat_history_collection, students_collection, faculty_collection, vectors_collection
8
+ from chatbot import insert_chat_message
9
+ from bson import ObjectId
10
+ from live_polls import LivePollFeature
11
+
12
+ def get_current_user():
13
+ if 'current_user' not in st.session_state:
14
+ return None
15
+ return students_collection.find_one({"_id": st.session_state.user_id})
16
+
17
+ def display_preclass_content(session, student_id):
18
  """Display pre-class materials for a session"""
19
  st.subheader("Pre-class Materials")
20
 
 
50
  # create_notification("Notes saved successfully!", "success")
51
 
52
  # Display pre-class materials
53
+ print(f"student_id: {type(student_id)}")
54
+
55
  materials = resources_collection.find({"session_id": session['session_id']})
56
+ print(f"materials: {type(materials)}")
57
  for material in materials:
58
+ print(f"material: {type(material)}")
 
 
 
 
59
  with st.expander(f"{material['file_name']} ({material['material_type'].upper()})"):
60
  file_type = material.get('file_type', 'unknown')
61
  if file_type == 'application/pdf':
 
72
  if st.button("Mark PDF as Read", key=f"pdf_{material['file_name']}"):
73
  create_notification("PDF marked as read!", "success")
74
 
75
+ user = get_current_user()
76
+ print(f"user: {type(user)}")
77
+
78
+ user = get_current_user()
79
 
80
+ # Chat input
81
+ # Add a check, if materials are available, only then show the chat input
82
+ if(st.session_state.user_type == "student"):
83
+ if materials:
84
+ if prompt := st.chat_input("Ask a question about Pre-class Materials"):
85
+ if len(st.session_state.messages) >= 20:
86
+ st.warning("Message limit (20) reached for this session.")
87
+ return
88
+
89
+ st.session_state.messages.append({"role": "user", "content": prompt})
90
+
91
+ # Display User Message
92
+ with st.chat_message("user"):
93
+ st.markdown(prompt)
94
+
95
+ # Get document context
96
+ context = ""
97
+ materials = resources_collection.find({"session_id": session['session_id']})
98
+ context = ""
99
+ vector_data = None
100
+
101
+ context = ""
102
+ for material in materials:
103
+ resource_id = material['_id']
104
+ vector_data = vectors_collection.find_one({"resource_id": resource_id})
105
+ if vector_data and 'text' in vector_data:
106
+ context += vector_data['text'] + "\n"
107
+
108
+ if not vector_data:
109
+ st.error("No Pre-class materials found for this session.")
110
+ return
111
+
112
+ try:
113
+ # Generate response using Gemini
114
+ context_prompt = f"""
115
+ Based on the following context, answer the user's question:
116
+
117
+ Context:
118
+ {context}
119
+
120
+ Question: {prompt}
121
+
122
+ Please provide a clear and concise answer based only on the information provided in the context.
123
+ """
124
+
125
+ response = model.generate_content(context_prompt)
126
+ if not response or not response.text:
127
+ st.error("No response received from the model")
128
+ return
129
+
130
+ assistant_response = response.text
131
+ # Display Assistant Response
132
+ with st.chat_message("assistant"):
133
+ st.markdown(assistant_response)
134
+
135
+ # Build the message
136
+ new_message = {
137
+ "prompt": prompt,
138
+ "response": assistant_response,
139
+ "timestamp": datetime.utcnow()
140
+ }
141
+ st.session_state.messages.append(new_message)
142
+
143
+ # Update database
144
+ try:
145
+ chat_history_collection.update_one(
146
+ {
147
+ "user_id": student_id,
148
+ "session_id": session['session_id']
149
+ },
150
+ {
151
+ "$push": {"messages": new_message},
152
+ "$setOnInsert": {
153
+ "user_id": student_id,
154
+ "session_id": session['session_id'],
155
+ "timestamp": datetime.utcnow()
156
+ }
157
+ },
158
+ upsert=True
159
+ )
160
+ except Exception as db_error:
161
+ st.error(f"Error saving chat history: {str(db_error)}")
162
+ except Exception as e:
163
+ st.error(f"Error generating response: {str(e)}")
164
 
165
+ st.subheader("Your Chat History")
166
+ # Initialize chat messages from database
167
+ if 'messages' not in st.session_state:
168
+ existing_chat = chat_history_collection.find_one({
169
+ "user_id": student_id,
170
+ "session_id": session['session_id']
171
+ })
172
+ if existing_chat and 'messages' in existing_chat:
173
+ st.session_state.messages = existing_chat['messages']
174
  else:
175
+ st.session_state.messages = []
176
+
177
+ # Display existing chat history
178
+ try:
179
+ for message in st.session_state.messages:
180
+ if 'prompt' in message and 'response' in message:
181
+ with st.chat_message("user"):
182
+ st.markdown(message["prompt"])
183
+ with st.chat_message("assistant"):
184
+ st.markdown(message["response"])
185
+ except Exception as e:
186
+ st.error(f"Error displaying chat history: {str(e)}")
187
+ st.session_state.messages = []
188
+
189
+ def display_in_class_content(session, user_type):
190
+ # """Display in-class activities and interactions"""
191
+ """Display in-class activities and interactions"""
192
+ st.header("In-class Activities")
193
 
194
+ # Initialize Live Polls feature
195
+ live_polls = LivePollFeature()
 
 
 
 
 
 
 
 
 
196
 
197
+ # Display appropriate interface based on user role
198
+ if user_type == 'faculty':
199
+ live_polls.display_faculty_interface(session['session_id'])
200
+ else:
201
+ live_polls.display_student_interface(session['session_id'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
 
203
+ def display_post_class_content(session, student_id, course_id):
204
  """Display post-class assignments and submissions"""
205
  st.header("Post-class Work")
206
 
207
+ if st.session_state.user_type == 'faculty':
208
+ st.subheader("Add Assignments")
209
+ # Add assignment form
210
+ with st.form("add_assignment_form"):
211
+ title = st.text_input("Assignment Title")
212
+ due_date = st.date_input("Due Date")
213
+ submit = st.form_submit_button("Add Assignment")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
+ if submit:
216
+ due_date = datetime.combine(due_date, datetime.min.time())
217
+ # Save the assignment to the database
218
+ assignment = {
219
+ "id": ObjectId(),
220
+ "title": title,
221
+ "due_date": due_date,
222
+ "status": "pending",
223
+ "submissions": []
224
+ }
225
+ courses_collection2.update_one(
226
+ {"course_id": course_id, "sessions.session_id": session['session_id']},
227
+ {"$push": {"sessions.$.post_class.assignments": assignment}}
228
+ )
229
+ st.success("Assignment added successfully!")
230
+ else:
231
+ # Display assignments
232
+ # assignments += courses_collection2.find_one(
233
+ # {"course_id": course_id, "sessions.session_id": session['session_id']},
234
+ # {"sessions.$.post_class.assignments": 1}
235
+ # )["sessions"][0]["post_class"]["assignments"]
236
+ session_data = courses_collection2.find_one(
237
+ {"course_id": course_id, "sessions.session_id": session['session_id']},
238
+ {"sessions.$": 1}
239
+ )
240
+ assignments = session_data["sessions"][0]["post_class"]["assignments"]
241
+ print(assignments)
242
+ for assignment in assignments:
243
+ with st.expander(f"Assignment: {assignment['title']}", expanded=True):
244
+ st.markdown(f"**Due Date:** {assignment['due_date']}")
245
+ st.markdown(f"**Status:** {assignment['status'].replace('_', ' ').title()}")
246
+
247
+ # Assignment details
248
+ st.markdown("### Instructions")
249
+ st.markdown("Complete the assignment according to the provided guidelines.")
250
+
251
+ # File submission
252
+ st.markdown("### Submission")
253
+ uploaded_file = st.file_uploader(
254
+ "Upload your work",
255
+ type=['pdf', 'py', 'ipynb'],
256
+ key=f"upload_{assignment['id']}"
257
+ )
258
+
259
+ if uploaded_file is not None:
260
+ st.success("File uploaded successfully!")
261
+
262
+ if st.button("Submit Assignment", key=f"submit_{assignment['id']}"):
263
+ # Save the file to a location and get the file URL
264
+ assignment_submit(student_id, course_id, session['session_id'], uploaded_file.name, uploaded_file, uploaded_file.type)
265
+
266
+ # Display submitted assignments
267
+ st.markdown(f"📑 [Click to view Submission]({uploaded_file['file_name']})")
268
+ if st.button("View PDF", key=f"view_pdf_{uploaded_file['file_name']}"):
269
+ st.text_area("PDF Content", uploaded_file['text_content'], height=300)
270
+ if st.button("Download PDF", key=f"download_pdf_{uploaded_file['file_name']}"):
271
+ st.download_button(
272
+ label="Download PDF",
273
+ data=uploaded_file['file_content'],
274
+ file_name=uploaded_file['file_name'],
275
+ mime='application/pdf'
276
+ )
277
+
278
+ # Feedback section (if assignment is completed)
279
+ if assignment['status'] == 'completed':
280
+ st.markdown("### Feedback")
281
+ st.info("Feedback will be provided here once the assignment is graded.")
282
+
283
+
284
+
285
+
286
+
287
 
288
  def display_preclass_analytics(session):
289
  """Display pre-class analytics for faculty"""
 
320
  """Display post-class analytics for faculty"""
321
  st.subheader("Post-class Analytics")
322
 
323
+ # # Display assignment completion rates
324
+ # for assignment in session['post_class']['assignments']:
325
+ # progress = SAMPLE_STUDENT_PROGRESS.get(assignment['id'], 0)
326
+ # display_progress_bar(progress, 100, assignment['title'])
327
 
328
 
329
  def upload_preclass_materials(session_id, course_id):
 
357
 
358
 
359
 
360
+ def display_session_content(student_id, course_id, session, username, user_type):
361
  st.title(f"Session {session['session_id']}: {session['title']}")
362
  st.markdown(f"**Date:** {format_datetime(session['date'])}")
363
  st.markdown(f"**Status:** {session['status'].replace('_', ' ').title()}")
 
385
  # Display pre-class materials
386
  if st.session_state.user_type == 'student':
387
  with pre_class_tab:
388
+ display_preclass_content(session, student_id)
389
 
390
  with in_class_tab:
391
+ display_in_class_content(session, st.session_state.user_type)
392
 
393
  # Post-class Content
394
  with post_class_tab:
395
+ display_post_class_content(session, student_id, course_id)
396
 
397
  if st.session_state.user_type == 'faculty':
398
  with pre_class_work:
399
  upload_preclass_materials(session['session_id'], course_id)
400
+ with in_class_work:
401
+ display_in_class_content(session, st.session_state.user_type)
402
+ with post_class_work:
403
+ display_post_class_content(session, student_id, course_id)
404
  with preclass_analytics:
405
  display_preclass_analytics(session)
406
  with inclass_analytics: