Commit 0e91389b authored by I.K Seneviratne's avatar I.K Seneviratne

Initial commit to the monitoring_student_behavior branch

parent 2a3db16a
...@@ -128,7 +128,7 @@ class LectureActivity(models.Model): ...@@ -128,7 +128,7 @@ class LectureActivity(models.Model):
# Lecture emotion report # Lecture emotion report
class LectureEmotionReport(models.Model): class LectureEmotionReport(models.Model):
lecture_emotion_id = models.CharField(max_length=10) lecture_emotion_id = models.CharField(max_length=10)
lecture_video_id = models.ForeignKey(LectureVideo, on_delete=models.CASCADE) lecture_video_id = models.ForeignKey(LectureVideo, on_delete=models.CASCADE, default=0)
happy_perct = models.DecimalField(default=0.0, max_digits=3, decimal_places=1) happy_perct = models.DecimalField(default=0.0, max_digits=3, decimal_places=1)
sad_perct = models.DecimalField(default=0.0, max_digits=3, decimal_places=1) sad_perct = models.DecimalField(default=0.0, max_digits=3, decimal_places=1)
angry_perct = models.DecimalField(default=0.0, max_digits=3, decimal_places=1) angry_perct = models.DecimalField(default=0.0, max_digits=3, decimal_places=1)
...@@ -143,6 +143,14 @@ class LectureEmotionReport(models.Model): ...@@ -143,6 +143,14 @@ class LectureEmotionReport(models.Model):
# POSE section # POSE section
# lecture pose estimation # lecture pose estimation
class LecturePoseEstimation(models.Model): class LectureGazeEstimation(models.Model):
lecture_pose_id = models.CharField(max_length=10) lecture_gaze_id = models.CharField(max_length=10)
lecture_video_id = models.ForeignKey(LectureVideo, on_delete=models.CASCADE) lecture_video_id = models.ForeignKey(LectureVideo, on_delete=models.CASCADE)
looking_up_and_right_perct = models.DecimalField(default=0.0, max_digits=3, decimal_places=1)
looking_up_and_left_perct = models.DecimalField(default=0.0, max_digits=3, decimal_places=1)
looking_down_and_right_perct = models.DecimalField(default=0.0, max_digits=3, decimal_places=1)
looking_down_and_left_perct = models.DecimalField(default=0.0, max_digits=3, decimal_places=1)
looking_front_perct = models.DecimalField(default=0.0, max_digits=3, decimal_places=1)
def __str__(self):
return self.lecture_gaze_id
\ No newline at end of file
from rest_framework.permissions import IsAuthenticated, IsAdminUser from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.authentication import SessionAuthentication, BasicAuthentication from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from . MongoModels import * from .MongoModels import *
from rest_framework.views import * from rest_framework.views import *
from . ImageOperations import saveImage from .ImageOperations import saveImage
from . logic import head_pose_estimation from .logic import head_pose_estimation
from . logic import video_extraction from .logic import video_extraction
from . logic import activity_recognition as ar from .logic import activity_recognition as ar
from . logic import posenet_calculation as pc from .logic import posenet_calculation as pc
from . import emotion_detector as ed from . import emotion_detector as ed
from . logic import id_generator as ig from .logic import id_generator as ig
from . models import Teachers, Video, VideoMeta, RegisterUser from .logic import pdf_file_generator as pdf
from . MongoModels import * from .logic import head_gaze_estimation as hge
from . serializers import * from .models import Teachers, Video, VideoMeta, RegisterUser
from .MongoModels import *
from .serializers import *
import datetime
# to create images # to create images
class ImageViewSet(APIView): class ImageViewSet(APIView):
...@@ -41,6 +46,7 @@ class VideoExtractionViewSet(APIView): ...@@ -41,6 +46,7 @@ class VideoExtractionViewSet(APIView):
response = video_extraction.VideoExtractor(request.data) response = video_extraction.VideoExtractor(request.data)
return Response({"response": response}) return Response({"response": response})
# lecture emotions view set # lecture emotions view set
class LectureEmotionViewSet(APIView): class LectureEmotionViewSet(APIView):
...@@ -75,6 +81,7 @@ class LectureViewSet(APIView): ...@@ -75,6 +81,7 @@ class LectureViewSet(APIView):
).save() ).save()
return Response({"response": request}) return Response({"response": request})
# API for Faculties # API for Faculties
class FacultyViewSet(APIView): class FacultyViewSet(APIView):
...@@ -90,6 +97,7 @@ class FacultyViewSet(APIView): ...@@ -90,6 +97,7 @@ class FacultyViewSet(APIView):
).save() ).save()
return Response(status=201, data={"response": "successfully added"}) return Response(status=201, data={"response": "successfully added"})
# API for subjects # API for subjects
class SubjectViewSet(APIView): class SubjectViewSet(APIView):
...@@ -99,7 +107,6 @@ class SubjectViewSet(APIView): ...@@ -99,7 +107,6 @@ class SubjectViewSet(APIView):
return Response(serializer.data) return Response(serializer.data)
def post(self, request): def post(self, request):
serializer = SubjectSerializer(data=request.data) serializer = SubjectSerializer(data=request.data)
if serializer.is_valid(raise_exception=ValueError): if serializer.is_valid(raise_exception=ValueError):
serializer.create(validated_data=request.data) serializer.create(validated_data=request.data)
...@@ -118,7 +125,6 @@ class LecturerViewSet(APIView): ...@@ -118,7 +125,6 @@ class LecturerViewSet(APIView):
return Response(serializer.data) return Response(serializer.data)
def post(self, request): def post(self, request):
serializer = LecturerSerializer(data=request.data) serializer = LecturerSerializer(data=request.data)
if serializer.is_valid(raise_exception=ValueError): if serializer.is_valid(raise_exception=ValueError):
serializer.create(validated_data=request.data) serializer.create(validated_data=request.data)
...@@ -137,7 +143,6 @@ class LecturerSubjectViewSet(APIView): ...@@ -137,7 +143,6 @@ class LecturerSubjectViewSet(APIView):
return Response(serializer.data) return Response(serializer.data)
def post(self, request): def post(self, request):
serializer = LecturerSubjectSerializer(data=request.data) serializer = LecturerSubjectSerializer(data=request.data)
if serializer.is_valid(raise_exception=ValueError): if serializer.is_valid(raise_exception=ValueError):
serializer.create(validated_data=request.data) serializer.create(validated_data=request.data)
...@@ -156,7 +161,6 @@ class FacultyTimetableViewSet(APIView): ...@@ -156,7 +161,6 @@ class FacultyTimetableViewSet(APIView):
return Response(serializer.data) return Response(serializer.data)
def post(self, request): def post(self, request):
serializer = FacultyTimetableSerializer(data=request.data) serializer = FacultyTimetableSerializer(data=request.data)
if serializer.is_valid(raise_exception=ValueError): if serializer.is_valid(raise_exception=ValueError):
serializer.create(validated_data=request.data) serializer.create(validated_data=request.data)
...@@ -175,7 +179,6 @@ class LectureVideoViewSet(APIView): ...@@ -175,7 +179,6 @@ class LectureVideoViewSet(APIView):
return Response(serializer.data) return Response(serializer.data)
def post(self, request): def post(self, request):
serializer = LectureVideoSerializer(data=request.data) serializer = LectureVideoSerializer(data=request.data)
if serializer.is_valid(raise_exception=ValueError): if serializer.is_valid(raise_exception=ValueError):
serializer.create(validated_data=request.data) serializer.create(validated_data=request.data)
...@@ -215,7 +218,6 @@ class LectureActivityViewSet(APIView): ...@@ -215,7 +218,6 @@ class LectureActivityViewSet(APIView):
return Response(serializer.data) return Response(serializer.data)
def post(self, request): def post(self, request):
serializer = LectureActivitySerializer(data=request.data) serializer = LectureActivitySerializer(data=request.data)
if serializer.is_valid(raise_exception=ValueError): if serializer.is_valid(raise_exception=ValueError):
serializer.create(validated_data=request.data) serializer.create(validated_data=request.data)
...@@ -337,6 +339,38 @@ class GetLectureActivityRecognitionsForFrames(APIView): ...@@ -337,6 +339,38 @@ class GetLectureActivityRecognitionsForFrames(APIView):
}) })
# API to create reports for Activity
class GenerateActivityReport(APIView):
def get(self, request):
subject = request.query_params.get('subject')
lecturer = int(request.query_params.get('lecturer'))
date = request.query_params.get('date')
# retrieve the subject name
subject_query = Subject.objects.filter(subject_code=subject)
subject_serializer = SubjectSerializer(subject_query, many=True)
subject_name = subject_serializer.data[0]['name']
# retrieve the lecturer name
# lecturer_query = Lecturer.objects.filter(lecturer_id=lecturer)
lecturer_query = Lecturer.objects.filter(id=lecturer)
lecturer_serializer = LecturerSerializer(lecturer_query, many=True)
lecturer_lname = lecturer_serializer.data[0]['lname']
lecturer_fname = lecturer_serializer.data[0]['fname']
lecturer_fullname = lecturer_fname + " " + lecturer_lname
# set the dictionary
object = {}
object['subject_name'] = subject_name
object['lecturer_name'] = lecturer_fullname
object['date'] = date
pdf.generate_pdf_file(object)
return Response({
"response": "success"
})
###### EMOTIONS section ##### ###### EMOTIONS section #####
...@@ -358,6 +392,7 @@ class GetLectureEmotionAvailability(APIView): ...@@ -358,6 +392,7 @@ class GetLectureEmotionAvailability(APIView):
"isActivityFound": isActivityFound "isActivityFound": isActivityFound
}) })
# to process lecture emotions for a lecture video # to process lecture emotions for a lecture video
class LectureEmotionProcess(APIView): class LectureEmotionProcess(APIView):
...@@ -455,11 +490,12 @@ class GetLectureVideoForPose(APIView): ...@@ -455,11 +490,12 @@ class GetLectureVideoForPose(APIView):
def get(self, request): def get(self, request):
lecturer = request.query_params.get('lecturer') lecturer = request.query_params.get('lecturer')
date = request.query_params.get('date') date = request.query_params.get('date')
index = int(request.query_params.get('index'))
lecturer_video = LectureVideo.objects.filter(lecturer_id=lecturer, date=date) lecturer_video = LectureVideo.objects.filter(lecturer_id=lecturer, date=date)
serializer = LectureVideoSerializer(lecturer_video, many=True) serializer = LectureVideoSerializer(lecturer_video, many=True)
return Response({ return Response({
"response": serializer.data "response": serializer.data[index]
}) })
...@@ -514,3 +550,168 @@ class ProcessIndividualStudentPoseEstimation(APIView): ...@@ -514,3 +550,168 @@ class ProcessIndividualStudentPoseEstimation(APIView):
}) })
##### GAZE ESTIMATION SECTION #####
class GetLectureGazeEstimationAvailaibility(APIView):
def get(self, request):
lecturer = request.query_params.get('lecturer')
date = request.query_params.get('date')
index = int(request.query_params.get('index'))
lecturer_video = LectureVideo.objects.filter(lecturer_id=lecturer, date=date)
serializer = LectureVideoSerializer(lecturer_video, many=True)
lecture_video_id = serializer.data[index]['lecture_video_id']
gaze_estimation = LectureGazeEstimation.objects.filter(lecture_video_id__lecture_video_id=lecture_video_id)
isGazeEstimationFound = (len(gaze_estimation) > 0)
return Response({
"response": serializer.data[index],
"isGazeEstimationFound": isGazeEstimationFound
})
# the API to process lecture gaze estimation
class ProcessLectureGazeEstimation(APIView):
def get(self, request):
video_name = request.query_params.get('lecture_video_name')
video_id = request.query_params.get('lecture_video_id')
percentages = hge.process_gaze_estimation(video_name)
self.estimate_gaze(video_id, percentages)
return Response({"response": True})
def post(self, request):
pass
def estimate_gaze(self, lec_video_id, percentages):
lec_video = LectureVideo.objects.get(lecture_video_id=lec_video_id)
last_lec_gaze = LectureGazeEstimation.objects.order_by('lecture_gaze_id').last()
lec_video_serializer = LectureVideoSerializer(lec_video, many=True)
new_lecture_gaze_id = "LG000001" if (last_lec_gaze is None) else ig.generate_new_id(
last_lec_gaze.lecture_gaze_id)
# creating a new lecture gaze estimation
LectureGazeEstimation(
lecture_gaze_id=new_lecture_gaze_id,
lecture_video_id=lec_video,
looking_up_and_right_perct=percentages['head_up_right_perct'],
looking_up_and_left_perct=percentages['head_up_left_perct'],
looking_down_and_right_perct=percentages['head_down_right_perct'],
looking_down_and_left_perct=percentages['head_down_left_perct'],
looking_front_perct=percentages['head_front_perct']
).save()
# the API to retrieve lecture gaze estimation
class GetLectureGazeEstimationViewSet(APIView):
def get(self, request):
lecture_video_id = request.query_params.get('lecture_video_id')
lecture_video_name = request.query_params.get('lecture_video_name')
# retrieve the extracted frames
extracted = hge.getExtractedFrames(lecture_video_name)
lecture_gaze_estimations = LectureGazeEstimation.objects.filter(
lecture_video_id__lecture_video_id=lecture_video_id)
serializer = LectureGazeEstimationSerializer(lecture_gaze_estimations, many=True)
return Response({
"response": serializer.data,
"extracted": extracted
})
# the API to retrieve Gaze estimation for frames
class GetLectureGazeEstimationForFrames(APIView):
def get(self, request):
video_name = request.query_params.get('video_name')
frame_detections, frame_rate = hge.get_lecture_gaze_esrimation_for_frames(video_name)
return Response({
"response": frame_detections,
"frame_rate": frame_rate
})
##### VIDEO RESULTS SECTION #####
# this API find the lectures which are yet to be processed
class LectureProcessAvailability(APIView):
def get(self, request):
lecturer = request.query_params.get('lecturer')
lecturer_videos = LectureVideo.objects.filter(lecturer_id=lecturer)
serializer = LectureVideoSerializer(lecturer_videos, many=True)
data = serializer.data
for video in data:
print('video name: ', video['video_name'])
return Response({
"response": "hello"
})
##### VIEW STUDENT BEHAVIOR SUMMARY SECTION #####
# this API will retrieve student behavior summary for specified time period
class GetStudentBehaviorSummaryForPeriod(APIView):
def get(self, request):
option = request.query_params.get('option')
lecturer = request.query_params.get('lecturer')
int_lecturer = int(lecturer)
int_option = int(option)
# int_option = 150
isRecordFound = False
activity_percentages = {}
emotion_percentages = {}
individual_lec_activties = []
individual_lec_emotions = []
activity_labels = []
emotion_labels = []
current_date = datetime.datetime.now().date()
option_date = datetime.timedelta(days=int_option)
previous_date = current_date - option_date
# retrieving lecture activities
lec_activity = LectureActivity.objects.filter(
lecture_video_id__date__gte=previous_date,
lecture_video_id__date__lte=current_date,
lecture_video_id__lecturer=lecturer
)
if len(lec_activity) > 0:
isRecordFound = True
activity_serializer = LectureActivitySerializer(lec_activity, many=True)
activity_data = activity_serializer.data
activity_percentages, individual_lec_activties, activity_labels = ar.get_student_activity_summary_for_period(activity_data)
# retrieving lecture emotions
lec_emotion = LectureEmotionReport.objects.filter(
lecture_video_id__date__gte=previous_date,
lecture_video_id__date__lte=current_date,
lecture_video_id__lecturer=lecturer
)
if len(lec_emotion) > 0:
emotion_serializer = LectureEmotionSerializer(lec_emotion, many=True)
emotion_data = emotion_serializer.data
emotion_percentages, individual_lec_emotions, emotion_labels = ed.get_student_emotion_summary_for_period(emotion_data)
return Response({
"activity_response": activity_percentages,
"emotion_response": emotion_percentages,
"individual_activities": individual_lec_activties,
"individual_emotions": individual_lec_emotions,
"activity_labels": activity_labels,
"emotion_labels": emotion_labels,
"isRecordFound": isRecordFound
})
...@@ -66,7 +66,6 @@ def detect_emotion(video): ...@@ -66,7 +66,6 @@ def detect_emotion(video):
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_classifier.detectMultiScale(gray,1.3,5) faces = face_classifier.detectMultiScale(gray,1.3,5)
print('number of faces: ', len(faces))
for (x, y, w, h) in faces: for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2) cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
...@@ -104,13 +103,9 @@ def detect_emotion(video): ...@@ -104,13 +103,9 @@ def detect_emotion(video):
elif (label == 'Sad'): elif (label == 'Sad'):
count_sad += 1 count_sad += 1
# path = os.path.join(BASE_DIR, 'static\\images\\Sad')
# cv2.imwrite(os.path.join(path, 'Sad-{0}.jpg'.format(count)), frame)
elif (label == 'Surprise'): elif (label == 'Surprise'):
count_surprise += 1 count_surprise += 1
# path = os.path.join(BASE_DIR, 'static\\images\\Surprise')
# cv2.imwrite(os.path.join(path, 'Surprise-{0}.jpg'.format(count)), frame)
label_position = (x, y) label_position = (x, y)
# cv2.putText(frame, label, label_position, cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 255, 0), 3) # cv2.putText(frame, label, label_position, cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 255, 0), 3)
...@@ -118,13 +113,9 @@ def detect_emotion(video): ...@@ -118,13 +113,9 @@ def detect_emotion(video):
else: else:
cv2.putText(frame, 'No Face Found', (20, 60), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 255, 0), 3) cv2.putText(frame, 'No Face Found', (20, 60), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 255, 0), 3)
# cv2.imshow('Emotion Detector',frame)
count_frames += 1 count_frames += 1
# if cv2.waitKey(1) & 0xFF == ord('q'):
# break
# setting up the counted values # setting up the counted values
meta_data.frame_count = count_frames meta_data.frame_count = count_frames
meta_data.happy_count = count_happy meta_data.happy_count = count_happy
meta_data.sad_count = count_sad meta_data.sad_count = count_sad
...@@ -328,11 +319,11 @@ def get_frame_emotion_recognition(video_name): ...@@ -328,11 +319,11 @@ def get_frame_emotion_recognition(video_name):
# calculating the percentages for the frame # calculating the percentages for the frame
happy_perct = float(happy_count / detection_count) * 100 happy_perct = float(happy_count / detection_count) * 100 if detection_count > 0 else 0
sad_perct = float(sad_count / detection_count) * 100 sad_perct = float(sad_count / detection_count) * 100 if detection_count > 0 else 0
angry_perct = float(angry_count / detection_count) * 100 angry_perct = float(angry_count / detection_count) * 100 if detection_count > 0 else 0
neutral_perct = float(neutral_count / detection_count) * 100 neutral_perct = float(neutral_count / detection_count) * 100 if detection_count > 0 else 0
surprise_perct = float(surprise_count / detection_count) * 100 surprise_perct = float(surprise_count / detection_count) * 100 if detection_count > 0 else 0
# this dictionary will be returned # this dictionary will be returned
frame_details['happy_perct'] = happy_perct frame_details['happy_perct'] = happy_perct
...@@ -349,3 +340,62 @@ def get_frame_emotion_recognition(video_name): ...@@ -349,3 +340,62 @@ def get_frame_emotion_recognition(video_name):
# return the detected frame percentages # return the detected frame percentages
return sorted_activity_frame_recognitions return sorted_activity_frame_recognitions
# this method will retrieve student activity summary for given time period
def get_student_emotion_summary_for_period(emotions):
# declare variables to add percentage values
happy_perct_combined = 0.0
sad_perct_combined = 0.0
angry_perct_combined = 0.0
disgust_perct_combined = 0.0
surprise_perct_combined = 0.0
neutral_perct_combined = 0.0
# get the number of activties to calculate average
no_of_emotions = len(emotions)
individual_lec_emotions = []
emotion_labels = ["happy_perct", "sad_perct", "angry_perct", "disgust_perct", "surprise_perct", "neutral_perct"]
# iterate through the activities
for emotion in emotions:
individual_emotion = {}
individual_emotion["happy_perct"] = float(emotion['happy_perct'])
individual_emotion["sad_perct"] = float(emotion['sad_perct'])
individual_emotion["angry_perct"] = float(emotion['angry_perct'])
individual_emotion["disgust_perct"] = float(emotion['disgust_perct'])
individual_emotion["surprise_perct"] = float(emotion['surprise_perct'])
individual_emotion["neutral_perct"] = float(emotion['neutral_perct'])
happy_perct_combined += float(emotion['happy_perct'])
sad_perct_combined += float(emotion['sad_perct'])
angry_perct_combined += float(emotion['angry_perct'])
disgust_perct_combined += float(emotion['disgust_perct'])
surprise_perct_combined += float(emotion['surprise_perct'])
neutral_perct_combined += float(emotion['neutral_perct'])
# append to the list
individual_lec_emotions.append(individual_emotion)
# calculate the average percentages
happy_average_perct = round((happy_perct_combined / no_of_emotions), 1)
sad_average_perct = round((sad_perct_combined / no_of_emotions), 1)
angry_average_perct = round((angry_perct_combined / no_of_emotions), 1)
disgust_average_perct = round((disgust_perct_combined / no_of_emotions), 1)
surprise_average_perct = round((surprise_perct_combined / no_of_emotions), 1)
neutral_average_perct = round((neutral_perct_combined / no_of_emotions), 1)
percentages = {}
percentages["happy_perct"] = happy_average_perct
percentages["sad_perct"] = sad_average_perct
percentages["angry_perct"] = angry_average_perct
percentages["disgust_perct"] = disgust_average_perct
percentages["surprise_perct"] = surprise_average_perct
percentages["neutral_perct"] = neutral_average_perct
return percentages, individual_lec_emotions, emotion_labels
\ No newline at end of file
...@@ -51,7 +51,7 @@ def activity_recognition(video_path): ...@@ -51,7 +51,7 @@ def activity_recognition(video_path):
note_taking_count = 0 note_taking_count = 0
listening_count = 0 listening_count = 0
# video activity didrectory # video activity directory
VIDEO_ACTIVITY_DIR = os.path.join(ACTIVITY_DIR, video_path) VIDEO_ACTIVITY_DIR = os.path.join(ACTIVITY_DIR, video_path)
# creating the directory for the video # creating the directory for the video
...@@ -75,7 +75,6 @@ def activity_recognition(video_path): ...@@ -75,7 +75,6 @@ def activity_recognition(video_path):
os.mkdir(FRAME_DIR) os.mkdir(FRAME_DIR)
image = cv2.resize(image, size) image = cv2.resize(image, size)
# image = ImageOps.fit(image, size, Image.ANTIALIAS)
detections = person_detection(image, net) detections = person_detection(image, net)
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
...@@ -130,10 +129,10 @@ def activity_recognition(video_path): ...@@ -130,10 +129,10 @@ def activity_recognition(video_path):
p.write("yes") p.write("yes")
# calculating the percentages for each label # calculating the percentages for each label
phone_perct = float(phone_checking_count / total_detections) * 100 phone_perct = float(phone_checking_count / total_detections) * 100 if total_detections > 0 else 0
talking_perct = float(talking_count / total_detections) * 100 talking_perct = float(talking_count / total_detections) * 100 if total_detections > 0 else 0
note_perct = float(note_taking_count / total_detections) * 100 note_perct = float(note_taking_count / total_detections) * 100 if total_detections > 0 else 0
listening_perct = float(listening_count / total_detections) * 100 listening_perct = float(listening_count / total_detections) * 100 if total_detections > 0 else 0
# assigning the percentages to the dictionary # assigning the percentages to the dictionary
percentages["phone_perct"] = phone_perct percentages["phone_perct"] = phone_perct
...@@ -572,3 +571,47 @@ def get_individual_student_evaluation(video_name, student_name): ...@@ -572,3 +571,47 @@ def get_individual_student_evaluation(video_name, student_name):
percentages['listening_perct'] = listening_perct percentages['listening_perct'] = listening_perct
return percentages return percentages
# this method will retrieve student activity summary for given time period
def get_student_activity_summary_for_period(activities):
# declare variables to add percentage values
phone_checking_perct_combined = 0.0
listening_perct_combined = 0.0
note_taking_perct_combined = 0.0
# get the number of activties to calculate average
no_of_activities = len(activities)
individual_lec_activities = []
activity_labels = ["phone_perct", "listening_perct", "writing_perct"]
# iterate through the activities
for activity in activities:
individual_activity = {}
individual_activity["phone_perct"] = float(activity['phone_perct'])
individual_activity["listening_perct"] = float(activity['listening_perct'])
individual_activity["writing_perct"] = float(activity['writing_perct'])
phone_checking_perct_combined += float(activity['phone_perct'])
listening_perct_combined += float(activity['listening_perct'])
note_taking_perct_combined += float(activity['writing_perct'])
# append to the list
individual_lec_activities.append(individual_activity)
# calculate the average percentages
phone_checking_average_perct = round((phone_checking_perct_combined / no_of_activities), 1)
listening_average_perct = round((listening_perct_combined / no_of_activities), 1)
note_taking_average_perct = round((note_taking_perct_combined / no_of_activities), 1)
percentages = {}
percentages["phone_perct"] = phone_checking_average_perct
percentages["listening_perct"] = listening_average_perct
percentages["writing_perct"] = note_taking_average_perct
return percentages, individual_lec_activities, activity_labels
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
Created on Wed Jul 29 17:52:00 2020
@author: hp
"""
import cv2
import numpy as np
import os
def get_face_detector(modelFile = "models/res10_300x300_ssd_iter_140000.caffemodel",
configFile = "models/deploy.prototxt"):
"""
Get the face detection caffe model of OpenCV's DNN module
Parameters
----------
modelFile : string, optional
Path to model file. The default is "models/res10_300x300_ssd_iter_140000.caffemodel".
configFile : string, optional
Path to config file. The default is "models/deploy.prototxt".
Returns
-------
model : dnn_Net
"""
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
CLASSIFIER_DIR = os.path.join(BASE_DIR, "FirstApp\\classifiers")
modelFile = os.path.join(CLASSIFIER_DIR, "res10_300x300_ssd_iter_140000.caffemodel")
configFile = os.path.join(CLASSIFIER_DIR, "deploy.prototxt")
model = cv2.dnn.readNetFromCaffe(configFile, modelFile)
return model
def find_faces(img, model):
"""
Find the faces in an image
Parameters
----------
img : np.uint8
Image to find faces from
model : dnn_Net
Face detection model
Returns
-------
faces : list
List of coordinates of the faces detected in the image
"""
h, w = img.shape[:2]
blob = cv2.dnn.blobFromImage(cv2.resize(img, (300, 300)), 1.0,
(300, 300), (104.0, 177.0, 123.0))
model.setInput(blob)
res = model.forward()
faces = []
for i in range(res.shape[2]):
confidence = res[0, 0, i, 2]
if confidence > 0.5:
box = res[0, 0, i, 3:7] * np.array([w, h, w, h])
(x, y, x1, y1) = box.astype("int")
faces.append([x, y, x1, y1])
return faces
def draw_faces(img, faces):
"""
Draw faces on image
Parameters
----------
img : np.uint8
Image to draw faces on
faces : List of face coordinates
Coordinates of faces to draw
Returns
-------
None.
"""
for x, y, x1, y1 in faces:
cv2.rectangle(img, (x, y), (x1, y1), (0, 0, 255), 3)
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
Created on Wed Jul 29 19:47:08 2020
@author: hp
"""
import cv2
import numpy as np
import tensorflow as tf
from tensorflow import keras
import os
def get_landmark_model():
"""
Get the facial landmark model.
Original repository: https://github.com/yinguobing/cnn-facial-landmark
Parameters
----------
saved_model : string, optional
Path to facial landmarks model. The default is 'models/pose_model'.
Returns
-------
model : Tensorflow model
Facial landmarks model
"""
# define the location of the pose model
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
saved_model = os.path.join(BASE_DIR, "FirstApp\\classifiers\\pose_model")
model = keras.models.load_model(saved_model)
return model
def get_square_box(box):
"""Get a square box out of the given box, by expanding it."""
left_x = box[0]
top_y = box[1]
right_x = box[2]
bottom_y = box[3]
box_width = right_x - left_x
box_height = bottom_y - top_y
# Check if box is already a square. If not, make it a square.
diff = box_height - box_width
delta = int(abs(diff) / 2)
if diff == 0: # Already a square.
return box
elif diff > 0: # Height > width, a slim box.
left_x -= delta
right_x += delta
if diff % 2 == 1:
right_x += 1
else: # Width > height, a short box.
top_y -= delta
bottom_y += delta
if diff % 2 == 1:
bottom_y += 1
# Make sure box is always square.
assert ((right_x - left_x) == (bottom_y - top_y)), 'Box is not square.'
return [left_x, top_y, right_x, bottom_y]
def move_box(box, offset):
"""Move the box to direction specified by vector offset"""
left_x = box[0] + offset[0]
top_y = box[1] + offset[1]
right_x = box[2] + offset[0]
bottom_y = box[3] + offset[1]
return [left_x, top_y, right_x, bottom_y]
def detect_marks(img, model, face):
"""
Find the facial landmarks in an image from the faces
Parameters
----------
img : np.uint8
The image in which landmarks are to be found
model : Tensorflow model
Loaded facial landmark model
face : list
Face coordinates (x, y, x1, y1) in which the landmarks are to be found
Returns
-------
marks : numpy array
facial landmark points
"""
offset_y = int(abs((face[3] - face[1]) * 0.1))
box_moved = move_box(face, [0, offset_y])
facebox = get_square_box(box_moved)
# reassigning the facebox values
facebox[0] = facebox[0] if facebox[0] > 0 else 0
facebox[1] = facebox[1] if facebox[1] > 0 else 0
facebox[2] = facebox[2] if facebox[2] > 0 else 0
facebox[3] = facebox[3] if facebox[3] > 0 else 0
# draw a bounding box
cv2.rectangle(img, (facebox[0], facebox[1]), (facebox[2], facebox[3]), (0, 255, 0), 2)
face_img = img[facebox[1]: facebox[3],
facebox[0]: facebox[2]]
marks = np.zeros((68, 2))
# if the list length is more than 0
if len(face_img) > 0:
face_img = cv2.resize(face_img, (128, 128))
face_img = cv2.cvtColor(face_img, cv2.COLOR_BGR2RGB)
# # Actual detection.
predictions = model.signatures["predict"](
tf.constant([face_img], dtype=tf.uint8))
# Convert predictions to landmarks.
marks = np.array(predictions['output']).flatten()[:136]
marks = np.reshape(marks, (-1, 2))
marks *= (facebox[2] - facebox[0])
marks[:, 0] += facebox[0]
marks[:, 1] += facebox[1]
marks = marks.astype(np.uint)
# return marks
# return detected facial marks and face coordinates
return marks, facebox
def draw_marks(image, marks, color=(0, 255, 0)):
"""
Draw the facial landmarks on an image
Parameters
----------
image : np.uint8
Image on which landmarks are to be drawn.
marks : list or numpy array
Facial landmark points
color : tuple, optional
Color to which landmarks are to be drawn with. The default is (0, 255, 0).
Returns
-------
None.
"""
for mark in marks:
cv2.circle(image, (mark[0], mark[1]), 2, color, -1, cv2.LINE_AA)
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
Created on Fri Jul 31 03:00:36 2020
@author: hp
"""
from decimal import Decimal
from . custom_sorter import *
import cv2
import numpy as np
import math
from . face_detector import get_face_detector, find_faces
from . face_landmarks import get_landmark_model, detect_marks
import os
import shutil
import math
def get_2d_points(img, rotation_vector, translation_vector, camera_matrix, val):
"""Return the 3D points present as 2D for making annotation box"""
point_3d = []
dist_coeffs = np.zeros((4, 1))
rear_size = val[0]
rear_depth = val[1]
point_3d.append((-rear_size, -rear_size, rear_depth))
point_3d.append((-rear_size, rear_size, rear_depth))
point_3d.append((rear_size, rear_size, rear_depth))
point_3d.append((rear_size, -rear_size, rear_depth))
point_3d.append((-rear_size, -rear_size, rear_depth))
front_size = val[2]
front_depth = val[3]
point_3d.append((-front_size, -front_size, front_depth))
point_3d.append((-front_size, front_size, front_depth))
point_3d.append((front_size, front_size, front_depth))
point_3d.append((front_size, -front_size, front_depth))
point_3d.append((-front_size, -front_size, front_depth))
point_3d = np.array(point_3d, dtype=np.float).reshape(-1, 3)
# Map to 2d img points
(point_2d, _) = cv2.projectPoints(point_3d,
rotation_vector,
translation_vector,
camera_matrix,
dist_coeffs)
point_2d = np.int32(point_2d.reshape(-1, 2))
return point_2d
def draw_annotation_box(img, rotation_vector, translation_vector, camera_matrix,
rear_size=300, rear_depth=0, front_size=500, front_depth=400,
color=(255, 255, 0), line_width=2):
"""
Draw a 3D anotation box on the face for head pose estimation
Parameters
----------
img : np.unit8
Original Image.
rotation_vector : Array of float64
Rotation Vector obtained from cv2.solvePnP
translation_vector : Array of float64
Translation Vector obtained from cv2.solvePnP
camera_matrix : Array of float64
The camera matrix
rear_size : int, optional
Size of rear box. The default is 300.
rear_depth : int, optional
The default is 0.
front_size : int, optional
Size of front box. The default is 500.
front_depth : int, optional
Front depth. The default is 400.
color : tuple, optional
The color with which to draw annotation box. The default is (255, 255, 0).
line_width : int, optional
line width of lines drawn. The default is 2.
Returns
-------
None.
"""
rear_size = 1
rear_depth = 0
front_size = img.shape[1]
front_depth = front_size * 2
val = [rear_size, rear_depth, front_size, front_depth]
point_2d = get_2d_points(img, rotation_vector, translation_vector, camera_matrix, val)
# # Draw all the lines
cv2.polylines(img, [point_2d], True, color, line_width, cv2.LINE_AA)
cv2.line(img, tuple(point_2d[1]), tuple(
point_2d[6]), color, line_width, cv2.LINE_AA)
cv2.line(img, tuple(point_2d[2]), tuple(
point_2d[7]), color, line_width, cv2.LINE_AA)
cv2.line(img, tuple(point_2d[3]), tuple(
point_2d[8]), color, line_width, cv2.LINE_AA)
def head_pose_points(img, rotation_vector, translation_vector, camera_matrix):
"""
Get the points to estimate head pose sideways
Parameters
----------
img : np.unit8
Original Image.
rotation_vector : Array of float64
Rotation Vector obtained from cv2.solvePnP
translation_vector : Array of float64
Translation Vector obtained from cv2.solvePnP
camera_matrix : Array of float64
The camera matrix
Returns
-------
(x, y) : tuple
Coordinates of line to estimate head pose
"""
rear_size = 1
rear_depth = 0
front_size = img.shape[1]
front_depth = front_size * 2
val = [rear_size, rear_depth, front_size, front_depth]
point_2d = get_2d_points(img, rotation_vector, translation_vector, camera_matrix, val)
y = (point_2d[5] + point_2d[8]) // 2
x = point_2d[2]
return (x, y)
# this method will perform gaze estimation for a lecture
def process_gaze_estimation(video_path):
# get the base directory
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
VIDEO_PATH = os.path.join(BASE_DIR, "assets\\FirstApp\\videos\\{}".format(video_path))
GAZE_DIR = os.path.join(BASE_DIR, "static\\FirstApp\\gaze")
# create a folder with the same name as the video
VIDEO_DIR = os.path.join(GAZE_DIR, video_path)
# define a dictionary to return the percentage values
percentages = {}
# checking whether the video directory exist
if os.path.isdir(VIDEO_DIR):
shutil.rmtree(VIDEO_DIR)
# create the new directory
os.mkdir(VIDEO_DIR)
# load the face detection model
face_model = get_face_detector()
# load the facial landamrk model
landmark_model = get_landmark_model()
cap = cv2.VideoCapture(VIDEO_PATH)
ret, img = cap.read()
size = img.shape
font = cv2.FONT_HERSHEY_SIMPLEX
# 3D model points.
model_points = np.array([
(0.0, 0.0, 0.0), # Nose tip
(0.0, -330.0, -65.0), # Chin
(-225.0, 170.0, -135.0), # Left eye left corner
(225.0, 170.0, -135.0), # Right eye right corne
(-150.0, -150.0, -125.0), # Left Mouth corner
(150.0, -150.0, -125.0) # Right mouth corner
])
# setting up the count variables
head_front_count = 0
head_up_right_count = 0
head_up_left_count = 0
head_down_right_count = 0
head_down_left_count = 0
# define a variable to count the frames
frame_count = 0
face_count = 0
# set a threshold angle
# THRESHOLD = 15
THRESHOLD = 22
# THRESHOLD = 30
# THRESHOLD = 45
# THRESHOLD = 48
# Camera internals
focal_length = size[1]
center = (size[1] / 2, size[0] / 2)
camera_matrix = np.array(
[[focal_length, 0, center[0]],
[0, focal_length, center[1]],
[0, 0, 1]], dtype="double"
)
# iterate the video frames
while True:
ret, img = cap.read()
if ret == True:
faces = find_faces(img, face_model)
# print('no of faces found: ', len(faces))
student_count = 0
# iterate through each detected face
for face in faces:
# declaring boolean variables
isLookingUp = False
isLookingDown = False
isLookingRight = False
isLookingLeft = False
isLookingFront = False
# deriving the student name to display in the image
student_name = 'student-{}'.format(student_count)
# retrieving the facial landmarks and face bounding box coordinates
marks, facebox = detect_marks(img, landmark_model, face)
# mark_detector.draw_marks(img, marks, color=(0, 255, 0))
image_points = np.array([
marks[30], # Nose tip
marks[8], # Chin
marks[36], # Left eye left corner
marks[45], # Right eye right corne
marks[48], # Left Mouth corner
marks[54] # Right mouth corner
], dtype="double")
dist_coeffs = np.zeros((4, 1)) # Assuming no lens distortion
(success, rotation_vector, translation_vector) = cv2.solvePnP(model_points, image_points, camera_matrix,
dist_coeffs, flags=cv2.SOLVEPNP_UPNP)
# Project a 3D point (0, 0, 1000.0) onto the image plane.
# We use this to draw a line sticking out of the nose
(nose_end_point2D, jacobian) = cv2.projectPoints(np.array([(0.0, 0.0, 1000.0)]), rotation_vector,
translation_vector, camera_matrix, dist_coeffs)
p1 = (int(image_points[0][0]), int(image_points[0][1]))
p2 = (int(nose_end_point2D[0][0][0]), int(nose_end_point2D[0][0][1]))
x1, x2 = head_pose_points(img, rotation_vector, translation_vector, camera_matrix)
# measuring the angles
try:
m = (p2[1] - p1[1]) / (p2[0] - p1[0])
ang1 = int(math.degrees(math.atan(m)))
except:
ang1 = 90
try:
m = (x2[1] - x1[1]) / (x2[0] - x1[0])
ang2 = int(math.degrees(math.atan(-1 / m)))
except:
ang2 = 90
# print('angle 1: {}, angle 2: {}'.format(ang1, ang2))
# checking for angle 1
if ang1 >= THRESHOLD:
# cv2.putText(img, 'looking down', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
isLookingDown = True
elif ang1 <= -THRESHOLD:
# cv2.putText(img, 'looking up', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
isLookingUp = True
else:
# cv2.putText(img, 'looking front', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
isLookingFront = True
# checking for angle 2
if ang2 >= THRESHOLD:
# cv2.putText(img, 'looking right', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
isLookingRight = True
elif ang2 <= -THRESHOLD:
# cv2.putText(img, 'looking left', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
isLookingLeft = True
# checking for vertical and horizontal directions
if isLookingDown & isLookingRight:
cv2.putText(img, 'looking down and right', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
head_down_right_count += 1
elif isLookingDown & isLookingLeft:
cv2.putText(img, 'looking down and left', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
head_down_left_count += 1
elif isLookingUp & isLookingRight:
cv2.putText(img, 'looking up and right', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
head_up_right_count += 1
elif isLookingUp & isLookingLeft:
cv2.putText(img, 'looking up and left', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
head_up_left_count += 1
elif isLookingFront:
cv2.putText(img, 'Head front', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
head_front_count += 1
# indicate the student name
cv2.putText(img, student_name, (facebox[2], facebox[3]), font, 2, (255, 255, 128), 3)
# increment the face count
face_count += 1
# naming the new image
image_name = "frame-{}.png".format(frame_count)
# new image path
image_path = os.path.join(VIDEO_DIR, image_name)
# save the new image
cv2.imwrite(image_path, img)
# increment the frame count
frame_count += 1
else:
break
# after extracting the frames, save the changes to static content
p = os.popen("python manage.py collectstatic", "w")
p.write("yes")
# calculate percentages
head_up_right_perct = (Decimal(head_up_right_count) / Decimal(face_count)) * 100
head_up_left_perct = (Decimal(head_up_left_count) / Decimal(face_count)) * 100
head_down_right_perct = (Decimal(head_down_right_count) / Decimal(face_count)) * 100
head_down_left_perct = (Decimal(head_down_left_count) / Decimal(face_count)) * 100
head_front_perct = (Decimal(head_front_count) / Decimal(face_count)) * 100
# collect the percentages to a dictionary
percentages['head_up_right_perct'] = head_up_right_perct
percentages['head_up_left_perct'] = head_up_left_perct
percentages['head_down_right_perct'] = head_down_right_perct
percentages['head_down_left_perct'] = head_down_left_perct
percentages['head_front_perct'] = head_front_perct
cv2.destroyAllWindows()
cap.release()
# return the dictionary
return percentages
# this method will retrieve extracted frames
def getExtractedFrames(lecture_video_name):
image_list = []
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
EXTRACTED_DIR = os.path.join(BASE_DIR, "assets\\FirstApp\\gaze\\{}".format(lecture_video_name))
# listing all the images in the directory
for image_path in os.listdir(EXTRACTED_DIR):
image_list.append(image_path)
# checking for the number of frames
if (len(image_list) > 0):
image_list = custom_sort(image_list)
return image_list
else:
return "No extracted frames were found"
# this method will retrieve lecture gaze estimation for each frame
def get_lecture_gaze_esrimation_for_frames(video_name):
# get the base directory
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
VIDEO_PATH = os.path.join(BASE_DIR, "assets\\FirstApp\\videos\\{}".format(video_name))
# play the video
video = cv2.VideoCapture(VIDEO_PATH)
frame_rate = video.get(cv2.CAP_PROP_FPS)
frame_detections = []
face_model = get_face_detector()
landmark_model = get_landmark_model()
cap = cv2.VideoCapture(VIDEO_PATH)
ret, img = cap.read()
size = img.shape
font = cv2.FONT_HERSHEY_SIMPLEX
# 3D model points.
model_points = np.array([
(0.0, 0.0, 0.0), # Nose tip
(0.0, -330.0, -65.0), # Chin
(-225.0, 170.0, -135.0), # Left eye left corner
(225.0, 170.0, -135.0), # Right eye right corne
(-150.0, -150.0, -125.0), # Left Mouth corner
(150.0, -150.0, -125.0) # Right mouth corner
])
# define a variable to count the frames
frame_count = 0
# set a threshold angle
# THRESHOLD = 15
THRESHOLD = 22
# THRESHOLD = 30
# THRESHOLD = 45
# THRESHOLD = 48
# Camera internals
focal_length = size[1]
center = (size[1] / 2, size[0] / 2)
camera_matrix = np.array(
[[focal_length, 0, center[0]],
[0, focal_length, center[1]],
[0, 0, 1]], dtype="double"
)
# iterate the video frames
while True:
ret, img = cap.read()
if ret == True:
# setting up the count variables
head_front_count = 0
head_up_right_count = 0
head_up_left_count = 0
head_down_right_count = 0
head_down_left_count = 0
face_count = 0
# find the number of faces
faces = find_faces(img, face_model)
student_count = 0
# iterate through each detected face
for face in faces:
# declaring boolean variables
isLookingUp = False
isLookingDown = False
isLookingRight = False
isLookingLeft = False
isLookingFront = False
# deriving the student name to display in the image
student_name = 'student-{}'.format(student_count)
# retrieving the facial landmarks and face bounding box coordinates
marks, facebox = detect_marks(img, landmark_model, face)
# mark_detector.draw_marks(img, marks, color=(0, 255, 0))
image_points = np.array([
marks[30], # Nose tip
marks[8], # Chin
marks[36], # Left eye left corner
marks[45], # Right eye right corne
marks[48], # Left Mouth corner
marks[54] # Right mouth corner
], dtype="double")
dist_coeffs = np.zeros((4, 1)) # Assuming no lens distortion
(success, rotation_vector, translation_vector) = cv2.solvePnP(model_points, image_points, camera_matrix,
dist_coeffs, flags=cv2.SOLVEPNP_UPNP)
# Project a 3D point (0, 0, 1000.0) onto the image plane.
# We use this to draw a line sticking out of the nose
(nose_end_point2D, jacobian) = cv2.projectPoints(np.array([(0.0, 0.0, 1000.0)]), rotation_vector,
translation_vector, camera_matrix, dist_coeffs)
p1 = (int(image_points[0][0]), int(image_points[0][1]))
p2 = (int(nose_end_point2D[0][0][0]), int(nose_end_point2D[0][0][1]))
x1, x2 = head_pose_points(img, rotation_vector, translation_vector, camera_matrix)
# measuring the angles
try:
m = (p2[1] - p1[1]) / (p2[0] - p1[0])
ang1 = int(math.degrees(math.atan(m)))
except:
ang1 = 90
try:
m = (x2[1] - x1[1]) / (x2[0] - x1[0])
ang2 = int(math.degrees(math.atan(-1 / m)))
except:
ang2 = 90
# print('angle 1: {}, angle 2: {}'.format(ang1, ang2))
# checking for angle 1
if ang1 >= THRESHOLD:
# cv2.putText(img, 'looking down', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
isLookingDown = True
elif ang1 <= -THRESHOLD:
# cv2.putText(img, 'looking up', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
isLookingUp = True
else:
# cv2.putText(img, 'looking front', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
isLookingFront = True
# checking for angle 2
if ang2 >= THRESHOLD:
# cv2.putText(img, 'looking right', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
isLookingRight = True
elif ang2 <= -THRESHOLD:
# cv2.putText(img, 'looking left', (facebox[0], facebox[1]), font, 2, (255, 255, 128), 3)
isLookingLeft = True
# checking for vertical and horizontal directions
if isLookingDown & isLookingRight:
head_down_right_count += 1
elif isLookingDown & isLookingLeft:
head_down_left_count += 1
elif isLookingUp & isLookingRight:
head_up_right_count += 1
elif isLookingUp & isLookingLeft:
head_up_left_count += 1
elif isLookingFront:
head_front_count += 1
# increment the face count
face_count += 1
# the percentages will be calculated here
head_up_right_perct = (Decimal(head_up_right_count) / Decimal(face_count)) * 100 if (face_count != 0) else 0
head_up_left_perct = (Decimal(head_up_left_count) / Decimal(face_count)) * 100 if (face_count != 0) else 0
head_down_right_perct = (Decimal(head_down_right_count) / Decimal(face_count)) * 100 if (face_count != 0) else 0
head_down_left_perct = (Decimal(head_down_left_count) / Decimal(face_count)) * 100 if (face_count != 0) else 0
head_front_perct = (Decimal(head_front_count) / Decimal(face_count)) * 100 if (face_count != 0) else 0
# the dictionary
percentages = {}
# collect the percentages to a dictionary
percentages['frame_name'] = "frame-{}".format(frame_count)
percentages['head_up_right_perct'] = head_up_right_perct
percentages['head_up_left_perct'] = head_up_left_perct
percentages['head_down_right_perct'] = head_down_right_perct
percentages['head_down_left_perct'] = head_down_left_perct
percentages['head_front_perct'] = head_front_perct
# append the calculated percentages to the frame_detections
frame_detections.append(percentages)
frame_count += 1
else:
break
return frame_detections, frame_rate
\ No newline at end of file
import jinja2 as ji
import pdfkit
import os
# from DemoProject import jinja2
from integrated_slpes import jinja2
def generate_pdf_file(object):
# templateLoader = jinja2.FileSystemLoader(searchpath="../")
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
TEMPLATE_DIR = os.path.join(BASE_DIR, "FirstApp\\templates\\FirstApp")
HTML_PATH = os.path.join(TEMPLATE_DIR, "pdf_template_1.html")
PDF_DIRECTORY = os.path.join(BASE_DIR, "FirstApp\\files")
templateLoader = ji.FileSystemLoader(TEMPLATE_DIR)
new_env = jinja2.environment()
templateEnv = jinja2.Environment(loader=templateLoader)
TEMPLATE_FILE = "pdf_template.html"
template = templateEnv.get_template(TEMPLATE_FILE)
print('variables: ', templateEnv.globals['dict'])
# render the template
outputText = template.render(lecturer_name=object['lecturer_name'], subject=object['subject_name'], date=object['date'], static=new_env.globals['static'])
html_file = open(HTML_PATH, "w")
html_file.write(outputText)
html_file.close()
# create a new pdf file path
NEW_PDF_PATH = os.path.join(PDF_DIRECTORY, "activity.pdf")
asset_path = os.path.join('D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/css/sb-admin-2.min.css')
network_path = "file:/" + asset_path
# options = {'enable-local-file-access': network_path}
options = {'enable-local-file-access': asset_path, 'load-error-handling': 'ignore'}
# create a new pdf file
pdfkit.from_file(HTML_PATH, NEW_PDF_PATH, options=options)
...@@ -117,10 +117,6 @@ def calculate_pose_estimation_for_student(video_name, student, poses): ...@@ -117,10 +117,6 @@ def calculate_pose_estimation_for_student(video_name, student, poses):
left_upper_x = 0 if (middle_x - fraction) < 0 else (middle_x - fraction) left_upper_x = 0 if (middle_x - fraction) < 0 else (middle_x - fraction)
print('head_y: ', head_y)
print('fraction: ', fraction)
print('distance: ', distance)
print('left_upper_x: ', left_upper_x)
# extract the new image # extract the new image
new_img = detection_img[head_y:head_y+fraction, left_upper_x:left_upper_x+distance] new_img = detection_img[head_y:head_y+fraction, left_upper_x:left_upper_x+distance]
......
# Generated by Django 2.2.11 on 2020-08-25 11:28
import FirstApp.MongoModels
from django.db import migrations, models
import django.db.models.deletion
import djongo.models.fields
class Migration(migrations.Migration):
dependencies = [
('FirstApp', '0006_lecturercredentials'),
]
operations = [
migrations.RenameField(
model_name='lectureemotionreport',
old_name='lecture_id',
new_name='lecture_emotion_id',
),
migrations.AlterField(
model_name='lectureemotionreport',
name='angry_perct',
field=models.DecimalField(decimal_places=1, default=0.0, max_digits=3),
),
migrations.AlterField(
model_name='lectureemotionreport',
name='disgust_perct',
field=models.DecimalField(decimal_places=1, default=0.0, max_digits=3),
),
migrations.AlterField(
model_name='lectureemotionreport',
name='happy_perct',
field=models.DecimalField(decimal_places=1, default=0.0, max_digits=3),
),
migrations.AlterField(
model_name='lectureemotionreport',
name='neutral_perct',
field=models.DecimalField(decimal_places=1, default=0.0, max_digits=3),
),
migrations.AlterField(
model_name='lectureemotionreport',
name='sad_perct',
field=models.DecimalField(decimal_places=1, default=0.0, max_digits=3),
),
migrations.AlterField(
model_name='lectureemotionreport',
name='surprise_perct',
field=models.DecimalField(decimal_places=1, default=0.0, max_digits=3),
),
migrations.CreateModel(
name='LectureVideo',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('lecture_video_id', models.CharField(max_length=10)),
('date', models.DateField()),
('video_name', models.CharField(max_length=50)),
('video_length', models.DurationField()),
('lecturer', models.ForeignKey(default=0, on_delete=django.db.models.deletion.CASCADE, to='FirstApp.Lecturer')),
('subject', models.ForeignKey(default=0, on_delete=django.db.models.deletion.CASCADE, to='FirstApp.Subject')),
],
),
migrations.CreateModel(
name='LectureGazeEstimation',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('lecture_gaze_id', models.CharField(max_length=10)),
('lecture_video_id',
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='FirstApp.LectureVideo')),
],
),
migrations.CreateModel(
name='LectureActivity',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('lecture_activity_id', models.CharField(max_length=10)),
('talking_perct', models.DecimalField(decimal_places=1, default=0.0, max_digits=3)),
('listening_perct', models.DecimalField(decimal_places=1, default=0.0, max_digits=3)),
('writing_perct', models.DecimalField(decimal_places=1, default=0.0, max_digits=3)),
('phone_perct', models.DecimalField(decimal_places=1, default=0.0, max_digits=3)),
('lecture_video_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='FirstApp.LectureVideo')),
],
),
migrations.CreateModel(
name='FacultyTimetable',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('timetable_id', models.CharField(max_length=10)),
('timetable', djongo.models.fields.ArrayField(model_container=FirstApp.MongoModels.DateTimeTable)),
('faculty', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='FirstApp.Faculty')),
],
),
migrations.AddField(
model_name='lectureemotionreport',
name='lecture_video_id',
field=models.ForeignKey(default=0, on_delete=django.db.models.deletion.CASCADE, to='FirstApp.LectureVideo'),
),
]
# Generated by Django 2.2.11 on 2020-08-25 12:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('FirstApp', '0007_auto_20200825_1658'),
]
operations = [
migrations.AddField(
model_name='lecturegazeestimation',
name='looking_down_and_left_perct',
field=models.DecimalField(decimal_places=1, default=0.0, max_digits=3),
),
migrations.AddField(
model_name='lecturegazeestimation',
name='looking_down_and_right_perct',
field=models.DecimalField(decimal_places=1, default=0.0, max_digits=3),
),
migrations.AddField(
model_name='lecturegazeestimation',
name='looking_front_perct',
field=models.DecimalField(decimal_places=1, default=0.0, max_digits=3),
),
migrations.AddField(
model_name='lecturegazeestimation',
name='looking_up_and_left_perct',
field=models.DecimalField(decimal_places=1, default=0.0, max_digits=3),
),
migrations.AddField(
model_name='lecturegazeestimation',
name='looking_up_and_right_perct',
field=models.DecimalField(decimal_places=1, default=0.0, max_digits=3),
),
]
...@@ -226,3 +226,12 @@ class VideoMetaSerializer(serializers.ModelSerializer): ...@@ -226,3 +226,12 @@ class VideoMetaSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = VideoMeta model = VideoMeta
fields = '__all__' fields = '__all__'
# lecture gaze serializer
class LectureGazeEstimationSerializer(serializers.ModelSerializer):
lecture_video_id = LectureVideoSerializer()
class Meta:
model = LectureGazeEstimation
fields = '__all__'
\ No newline at end of file
{% extends 'FirstApp/template.html' %} {% extends 'FirstApp/template.html' %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<!--{% block 'head' %}--> {#{% block 'head' %}#}
<!--{% endblock %}--> {# {% endblock %}#}
<body id="page-top"> <body id="page-top">
<!-- Page Wrapper -->
<div id="wrapper"> {% block javascript %}
{% load static %}
<!-- Bootstrap core JavaScript-->
<script src="{% static 'FirstApp/vendor/jquery/jquery.min.js' %}"></script>
<script src="{% static 'FirstApp/vendor/bootstrap/js/bootstrap.bundle.min.js' %}"></script>
<!-- Page level plugins -->
<script src="{% static 'FirstApp/vendor/datatables/jquery.dataTables.min.js' %}"></script>
<script src="{% static 'FirstApp/vendor/datatables/dataTables.bootstrap4.min.js' %}"></script>
<!-- Page level custom scripts -->
<script src="{% static 'FirstApp/js/demo/datatables-demo.js' %}"></script>
<!-- Core plugin JavaScript-->
<script src="{% static 'FirstApp/vendor/jquery-easing/jquery.easing.min.js' %}"></script>
<!-- canvasJS implementation -->
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
<!--basic jquery functions-->
<script type="text/javascript">
var global_lecturer = 0;
var global_lecturer_subject_index = 0;
var global_lecture_date = '';
var global_lecture_video_id = '';
var global_video_name = '';
var student_behavior_summary = {};
$(document).ready(function () {
$('.lecture_radio').click(function () {
//hide the previously displayed progress areas
$('#progress_areas').attr('hidden', true);
//hide the summary button
$('#student_behavior_OR_text').attr('hidden', true);
//hide the summart button
$('#student_behavior_view_summary').attr('hidden', true);
global_lecturer_subject_index = $(this).attr('data-index');
global_lecturer = $(this).attr('data-lecturer');
global_lecture_date = $(this).attr('data-date');
let real_date = new Date(global_lecture_date);
//extract the day
let day = '' + real_date.getDate();
let month = '' + (real_date.getMonth() + 1);
let year = '' + real_date.getFullYear();
if (month.length < 2)
month = '0' + month;
if (day.length < 2)
day = '0' + day;
let date_format = [year, month, day].join('-');
//hide the message
$('#student_behavior_overview').attr('hidden', true);
//display the loader
$('#student_behavior_loader').attr('hidden', false);
//display the video loading message
$('#student_behavior_video_loading').attr('hidden', false);
fetch('http://127.0.0.1:8000/get-lecture-video/?lecturer=' + global_lecturer + '&date=' + date_format + '&index=' + global_lecturer_subject_index)
.then((res) => res.json())
.then((out) => retrieveLectureVideoDetails(out))
.catch((error) => alert('an error occurred: ' + error));
});
//function to display student behavior
function displayStudentBehavior(res) {
//hide the loader
$('#student_behavior_loader').attr('hidden', true);
}
//this function will retrieve lecture video details
function retrieveLectureVideoDetails(lecVideo) {
//hide the loading video details message
$('#student_behavior_video_loading').attr('hidden', true);
//display the activity loading message
$('#student_behavior_activity').attr('hidden', false);
//get the lecture video response
let video = lecVideo.response;
global_lecture_video_id = video.lecture_video_id;
global_video_name = video.video_name;
//after retrieving lecture video details, get lecture activity details
fetch('http://127.0.0.1:8000/get-lecture-activity/?lecture_video_id=' + global_lecture_video_id + '&lecture_video_name=' + global_video_name)
.then((res) => res.json())
.then((out) => displayActivity(out))
.catch((err) => alert('error: ' + err));
}
//this function will display the activity
function displayActivity(activity) {
//hide the activity loading message
$('#student_behavior_video_loading').attr('hidden', true);
//hide the loading message
$('#student_behavior_activity').attr('hidden', true);
//display the emotion loading message
$('#student_behavior_emotion').hide();
activity.response.map((act, index) => {
//setting the percentage values
$('#phone_perct').text(act.phone_perct + '%');
$('#talking_perct').text(act.talking_perct + '%');
$('#listening_perct').text(act.listening_perct + '%');
$('#writing_perct').text(act.writing_perct + '%');
//setting the width in the progress bars
$('#phone_width').width(act.phone_perct + '%');
$('#talking_width').width(act.talking_perct + '%');
$('#listening_width').width(act.listening_perct + '%');
$('#writing_width').width(act.writing_perct + '%');
});
//retrieve the lecture emotions
retrieveLectureEmotion();
}
//this function will retrieve lecture emotion details
function retrieveLectureEmotion() {
//using fetch API
fetch('http://127.0.0.1:8000/get-lecture-emotion/?lecture_video_id=' + global_lecture_video_id + '&lecture_video_name=' + global_video_name)
.then((res) => res.json())
.then((out) => displayEmotion(out))
.catch((err) => alert('error: ' + err));
}
//displaying the activity percentages in the progress bars
function displayEmotion(emotion) {
//hide the emotion loading message
$('#student_behavior_emotion').attr('hidden', true);
//display the gaze message
$('#student_behavior_gaze').attr('hidden', false);
emotion.response.map((act, index) => {
//setting the percentage values
$('#happy_perct').text(act.happy_perct + '%');
$('#sad_perct').text(act.sad_perct + '%');
$('#anger_perct').text(act.angry_perct + '%');
$('#surprise_perct').text(act.surprise_perct + '%');
$('#neutral_perct').text(act.neutral_perct + '%');
//setting the width in the progress bars
$('#happy_width').width(act.happy_perct + '%');
$('#sad_width').width(act.sad_perct + '%');
$('#anger_width').width(act.angry_perct + '%');
$('#surprise_width').width(act.surprise_perct + '%');
$('#neutral_width').width(act.neutral_perct + '%');
});
//retrieve the lecture gaze estimation
retrieveLectureGazeEstimation();
//display the progress bar area
//$('#progress_areas').attr('hidden', false);
}
//this function will retrieve lecture gaze estimations
function retrieveLectureGazeEstimation() {
//using fetch API
fetch('http://127.0.0.1:8000/get-lecture-gaze-estimation/?lecture_video_id=' + global_lecture_video_id + '&lecture_video_name=' + global_video_name)
.then((res) => res.json())
.then((out) => displayGazeEstimation(out))
.catch((err) => alert('error: ' + err));
}
//displaying the activity percentages in the progress bars
function displayGazeEstimation(gaze_estimation) {
//hide the loader
$('#student_behavior_loader').attr('hidden', true);
//hide the emotion loading message
$('#student_behavior_gaze').attr('hidden', true);
gaze_estimation.response.map((act, index) => {
//setting the percentage values
$('#looking_up_right_perct').text(act.looking_up_and_right_perct + '%');
$('#looking_up_left_perct').text(act.looking_up_and_left_perct + '%');
$('#looking_down_right_perct').text(act.looking_down_and_right_perct + '%');
$('#looking_down_left_perct').text(act.looking_down_and_left_perct + '%');
$('#looking_front_perct').text(act.looking_front_perct + '%');
//setting the width in the progress bars
$('#looking_up_right_width').width(act.looking_up_and_right_perct + '%');
$('#looking_up_left_width').width(act.looking_up_and_left_perct + '%');
$('#looking_down_right_width').width(act.looking_down_and_right_perct + '%');
$('#looking_down_left_width').width(act.looking_down_and_left_perct + '%');
$('#looking_front_width').width(act.looking_front_perct + '%');
});
//display the progress bar area
$('#progress_areas').attr('hidden', false);
}
//this function will handle the 'summary' button
$('#summary_btn').click(function () {
//open the modal
$('#summaryModal').modal();
let test_date = new Date(0, 0, 0, 0, 12, 30, 0);
//render the chart onto the modal body
renderChart();
});
//this function will call the chart function
function renderChart() {
var chart = new CanvasJS.Chart("chartContainer", {
animationEnabled: true,
theme: "light2",
title: {
text: "Student Behavior"
},
axisX: {
title: "Duration",
{#valueFormatString: "DD MMM",#}
valueFormatString: "hh:mm:ss",
crosshair: {
enabled: true,
snapToDataPoint: true
}
},
axisY: {
title: "Number of Students",
includeZero: true,
crosshair: {
enabled: true
}
},
toolTip: {
shared: true
},
legend: {
cursor: "pointer",
verticalAlign: "bottom",
horizontalAlign: "left",
dockInsidePlotArea: true,
itemclick: toogleDataSeries
},
data: [{
type: "line",
showInLegend: true,
name: "Activity",
markerType: "square",
{#xValueFormatString: "DD MMM, YYYY",#}
xValueFormatString: "hh:mm:ss",
color: "#000000",
dataPoints: [
{x: new Date(2017, 0, 3, 0, 2, 0), y: 650},
{x: new Date(2017, 0, 4, 0, 4, 0), y: 700},
{x: new Date(2017, 0, 5, 0, 6, 0), y: 710},
{x: new Date(2017, 0, 6, 0, 8, 0), y: 658},
{x: new Date(2017, 0, 7, 0, 10, 0), y: 734},
{x: new Date(2017, 0, 8, 0, 12, 0), y: 963},
{x: new Date(2017, 0, 9, 0, 14, 0), y: 847},
{x: new Date(2017, 0, 10, 0, 16, 0), y: 853},
{x: new Date(2017, 0, 11, 0, 18, 0), y: 869},
{x: new Date(2017, 0, 12, 0, 20, 0), y: 943},
{x: new Date(2017, 0, 13, 0, 22, 0), y: 970},
{x: new Date(2017, 0, 14, 0, 24, 0), y: 869},
{x: new Date(2017, 0, 15, 0, 26, 0), y: 890},
{x: new Date(2017, 0, 16, 0, 28, 0), y: 930}
]
},
{
type: "line",
showInLegend: true,
name: "Emotion",
lineDashType: "dash",
dataPoints: [
{x: new Date(2017, 0, 3, 0, 2, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 4, 0, 4, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 5, 0, 6, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 6, 0, 8, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 7, 0, 10, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 8, 0, 12, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 9, 0, 14, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 10, 0, 16, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 11, 0, 18, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 12, 0, 20, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 13, 0, 22, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 14, 0, 24, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 15, 0, 26, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 16, 0, 28, 0), y: Number(Math.round(Math.random() * 1000), 0)}
]
},
{
type: "line",
showInLegend: true,
name: "Gaze",
lineDashType: "dash",
dataPoints: [
{x: new Date(2017, 0, 3, 0, 2, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 4, 0, 4, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 5, 0, 6, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 6, 0, 8, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 7, 0, 10, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 8, 0, 12, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 9, 0, 14, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 10, 0, 16, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 11, 0, 18, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 12, 0, 20, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 13, 0, 22, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 14, 0, 24, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 15, 0, 26, 0), y: Number(Math.round(Math.random() * 1000), 0)},
{x: new Date(2017, 0, 16, 0, 28, 0), y: Number(Math.round(Math.random() * 1000), 0)}
]
}]
});
chart.render();
}
//this function will render the chart for Activity statistics
function renderActivityStatistics() {
let individual_activities = student_behavior_summary.individual_activities;
let activity_labels = student_behavior_summary.activity_labels;
let activity_length = individual_activities.length;
let label_length = activity_labels.length;
let data = [];
let colors = [
"#000000",
"#00FF00",
"#0000FF"
];
for (let i = 0; i < label_length; i++) {
let label = activity_labels[i];
let datapoints = [];
for (let j = 0; j < activity_length; j++) {
let activity = individual_activities[j];
datapoints.push({label: "lecture " + (j+1), y: activity[label]});
}
let obj = {
type: "line",
showInLegend: true,
name: label,
markerType: "square",
{#xValueFormatString: "DD MMM, YYYY",#}
xValueFormatString: "Lec " + (i+1),
color: getRandomColor(),
dataPoints: datapoints
};
data.push(obj);
}
var chart = new CanvasJS.Chart("activity_stats_chart", {
animationEnabled: true,
theme: "light2",
title: {
text: "Activity Statistics"
},
axisX: {
title: "Lecture",
{#valueFormatString: "DD MMM",#}
valueFormatString: "lec",
crosshair: {
enabled: true,
snapToDataPoint: true
}
},
axisY: {
title: "Percentage",
includeZero: true,
crosshair: {
enabled: true
}
},
toolTip: {
shared: true
},
legend: {
cursor: "pointer",
verticalAlign: "bottom",
horizontalAlign: "center",
{#dockInsidePlotArea: true,#}
itemclick: toogleDataSeries
},
data: data
});
chart.render();
}
//this function render the chart for Emotion statistics
function renderEmotionStatistics() {
let individual_emotions = student_behavior_summary.individual_emotions;
let emotion_labels = student_behavior_summary.emotion_labels;
let emotion_length = individual_emotions.length;
let label_length = emotion_labels.length;
let data = [];
let colors = [
"#000000",
"#00FF00",
"#0000FF"
];
for (let i = 0; i < label_length; i++) {
let label = emotion_labels[i];
let datapoints = [];
for (let j = 0; j < emotion_length; j++) {
let emotion = individual_emotions[j];
datapoints.push({label: "lecture " + (j+1), y: emotion[label]});
}
let obj = {
type: "line",
showInLegend: true,
name: label,
markerType: "square",
{#xValueFormatString: "DD MMM, YYYY",#}
xValueFormatString: "Lec " + (i+1),
color: colors[i - 1],
dataPoints: datapoints
};
data.push(obj);
}
var chart = new CanvasJS.Chart("emotion_stats_chart", {
animationEnabled: true,
theme: "light2",
title: {
text: "Emotion Statistics"
},
axisX: {
title: "Lecture",
{#valueFormatString: "DD MMM",#}
valueFormatString: "lec" ,
crosshair: {
enabled: true,
snapToDataPoint: true
}
},
axisY: {
title: "Percentage",
includeZero: true,
crosshair: {
enabled: true
}
},
toolTip: {
shared: true
},
legend: {
cursor: "pointer",
verticalAlign: "bottom",
horizontalAlign: "center",
{#dockInsidePlotArea: true,#}
itemclick: toogleDataSeries
},
data: data
});
chart.render();
}
//this function will toggle the content
function toogleDataSeries(e) {
if (typeof (e.dataSeries.visible) === "undefined" || e.dataSeries.visible) {
e.dataSeries.visible = false;
} else {
e.dataSeries.visible = true;
}
chart.render();
}
//this function will handle the 'View Summary' button click events
$('#student_behavior_view_summary_btn').click(function () {
$('#student_behavior_view_summary_modal').modal();
});
//this function will handle the view summary option form
$('#view_summary_option_form').submit(function (e) {
let option = $("input[name='option']:checked").val();
let lecturer = "{{ lecturer }}";
e.preventDefault();
//send the data using fetch API
fetch('http://127.0.0.1:8000/get-student-behavior-summary-for-period/?option=' + option + "&lecturer=" + lecturer)
.then((res) => res.json())
.then((out) => displayPeriodStudentActivitySummary(out))
.catch((err) => alert('error: ' + err))
});
//this function will display the percentages
function displayPeriodStudentActivitySummary(out) {
//assign the response to the global variable
student_behavior_summary = out;
if (out.isRecordFound) {
//show the summary tables
$('#student_behavior_summary_for_period').attr('hidden', false);
//assign the activity values
$('#phone_perct_for_period').text(out.activity_response.phone_perct);
$('#listening_perct_for_period').text(out.activity_response.listening_perct);
$('#writing_perct_for_period').text(out.activity_response.writing_perct);
//assign the emotion values
$('#happy_perct_for_period').text(out.emotion_response.happy_perct);
$('#sad_perct_for_period').text(out.emotion_response.sad_perct);
$('#angry_perct_for_period').text(out.emotion_response.angry_perct);
$('#disgust_perct_for_period').text(out.emotion_response.disgust_perct);
$('#surprise_perct_for_period').text(out.emotion_response.surprise_perct);
$('#neutral_perct_for_period').text(out.emotion_response.neutral_perct);
} else {
$('#student_summary_not_found_message').attr('hidden', false);
}
//hide the modal
$('#student_behavior_view_summary_modal').modal("hide");
}
//this function will view activity statistics
$('#view_activity_stats').click(function () {
//render the chart
renderActivityStatistics();
//open the modal
$('#activity_stats_modal').modal();
});
//this function will view emotion statistics
$('#view_emotion_stats').click(function () {
//render the chart
renderEmotionStatistics();
//open the modal
$('#emotion_stats_modal').modal();
});
//this function will generate random colors
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
});
</script>
{% endblock %}
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Content Wrapper --> <!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column"> <div id="content-wrapper" class="d-flex flex-column">
...@@ -19,285 +633,668 @@ ...@@ -19,285 +633,668 @@
<!-- Page Heading --> <!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between mb-4"> <div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800">{{object.Message}}</h1> <h1 class="h3 mb-0 text-gray-800">{{ object.Message }}</h1>
<a href="#" class="d-none d-sm-inline-block btn btn-sm btn-primary shadow-sm"><i class="fas fa-download fa-sm text-white-50"></i> Generate Report</a> {# <a href="#" class="d-none d-sm-inline-block btn btn-sm btn-primary shadow-sm"><i class="fas fa-download fa-sm text-white-50"></i> Generate Report</a>#}
</div> </div>
<!-- Content Row --> <!-- Content Row -->
{# <div class="row">#}
{##}
{# <!-- Earnings (Monthly) Card Example -->#}
{# <div class="col-xl-3 col-md-6 mb-4">#}
{# <div class="card border-left-primary shadow h-100 py-2">#}
{# <div class="card-body">#}
{# <div class="row no-gutters align-items-center">#}
{# <div class="col mr-2">#}
{# <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Earnings (Monthly)</div>#}
{# <div class="h5 mb-0 font-weight-bold text-gray-800">$40,000</div>#}
{# </div>#}
{# <div class="col-auto">#}
{# <i class="fas fa-calendar fa-2x text-gray-300"></i>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{##}
{# <!-- Earnings (Monthly) Card Example -->#}
{# <div class="col-xl-3 col-md-6 mb-4">#}
{# <div class="card border-left-success shadow h-100 py-2">#}
{# <div class="card-body">#}
{# <div class="row no-gutters align-items-center">#}
{# <div class="col mr-2">#}
{# <div class="text-xs font-weight-bold text-success text-uppercase mb-1">Earnings (Annual)</div>#}
{# <div class="h5 mb-0 font-weight-bold text-gray-800">$215,000</div>#}
{# </div>#}
{# <div class="col-auto">#}
{# <i class="fas fa-dollar-sign fa-2x text-gray-300"></i>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{##}
{# <!-- Earnings (Monthly) Card Example -->#}
{# <div class="col-xl-3 col-md-6 mb-4">#}
{# <div class="card border-left-info shadow h-100 py-2">#}
{# <div class="card-body">#}
{# <div class="row no-gutters align-items-center">#}
{# <div class="col mr-2">#}
{# <div class="text-xs font-weight-bold text-info text-uppercase mb-1">Tasks</div>#}
{# <div class="row no-gutters align-items-center">#}
{# <div class="col-auto">#}
{# <div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">50%</div>#}
{# </div>#}
{# <div class="col">#}
{# <div class="progress progress-sm mr-2">#}
{# <div class="progress-bar bg-info" role="progressbar" style="width: 50%" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"></div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# <div class="col-auto">#}
{# <i class="fas fa-clipboard-list fa-2x text-gray-300"></i>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{##}
{# <!-- Pending Requests Card Example -->#}
{# <div class="col-xl-3 col-md-6 mb-4">#}
{# <div class="card border-left-warning shadow h-100 py-2">#}
{# <div class="card-body">#}
{# <div class="row no-gutters align-items-center">#}
{# <div class="col mr-2">#}
{# <div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Pending Requests</div>#}
{# <div class="h5 mb-0 font-weight-bold text-gray-800">18</div>#}
{# </div>#}
{# <div class="col-auto">#}
{# <i class="fas fa-comments fa-2x text-gray-300"></i>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{##}
{# </div>#}
<!-- Content Row -->
<div class="row"> <div class="row">
<!-- Earnings (Monthly) Card Example --> <!-- Area Chart -->
<div class="col-xl-3 col-md-6 mb-4"> <div class="col-lg-6">
<div class="card border-left-primary shadow h-100 py-2"> <div class="card shadow mb-4">
<div class="card-body"> <!-- Card Header - Dropdown -->
<div class="row no-gutters align-items-center"> <div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<div class="col mr-2"> <h6 class="m-0 font-weight-bold text-primary">Student Behavior Overview</h6>
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Earnings (Monthly)</div> <div class="dropdown no-arrow">
<div class="h5 mb-0 font-weight-bold text-gray-800">$40,000</div> <a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink"
</div> data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<div class="col-auto"> <i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
<i class="fas fa-calendar fa-2x text-gray-300"></i> </a>
</div> </div>
</div> </div>
<!-- Card Body -->
<div class="card-body">
<!-- default message -->
<div class="text-center" id="student_behavior_overview">
<span class="font-italic">Please select a date to preview</span>
</div> </div>
<!-- OR message -->
<div class="text-center mt-4" id="student_behavior_OR_text">
<span class="font-italic">---OR---</span>
</div> </div>
<!-- 'View summary' button section -->
<div class="text-center my-4" id="student_behavior_view_summary">
<button type="button" class="btn btn-primary"
id="student_behavior_view_summary_btn">View Summary
</button>
</div> </div>
<!-- Earnings (Monthly) Card Example --> <!-- loading video details message -->
<div class="col-xl-3 col-md-6 mb-4"> <div class="text-center" id="student_behavior_video_loading" hidden>
<div class="card border-left-success shadow h-100 py-2"> <span class="font-italic">Loading Video Details...</span>
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">Earnings (Annual)</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">$215,000</div>
</div> </div>
<div class="col-auto">
<i class="fas fa-dollar-sign fa-2x text-gray-300"></i> <!-- loading lecture activity message -->
<div class="text-center" id="student_behavior_activity" hidden>
<span class="font-italic">Loading Student Activity...</span>
</div> </div>
<!-- loading lecture emotion message -->
<div class="text-center" id="student_behavior_emotion" hidden>
<span class="font-italic">Loading Student Emotion...</span>
</div> </div>
<!-- loading lecture gaze estimation message -->
<div class="text-center" id="student_behavior_gaze" hidden>
<span class="font-italic">Loading Student Gaze estimation...</span>
</div> </div>
<!--loader -->
<div class="text-center" id="student_behavior_loader" hidden>
<img src="{% static 'FirstApp/images/ajax-loader.gif' %}" alt="Loader">
</div> </div>
<!-- student summary not found message -->
<div class="text-center mt-4" id="student_summary_not_found_message" hidden>
<span class="font-italic">No student summary was found</span>
</div> </div>
<!-- Earnings (Monthly) Card Example --> <!-- to display student behavior summary for period -->
<div class="col-xl-3 col-md-6 mb-4"> <div class="text-center" id="student_behavior_summary_for_period" hidden>
<div class="card border-left-info shadow h-100 py-2"> <!-- Activity card -->
<div class="card shadow-lg mb-2">
<div class="card-body"> <div class="card-body">
<div class="row no-gutters align-items-center"> <!-- put the heading -->
<div class="col mr-2"> <div class="text-center mt-2">
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">Tasks</div> <h4 class="font-weight-bold">Activity</h4>
<div class="row no-gutters align-items-center">
<div class="col-auto">
<div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">50%</div>
</div>
<div class="col">
<div class="progress progress-sm mr-2">
<div class="progress-bar bg-info" role="progressbar" style="width: 50%" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
</div>
<div class="col-auto">
<i class="fas fa-clipboard-list fa-2x text-gray-300"></i>
</div> </div>
<!-- percentages -->
<div class="text-center">
<!-- activity table -->
<table class="table table-borderless table-striped">
<tbody>
<tr>
<td>
Phone percentage
<hr style="height: 5px">
</td>
<td id="phone_perct_for_period"></td>
</tr>
<tr>
<td>
Listening percentage
<hr style="height: 5px">
</td>
<td id="listening_perct_for_period"></td>
</tr>
<tr>
<td>
Note taking percentage
<hr style="height: 5px">
</td>
<td id="writing_perct_for_period"></td>
</tr>
</tbody>
</table>
<!-- end of activity table -->
</div> </div>
<!-- stats button -->
<div class="float-right">
<button type="button" class="btn btn-primary"
id="view_activity_stats">
<i class="fa fa-line-chart"></i>
View stats
</button>
</div> </div>
<!-- end of stats button -->
</div> </div>
</div> </div>
<!-- end of Activity card -->
<!-- Pending Requests Card Example --> <!-- Emotion card -->
<div class="col-xl-3 col-md-6 mb-4"> <div class="card shadow-lg mb-2">
<div class="card border-left-warning shadow h-100 py-2">
<div class="card-body"> <div class="card-body">
<div class="row no-gutters align-items-center"> <!-- put the heading -->
<div class="col mr-2"> <div class="text-center mt-2">
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Pending Requests</div> <h4 class="font-weight-bold">Emotion</h4>
<div class="h5 mb-0 font-weight-bold text-gray-800">18</div>
</div>
<div class="col-auto">
<i class="fas fa-comments fa-2x text-gray-300"></i>
</div>
</div> </div>
<!-- percentages -->
<div class="text-center">
<!-- emotion table -->
<table class="table table-borderless table-striped">
<tbody>
<tr>
<td>
Happy percentage
<hr style="height: 5px">
</td>
<td id="happy_perct_for_period"></td>
</tr>
<tr>
<td>
Sad percentage
<hr style="height: 5px">
</td>
<td id="sad_perct_for_period"></td>
</tr>
<tr>
<td>
Angry percentage
<hr style="height: 5px">
</td>
<td id="angry_perct_for_period"></td>
</tr>
<tr>
<td>
Disgust percentage
<hr style="height: 5px">
</td>
<td id="disgust_perct_for_period"></td>
</tr>
<tr>
<td>
Surprise percentage
<hr style="height: 5px">
</td>
<td id="surprise_perct_for_period"></td>
</tr>
<tr>
<td>
Neutral percentage
<hr style="height: 5px">
</td>
<td id="neutral_perct_for_period"></td>
</tr>
</tbody>
</table>
<!-- end of emotion table -->
</div> </div>
<!-- end of percentages -->
<!-- stats button -->
<div class="float-right">
<button type="button" class="btn btn-primary"
id="view_emotion_stats">
<i class="fa fa-line-chart"></i>
View stats
</button>
</div> </div>
<!-- end of stats button -->
</div> </div>
</div> </div>
<!-- end of Emotion card -->
<!-- Content Row -->
<div class="row">
<!-- Area Chart -->
<div class="col-xl-8 col-lg-7">
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Attendance Overview</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
</a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in" aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Dropdown Header:</div>
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div> </div>
<!-- end of student behavior summary -->
<!-- a vertical list displaying the student engagement categories -->
<ul class="list-group" id="progress_areas" hidden>
<li class="list-group-item border">
<button type="button" class="btn btn-link"
data-target="#progress_area_activity" data-toggle="collapse">
<h5 class="font-weight-bold">Activity</h5>
</button>
<!--this area will display the activity progress bars -->
<div id="progress_area_activity" class="collapse">
<!--talking with friends -->
<h4 class="small font-weight-bold">Talking with friends</h4>
<span class="float-right" id="talking_perct">40%</span>
<div class="progress mb-4">
<div class="progress-bar bg-danger" role="progressbar"
id="talking_width"
style="width: 20%"
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<!-- Card Body -->
<div class="card-body"> <!--phone checking -->
<div class="chart-area"> <h4 class="small font-weight-bold">Phone checking</h4>
<canvas id="myAreaChart"></canvas>
</div> <span class="float-right" id="phone_perct">45%</span>
<div class="progress mb-4">
<div class="progress-bar bg-warning" role="progressbar"
id="phone_width"
style="width: 40%"
aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<!--note taking -->
<h4 class="small font-weight-bold">Writing</h4>
<span class="float-right" id="writing_perct">50%</span>
<div class="progress mb-4">
<div class="progress-bar" role="progressbar" id="writing_width"
style="width: 60%"
aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<!--listening-->
<h4 class="small font-weight-bold">Listening</h4>
<span class="float-right" id="listening_perct">60%</span>
<div class="progress mb-4">
<div class="progress-bar bg-info" role="progressbar"
id="listening_width" style="width: 80%"
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<!-- Pie Chart -->
<div class="col-xl-4 col-lg-5">
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Revenue Sources</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
</a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in" aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Dropdown Header:</div>
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div> </div>
<!-- end of progress area (activity) -->
<hr>
</li>
<!-- end of the activity list item -->
<!-- beginning of the emotion list item -->
<li class="list-group-item">
<button type="button" class="btn btn-link"
data-target="#progress_area_emotion"
data-toggle="collapse">
<h5 class="font-weight-bold">Emotion</h5>
</button>
<!-- this area will display the emotion progress bars -->
<!--this area will display the progress bars -->
<div id="progress_area_emotion" class="collapse">
<!--Happy -->
<h4 class="small font-weight-bold">Happy</h4>
<span class="float-right" id="happy_perct">40%</span>
<div class="progress mb-4">
<div class="progress-bar bg-danger" role="progressbar"
id="happy_width"
style="width: 20%"
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<!--sad -->
<h4 class="small font-weight-bold">Sad</h4>
<span class="float-right" id="sad_perct">45%</span>
<div class="progress mb-4">
<div class="progress-bar bg-warning" role="progressbar"
id="sad_width"
style="width: 40%"
aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<!-- Card Body -->
<div class="card-body"> <!--anger -->
<div class="chart-pie pt-4 pb-2"> <h4 class="small font-weight-bold">Anger</h4>
<canvas id="myPieChart"></canvas> <span class="float-right" id="anger_perct">50%</span>
<div class="progress mb-4">
<div class="progress-bar" role="progressbar" id="anger_width"
style="width: 60%"
aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<div class="mt-4 text-center small">
<span class="mr-2"> <!--surprise-->
<i class="fas fa-circle text-primary"></i> Direct <h4 class="small font-weight-bold">Surprise</h4>
</span> <span class="float-right" id="surprise_perct">60%</span>
<span class="mr-2"> <div class="progress mb-4">
<i class="fas fa-circle text-success"></i> Social <div class="progress-bar bg-info" role="progressbar"
</span> id="surprise_width" style="width: 80%"
<span class="mr-2"> aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
<i class="fas fa-circle text-info"></i> Referral
</span>
</div> </div>
<!--neutral-->
<h4 class="small font-weight-bold">Neutral</h4>
<span class="float-right" id="neutral_perct">60%</span>
<div class="progress mb-4">
<div class="progress-bar bg-info" role="progressbar"
id="neutral_width" style="width: 80%"
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
</div> </div>
<!-- end of emotion progress bars -->
<hr>
</li>
<!-- end of the emotion list item -->
<!-- beginning of the gaze list item -->
<li class="list-group-item border">
<button type="button" class="btn btn-link"
data-target="#progress_area_gaze" data-toggle="collapse">
<h5 class="font-weight-bold">Gaze</h5>
</button>
<!--this area will display the activity progress bars -->
<div id="progress_area_gaze" class="collapse">
<!--looking up and right -->
<h4 class="small font-weight-bold">Looking up and right</h4>
<span class="float-right" id="looking_up_right_perct">40%</span>
<div class="progress mb-4">
<div class="progress-bar bg-danger" role="progressbar"
id="looking_up_right_width"
style="width: 20%"
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<!--looking up and left -->
<h4 class="small font-weight-bold">Looking up and left</h4>
<span class="float-right" id="looking_up_left_perct">45%</span>
<div class="progress mb-4">
<div class="progress-bar bg-warning" role="progressbar"
id="looking_up_left_width"
style="width: 40%"
aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<!-- Content Row --> <!--looking down and right -->
<div class="row">
<!-- Content Column --> <h4 class="small font-weight-bold">Looking down and right</h4>
<div class="col-lg-6 mb-4">
<!-- Project Card Example --> <span class="float-right" id="looking_down_right_perct">50%</span>
<div class="card shadow mb-4"> <div class="progress mb-4">
<div class="card-header py-3"> <div class="progress-bar bg-success" role="progressbar" id="looking_down_right_width"
<h6 class="m-0 font-weight-bold text-primary">Student Behavior</h6> style="width: 60%"
aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<div class="card-body">
{% load static %}
<video width="500" height="300" controls>
<source src="{% static 'FirstApp/videos/Classroom_Video.mp4' %}" type="video/mp4">
Your browser does not support the video tag.
</video>
<a href="/webcam" class="btn btn-outline-primary" id="processBtn">Process</a> <!--Looking down and left-->
</div>
<h4 class="small font-weight-bold">Looking down and left</h4>
<span class="float-right" id="looking_down_left_perct">60%</span>
<div class="progress mb-4">
<div class="progress-bar bg-info" role="progressbar"
id="looking_down_left_width" style="width: 80%"
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<!-- Color System --> <!--Looking front-->
<div class="row">
<div class="col-lg-6 mb-4"> <h4 class="small font-weight-bold">Looking front</h4>
<div class="card bg-primary text-white shadow"> <span class="float-right" id="looking_front_perct">60%</span>
<div class="card-body"> <div class="progress mb-4">
Primary <div class="progress-bar bg-secondary" role="progressbar"
<div class="text-white-50 small">#4e73df</div> id="looking_front_width" style="width: 80%"
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
</div> </div>
<!-- end of progress area (gaze) -->
<hr>
</li>
<!-- end of the gaze list item -->
<!-- button to view a summary -->
<li class="list-group-item">
<button type="button" class="btn btn-primary float-right" id="summary_btn">
Summary
</button>
</li>
</ul>
</div> </div>
<div class="col-lg-6 mb-4">
<div class="card bg-success text-white shadow">
<div class="card-body">
Success
<div class="text-white-50 small">#1cc88a</div>
</div> </div>
</div> </div>
<!-- list of recent lectures -->
<div class="col-lg-6">
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Recent Lecture Recordings</h6>
</div> </div>
<div class="col-lg-6 mb-4">
<div class="card bg-info text-white shadow">
<div class="card-body"> <div class="card-body">
Info <table class="table table-bordered">
<div class="text-white-50 small">#36b9cc</div> <thead>
</div> <tr>
<th></th>
<th>Date</th>
<th>Subject</th>
</tr>
</thead>
<tbody>
{% for lecturer_detail in lecturer_details %}
<tr>
<td>
<div class="radio">
<label><input type="radio"
class="lecture_radio"
name="recent_recordings_radio"
data-lecturer="{{ lecturer_detail.lecturer }}"
data-index="{{ lecturer_detail.index }}"
data-date="{{ lecturer_detail.date }}">
</label>
</div> </div>
</td>
<td>
{{ lecturer_detail.date }}
</td>
<td>
{{ lecturer_detail.subject_name }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- end of table -->
<!-- button -->
{# <div class="float-right">#}
{# <button type="button" class="btn btn-info" id="weekly_summary">Weekly Summary</button>#}
{# </div>#}
</div> </div>
<div class="col-lg-6 mb-4">
<div class="card bg-warning text-white shadow">
<div class="card-body">
Warning
<div class="text-white-50 small">#f6c23e</div>
</div> </div>
</div> </div>
</div> </div>
<!-- Content Row -->
<div class="row">
<!-- 1st Column -->
<div class="col-lg-6 mb-4"> <div class="col-lg-6 mb-4">
<div class="card bg-danger text-white shadow">
<div class="card-body"> {% load static %}
Danger <!-- Project Card Example -->
<div class="text-white-50 small">#e74a3b</div> <div class="card shadow mb-4">
</div> <div class="card-header py-3">
</div> <h6 class="m-0 font-weight-bold text-primary">Attendance Preview</h6>
</div> </div>
<div class="col-lg-6 mb-4">
<div class="card bg-secondary text-white shadow">
<div class="card-body"> <div class="card-body">
Secondary <div class="text-center" id="temp_attendance_content">
<div class="text-white-50 small">#858796</div> <span class="font-italic">Attendance preview will be displayed here</span>
</div>
</div> </div>
</div> </div>
</div> </div>
<!-- Color System -->
{# <div class="row">#}
{# <div class="col-lg-6 mb-4">#}
{# <div class="card bg-primary text-white shadow">#}
{# <div class="card-body">#}
{# Primary#}
{# <div class="text-white-50 small">#4e73df</div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# <div class="col-lg-6 mb-4">#}
{# <div class="card bg-success text-white shadow">#}
{# <div class="card-body">#}
{# Success#}
{# <div class="text-white-50 small">#1cc88a</div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# <div class="col-lg-6 mb-4">#}
{# <div class="card bg-info text-white shadow">#}
{# <div class="card-body">#}
{# Info#}
{# <div class="text-white-50 small">#36b9cc</div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# <div class="col-lg-6 mb-4">#}
{# <div class="card bg-warning text-white shadow">#}
{# <div class="card-body">#}
{# Warning#}
{# <div class="text-white-50 small">#f6c23e</div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# <div class="col-lg-6 mb-4">#}
{# <div class="card bg-danger text-white shadow">#}
{# <div class="card-body">#}
{# Danger#}
{# <div class="text-white-50 small">#e74a3b</div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# <div class="col-lg-6 mb-4">#}
{# <div class="card bg-secondary text-white shadow">#}
{# <div class="card-body">#}
{# Secondary#}
{# <div class="text-white-50 small">#858796</div>#}
{# </div>#}
{# </div>#}
{# </div>#}
{# </div>#}
</div> </div>
<!-- 2nd column -->
<div class="col-lg-6 mb-4"> <div class="col-lg-6 mb-4">
<!-- Illustrations --> <!-- Approach -->
<div class="card shadow mb-4"> <div class="card shadow mb-4">
<div class="card-header py-3"> <div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Lecture Recordings</h6> <h6 class="m-0 font-weight-bold text-primary">My Performances</h6>
</div> </div>
<div class="card-body"> <div class="card-body">
<!-- beginning of the table -->
<table class="table table-bordered"> <table class="table table-bordered">
<thead> <thead>
<tr> <tr>
<th>Video Name</th> <th></th>
<th>Length</th> <th>Date</th>
<th>Subject</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for video in Videos %} {% for lecturer_detail in lecturer_details %}
<tr> <tr>
<td> <td>
<a href="{% url 'video' %}?video_name={{video.name}}" class="btn btn-link">{{video.name}}</a> <div class="radio">
<label><input type="radio"
id="{{ subject.0.subject_code }}"
name="recent_recordings_radio"
data-lecturer="{{ lecturer }}"
data-index="{{ lecturer_detail.index }}"
data-date="{{ lecturer_detail.date }}">
</label>
</div>
</td>
<td>
{{ lecturer_detail.date }}
</td> </td>
<td>{{video.duration}}</td>
<td> <td>
<a href="{% url 'video' %}?video_name={{video.name}}" class="btn btn-outline-info">Process</a> {{ lecturer_detail.subject_name }}
</td>
<td>
<button type="button" class="btn btn-primary">View</button>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<!-- <div class="text-center">--> <!-- end of table -->
<!-- <img class="img-fluid px-3 px-sm-4 mt-3 mb-4" style="width: 25rem;" src="img/undraw_posting_photo.svg" alt="">-->
<!-- </div>-->
<!-- <p>Add some quality, svg illustrations to your project courtesy of <a target="_blank" rel="nofollow" href="https://undraw.co/">unDraw</a>, a constantly updated collection of beautiful svg images that you can use completely free and without attribution!</p>-->
<!-- <a target="_blank" rel="nofollow" href="https://undraw.co/">Browse Illustrations on unDraw &rarr;</a>-->
</div>
</div>
<!-- Approach -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Development Approach</h6>
</div>
<div class="card-body">
<p>SB Admin 2 makes extensive use of Bootstrap 4 utility classes in order to reduce CSS bloat and poor page performance. Custom CSS classes are used to create custom components and custom utility classes.</p>
<p class="mb-0">Before working with this theme, you should become familiar with the Bootstrap framework, especially the utility classes.</p>
</div> </div>
</div> </div>
...@@ -314,17 +1311,18 @@ ...@@ -314,17 +1311,18 @@
</div> </div>
<!-- End of Content Wrapper --> <!-- End of Content Wrapper -->
</div> </div>
<!-- End of Page Wrapper --> <!-- End of Page Wrapper -->
<!-- scroll to top button--> <!-- scroll to top button-->
{% block 'modal' %} {% block 'modal' %}
<a class="scroll-to-top rounded" href="#page-top"> <a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i> <i class="fas fa-angle-up"></i>
</a> </a>
<!-- Logout Modal--> <!-- Logout Modal-->
<div class="modal fade" id="logoutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal fade" id="logoutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
...@@ -341,13 +1339,148 @@ ...@@ -341,13 +1339,148 @@
</div> </div>
</div> </div>
</div> </div>
<!-- end of logout modal -->
{% endblock %} <!-- summary Modal-->
<div class="modal fade" id="summaryModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document" style="max-width: 1300px">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Summary</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div id="chartContainer" style="height: 370px; max-width: 920px; margin: 0px auto;"></div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
<!-- end of summary modal -->
<!-- student behavior view summary modal -->
<div class="modal fade" id="student_behavior_view_summary_modal" tabindex="-1" role="dialog"
aria-labelledby="exampleModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document" style="max-width: 500px">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title" id="exampleModalLabel">View Summary Options</h3>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<h5>View Summary for...</h5>
</div>
<!-- list of options -->
<form action="#" method="get" id="view_summary_option_form">
<div class="custom-control custom-radio mt-2">
<input type="radio" class="custom-control-input" id="customRadio" name="option" value="7">
<label class="custom-control-label" for="customRadio">one week</label>
</div>
<div class="custom-control custom-radio mt-2">
<input type="radio" class="custom-control-input" id="customRadio1" name="option" value="14">
<label class="custom-control-label" for="customRadio1">2 weeks</label>
</div>
<div class="custom-control custom-radio mt-2">
<input type="radio" class="custom-control-input" id="customRadio2" name="option" value="30">
<label class="custom-control-label" for="customRadio2">one month</label>
</div>
<div class="custom-control custom-radio mt-2">
<input type="radio" class="custom-control-input" id="customRadio3" name="option" value="10000">
<label class="custom-control-label" for="customRadio3">All</label>
</div>
<div class="form-group mt-4">
<button type="submit" class="btn btn-outline-success" id="submit_view_summary_option">
Submit
</button>
</div>
</form>
<!-- end of list of options -->
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
<!-- end of student behavior view summary modal -->
<!-- activity statistics Modal-->
<div class="modal fade" id="activity_stats_modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document" style="max-width: 1400px">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Activity Statistics</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body text-center">
<div id="activity_stats_chart" style="height: 370px; width: 100%"></div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
<!-- end of activity statistics modal -->
<!-- emotion statistics Modal-->
<div class="modal fade" id="emotion_stats_modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document" style="max-width: 1400px">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Emotion Statistics</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body text-center">
<div id="emotion_stats_chart" style="height: 370px; width: 100%"></div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
<!-- end of activity statistics modal -->
{% endblock %}
<!--scripts--> <!--scripts-->
{% block 'scripts' %} {% block 'scripts' %}
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
crossorigin="anonymous"></script>
<script src="{% static 'FirstApp/vendor/jquery/jquery.min.js' %}"></script> <script src="{% static 'FirstApp/vendor/jquery/jquery.min.js' %}"></script>
<script src="{% static 'FirstApp/vendor/bootstrap/js/bootstrap.bundle.min.js' %}"></script> <script src="{% static 'FirstApp/vendor/bootstrap/js/bootstrap.bundle.min.js' %}"></script>
...@@ -365,6 +1498,6 @@ ...@@ -365,6 +1498,6 @@
<script src="{% static 'FirstApp/js/demo/chart-area-demo.js' %}"></script> <script src="{% static 'FirstApp/js/demo/chart-area-demo.js' %}"></script>
<script src="{% static 'FirstApp/js/demo/chart-pie-demo.js' %}"></script> <script src="{% static 'FirstApp/js/demo/chart-pie-demo.js' %}"></script>
{% endblock %} {% endblock %}
</body> </body>
</html> </html>
\ No newline at end of file
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
var global_lecture_video_id = ''; var global_lecture_video_id = '';
var global_video_name = ''; var global_video_name = '';
var global_lecturer_subject_index = 0; var global_lecturer_subject_index = 0;
var global_lecture_date = '';
//jquery //jquery
$(document).ready(function () { $(document).ready(function () {
...@@ -72,6 +73,8 @@ ...@@ -72,6 +73,8 @@
real_class = '.' + real_class; real_class = '.' + real_class;
let date = e.target.parentNode.parentNode.firstChild.innerHTML; let date = e.target.parentNode.parentNode.firstChild.innerHTML;
//assign the date
global_lecture_date = date;
fetch('http://127.0.0.1:8000/get-lecture-video/?lecturer=' + global_lecturer + '&date=' + date + '&index=' + global_lecturer_subject_index) fetch('http://127.0.0.1:8000/get-lecture-video/?lecturer=' + global_lecturer + '&date=' + date + '&index=' + global_lecturer_subject_index)
.then((res) => res.json()) .then((res) => res.json())
...@@ -79,7 +82,7 @@ ...@@ -79,7 +82,7 @@
.catch((error) => alert('an error occurred: ' + error)); .catch((error) => alert('an error occurred: ' + error));
}); });
//this function will display the timetable for the lecturer
function createTimeTable(timetable, subject, lecturer) { function createTimeTable(timetable, subject, lecturer) {
$('#loader').attr('hidden', true); $('#loader').attr('hidden', true);
$('#timetable').attr('hidden', false); $('#timetable').attr('hidden', false);
...@@ -146,16 +149,19 @@ ...@@ -146,16 +149,19 @@
if (lectureVideo.isActivityFound) { if (lectureVideo.isActivityFound) {
e.target.parentNode.parentNode.lastChild.innerHTML = '<button type="button" class="btn btn-primary">Results</button>'; e.target.parentNode.parentNode.lastChild.innerHTML = '<button type="button" class="btn btn-primary" id="result_btn">Results</button>';
} else { } else {
e.target.parentNode.parentNode.lastChild.innerHTML = '<button type="button" class="btn btn-success">Process</button>'; e.target.parentNode.parentNode.lastChild.innerHTML = '<button type="button" class="btn btn-success">Process</button>';
} }
//enable the 'generate report' button
$('#generate_report_before').attr('disabled', false);
$('#video_modal').modal(); $('#video_modal').modal();
} }
//binding a click event for 'btn-primary' buttons //binding a click event for 'btn-primary' buttons
$(document).on('click', '.btn-primary', function (e) { $(document).on('click', '#result_btn', function (e) {
//removing the previous frames (if there is any) //removing the previous frames (if there is any)
$('#main_frames').remove(); $('#main_frames').remove();
...@@ -215,15 +221,15 @@ ...@@ -215,15 +221,15 @@
//sending the POST request to process the lecture activities //sending the POST request to process the lecture activities
fetch('http://127.0.0.1:8000/process-lecture-activity/?lecture_video_name=' + global_video_name + '&lecture_video_id=' + global_lecture_video_id) fetch('http://127.0.0.1:8000/process-lecture-activity/?lecture_video_name=' + global_video_name + '&lecture_video_id=' + global_lecture_video_id)
.then((res) => res.json()) .then((res) => res.json())
.then((out) => handleResponse(out.response, e)) .then((out) => handleActivityResponse(out.response, e))
.catch((error) => alert('error: ' + error)); .catch((error) => alert('error: ' + error));
}); });
//this is to change the button from 'process' to 'results' //this is to detect the response gained from activity recognition porcess
function handleResponse(response, e) { function handleActivityResponse(response, e) {
//change the button, if the response is positive //change the button, if the response is positive
if (response) { if (response) {
e.target.parentNode.parentNode.lastChild.innerHTML = '<button type="button" class="btn btn-primary">Results</button>'; e.target.parentNode.parentNode.lastChild.innerHTML = '<button type="button" class="btn btn-primary" id="result_btn">Results</button>';
} }
} }
...@@ -736,7 +742,7 @@ ...@@ -736,7 +742,7 @@
//to handle the 'integrate' modal //to handle the 'integrate' modal
$('#integrate_activity').click(function () { $('#integrate_gaze').click(function () {
//define the student video src //define the student video src
let video_src = "{% static '' %}FirstApp/videos/" + global_video_name; let video_src = "{% static '' %}FirstApp/videos/" + global_video_name;
...@@ -852,7 +858,7 @@ ...@@ -852,7 +858,7 @@
$('#listening_instant_value').width(listening_number + '%'); $('#listening_instant_value').width(listening_number + '%');
*/ */
}, 1000); }, 33);
//check for the current class //check for the current class
if (classes === play_class) { if (classes === play_class) {
...@@ -878,6 +884,29 @@ ...@@ -878,6 +884,29 @@
}); });
//this method will call the API to generate activity report
$('#generate_report_btn').click(function () {
//call the fetch API
//hide the message
$('#generate_report_message').hide();
fetch('http://127.0.0.1:8000/lecture-activity-report-generation/?lecturer=' + global_lecturer + '&subject=' + global_subject + '&date=' + global_lecture_date)
.then((res) => res.json())
.then((out) => {
//show the loader and loading message
$('#generate_report_loader').attr('hidden', true);
$('#generate_report_loading_message').attr('hidden', true);
$('#generateReportModal').modal('hide');
})
.catch((err) => alert('error: ' + err))
});
}); });
...@@ -901,9 +930,12 @@ ...@@ -901,9 +930,12 @@
{% load static %} {% load static %}
<!-- Page Heading --> <!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between mb-4"> {# <div class="d-sm-flex align-items-center justify-content-between mb-4">#}
<h1 class="h3 mb-0 text-gray-800">Student Activity Recognition</h1> {# <h1 class="h3 mb-0 text-gray-800">Student Activity Recognition</h1>#}
</div> {# <button type="button" data-target="#generateReportModal" data-toggle="modal" class="d-none d-sm-inline-block btn btn-sm btn-primary shadow-sm" id="generate_report_before" disabled><i#}
{# class="fas fa-download fa-sm text-white-50"></i> Generate Report</button>#}
{# </div>#}
<!--first row --> <!--first row -->
<div class="row p-2"> <div class="row p-2">
...@@ -1183,63 +1215,90 @@ ...@@ -1183,63 +1215,90 @@
<!--2nd column --> <!--2nd column -->
<div class="col-lg-6"> {# <div class="col-lg-6">#}
<!--card content -->
<div class="card shadow mb-4"> {# <!--card content -->#}
<!--card header --> {# <div class="card shadow mb-4">#}
<div class="card-header py-3"> {# <!--card header -->#}
<h5 class="m-0 font-weight-bold text-primary">Frame Detections</h5> {# <div class="card-header py-3">#}
</div> {# <h5 class="m-0 font-weight-bold text-primary">Frame Detections</h5>#}
{# </div>#}
{##}
{# <!--card body -->#}
{# <div class="text-center p-4" id="detection_frames">#}
{##}
{# <!--no content message-->#}
{# <div class="text-center p-2" id="no_detection_message_content">#}
{# <span class="font-italic">No frame is selected</span>#}
{# </div>#}
{##}
{# <div class="text-left m-3" id="detection_number_area" hidden>#}
{# <p>No of detections: <span id="no_of_detections"></span></p>#}
{# </div>#}
{# <!--the detection loader -->#}
{# <div class="text-center p-2" id="detection_loader" hidden>#}
{# <img src="{% static 'FirstApp/images/ajax-loader.gif' %}"#}
{# alt="Loader">#}
{# </div>#}
{# </div>#}
{# </div>#}
<!--card body -->
<div class="text-center p-4" id="detection_frames">
<!--no content message-->
<div class="text-center p-2" id="no_detection_message_content">
<span class="font-italic">No frame is selected</span>
</div>
<div class="text-left m-3" id="detection_number_area" hidden>
<p>No of detections: <span id="no_of_detections"></span></p>
</div>
<!--the detection loader -->
<div class="text-center p-2" id="detection_loader" hidden>
<img src="{% static 'FirstApp/images/ajax-loader.gif' %}"
alt="Loader">
</div>
</div>
</div>
<!--detection person card --> <!--detection person card -->
{# <div class="card shadow mb-4">#}
{# <!--card header -->#}
{# <div class="card-header py-3">#}
{# <h5 class="m-0 font-weight-bold text-primary">Detected Students (by activity#}
{# type)</h5>#}
{# </div>#}
{##}
{# <!--card body -->#}
{# <div class="text-center p-4" id="detection_students">#}
{# <!--activity type line -->#}
{# <div class="text-center p-2" id="activity_type" hidden>#}
{# <p>Activity Type: <span class="font-weight-bold" id="activity_type_text"></span>#}
{# </p>#}
{# </div>#}
{##}
{# <!--no content message-->#}
{# <div class="text-center p-2" id="no_detection_student_content">#}
{# <span class="font-italic">No activity type is selected</span>#}
{# </div>#}
{##}
{# <!--the detection student loader -->#}
{# <div class="text-center p-2" id="detection_student_loader" hidden>#}
{# <img src="{% static 'FirstApp/images/ajax-loader.gif' %}"#}
{# alt="Loader">#}
{# </div>#}
{##}
{# </div>#}
{# </div>#}
{# </div>#}
<!--2nd column -->
<div class="col-lg-6">
<!--card -->
<div class="card shadow mb-4"> <div class="card shadow mb-4">
<!--card header --> <!--card header -->
<div class="card-header py-3"> <div class="card-header">
<h5 class="m-0 font-weight-bold text-primary">Detected Students (by activity <h5 class="m-0 font-weight-bold text-primary">Integrated Evaluation</h5>
type)</h5>
</div> </div>
<!--card body --> <!--card body -->
<div class="text-center p-4" id="detection_students"> <div class="card-body">
<!--activity type line --> <div class="text-center" id="integrate_message">
<div class="text-center p-2" id="activity_type" hidden> <span class="font-italic">The integrated version student and lecturer evaluations will display here.</span>
<p>Activity Type: <span class="font-weight-bold" id="activity_type_text"></span>
</p>
</div>
<!--no content message-->
<div class="text-center p-2" id="no_detection_student_content">
<span class="font-italic">No activity type is selected</span>
</div> </div>
<!--the detection student loader --> <!--button -->
<div class="text-center p-2" id="detection_student_loader" hidden> <div class="text-right m-4">
<img src="{% static 'FirstApp/images/ajax-loader.gif' %}" <button type="button" class="btn btn-outline-success" id="integrate_gaze">
alt="Loader"> Process
</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!--end of 2nd column -->
</div> </div>
...@@ -1250,63 +1309,37 @@ ...@@ -1250,63 +1309,37 @@
<!--1st column --> <!--1st column -->
<div class="col-lg-6"> <div class="col-lg-6">
<!--card --> {# <!--card -->#}
<div class="card shadow mb-4"> {# <div class="card shadow mb-4">#}
<!--card header --> {# <!--card header -->#}
<div class="card-header"> {# <div class="card-header">#}
<h5 class="m-0 font-weight-bold text-primary">Evaluated Students</h5> {# <h5 class="m-0 font-weight-bold text-primary">Evaluated Students</h5>#}
</div> {# </div>#}
{##}
<!--card body --> {# <!--card body -->#}
<div class="card-body" id="evaluation_students"> {# <div class="card-body" id="evaluation_students">#}
{##}
<!--no content message--> {# <!--no content message-->#}
<div class="text-center p-2" id="no_evaluated_student_content"> {# <div class="text-center p-2" id="no_evaluated_student_content">#}
<span class="font-italic">Press 'Evaluate' button to evaluate students</span> {# <span class="font-italic">Press 'Evaluate' button to evaluate students</span>#}
</div> {# </div>#}
{##}
<!--the detection student loader --> {# <!--the detection student loader -->#}
<div class="text-center p-2" id="evaluate_student_loader" hidden> {# <div class="text-center p-2" id="evaluate_student_loader" hidden>#}
<img src="{% static 'FirstApp/images/ajax-loader.gif' %}" {# <img src="{% static 'FirstApp/images/ajax-loader.gif' %}"#}
alt="Loader"> {# alt="Loader">#}
</div> {# </div>#}
<!--end of student detection loader --> {# <!--end of student detection loader -->#}
{##}
{##}
</div> {# </div>#}
{##}
</div> {# </div>#}
</div> </div>
<!--end of 1st column --> <!--end of 1st column -->
<!--2nd column -->
<div class="col-lg-6">
<!--card -->
<div class="card shadow mb-4">
<!--card header -->
<div class="card-header">
<h5 class="m-0 font-weight-bold text-primary">Integrated Evaluation</h5>
</div>
<!--card body -->
<div class="card-body">
<div class="text-center" id="integrate_message">
<span class="font-italic">The integrated version student and lecturer evaluations will display here.</span>
</div>
<!--button -->
<div class="text-right m-4">
<button type="button" class="btn btn-outline-success" id="integrate_activity">
Process
</button>
</div>
</div>
</div>
</div>
<!--end of 2nd column -->
</div> </div>
<!--end of 3rd row --> <!--end of 3rd row -->
...@@ -1451,6 +1484,37 @@ ...@@ -1451,6 +1484,37 @@
</div> </div>
<!-- generate report Modal-->
<div class="modal fade" id="generateReportModal" tabindex="-1" role="dialog" aria-labelledby="generateReportModal"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Generate Activity Report</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div id="generate_report_message">
Are you sure you want to generate the report without going through the content?
</div>
<div class="text-center" id="generate_report_loader" hidden>
<img src="{% static 'FirstApp/images/ajax-loader-1.gif' %}" alt="loader">y
</div>
<div class="text-center" id="generate_report_loading_message" hidden>
<span class="font-italic">This will take some time</span>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal" id="generate_report_btn">Yes</button>
<button type="button" class="btn btn-danger" data-dismiss="modal">No</button>
</div>
</div>
</div>
</div>
<!--integrate modal --> <!--integrate modal -->
<div class="modal fade" id="integrate_modal" tabindex="-1" role="dialog" aria-labelledby="integrate_modal"> <div class="modal fade" id="integrate_modal" tabindex="-1" role="dialog" aria-labelledby="integrate_modal">
<div class="modal-dialog" style="max-width: 1300px"> <div class="modal-dialog" style="max-width: 1300px">
...@@ -1548,12 +1612,12 @@ ...@@ -1548,12 +1612,12 @@
<span class="font-italic">No video was found</span> <span class="font-italic">No video was found</span>
</div> </div>
<!-- video -->
<video width="500" height="300" id="lecturer_video" controls> {# <video width="500" height="300" id="lecturer_video" controls>#}
<source src="#" {# <source src="#"#}
type="video/mp4"> {# type="video/mp4">#}
Your browser does not support the video tag. {# Your browser does not support the video tag.#}
</video> {# </video>#}
</div> </div>
<!--end of lecture video section --> <!--end of lecture video section -->
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
<head> <head>
{% load static %}
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
...@@ -12,11 +14,11 @@ ...@@ -12,11 +14,11 @@
<title>SB Admin 2 - Charts</title> <title>SB Admin 2 - Charts</title>
<!-- Custom fonts for this template--> <!-- Custom fonts for this template-->
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css"> <link href="{% static 'FirstApp/vendor/fontawesome-free/css/all.min.css' %}" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i" rel="stylesheet">
<!-- Custom styles for this template--> <!-- Custom styles for this template-->
<link href="css/sb-admin-2.min.css" rel="stylesheet"> <link href="{% static 'FirstApp/css/sb-admin-2.min.css' %}" rel="stylesheet">
</head> </head>
......
...@@ -195,7 +195,6 @@ ...@@ -195,7 +195,6 @@
activity.response.map((act, index) => { activity.response.map((act, index) => {
//setting the percentage values //setting the percentage values
alert('happy perct: ' + act);
$('#happy_perct').text(act.happy_perct + '%'); $('#happy_perct').text(act.happy_perct + '%');
$('#sad_perct').text(act.sad_perct + '%'); $('#sad_perct').text(act.sad_perct + '%');
$('#anger_perct').text(act.angry_perct + '%'); $('#anger_perct').text(act.angry_perct + '%');
...@@ -1151,10 +1150,10 @@ ...@@ -1151,10 +1150,10 @@
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div> aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<!--evaluate button --> {# <!--evaluate button -->#}
<button type="button" class="btn btn-danger float-right" {# <button type="button" class="btn btn-danger float-right"#}
id="evaluate_button">Evaluate {# id="evaluate_button">Evaluate#}
</button> {# </button>#}
</div> </div>
...@@ -1215,63 +1214,63 @@ ...@@ -1215,63 +1214,63 @@
<!--2nd column --> <!--2nd column -->
<div class="col-lg-6"> {# <div class="col-lg-6">#}
<!--card content --> {# <!--card content -->#}
<div class="card shadow mb-4"> {# <div class="card shadow mb-4">#}
<!--card header --> {# <!--card header -->#}
<div class="card-header py-3"> {# <div class="card-header py-3">#}
<h5 class="m-0 font-weight-bold text-primary">Frame Detections</h5> {# <h5 class="m-0 font-weight-bold text-primary">Frame Detections</h5>#}
</div> {# </div>#}
{##}
<!--card body --> {# <!--card body -->#}
<div class="text-center p-4" id="detection_frames"> {# <div class="text-center p-4" id="detection_frames">#}
{##}
<!--no content message--> {# <!--no content message-->#}
<div class="text-center p-2" id="no_detection_message_content"> {# <div class="text-center p-2" id="no_detection_message_content">#}
<span class="font-italic">No frame is selected</span> {# <span class="font-italic">No frame is selected</span>#}
</div> {# </div>#}
{##}
<div class="text-left m-3" id="detection_number_area" hidden> {# <div class="text-left m-3" id="detection_number_area" hidden>#}
<p>No of detections: <span id="no_of_detections"></span></p> {# <p>No of detections: <span id="no_of_detections"></span></p>#}
</div> {# </div>#}
<!--the detection loader --> {# <!--the detection loader -->#}
<div class="text-center p-2" id="detection_loader" hidden> {# <div class="text-center p-2" id="detection_loader" hidden>#}
<img src="{% static 'FirstApp/images/ajax-loader.gif' %}" {# <img src="{% static 'FirstApp/images/ajax-loader.gif' %}"#}
alt="Loader"> {# alt="Loader">#}
</div> {# </div>#}
</div> {# </div>#}
</div> {# </div>#}
{##}
<!--detection person card --> {# <!--detection person card -->#}
<div class="card shadow mb-4"> {# <div class="card shadow mb-4">#}
<!--card header --> {# <!--card header -->#}
<div class="card-header py-3"> {# <div class="card-header py-3">#}
<h5 class="m-0 font-weight-bold text-primary">Detected Students (by emotion {# <h5 class="m-0 font-weight-bold text-primary">Detected Students (by emotion#}
type)</h5> {# type)</h5>#}
</div> {# </div>#}
{##}
<!--card body --> {# <!--card body -->#}
<div class="text-center p-4" id="detection_students"> {# <div class="text-center p-4" id="detection_students">#}
<!--activity type line --> {# <!--activity type line -->#}
<div class="text-center p-2" id="activity_type" hidden> {# <div class="text-center p-2" id="activity_type" hidden>#}
<p>Activity Type: <span class="font-weight-bold" id="activity_type_text"></span> {# <p>Activity Type: <span class="font-weight-bold" id="activity_type_text"></span>#}
</p> {# </p>#}
</div> {# </div>#}
{##}
<!--no content message--> {# <!--no content message-->#}
<div class="text-center p-2" id="no_detection_student_content"> {# <div class="text-center p-2" id="no_detection_student_content">#}
<span class="font-italic">No activity type is selected</span> {# <span class="font-italic">No activity type is selected</span>#}
</div> {# </div>#}
{##}
<!--the detection student loader --> {# <!--the detection student loader -->#}
<div class="text-center p-2" id="detection_student_loader" hidden> {# <div class="text-center p-2" id="detection_student_loader" hidden>#}
<img src="{% static 'FirstApp/images/ajax-loader.gif' %}" {# <img src="{% static 'FirstApp/images/ajax-loader.gif' %}"#}
alt="Loader"> {# alt="Loader">#}
</div> {# </div>#}
{##}
</div> {# </div>#}
</div> {# </div>#}
</div> {# </div>#}
</div> </div>
...@@ -1281,36 +1280,36 @@ ...@@ -1281,36 +1280,36 @@
<div class="row p-2"> <div class="row p-2">
<!--1st column --> <!--1st column -->
<div class="col-lg-6"> {# <div class="col-lg-6">#}
<!--card --> {# <!--card -->#}
<div class="card shadow mb-4"> {# <div class="card shadow mb-4">#}
<!--card header --> {# <!--card header -->#}
<div class="card-header"> {# <div class="card-header">#}
<h5 class="m-0 font-weight-bold text-primary">Evaluated Students</h5> {# <h5 class="m-0 font-weight-bold text-primary">Evaluated Students</h5>#}
</div> {# </div>#}
{##}
<!--card body --> {# <!--card body -->#}
<div class="card-body" id="evaluation_students"> {# <div class="card-body" id="evaluation_students">#}
{##}
<!--no content message--> {# <!--no content message-->#}
<div class="text-center p-2" id="no_evaluated_student_content"> {# <div class="text-center p-2" id="no_evaluated_student_content">#}
<span class="font-italic">Press 'Evaluate' button to evaluate students</span> {# <span class="font-italic">Press 'Evaluate' button to evaluate students</span>#}
</div> {# </div>#}
{##}
<!--the detection student loader --> {# <!--the detection student loader -->#}
<div class="text-center p-2" id="evaluate_student_loader" hidden> {# <div class="text-center p-2" id="evaluate_student_loader" hidden>#}
<img src="{% static 'FirstApp/images/ajax-loader.gif' %}" {# <img src="{% static 'FirstApp/images/ajax-loader.gif' %}"#}
alt="Loader"> {# alt="Loader">#}
</div> {# </div>#}
<!--end of student detection loader --> {# <!--end of student detection loader -->#}
{##}
{##}
</div> {# </div>#}
{##}
</div> {# </div>#}
{##}
{##}
</div> {# </div>#}
<!--end of 1st column --> <!--end of 1st column -->
......
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
let date = e.target.parentNode.parentNode.firstChild.innerHTML; let date = e.target.parentNode.parentNode.firstChild.innerHTML;
fetch('http://127.0.0.1:8000/get-lecture-video/?lecturer=' + global_lecturer + '&date=' + date + '&index=' + global_lecturer_subject_index) fetch('http://127.0.0.1:8000/get-lecture-video-gaze-estimation-availability/?lecturer=' + global_lecturer + '&date=' + date + '&index=' + global_lecturer_subject_index)
.then((res) => res.json()) .then((res) => res.json())
.then((out) => displayLectureVideoDetails(out, object)) .then((out) => displayLectureVideoDetails(out, object))
.catch((error) => alert('an error occurred: ' + error)); .catch((error) => alert('an error occurred: ' + error));
...@@ -144,17 +144,19 @@ ...@@ -144,17 +144,19 @@
global_video_name = video.video_name; global_video_name = video.video_name;
if (lectureVideo.isActivityFound) { if (lectureVideo.isGazeEstimationFound) {
e.target.parentNode.parentNode.lastChild.innerHTML = '<button type="button" class="btn btn-primary">Results</button>'; e.target.parentNode.parentNode.lastChild.innerHTML = '<button type="button" class="btn btn-primary" id="result_btn">Results</button>';
} else { } else {
e.target.parentNode.parentNode.lastChild.innerHTML = '<button type="button" class="btn btn-success">Process</button>'; {#e.target.parentNode.parentNode.lastChild.innerHTML = "<span class='font-italic font-weight-bold text-danger'>Needs to be processed</span>";#}
e.target.parentNode.parentNode.lastChild.innerHTML = '<button type="button" class="btn btn-success" id="process_gaze">Process</button>';
} }
$('#video_modal').modal(); $('#video_modal').modal();
} }
//binding a click event for 'btn-primary' buttons //binding a click event for 'btn-primary' buttons
$(document).on('click', '.btn-primary', function (e) { $(document).on('click', '#result_btn', function (e) {
//removing the previous frames (if there is any) //removing the previous frames (if there is any)
$('#main_frames').remove(); $('#main_frames').remove();
...@@ -164,7 +166,7 @@ ...@@ -164,7 +166,7 @@
//hiding the temporary text //hiding the temporary text
$('#temporary_text').attr('hidden', true); $('#temporary_text').attr('hidden', true);
fetch('http://127.0.0.1:8000/get-lecture-activity/?lecture_video_id=' + global_lecture_video_id + '&lecture_video_name=' + global_video_name) fetch('http://127.0.0.1:8000/get-lecture-gaze-estimation/?lecture_video_id=' + global_lecture_video_id + '&lecture_video_name=' + global_video_name)
.then((res) => res.json()) .then((res) => res.json())
.then((out) => { .then((out) => {
let frames = createFrames(out); let frames = createFrames(out);
...@@ -179,7 +181,7 @@ ...@@ -179,7 +181,7 @@
}); });
//displaying the activity percentages in the progress bars //displaying the activity percentages in the progress bars
function displayActivity(activity) { function displayGazeEstimation(gaze) {
//hiding the loader (for the frames) //hiding the loader (for the frames)
$('#frame_loader').attr('hidden', true); $('#frame_loader').attr('hidden', true);
...@@ -190,29 +192,31 @@ ...@@ -190,29 +192,31 @@
$('video').attr({'hidden': false, 'src': src}); $('video').attr({'hidden': false, 'src': src});
activity.response.map((act, index) => { gaze.response.map((act, index) => {
//setting the percentage values //setting the percentage values
$('#phone_perct').text(act.phone_perct + '%'); $('#looking_up_right_perct').text(act.looking_up_and_right_perct + '%');
$('#talking_perct').text(act.talking_perct + '%'); $('#looking_up_left_perct').text(act.looking_up_and_left_perct + '%');
$('#listening_perct').text(act.listening_perct + '%'); $('#looking_down_right_perct').text(act.looking_down_and_right_perct + '%');
$('#writing_perct').text(act.writing_perct + '%'); $('#looking_down_left_perct').text(act.looking_down_and_left_perct + '%');
$('#looking_front_perct').text(act.looking_front_perct + '%');
//setting the width in the progress bars //setting the width in the progress bars
$('#phone_width').width(act.phone_perct + '%'); $('#looking_up_right_width').width(act.looking_up_and_right_perct + '%');
$('#talking_width').width(act.talking_perct + '%'); $('#looking_up_left_width').width(act.looking_up_and_left_perct + '%');
$('#listening_width').width(act.listening_perct + '%'); $('#looking_down_right_width').width(act.looking_down_and_right_perct + '%');
$('#writing_width').width(act.writing_perct + '%'); $('#looking_down_left_width').width(act.looking_down_and_left_perct + '%');
$('#looking_front_width').width(act.looking_front_perct + '%');
}); });
//display the progress bar area //display the progress bar area
$('.progress_area').attr('hidden', false); $('.progress_area').attr('hidden', false);
} }
//to handle the 'btn-success' (process) button //to handle the process button
$(document).on('click', '.btn-success', function (e) { $(document).on('click', '#process_gaze', function (e) {
//sending the POST request to process the lecture activities //sending the get request to process the lecture gaze estimations
fetch('http://127.0.0.1:8000/process-lecture-activity/?lecture_video_name=' + global_video_name + '&lecture_video_id=' + global_lecture_video_id) fetch('http://127.0.0.1:8000/process-lecture-gaze-estimation/?lecture_video_name=' + global_video_name + '&lecture_video_id=' + global_lecture_video_id)
.then((res) => res.json()) .then((res) => res.json())
.then((out) => handleResponse(out.response, e)) .then((out) => handleResponse(out.response, e))
.catch((error) => alert('error: ' + error)); .catch((error) => alert('error: ' + error));
...@@ -222,7 +226,7 @@ ...@@ -222,7 +226,7 @@
function handleResponse(response, e) { function handleResponse(response, e) {
//change the button, if the response is positive //change the button, if the response is positive
if (response) { if (response) {
e.target.parentNode.parentNode.lastChild.innerHTML = '<button type="button" class="btn btn-primary">Results</button>'; e.target.parentNode.parentNode.lastChild.innerHTML = '<button type="button" class="btn btn-primary" id="result_btn" >Results</button>';
} }
} }
...@@ -236,15 +240,14 @@ ...@@ -236,15 +240,14 @@
//loop through the frames //loop through the frames
res.extracted.map((image) => { res.extracted.map((image) => {
let img_src = ""; let img_src = "";
let len = image.detections.length;
if (count === 0) { if (count === 0) {
main_frame_content += "<li class='list-group-item text-center' id='image_0'>"; main_frame_content += "<li class='list-group-item text-center' id='image_0'>";
img_src = "<img src='{% static '' %}FirstApp/activity/" + global_video_name + "/" + res.extracted[0].frame + "/" + res.extracted[0].detections[0] + "' width='400' height='400'>"; img_src = "<img src='{% static '' %}FirstApp/gaze/" + global_video_name + "/" + res.extracted[0] + "' width='400' height='400'>";
} else { } else {
main_frame_content += "<li class='list-group-item other-frames' id='image_" + count + "' hidden>"; main_frame_content += "<li class='list-group-item other-frames' id='image_" + count + "' hidden>";
img_src = "<img src='{% static '' %}FirstApp/activity/" + global_video_name + "/" + image.frame + "/" + image.detections[len - 1] + "' class='img-link' width='400' height='400'>"; img_src = "<img src='{% static '' %}FirstApp/gaze/" + global_video_name + "/" + image + "' class='img-link' width='400' height='400'>";
} }
...@@ -261,12 +264,176 @@ ...@@ -261,12 +264,176 @@
$('#myActivityRange').attr({'min': 0, 'max': count}); $('#myActivityRange').attr({'min': 0, 'max': count});
//display the progress bars //display the progress bars
displayActivity(res); displayGazeEstimation(res);
return main_frame_content; return main_frame_content;
} }
//to handle the 'integrate' modal
$('#integrate_activity').click(function () {
//define the student video src
let video_src = "{% static '' %}FirstApp/videos/" + global_video_name;
//assign the video src
$('#student_video').attr('src', video_src);
$('#integrate_modal').modal();
//fetch data from the API
fetch('http://127.0.0.1:8000/get-lecture-gaze-estimation-for-frame/?video_name=' + global_video_name)
.then((res) => res.json())
.then((out) => displayGazeEstimationForFrame(out.response))
.catch((err) => alert('error: ' + err));
});
//this function will load the activity recognition for frames
function displayGazeEstimationForFrame(response) {
//hide the loader
$('#student_video_progress_loader').attr('hidden', true);
//show the progress bars
$('#student_video_progress').attr('hidden', false);
//creating the html string
let htmlString = "";
//creating the html string, iteratively
response.map((frame) => {
let frame_name = frame.frame_name;
let look_up_right = Math.round(frame.head_up_right_perct, 0);
let look_up_left = Math.round(frame.head_up_left_perct, 0);
let look_down_right = Math.round(frame.head_down_right_perct, 0);
let look_down_left = Math.round(frame.head_down_left_perct, 0);
let look_front = Math.round(frame.head_front_perct, 0);
//append to the html string
//looking up and right
htmlString += "<div class='progress_area' id='progress_" +frame_name+ "' hidden>";
htmlString += "<h4 class='small font-weight-bold'>Looking up and right</h4>";
htmlString += "<span class='float-right' id='look_up_right_instant_" +frame_name+ "'>" +look_up_right+ "%</span>";
htmlString += "<div class='progress mb-4'>";
htmlString += "<div class='progress-bar bg-warning' role='progressbar' id='look_up_right_instant_value_" +frame_name+ "' style='width: " +look_up_right+ "%' aria-valuenow='40' aria-valuemin='0' aria-valuemax='100'></div>";
htmlString += "</div>";
//looking up and left
htmlString += "<h4 class='small font-weight-bold'>Looking up and left</h4>";
htmlString += "<span class='float-right' id='look_up_left_instant_" +frame_name+ "'>" +look_up_left+ "%</span>";
htmlString += "<div class='progress mb-4'>";
htmlString += "<div class='progress-bar' role='progressbar' id='look_up_left_instant_value_" +frame_name+ "' style='width: " +look_up_left+ "%' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div>";
htmlString += "</div>";
//looking down and right
htmlString += "<h4 class='small font-weight-bold'>Looking down and right</h4>";
htmlString += "<span class='float-right' id='look_down_right_instant_" +frame_name+ "'>" +look_down_right+ "%</span>";
htmlString += "<div class='progress mb-4'>";
htmlString += "<div class='progress-bar bg-info' role='progressbar' id='look_down_right_instant_value_" +frame_name+ "' style='width: " +look_down_right+ "%' aria-valuenow='80' aria-valuemin='0' aria-valuemax='100'></div>";
htmlString += "</div>";
//looking down and left
htmlString += "<h4 class='small font-weight-bold'>Looking down and left</h4>";
htmlString += "<span class='float-right' id='look_down_left_instant_" +frame_name+ "'>" +look_down_left+ "%</span>";
htmlString += "<div class='progress mb-4'>";
htmlString += "<div class='progress-bar bg-info' role='progressbar' id='look_down_left_instant_value_" +frame_name+ "' style='width: " +look_down_left+ "%' aria-valuenow='80' aria-valuemin='0' aria-valuemax='100'></div>";
htmlString += "</div>";
//looking front
htmlString += "<h4 class='small font-weight-bold'>Looking front</h4>";
htmlString += "<span class='float-right' id='look_front_instant_" +frame_name+ "'>" +look_front+ "%</span>";
htmlString += "<div class='progress mb-4'>";
htmlString += "<div class='progress-bar bg-info' role='progressbar' id='look_front_instant_value_" +frame_name+ "' style='width: " +look_front+ "%' aria-valuenow='80' aria-valuemin='0' aria-valuemax='100'></div>";
htmlString += "</div>";
//ending the progress area
htmlString += "</div>";
});
//append the html
$('#student_video_column').append(htmlString);
}
//to handle the 'integrate' play button
$('#play_integrate_button').click(function () {
let video = $('video')[0];
let test_video = document.getElementsByTagName('video')[0];
let play_class = 'btn btn-outline-danger play';
let pause_class = 'btn btn-outline-danger pause';
let count = 0;
let classes = $(this).attr('class');
let video_interval = setInterval(() => {
{#let talking_number = Math.round(Math.random() * 100, 0);#}
{#let phone_number = Math.round(Math.random() * 100, 0);#}
{#let note_number = Math.round(Math.random() * 100, 0);#}
{#let listening_number = Math.round(Math.random() * 100, 0);#}
//get the relevant progress area
let progress_area = "progress_frame-" + count;
let progress_area_id = "#" + progress_area;
//find the corresponding progress area
let progress_area_html = document.getElementById(progress_area);
//display the retrieved progress area
$(progress_area_id).attr('hidden', false);
//replace the current progress area with the selected one
$('#student_video_progress').html(progress_area_html);
//increment the count
count++;
//setting the values
{#$('#looking_up_right_instant_perct').text(talking_number + '%');#}
{#$('#looking_up_left_instant_perct').text(phone_number + '%');#}
{#$('#looking_down_right_instant_perct').text(note_number + '%');#}
{#$('#looking_down_left_instant_perct').text(listening_number + '%');#}
{#$('#looking_front_instant_perct').text(listening_number + '%');#}
{##}
{#//setting the width#}
{#$('#talking_instant_value').width(talking_number + '%');#}
{#$('#phone_checking_instant_value').width(phone_number + '%');#}
{#$('#note_taking_instant_value').width(note_number + '%');#}
{#$('#listening_instant_value').width(listening_number + '%');#}
}, 33);
//check for the current class
if (classes === play_class) {
$(this).text('Pause');
$(this).attr('class', pause_class);
video.play();
} else if (classes === pause_class) {
$(this).text('Play');
$(this).attr('class', play_class);
video.pause();
}
//function to do when the video is paused
//function to do when the video is ended
video.onended = function (e) {
//stop changing the activity values
clearInterval(video_interval);
}
});
//declaring the variable for setInterval function //declaring the variable for setInterval function
let timeVar = null; let timeVar = null;
...@@ -422,10 +589,9 @@ ...@@ -422,10 +589,9 @@
if (student_count === 0) { if (student_count === 0) {
images += "<li class='list-group-item frame-0' id='image_0_" +title+ "'>"; images += "<li class='list-group-item frame-0' id='image_0_" + title + "'>";
} } else {
else { images += "<li class='list-group-item other-student-frames' id='image_" + student_count + "_" + title + "' hidden>";
images += "<li class='list-group-item other-student-frames' id='image_" +student_count+ "_" +title+ "' hidden>";
} }
images += "<img src='{% static '' %}FirstApp/Activity/" + global_video_name + "/" + frame.frame + "/" + student + "' width='200' height='200'>"; images += "<img src='{% static '' %}FirstApp/Activity/" + global_video_name + "/" + frame.frame + "/" + student + "' width='200' height='200'>";
...@@ -443,10 +609,10 @@ ...@@ -443,10 +609,10 @@
htmlString += "<div class='slidecontainer'>"; htmlString += "<div class='slidecontainer'>";
htmlString += "<div class='row m-3'></div>"; htmlString += "<div class='row m-3'></div>";
htmlString += "<div class='row'>"; htmlString += "<div class='row'>";
htmlString += "<span><i class='fas fa-play play-pause-icon-student-frames' id='icon_" +title+ "'></i></span>"; htmlString += "<span><i class='fas fa-play play-pause-icon-student-frames' id='icon_" + title + "'></i></span>";
htmlString += "</div>"; htmlString += "</div>";
htmlString += "<input type='range' min='1' max='100' value='0' class='slider' id='slider_" +title+ "'>"; htmlString += "<input type='range' min='1' max='100' value='0' class='slider' id='slider_" + title + "'>";
htmlString += "<p>No of frames: <span id='demo_" +title+ "'></span></p>"; htmlString += "<p>No of frames: <span id='demo_" + title + "'></span></p>";
htmlString += "</div>"; htmlString += "</div>";
htmlString += "</div>"; htmlString += "</div>";
}); });
...@@ -500,7 +666,7 @@ ...@@ -500,7 +666,7 @@
output.innerHTML = new_slider_value.toString(); output.innerHTML = new_slider_value.toString();
let selectedImage = '#image_' +Number(value)+ '_' + title; let selectedImage = '#image_' + Number(value) + '_' + title;
//displaying the relevant image //displaying the relevant image
$('#image_0_' + title).html($(selectedImage).html()); $('#image_0_' + title).html($(selectedImage).html());
...@@ -707,53 +873,66 @@ ...@@ -707,53 +873,66 @@
<!--this area will display the progress bars --> <!--this area will display the progress bars -->
<div class="progress_area" hidden> <div class="progress_area" hidden>
<!--talking with friends --> <!--Looking up and right -->
<a href="#" class="btn btn-link labels" data-number="1"> <a href="#" class="btn btn-link labels" data-number="1">
<h4 class="small font-weight-bold">Talking with friends</h4> <h4 class="small font-weight-bold">Looking up and right</h4>
</a> </a>
<span class="float-right" id="talking_perct">40%</span> <span class="float-right" id="looking_up_right_perct">40%</span>
<div class="progress mb-4"> <div class="progress mb-4">
<div class="progress-bar bg-danger" role="progressbar" <div class="progress-bar bg-danger" role="progressbar"
id="talking_width" id="looking_up_right_width"
style="width: 20%" style="width: 20%"
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div> aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<!--phone checking --> <!--looking up and left -->
<a href="#" class="btn btn-link labels" data-number="0"> <a href="#" class="btn btn-link labels" data-number="0">
<h4 class="small font-weight-bold">Phone checking</h4> <h4 class="small font-weight-bold">Looking up and left</h4>
</a> </a>
<span class="float-right" id="phone_perct">45%</span> <span class="float-right" id="looking_up_left_perct">45%</span>
<div class="progress mb-4"> <div class="progress mb-4">
<div class="progress-bar bg-warning" role="progressbar" <div class="progress-bar bg-warning" role="progressbar"
id="phone_width" id="looking_up_left_width"
style="width: 40%" style="width: 40%"
aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div> aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<!--note taking --> <!--looking down and right -->
<a href="#" class="btn btn-link labels" data-number="2"> <a href="#" class="btn btn-link labels" data-number="2">
<h4 class="small font-weight-bold">Writing</h4> <h4 class="small font-weight-bold">Looking down and right</h4>
</a> </a>
<span class="float-right" id="writing_perct">50%</span> <span class="float-right" id="looking_down_right_perct">50%</span>
<div class="progress mb-4"> <div class="progress mb-4">
<div class="progress-bar" role="progressbar" id="writing_width" <div class="progress-bar" role="progressbar"
id="looking_down_right_width"
style="width: 60%" style="width: 60%"
aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div> aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
<!--listening--> <!--Looking down and left-->
<a href="#" class="btn btn-link labels">
<h4 class="small font-weight-bold">Looking down and left</h4>
</a>
<span class="float-right" id="looking_down_left_perct">60%</span>
<div class="progress mb-4">
<div class="progress-bar bg-info" role="progressbar"
id="looking_down_left_width" style="width: 80%"
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<!--Looking front-->
<a href="#" class="btn btn-link labels"> <a href="#" class="btn btn-link labels">
<h4 class="small font-weight-bold">Listening</h4> <h4 class="small font-weight-bold">Looking Front</h4>
</a> </a>
<span class="float-right" id="listening_perct">60%</span> <span class="float-right" id="looking_front_perct">60%</span>
<div class="progress mb-4"> <div class="progress mb-4">
<div class="progress-bar bg-info" role="progressbar" <div class="progress-bar bg-info" role="progressbar"
id="listening_width" style="width: 80%" id="looking_front_width" style="width: 80%"
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div> aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
</div> </div>
<!-- end of progress area -->
</div> </div>
...@@ -813,55 +992,29 @@ ...@@ -813,55 +992,29 @@
<!--2nd column --> <!--2nd column -->
<div class="col-lg-6"> <div class="col-lg-6">
<!--card content --> <!--card -->
<div class="card shadow mb-4">
<!--card header -->
<div class="card-header py-3">
<h5 class="m-0 font-weight-bold text-primary">Frame Detections</h5>
</div>
<!--card body -->
<div class="text-center p-4" id="detection_frames">
<!--no content message-->
<div class="text-center p-2" id="no_detection_message_content">
<span class="font-italic">No frame is selected</span>
</div>
<div class="text-left m-3" id="detection_number_area" hidden>
<p>No of detections: <span id="no_of_detections"></span></p>
</div>
<!--the detection loader -->
<div class="text-center p-2" id="detection_loader" hidden>
<img src="{% static 'FirstApp/images/ajax-loader.gif' %}"
alt="Loader">
</div>
</div>
</div>
<!--detection person card -->
<div class="card shadow mb-4"> <div class="card shadow mb-4">
<!--card header --> <!--card header -->
<div class="card-header py-3"> <div class="card-header">
<h5 class="m-0 font-weight-bold text-primary">Detected Students</h5> <h5 class="m-0 font-weight-bold text-primary">Integrated Evaluation</h5>
</div> </div>
<!--card body --> <!--card body -->
<div class="text-center p-4" id="detection_students"> <div class="card-body">
<!--no content message--> <div class="text-center" id="integrate_message">
<div class="text-center p-2" id="no_detection_student_content"> <span class="font-italic">The integrated version student and lecturer evaluations will display here.</span>
<span class="font-italic">No activity type is selected</span>
</div> </div>
<!--the detection student loader --> <!--button -->
<div class="text-center p-2" id="detection_student_loader" hidden> <div class="text-right m-4">
<img src="{% static 'FirstApp/images/ajax-loader.gif' %}" <button type="button" class="btn btn-outline-success" id="integrate_activity">
alt="Loader"> Process
</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!--end of 2nd column -->
</div> </div>
...@@ -943,6 +1096,157 @@ ...@@ -943,6 +1096,157 @@
</div> </div>
</div> </div>
</div> </div>
<!-- end of logout modal -->
<!--integrate modal -->
<div class="modal fade" id="integrate_modal" tabindex="-1" role="dialog" aria-labelledby="integrate_modal">
<div class="modal-dialog" style="max-width: 1300px">
<div class="modal-content">
<!--modal header -->
<div class="modal-header">
<h4 class="modal-title">Integrated Version</h4>
</div>
<!--modal body -->
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<!--1st column -->
<div class="col-md-6" id="student_video_column" style="border-right: 1px solid black">
<div class="text-center">
<span class="h3 font-italic font-weight-bold">Student Behavior</span>
</div>
<!--display student video -->
<div class="text-center m-3" id="student_video_section">
<video width="500" height="300" id="student_video" controls>
<source src="#"
type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
<!--end of student video section -->
<!-- ajax loader section -->
<div class="text-center mt-3" id="student_video_progress_loader">
<img src="{% static 'FirstApp/images/ajax-loader-1.gif' %}" alt="loader">
</div>
<!--progress bar section -->
<div class="progress_area" id="student_video_progress" hidden>
<!--Looking up and right -->
<a href="#" class="btn btn-link labels" data-number="1">
<h4 class="small font-weight-bold">Looking up and right</h4>
</a>
<span class="float-right" id="looking_up_right_instant_perct">40%</span>
<div class="progress mb-4">
<div class="progress-bar bg-danger" role="progressbar"
id="looking_up_right_instant_width"
style="width: 20%"
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<!--looking up and left -->
<a href="#" class="btn btn-link labels" data-number="0">
<h4 class="small font-weight-bold">Looking up and left</h4>
</a>
<span class="float-right" id="looking_up_left_instant_perct">45%</span>
<div class="progress mb-4">
<div class="progress-bar bg-warning" role="progressbar"
id="looking_up_left_instant_width"
style="width: 40%"
aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<!--looking down and right -->
<a href="#" class="btn btn-link labels" data-number="2">
<h4 class="small font-weight-bold">Looking down and right</h4>
</a>
<span class="float-right" id="looking_down_right_instant_perct">50%</span>
<div class="progress mb-4">
<div class="progress-bar" role="progressbar" id="looking_down_right_instant_width"
style="width: 60%"
aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<!--Looking down and left-->
<a href="#" class="btn btn-link labels">
<h4 class="small font-weight-bold">Looking down and left</h4>
</a>
<span class="float-right" id="looking_down_left_instant_perct">60%</span>
<div class="progress mb-4">
<div class="progress-bar bg-info" role="progressbar"
id="looking_down_left_instant_width" style="width: 80%"
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<!--Looking front-->
<a href="#" class="btn btn-link labels">
<h4 class="small font-weight-bold">Looking Front</h4>
</a>
<span class="float-right" id="looking_front_instant_perct">60%</span>
<div class="progress mb-4">
<div class="progress-bar bg-info" role="progressbar"
id="looking_front_instant_width" style="width: 80%"
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<!--end of progress bar section -->
</div>
<!--end of 1st column -->
<!--2nd column -->
<div class="col-md-6">
<div class="text-center">
<span class="h3 font-italic font-weight-bold">Lecturer Performance</span>
</div>
<!--display lecture video -->
<div class="text-center m-3" id="lecturer_video_section">
<!--temporary text -->
<div class="text-center" id="temp_lecturer_text">
<span class="font-italic">No video was found</span>
</div>
{# <video width="500" height="300" id="lecturer_video" controls>#}
{# <source src="#"#}
{# type="video/mp4">#}
{# Your browser does not support the video tag.#}
{# </video>#}
</div>
<!--end of lecture video section -->
</div>
<!--end of 2nd column -->
</div>
<!--end of 1st row -->
<!--2nd row -->
<div class="row">
<!--play button -->
<div class="col-md-12">
<div class="text-center p-3">
<button type="button" class="btn btn-outline-danger play"
id="play_integrate_button">Play
</button>
</div>
</div>
</div>
<!--end of 2nd row -->
</div>
</div>
<!-- modal footer -->
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-danger text-white">Close</button>
</div>
</div>
</div>
</div>
<!--end of integrate modal -->
{% endblock %} {% endblock %}
</body> </body>
......
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>SLPES</title>
<link rel="shortcut icon" href="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/images/favicon.ico" type="image/x-icon"/>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<link rel="stylesheet" href="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/css/sb-admin-2.min.css" type="text/css">
<link rel="stylesheet" href="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/css/slider.css" type="text/css">
<link href="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet">
<link rel="stylesheet" href="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/css/all.min.css" type="text/css">
<link href="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet" type="text/css">
</head>
<body id="page-top">
<!-- main content -->
<div id="wrapper">
<div id="content-wrapper" class="d-flex flex-column">
<!-- Main Content -->
<div id="content">
<!-- Topbar -->
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
<!-- Sidebar Toggle (Topbar) -->
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Search -->
<!--form class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<div class="input-group">
<input type="text" class="form-control bg-light border-0 small" placeholder="Search for..."
aria-label="Search" aria-describedby="basic-addon2">
<div class="input-group-append">
<button class="btn btn-primary" type="button">
<i class="fas fa-search fa-sm"></i>
</button>
</div>
</div>
</form-->
<!-- logo -->
<div id="logo" class="text-left">
<img src="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/images/logo.PNG" alt="Logo" width="80" height="60">
</div>
<div class="m-4">
<h5>Student and Lecturer</h5>
<h5>Performance Enhancement System</h5>
</div>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Nav Item - Search Dropdown (Visible Only XS) -->
<li class="nav-item dropdown no-arrow d-sm-none">
<a class="nav-link dropdown-toggle" href="#" id="searchDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-search fa-fw"></i>
</a>
<!-- Dropdown - Messages -->
<div class="dropdown-menu dropdown-menu-right p-3 shadow animated--grow-in"
aria-labelledby="searchDropdown">
<form class="form-inline mr-auto w-100 navbar-search">
<div class="input-group">
<input type="text" class="form-control bg-light border-0 small"
placeholder="Search for..." aria-label="Search"
aria-describedby="basic-addon2">
<div class="input-group-append">
{# <button class="btn btn-primary" type="button">#}
{# <i class="fas fa-search fa-sm"></i>#}
{# </button>#}
</div>
</div>
</form>
</div>
</li>
<!-- Nav Item - Alerts -->
<li class="nav-item dropdown no-arrow mx-1">
<a class="nav-link dropdown-toggle" href="#" id="alertsDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{# <i class="fas fa-bell fa-fw"></i>#}
<!-- Counter - Alerts -->
{# <span class="badge badge-danger badge-counter">3+</span>#}
</a>
<!-- Dropdown - Alerts -->
<div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in"
aria-labelledby="alertsDropdown">
<h6 class="dropdown-header">
Alerts Center
</h6>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="mr-3">
<div class="icon-circle bg-primary">
<i class="fas fa-file-alt text-white"></i>
</div>
</div>
<div>
<div class="small text-gray-500">December 12, 2019</div>
<span class="font-weight-bold">A new monthly report is ready to download!</span>
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="mr-3">
<div class="icon-circle bg-success">
<i class="fas fa-donate text-white"></i>
</div>
</div>
<div>
<div class="small text-gray-500">December 7, 2019</div>
$290.29 has been deposited into your account!
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="mr-3">
<div class="icon-circle bg-warning">
<i class="fas fa-exclamation-triangle text-white"></i>
</div>
</div>
<div>
<div class="small text-gray-500">December 2, 2019</div>
Spending Alert: We've noticed unusually high spending for your account.
</div>
</a>
<a class="dropdown-item text-center small text-gray-500" href="#">Show All Alerts</a>
</div>
</li>
<!-- Nav Item - Messages -->
<li class="nav-item dropdown no-arrow mx-1">
<a class="nav-link dropdown-toggle" href="#" id="messagesDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{# <i class="fas fa-envelope fa-fw"></i>#}
<!-- Counter - Messages -->
{# <span class="badge badge-danger badge-counter">7</span>#}
</a>
<!-- Dropdown - Messages -->
<div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in"
aria-labelledby="messagesDropdown">
<h6 class="dropdown-header">
Message Center
</h6>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="dropdown-list-image mr-3">
<img class="rounded-circle" src="https://source.unsplash.com/fn_BT9fwg_E/60x60"
alt="">
<div class="status-indicator bg-success"></div>
</div>
<div class="font-weight-bold">
<div class="text-truncate">Hi there! I am wondering if you can help me with a
problem I've been having.
</div>
<div class="small text-gray-500">Emily Fowler · 58m</div>
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="dropdown-list-image mr-3">
<img class="rounded-circle" src="https://source.unsplash.com/AU4VPcFN4LE/60x60"
alt="">
<div class="status-indicator"></div>
</div>
<div>
<div class="text-truncate">I have the photos that you ordered last month, how
would you like them sent to you?
</div>
<div class="small text-gray-500">Jae Chun · 1d</div>
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="dropdown-list-image mr-3">
<img class="rounded-circle" src="https://source.unsplash.com/CS2uCrpNzJY/60x60"
alt="">
<div class="status-indicator bg-warning"></div>
</div>
<div>
<div class="text-truncate">Last month's report looks great, I am very happy with
the progress so far, keep up the good work!
</div>
<div class="small text-gray-500">Morgan Alvarez · 2d</div>
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="dropdown-list-image mr-3">
<img class="rounded-circle" src="https://source.unsplash.com/Mv9hjnEUHR4/60x60"
alt="">
<div class="status-indicator bg-success"></div>
</div>
<div>
<div class="text-truncate">Am I a good boy? The reason I ask is because someone
told me that people say this to all dogs, even if they aren't good...
</div>
<div class="small text-gray-500">Chicken the Dog · 2w</div>
</div>
</a>
<a class="dropdown-item text-center small text-gray-500" href="#">Read More Messages</a>
</div>
</li>
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
<li class="nav-item dropdown no-arrow">
<img src="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/images/sliit.png" alt="sliit" width="200" height="70">
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in"
aria-labelledby="userDropdown">
<a class="dropdown-item" href="#">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="#">
<i class="fas fa-cogs fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="#">
<i class="fas fa-list fa-sm fa-fw mr-2 text-gray-400"></i>
Activity Log
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#logoutModal">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>
Logout
</a>
</div>
</li>
</ul>
</nav>
<!-- End of Topbar -->
<!-- beginning of container-fluid -->
<div class="container-fluid">
<!-- Page Heading -->
{# <div class="d-sm-flex align-items-center justify-content-between mb-4">#}
{# <h1 class="mb-0 text-gray-800">Activity Recognition</h1>#}
{# </div>#}
<div class="text-center">
<h1 class="mb-0">Activity Recognition</h1>
</div>
<hr class="p-2">
<!--1st row -->
<div class="row">
<!-- 1st column -->
<div class="col-lg-6">
<!-- card -->
<div class="card shadow mb-4 bg-white">
<div class="card-header">
<h5 class="m-0 font-weight-bold text-primary">Lecturer Information</h5>
</div>
<!-- card body -->
<div class="card-body">
<table class="table table-borderless">
<tr>
<td class="font-weight-bold h4">Name</td>
<td>{{ lecturer_name }}</td>
</tr>
<tr>
<td class="font-weight-bold h4">Subject</td>
<td>{{ subject }}</td>
</tr>
<tr>
<td class="font-weight-bold h4">Date</td>
<td>{{ date }}</td>
</tr>
</table>
</div>
</div>
</div>
<!-- end of 1st column -->
<!-- 2nd column -->
<div class="col-lg-6">
<!-- card -->
<div class="card shadow mb-4 bg-white">
<div class="card-header">
<h5 class="m-0 font-weight-bold text-primary">Activity Information</h5>
</div>
<!-- card body -->
<div class="card-body">
<div class="progress_area">
<!--talking with friends -->
<h4 class="small font-weight-bold">Talking with friends</h4>
<span class="float-right" id="talking_perct">40%</span>
<div class="progress mb-4">
<div class="progress-bar bg-danger" role="progressbar"
id="talking_width"
style="width: 20%"
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<!--phone checking -->
<h4 class="small font-weight-bold">Phone checking</h4>
<span class="float-right" id="phone_perct">45%</span>
<div class="progress mb-4">
<div class="progress-bar bg-warning" role="progressbar"
id="phone_width"
style="width: 40%"
aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<!--note taking -->
<h4 class="small font-weight-bold">Writing</h4>
<span class="float-right" id="writing_perct">50%</span>
<div class="progress mb-4">
<div class="progress-bar" role="progressbar" id="writing_width"
style="width: 60%"
aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<!--listening-->
<h4 class="small font-weight-bold">Listening</h4>
<span class="float-right" id="listening_perct">60%</span>
<div class="progress mb-4">
<div class="progress-bar bg-info" role="progressbar"
id="listening_width" style="width: 80%"
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
</div>
</div>
<!-- end of 2nd column -->
</div>
<!-- end of 1st row -->
<!-- 2nd row -->
<!-- Area Chart -->
<div class="col-xl-8 col-lg-7">
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Activity Overview</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
</a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"
aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Dropdown Header:</div>
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="chart-area">
<canvas id="myAreaChart"></canvas>
</div>
</div>
</div>
</div>
<!-- end of 2nd row -->
</div>
<!-- end of container-fluid -->
</div>
<!--end of content -->
</div>
<!--end of content-wrapper -->
</div>
<!--end of wrapper -->
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
crossorigin="anonymous"></script>
<script src="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/vendor/jquery/jquery.js"></script>
<script src="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
<script src="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/vendor/chart.js/Chart.min.js"></script>
<!-- Page level custom scripts -->
<script src="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/js/demo/chart-area-demo.js"></script>
<script src="file:///D:/SLIIT/Year 4/CDAP/project/2020-101/assets/FirstApp/js/demo/chart-pie-demo.js"></script>
</body>
</html>
\ No newline at end of file
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
<link rel="stylesheet" href="{% static 'FirstApp/css/all.min.css' %}"> <link rel="stylesheet" href="{% static 'FirstApp/css/all.min.css' %}">
<link href="{% static 'FirstApp/vendor/datatables/dataTables.bootstrap4.min.css' %}" rel="stylesheet"> <link href="{% static 'FirstApp/vendor/datatables/dataTables.bootstrap4.min.css' %}" rel="stylesheet">
<!-- this link will import process workflow CSS -->
<link href="{% static 'FirstApp/css/process-worflow.css' %}" rel="stylesheet" type="text/css">
</head> </head>
{% endblock %} {% endblock %}
...@@ -72,7 +75,7 @@ ...@@ -72,7 +75,7 @@
<div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionSidebar"> <div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionSidebar">
<div class="bg-white py-2 collapse-inner rounded"> <div class="bg-white py-2 collapse-inner rounded">
<h6 class="collapse-header">Components:</h6> <h6 class="collapse-header">Components:</h6>
<a class="collapse-item" href="/pose">Pose</a> {# <a class="collapse-item" href="/pose">Pose</a>#}
<a class="collapse-item" href="/gaze">Gaze</a> <a class="collapse-item" href="/gaze">Gaze</a>
<a class="collapse-item" href="/emotion">Emotion</a> <a class="collapse-item" href="/emotion">Emotion</a>
<a class="collapse-item" href="/activity">Activity</a> <a class="collapse-item" href="/activity">Activity</a>
...@@ -89,10 +92,10 @@ ...@@ -89,10 +92,10 @@
<div id="collapseUtilities" class="collapse" aria-labelledby="headingUtilities" data-parent="#accordionSidebar"> <div id="collapseUtilities" class="collapse" aria-labelledby="headingUtilities" data-parent="#accordionSidebar">
<div class="bg-white py-2 collapse-inner rounded"> <div class="bg-white py-2 collapse-inner rounded">
<h6 class="collapse-header">Custom Utilities:</h6> <h6 class="collapse-header">Custom Utilities:</h6>
<a class="collapse-item" href="/extract">Video Extractor</a> {# <a class="collapse-item" href="/extract">Video Extractor</a>#}
<a class="collapse-item" href="/video_result">Video Results</a> <a class="collapse-item" href="/video_result">Video Results</a>
<a class="collapse-item" href="utilities-animation.html">Animations</a> {# <a class="collapse-item" href="utilities-animation.html">Animations</a>#}
<a class="collapse-item" href="utilities-other.html">Other</a> {# <a class="collapse-item" href="utilities-other.html">Other</a>#}
</div> </div>
</div> </div>
</li> </li>
...@@ -100,44 +103,44 @@ ...@@ -100,44 +103,44 @@
<!-- Divider --> <!-- Divider -->
<hr class="sidebar-divider"> <hr class="sidebar-divider">
<!-- Heading --> {# <!-- Heading -->#}
<div class="sidebar-heading"> {# <div class="sidebar-heading">#}
Addons {# Addons#}
</div> {# </div>#}
<!-- Nav Item - Pages Collapse Menu --> <!-- Nav Item - Pages Collapse Menu -->
<li class="nav-item"> {# <li class="nav-item">#}
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapsePages" aria-expanded="true" aria-controls="collapsePages"> {# <a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapsePages" aria-expanded="true" aria-controls="collapsePages">#}
<i class="fas fa-fw fa-folder"></i> {# <i class="fas fa-fw fa-folder"></i>#}
<span>Pages</span> {# <span>Pages</span>#}
</a> {# </a>#}
<div id="collapsePages" class="collapse" aria-labelledby="headingPages" data-parent="#accordionSidebar"> {# <div id="collapsePages" class="collapse" aria-labelledby="headingPages" data-parent="#accordionSidebar">#}
<div class="bg-white py-2 collapse-inner rounded"> {# <div class="bg-white py-2 collapse-inner rounded">#}
<h6 class="collapse-header">Login Screens:</h6> {# <h6 class="collapse-header">Login Screens:</h6>#}
<a class="collapse-item" href="/login">Login</a> {# <a class="collapse-item" href="/login">Login</a>#}
<a class="collapse-item" href="/register">Register</a> {# <a class="collapse-item" href="/register">Register</a>#}
<a class="collapse-item" href="/forgot-password">Forgot Password</a> {# <a class="collapse-item" href="/forgot-password">Forgot Password</a>#}
<div class="collapse-divider"></div> {# <div class="collapse-divider"></div>#}
<h6 class="collapse-header">Other Pages:</h6> {# <h6 class="collapse-header">Other Pages:</h6>#}
<a class="collapse-item" href="/404">404 Page</a> {# <a class="collapse-item" href="/404">404 Page</a>#}
<a class="collapse-item" href="/blank">Blank Page</a> {# <a class="collapse-item" href="/blank">Blank Page</a>#}
</div> {# </div>#}
</div> {# </div>#}
</li> {# </li>#}
<!-- Nav Item - Charts --> {# <!-- Nav Item - Charts -->#}
<li class="nav-item"> {# <li class="nav-item">#}
<a class="nav-link" href="charts.html"> {# <a class="nav-link" href="charts.html">#}
<i class="fas fa-fw fa-chart-area"></i> {# <i class="fas fa-fw fa-chart-area"></i>#}
<span>Charts</span></a> {# <span>Charts</span></a>#}
</li> {# </li>#}
{##}
<!-- Nav Item - Tables --> {# <!-- Nav Item - Tables -->#}
<li class="nav-item"> {# <li class="nav-item">#}
<a class="nav-link" href="/tables"> {# <a class="nav-link" href="/tables">#}
<i class="fas fa-fw fa-table"></i> {# <i class="fas fa-fw fa-table"></i>#}
<span>Tables</span></a> {# <span>Tables</span></a>#}
</li> {# </li>#}
<!-- Divider --> <!-- Divider -->
<hr class="sidebar-divider d-none d-md-block"> <hr class="sidebar-divider d-none d-md-block">
...@@ -164,144 +167,144 @@ ...@@ -164,144 +167,144 @@
</button> </button>
<!-- Topbar Search --> <!-- Topbar Search -->
<form class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search"> {# <form class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">#}
<div class="input-group"> {# <div class="input-group">#}
<input type="text" class="form-control bg-light border-0 small" placeholder="Search for..." aria-label="Search" aria-describedby="basic-addon2"> {# <input type="text" class="form-control bg-light border-0 small" placeholder="Search for..." aria-label="Search" aria-describedby="basic-addon2">#}
<div class="input-group-append"> {# <div class="input-group-append">#}
<button class="btn btn-primary" type="button"> {# <button class="btn btn-primary" type="button">#}
<i class="fas fa-search fa-sm"></i> {# <i class="fas fa-search fa-sm"></i>#}
</button> {# </button>#}
</div> {# </div>#}
</div> {# </div>#}
</form> {# </form>#}
<!-- Topbar Navbar --> <!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto"> <ul class="navbar-nav ml-auto">
<!-- Nav Item - Search Dropdown (Visible Only XS) --> <!-- Nav Item - Search Dropdown (Visible Only XS) -->
<li class="nav-item dropdown no-arrow d-sm-none"> {# <li class="nav-item dropdown no-arrow d-sm-none">#}
<a class="nav-link dropdown-toggle" href="#" id="searchDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> {# <a class="nav-link dropdown-toggle" href="#" id="searchDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">#}
<i class="fas fa-search fa-fw"></i> {# <i class="fas fa-search fa-fw"></i>#}
</a> {# </a>#}
<!-- Dropdown - Messages --> {# <!-- Dropdown - Messages -->#}
<div class="dropdown-menu dropdown-menu-right p-3 shadow animated--grow-in" aria-labelledby="searchDropdown"> {# <div class="dropdown-menu dropdown-menu-right p-3 shadow animated--grow-in" aria-labelledby="searchDropdown">#}
<form class="form-inline mr-auto w-100 navbar-search"> {# <form class="form-inline mr-auto w-100 navbar-search">#}
<div class="input-group"> {# <div class="input-group">#}
<input type="text" class="form-control bg-light border-0 small" placeholder="Search for..." aria-label="Search" aria-describedby="basic-addon2"> {# <input type="text" class="form-control bg-light border-0 small" placeholder="Search for..." aria-label="Search" aria-describedby="basic-addon2">#}
<div class="input-group-append"> {# <div class="input-group-append">#}
<button class="btn btn-primary" type="button"> {# <button class="btn btn-primary" type="button">#}
<i class="fas fa-search fa-sm"></i> {# <i class="fas fa-search fa-sm"></i>#}
</button> {# </button>#}
</div> {# </div>#}
</div> {# </div>#}
</form> {# </form>#}
</div> {# </div>#}
</li> {# </li>#}
{##}
<!-- Nav Item - Alerts --> {# <!-- Nav Item - Alerts -->#}
<li class="nav-item dropdown no-arrow mx-1"> {# <li class="nav-item dropdown no-arrow mx-1">#}
<a class="nav-link dropdown-toggle" href="#" id="alertsDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> {# <a class="nav-link dropdown-toggle" href="#" id="alertsDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">#}
<i class="fas fa-bell fa-fw"></i> {# <i class="fas fa-bell fa-fw"></i>#}
<!-- Counter - Alerts --> {# <!-- Counter - Alerts -->#}
<span class="badge badge-danger badge-counter">3+</span> {# <span class="badge badge-danger badge-counter">3+</span>#}
</a> {# </a>#}
<!-- Dropdown - Alerts --> {# <!-- Dropdown - Alerts -->#}
<div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="alertsDropdown"> {# <div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="alertsDropdown">#}
<h6 class="dropdown-header"> {# <h6 class="dropdown-header">#}
Alerts Center {# Alerts Center#}
</h6> {# </h6>#}
<a class="dropdown-item d-flex align-items-center" href="#"> {# <a class="dropdown-item d-flex align-items-center" href="#">#}
<div class="mr-3"> {# <div class="mr-3">#}
<div class="icon-circle bg-primary"> {# <div class="icon-circle bg-primary">#}
<i class="fas fa-file-alt text-white"></i> {# <i class="fas fa-file-alt text-white"></i>#}
</div> {# </div>#}
</div> {# </div>#}
<div> {# <div>#}
<div class="small text-gray-500">December 12, 2019</div> {# <div class="small text-gray-500">December 12, 2019</div>#}
<span class="font-weight-bold">A new monthly report is ready to download!</span> {# <span class="font-weight-bold">A new monthly report is ready to download!</span>#}
</div> {# </div>#}
</a> {# </a>#}
<a class="dropdown-item d-flex align-items-center" href="#"> {# <a class="dropdown-item d-flex align-items-center" href="#">#}
<div class="mr-3"> {# <div class="mr-3">#}
<div class="icon-circle bg-success"> {# <div class="icon-circle bg-success">#}
<i class="fas fa-donate text-white"></i> {# <i class="fas fa-donate text-white"></i>#}
</div> {# </div>#}
</div> {# </div>#}
<div> {# <div>#}
<div class="small text-gray-500">December 7, 2019</div> {# <div class="small text-gray-500">December 7, 2019</div>#}
$290.29 has been deposited into your account! {# $290.29 has been deposited into your account!#}
</div> {# </div>#}
</a> {# </a>#}
<a class="dropdown-item d-flex align-items-center" href="#"> {# <a class="dropdown-item d-flex align-items-center" href="#">#}
<div class="mr-3"> {# <div class="mr-3">#}
<div class="icon-circle bg-warning"> {# <div class="icon-circle bg-warning">#}
<i class="fas fa-exclamation-triangle text-white"></i> {# <i class="fas fa-exclamation-triangle text-white"></i>#}
</div> {# </div>#}
</div> {# </div>#}
<div> {# <div>#}
<div class="small text-gray-500">December 2, 2019</div> {# <div class="small text-gray-500">December 2, 2019</div>#}
Spending Alert: We've noticed unusually high spending for your account. {# Spending Alert: We've noticed unusually high spending for your account.#}
</div> {# </div>#}
</a> {# </a>#}
<a class="dropdown-item text-center small text-gray-500" href="#">Show All Alerts</a> {# <a class="dropdown-item text-center small text-gray-500" href="#">Show All Alerts</a>#}
</div> {# </div>#}
</li> {# </li>#}
<!-- Nav Item - Messages --> <!-- Nav Item - Messages -->
<li class="nav-item dropdown no-arrow mx-1"> {# <li class="nav-item dropdown no-arrow mx-1">#}
<a class="nav-link dropdown-toggle" href="#" id="messagesDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> {# <a class="nav-link dropdown-toggle" href="#" id="messagesDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">#}
<i class="fas fa-envelope fa-fw"></i> {# <i class="fas fa-envelope fa-fw"></i>#}
<!-- Counter - Messages --> {# <!-- Counter - Messages -->#}
<span class="badge badge-danger badge-counter">7</span> {# <span class="badge badge-danger badge-counter">7</span>#}
</a> {# </a>#}
<!-- Dropdown - Messages --> {# <!-- Dropdown - Messages -->#}
<div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="messagesDropdown"> {# <div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="messagesDropdown">#}
<h6 class="dropdown-header"> {# <h6 class="dropdown-header">#}
Message Center {# Message Center#}
</h6> {# </h6>#}
<a class="dropdown-item d-flex align-items-center" href="#"> {# <a class="dropdown-item d-flex align-items-center" href="#">#}
<div class="dropdown-list-image mr-3"> {# <div class="dropdown-list-image mr-3">#}
<img class="rounded-circle" src="https://source.unsplash.com/fn_BT9fwg_E/60x60" alt=""> {# <img class="rounded-circle" src="https://source.unsplash.com/fn_BT9fwg_E/60x60" alt="">#}
<div class="status-indicator bg-success"></div> {# <div class="status-indicator bg-success"></div>#}
</div> {# </div>#}
<div class="font-weight-bold"> {# <div class="font-weight-bold">#}
<div class="text-truncate">Hi there! I am wondering if you can help me with a problem I've been having.</div> {# <div class="text-truncate">Hi there! I am wondering if you can help me with a problem I've been having.</div>#}
<div class="small text-gray-500">Emily Fowler · 58m</div> {# <div class="small text-gray-500">Emily Fowler · 58m</div>#}
</div> {# </div>#}
</a> {# </a>#}
<a class="dropdown-item d-flex align-items-center" href="#"> {# <a class="dropdown-item d-flex align-items-center" href="#">#}
<div class="dropdown-list-image mr-3"> {# <div class="dropdown-list-image mr-3">#}
<img class="rounded-circle" src="https://source.unsplash.com/AU4VPcFN4LE/60x60" alt=""> {# <img class="rounded-circle" src="https://source.unsplash.com/AU4VPcFN4LE/60x60" alt="">#}
<div class="status-indicator"></div> {# <div class="status-indicator"></div>#}
</div> {# </div>#}
<div> {# <div>#}
<div class="text-truncate">I have the photos that you ordered last month, how would you like them sent to you?</div> {# <div class="text-truncate">I have the photos that you ordered last month, how would you like them sent to you?</div>#}
<div class="small text-gray-500">Jae Chun · 1d</div> {# <div class="small text-gray-500">Jae Chun · 1d</div>#}
</div> {# </div>#}
</a> {# </a>#}
<a class="dropdown-item d-flex align-items-center" href="#"> {# <a class="dropdown-item d-flex align-items-center" href="#">#}
<div class="dropdown-list-image mr-3"> {# <div class="dropdown-list-image mr-3">#}
<img class="rounded-circle" src="https://source.unsplash.com/CS2uCrpNzJY/60x60" alt=""> {# <img class="rounded-circle" src="https://source.unsplash.com/CS2uCrpNzJY/60x60" alt="">#}
<div class="status-indicator bg-warning"></div> {# <div class="status-indicator bg-warning"></div>#}
</div> {# </div>#}
<div> {# <div>#}
<div class="text-truncate">Last month's report looks great, I am very happy with the progress so far, keep up the good work!</div> {# <div class="text-truncate">Last month's report looks great, I am very happy with the progress so far, keep up the good work!</div>#}
<div class="small text-gray-500">Morgan Alvarez · 2d</div> {# <div class="small text-gray-500">Morgan Alvarez · 2d</div>#}
</div> {# </div>#}
</a> {# </a>#}
<a class="dropdown-item d-flex align-items-center" href="#"> {# <a class="dropdown-item d-flex align-items-center" href="#">#}
<div class="dropdown-list-image mr-3"> {# <div class="dropdown-list-image mr-3">#}
<img class="rounded-circle" src="https://source.unsplash.com/Mv9hjnEUHR4/60x60" alt=""> {# <img class="rounded-circle" src="https://source.unsplash.com/Mv9hjnEUHR4/60x60" alt="">#}
<div class="status-indicator bg-success"></div> {# <div class="status-indicator bg-success"></div>#}
</div> {# </div>#}
<div> {# <div>#}
<div class="text-truncate">Am I a good boy? The reason I ask is because someone told me that people say this to all dogs, even if they aren't good...</div> {# <div class="text-truncate">Am I a good boy? The reason I ask is because someone told me that people say this to all dogs, even if they aren't good...</div>#}
<div class="small text-gray-500">Chicken the Dog · 2w</div> {# <div class="small text-gray-500">Chicken the Dog · 2w</div>#}
</div> {# </div>#}
</a> {# </a>#}
<a class="dropdown-item text-center small text-gray-500" href="#">Read More Messages</a> {# <a class="dropdown-item text-center small text-gray-500" href="#">Read More Messages</a>#}
</div> {# </div>#}
</li> {# </li>#}
<div class="topbar-divider d-none d-sm-block"></div> <div class="topbar-divider d-none d-sm-block"></div>
......
...@@ -24,207 +24,284 @@ ...@@ -24,207 +24,284 @@
<script type="text/javascript"> <script type="text/javascript">
var global_subject = '';
var global_lecturer = '';
var global_lecture_video_id = '';
var global_video_name = '';
var global_lecturer_subject_index = 0;
var global_lecture_date = '';
var class1 = 'col-4 smpl-step-step complete';
var class2 = 'col-4 smpl-step-step active';
var class3 = 'col-4 smpl-step-step disabled';
//jquery //jquery
$(document).ready(function () { $(document).ready(function () {
let folder = ''; let folder = '';
//select a particular subject
//select a particular subject //select a particular subject
$('input[type=radio]').click(function () { $('input[type=radio]').click(function () {
let subject_id = $(this).attr('id'); let subject_id = $(this).attr('id');
global_subject = subject_id;
let lecturer = $(this).attr('data-lecturer');
global_lecturer = lecturer;
let subject_name = $(this).attr('data-name'); let subject_name = $(this).attr('data-name');
$('#timetable').attr('hidden', false); {#$('#timetable').attr('hidden', true);#}
$('#no_subject_selected').attr('hidden', true); $('#no_timetable_content').attr('hidden', true);
$('.student-detection-rows').remove();
$('#timetable_caption').text('subject: ' +subject_name);
$('#timetable_body').children().map(function () {
$(this).remove();
}); });
//view the video details
$('.modal-expand').click(function () {
let clicked_id = $(this).attr('id');
folder = clicked_id;
$('input[type=hidden]').each(function () { $('#no_subject_selected').attr('hidden', true);
let hidden_id = $(this).attr('id');
if (clicked_id === hidden_id) { $('#timetable_caption').text('subject: ' + subject_name);
let duration = $(this).attr('data-duration'); $('#loader').attr('hidden', false);
$('#video_name').text(clicked_id);
$('#video_duration').text(duration); //fetching the timetable from the db
$('#video_date').text(new Date().toDateString()); fetch('http://127.0.0.1:8000/timetables')
.then((res) => res.json())
.then((out) => createTimeTable(out, subject_id, lecturer))
.catch((error) => alert('this is the error: ' + error))
}
}); });
//after data assigning, load the modal //this function will display the timetable for the lecturer
$('#video_modal').modal(); function createTimeTable(timetable, subject, lecturer) {
}); $('#loader').attr('hidden', true);
$('#timetable').attr('hidden', false);
let isTimetableSubject = false;
//retrieve the lecture details timetable.map((item, i) => {
$('.retrieve').click(function () { item.timetable.map((table, index) => {
let lecture = $(this).attr('data-id');
//removing the previous frames let lecturer_subject_index_arr = [];
$('#main_frames').remove();
$('#error_message').attr('hidden', true);
$('#nav_bar').attr('hidden', true);
$('#tabContentDetails').attr('hidden', true);
//disabling all the 'retrive' buttons //to get the number of subjects taught by the lecturer in a day
$('.retrieve').each(function () { table.time_slots.forEach((slot1, ind) => {
$(this).attr('disabled', 'disabled'); let isLecturer = slot1.lecturer.id === Number(lecturer);
if (isLecturer) {
lecturer_subject_index_arr.push(ind);
}
}); });
//iterating each slot (for a given day)
let url = 'http://127.0.0.1:8000/videoExtract/?folder_name=' + lecture; table.time_slots.forEach((slot, in1) => {
//retrieve frames let isLecturer = slot.lecturer.id === Number(lecturer);
fetch(url) let isLecSubject = slot.subject.subject_code === subject;
let message = '';
if (isLecturer && isLecSubject) {
let html = '';
let isProcessPerformed = false;
global_lecturer_subject_index = lecturer_subject_index_arr.findIndex((inner) => inner === in1);
isTimetableSubject = true;
{#check for the lecture video status#}
let date = table.date;
//assign the date
global_lecture_date = date;
fetch('http://127.0.0.1:8000/get-lecture-video/?lecturer=' + global_lecturer + '&date=' + date + '&index=' + global_lecturer_subject_index)
.then((res) => res.json()) .then((res) => res.json())
.then((out) => { .then((out) => {
//create the frames isProcessPerformed = out.response.isActivityFound;
let frameHTML = createFrames(out.response, lecture); alert('response: ' + out.response.isActivityFound);
return frameHTML;
})
.then((obj) => {
//after loading the frames, display the rest of the images
$('#loader').attr('hidden', false);
setTimeout(() => {
$('#nav_bar').attr('hidden', false);
$('#tabContentDetails').attr('hidden', false);
$('#loader').attr('hidden', true);
//enabling the 'retrive' buttons if (isProcessPerformed) {
$('.retrieve').each(function () { message = '<td><span class="font-italic font-weight-bold text-primary" id="message">Already processed</span></td>';
$(this).removeAttr('disabled'); } else {
message = '<td><button type="button" class="btn btn-success">Process</button></td>';
}
}); html += "<tr class='lecture-details'><td class='slot_date'>" + table.date + "</td>"
}, 65000); + "<td>" + slot.location + "</td>"
{#$('#nav_bar').attr('hidden', false);#} + "<td>" + slot.start_time + "</td>"
{#$('#tabContentDetails').attr('hidden', false);#} + "<td>" + slot.end_time + "</td>"
//load the frames + message
$('#emotion_frames').prepend(obj); + "</tr>";
$('#timetable_body').append(html);
}) })
.catch((error) => { .catch((error) => alert('an error occurred: ' + error));
$('#error_message').attr('hidden', false);
//enabling the 'retrieve' buttons
$('.retrieve').each(function () {
$(this).removeAttr('disabled');
}
}); });
}); });
//setting some values if (!isTimetableSubject) {
$('#no_content_message').attr('hidden', true); $('#timetable').attr('hidden', true);
$('#no_timetable_content').attr('hidden', false);
}
}); });
}
//this function will retrieve the lecture video for a given lecture
$(document).on('click', '.btn-info', function (e) {
let clicked_class = e.target.className;
let object = e;
let real_class = clicked_class.split(' ')[1];
real_class = '.' + real_class;
let date = e.target.parentNode.parentNode.firstChild.innerHTML;
//assign the date
global_lecture_date = date;
fetch('http://127.0.0.1:8000/get-lecture-video/?lecturer=' + global_lecturer + '&date=' + date + '&index=' + global_lecturer_subject_index)
.then((res) => res.json())
.then((out) => displayLectureVideoDetails(out, object))
.catch((error) => alert('an error occurred: ' + error));
});
//function to display lecture video details
function displayLectureVideoDetails(lectureVideo, e) {
//get the lecture video response
let video = lectureVideo.response;
$('#video_name').text(video.video_name);
$('#video_duration').text(video.video_length);
$('#video_date').text(video.date);
global_lecture_video_id = video.lecture_video_id;
global_video_name = video.video_name;
//creating the frame content
function createFrames(response, folder) {
let main_frame_content = "<div class='row' id='main_frames'>";
main_frame_content += "<ul class='list-group list-group-horizontal'>";
let count = 0;
//loop through the frames
response.map((image) => {
let img_src = "";
if (count === 0) { if (lectureVideo.isActivityFound) {
main_frame_content += "<li class='list-group-item text-center' id='image_0'>"; {#e.target.parentNode.parentNode.lastChild.innerHTML = '<span class="font-italic font-weight-bold text-primary" id="message">Already processed</span>';#}
img_src = "<img src='{% static '' %}FirstApp/extracted/" + folder + "/" + response[0].image + "' width='500' height='500'>"; alert('I was found');
} else {
{#e.target.parentNode.parentNode.lastChild.innerHTML = '<button type="button" class="btn btn-success">Process</button>';#}
alert('I am not here');
} }
else {
main_frame_content += "<li class='list-group-item other-frames' id='image_" +count+ "' hidden>";
img_src = "<img src='{% static '' %}FirstApp/extracted/" + folder + "/" + image.image + "' width='500' height='500'>";
} }
main_frame_content += img_src; // this function simulate the process workflow
main_frame_content += "</li>"; $('#simulate_process').click(function () {
count++;
});
main_frame_content += "</ul>";
main_frame_content += "</div>";
let classname = $('#step_1').attr('class');
//setting the min, max values of the slider setTimeout(() => {
$('#myRange').attr({'min': 0, 'max': count}); $('#step_1').attr('class', class1)
}, 2000);
return main_frame_content; setTimeout(() => {
} $('#step_2').attr('class', class1)
}, 4000);
setTimeout(() => {
$('#step_3').attr('class', class1)
}, 6000);
setTimeout(() => {
$('#step_4').attr('class', class1)
}, 8000);
});
//this function will handle the batch process button
$('.batch_process').click(function () {
let video_id = $(this).attr("data-video-id");
let video_name = $(this).attr("data-video-name");
//declaring the variable for setInterval function //display the activity loader
let timeVar = null; $('#activity_loader').attr("hidden", false);
//handling the play button global_lecture_video_id = video_id;
$('#play_pause_icon').click(function () { global_video_name = video_name;
//defining the two possible classes
let play_class = "fas fa-play";
let pause_class = "fas fa-pause";
//retrieving the current icon class
let current_class = $(this).attr('class');
//assigning the correct class based on the icon clicked
let new_class = (current_class === play_class) ? pause_class : play_class;
//setting the new class //perform activity recognition
$(this).attr('class', new_class); fetch('http://127.0.0.1:8000/process-lecture-activity/?lecture_video_name=' + global_video_name + '&lecture_video_id=' + global_lecture_video_id)
.then((res) => res.json())
.then((out) => handleActivityResponse(out.response))
.catch((error) => alert('error: ' + error));
//handling the slider });
let slider = document.getElementById("myRange");
let output = document.getElementById("demo");
//when the button is playing
if (current_class === play_class) {
timeVar = setInterval(() => {
let value = slider.value;
let new_slider_value = Number(value) + 1;
slider.value = new_slider_value;
output.innerHTML = new_slider_value.toString();
//this is to detect the response gained from activity recognition porcess
function handleActivityResponse(response, e) {
//change the button, if the response is positive
if (response) {
//display the activity process as completed
$('#step_1').attr('class', class1);
let selectedImage = '#image_' + Number(value); //hide the activity loader
$('#activity_loader').hide();
//displaying the relevant image //display the emotion loader
$('#image_0').html($(selectedImage).html()); $('#emotion_loader').attr('hidden', false);
}, 10); //sending the request to process the lecture emotions
fetch('http://127.0.0.1:8000/process-lecture-emotion/?lecture_video_name=' + global_video_name + '&lecture_video_id=' + global_lecture_video_id)
.then((res) => res.json())
.then((out) => handleEmotionResponse(out.response))
.catch((error) => alert('error: ' + error));
} }
//when the button is paused
else if (current_class === pause_class) {
clearInterval(timeVar);
} }
}); //this is to detect the response gained from emotion recognition process
function handleEmotionResponse(response) {
//change the button, if the response is positive
if (response) {
//display the activity process as completed
$('#step_2').attr('class', class1);
//hide the emotion loader
$('#emotion_loader').hide();
//handling the slider //display the gaze loader
let slider = document.getElementById("myRange"); $('#gaze_loader').attr('hidden', false);
let output = document.getElementById("demo");
output.innerHTML = slider.value;
slider.oninput = function () { //sending the get request to process the lecture gaze estimations
output.innerHTML = this.value; fetch('http://127.0.0.1:8000/process-lecture-gaze-estimation/?lecture_video_name=' + global_video_name + '&lecture_video_id=' + global_lecture_video_id)
let selectedImage = '#image_' + Number(this.value); .then((res) => res.json())
.then((out) => handleGazeResponse(out.response, e))
.catch((error) => alert('error: ' + error));
}
}
//hide
{#$('#image_0').attr('hidden', true);#}
$('#image_0').html($(selectedImage).html());
//setting the selected image //this is to detect the response gained from emotion recognition process
{#$(selectedImage).attr('hidden', false);#} function handleGazeResponse(response) {
//change the button, if the response is positive
if (response) {
//display the activity process as completed
$('#step_3').attr('class', class1);
//hide the activity loader
$('#gaze_loader').hide();
alert('good');
} }
}
}); });
</script> </script>
...@@ -248,488 +325,158 @@ ...@@ -248,488 +325,158 @@
<!-- Page Heading --> <!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between mb-4"> <div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800">Video Results</h1> <h1 class="h3 mb-0 text-gray-800">Lecture Video Results</h1>
</div> </div>
<!--first row --> <!--first row -->
<div class="row p-2"> <div class="row p-2">
<!--first column -->
<div class="col-lg-6"> <!--second column (timetable column) -->
<div class="col-lg-8" style="overflow-x: scroll">
<div class="card shadow mb-4"> <div class="card shadow mb-4">
<!--card header --> <!--card header -->
<div class="card-header py-3"> <div class="card-header py-3">
<h5 class="m-0 font-weight-bold text-primary">Lecturer Subjects</h5> <h5 class="m-0 font-weight-bold text-primary">Waiting List</h5>
</div> </div>
<!--card body --> <!--card body -->
<div class="card-body"> <div class="card-body">
{% if lecturer_subjects.count == 0 %}
<div class="text-center">
<span class="font-italic">No subjects</span>
</div>
{% else %}
<div class="table-responsive">
<table class="table table-bordered" id="datatable">
<thead>
<tr>
<th></th>
<th>Subject Name</th>
<th>Year</th>
</tr>
</thead>
<tbody>
{% for subject in subjects %}
<tr class="subjects not_clicked" id="{{ subject.0.subject_code }}">
<td>
<div class="radio">
<label><input type="radio" id="{{ subject.0.subject_code }}" name="subject_radio" data-name="{{ subject.0.name }}"></label>
</div>
</td>
<td>{{ subject.0.name}}</td>
<td>{{ subject.0.year }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %} <!--loading gif -->
</div> {% if due_lectures.count == 0 %}
</div> <div class="text-center" id="no_subject_selected">
<span class="font-italic">No lecture is to be processed</span>
</div> </div>
<!--end of first column --> {% endif %}
<!--no lecture selected message -->
<div class="text-center" id="loader" hidden>
<!--second column (timetable column) --> <img src="{% static 'FirstApp/images/ajax-loader.gif' %}" alt="Loader">
<div class="col-lg-6">
<div class="card shadow mb-4">
<!--card header -->
<div class="card-header py-3">
<h5 class="m-0 font-weight-bold text-primary">View timetable</h5>
</div> </div>
<!--card body -->
<div class="card-body">
<!--no lecture selected message --> <!--no lecture selected message -->
<div class="text-center" id="no_subject_selected"> <div class="text-center" id="no_timetable_content" hidden>
<span class="font-italic">No lecture is selected</span> <span class="font-italic">Not included in the timetable</span>
</div> </div>
<!--displaying the timetable --> <!--displaying the timetable -->
<table class="table table-striped" id="timetable" hidden> <table class="table table-striped" id="timetable">
<caption id="timetable_caption"></caption> {# <caption id="timetable_caption"></caption>#}
<thead> <thead>
<tr> <tr>
<th>Date</th> <th>Date</th>
<th>Hall No.</th> <th>Subject</th>
<th>Time</th> <th>start time</th>
</tr> <th>end time</th>
</thead>
</table>
</div>
</div>
</div>
<!--end of first column -->
</div>
<div class="row p-2">
<!--first column-->
<div class="col-lg-6">
<!-- card content -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h5 class="m-0 font-weight-bold text-primary">List of Lecture Videos</h5>
</div>
<div class="card-body">
<table class="table table-bordered">
<thead>
<tr>
<th>Video Name</th>
<th>Length</th>
<th></th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody id="timetable_body">
{% for video in Videos %} {% for lecture in due_lectures %}
<tr class="video_row" id="{{ video.name }}" data-duration="{{ video.duration }}"> <tr>
<td> <td class="font-weight-bolder">{{ lecture.date }}</td>
{{ video.name }} {# <td>{{ lecture.subject }}</td>#}
</td> <td class="font-weight-bolder">{{ lecture.subject_name }}</td>
<td>{{ video.duration }}</td> <td class="font-weight-bolder">{{ lecture.start_time }}</td>
<td> <td class="font-weight-bolder">{{ lecture.end_time }}</td>
<button class="btn btn-link modal-expand" id="{{ video.name }}">View</button>
</td>
<td> <td>
<button class="btn btn-info retrieve" data-id="{{ video.name }}">Retrieve</button> <button type="button" class="btn btn-success batch_process" data-video-id="{{ lecture.video_id }}" data-video-name="{{ lecture.video_name }}" id="{{ lecture.subject }}">Process</button>
</td> {# <span class="font-italic font-weight-bolder text-success">Processing</span>#}
<!--<td>
<select name="category" id="select_{{ video.name }}" class="form-control select_cat">
<option value="">-------</option>
<option value="Emotion">Emotion</option>
<option value="Gaze">Gaze</option>
<option value="Activity">Activity</option>
</select>
</td>-->
<!-- to store the video details -->
<td hidden>
<input type="hidden" id="{{ video.name }}" data-duration="{{ video.duration }}">
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div>
</div>
</div>
<!--second column-->
<div class="col-lg-6">
<!-- card content -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h5 class="m-0 font-weight-bold text-primary">Emotion Detection</h5>
</div>
<div class="card-body">
<!-- no video selected messge -->
<div class="text-center" id="no_content_message">
<p>No content to be displayed</p>
</div>
<!-- error messge -->
<div class="text-center text-danger" id="error_message" hidden>
<p class="font-italic">No frames were found for this video</p>
</div>
<!-- loader -->
<div class="text-center" id="loader" hidden>
<img src="{% static 'FirstApp/images/ajax-loader.gif' %}" alt="Loading image">
</div>
<!--nav tabs-->
<ul class="nav nav-tabs nav-fill" id="nav_bar" role="tablist" hidden>
<li class="nav-item">
<a class="nav-link active" id="frame-tab" data-toggle="tab" href="#frame" role="tab" aria-controls="frame" aria-selected="true">Frame</a>
</li>
<li class="nav-item">
<a class="nav-link" id="graph-tab" data-toggle="tab" href="#graph" role="tab" aria-controls="graph" aria-selected="false">Graphs</a>
</li>
</ul>
<!--tab content -->
<div class="tab-content" id="tabContentDetails" hidden>
<div class="tab-pane fade show active" id="frame" role="tabpanel" aria-labelledby="home-tab">
<div class="text-center p-4" id="emotion_frames">
<!-- slide container -->
<div class="slidecontainer">
<div class="row">
<div class="col-1">0</div>
<div class="col-9"></div>
<div class="col-2">100</div>
</div>
<!-- play/pause icon -->
<div class="row">
<span><i class="fas fa-play" id="play_pause_icon"></i></span>
</div>
<input type="range" min="1" max="100" value="0" class="slider" id="myRange">
<p>No of frames: <span id="demo"></span></p>
</div>
</div>
</div>
<!-- graph content -->
<div class="tab-pane fade" id="graph" role="tabpanel" aria-labelledby="profile-tab">
<!--card content -->
<div class="card shadow mb-4 p-3">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Revenue Sources</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button"
id="dropdownMenuLink" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
</a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"
aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Dropdown Header:</div>
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="chart-pie pt-4 pb-2">
<canvas id="myPieChart"></canvas>
</div>
<div class="mt-4 text-center small">
<span class="mr-2">
<i class="fas fa-circle text-primary"></i> Direct
</span>
<span class="mr-2">
<i class="fas fa-circle text-success"></i> Social
</span>
<span class="mr-2">
<i class="fas fa-circle text-info"></i> Referral
</span>
</div>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
<!--end of first column -->
</div> </div>
<!-- end of 2nd row -->
<!--3rd row --> <!-- progress row -->
<div class="row p-2"> <div class="row p-2" id="progress_row">
<!--1st column --> <!--first column-->
<!--second column--> <div class="col-lg-12">
<div class="col-lg-6">
<!-- card content --> <!-- card content -->
<div class="card shadow mb-4"> <div class="card shadow mb-4">
<div class="card-header py-3">
<h5 class="m-0 font-weight-bold text-primary">Gaze Estimation</h5>
</div>
<div class="card-body">
<!-- no video selected messge -->
<div class="text-center" id="no_content_message_gaze">
<p>No Gaze estimation content to be displayed</p>
</div>
<!-- error message -->
<div class="text-center text-danger" id="error_message_gaze" hidden>
<p class="font-italic">No frames were found for this video</p>
</div>
<!-- loader -->
<div class="text-center" id="loader_gaze" hidden>
<img src="{% static 'FirstApp/images/ajax-loader.gif' %}" alt="Loading image">
</div>
<!--nav tabs-->
<ul class="nav nav-tabs nav-fill" id="nav_bar_gaze" role="tablist" hidden>
<li class="nav-item">
<a class="nav-link active" id="frame-tab_gaze" data-toggle="tab" href="#frame_gaze"
role="tab" aria-controls="frame_gaze" aria-selected="true">Frame</a>
</li>
<li class="nav-item">
<a class="nav-link" id="graph-tab_gaze" data-toggle="tab" href="#graph_gaze"
role="tab" aria-controls="graph_gaze" aria-selected="false">Graphs</a>
</li>
</ul>
<!--tab content -->
<div class="tab-content" id="tabContentDetails_gaze" hidden>
<div class="tab-pane fade show active" id="frame_gaze" role="tabpanel"
aria-labelledby="frame-tab_gaze">
<div class="text-center p-4" id="gaze_frames">
<!-- slide container -->
<div class="slidecontainer_gaze">
<div class="row">
<div class="col-1">0</div>
<div class="col-9"></div>
<div class="col-2">100</div>
</div>
<!-- play/pause icon -->
<div class="row">
<span><i class="fas fa-play" id="play_pause_icon_gaze"></i></span>
</div>
<input type="range" min="1" max="100" value="0" class="slider"
id="myRange_gaze">
<p>No of frames: <span id="demo_gaze"></span></p>
</div>
</div>
</div>
<!-- graph content -->
<div class="tab-pane fade" id="graph_gaze" role="tabpanel"
aria-labelledby="graph-tab_gaze">
<!--card content -->
<div class="card shadow mb-4 p-3">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Gaze distribution</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button"
id="dropdownMenuLink" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
</a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"
aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Graph options:</div>
<a class="dropdown-item" href="#">Pie</a>
<a class="dropdown-item" href="#">Bar</a>
<div class="dropdown-divider">Column</div>
<a class="dropdown-item" href="#">Line</a>
</div>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="chart-pie pt-4 pb-2">
<canvas id="myPieChart_gaze"></canvas>
</div>
<div class="mt-4 text-center small">
<span class="mr-2">
<i class="fas fa-circle text-primary"></i> Direct
</span>
<span class="mr-2">
<i class="fas fa-circle text-success"></i> Social
</span>
<span class="mr-2">
<i class="fas fa-circle text-info"></i> Referral
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div> <div class="card-header py-3 text-center">
<!-- end of gaze column --> <h5 class="m-0 font-weight-bold text-primary">Process Workflow</h5>
<!-- student activity column -->
<div class="col-lg-6">
<!-- card content -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h5 class="m-0 font-weight-bold text-primary">Student Activity Recognition</h5>
</div> </div>
<div class="card-body"> <div class="card-body">
<!-- no video selected messge --> <div class="container">
<div class="text-center" id="no_content_message_activity"> <div class="row smpl-step" style="border-bottom: 0; min-width: 500px;">
<p>No Activity Recognition content to be displayed</p>
</div> <!-- step 1 -->
<div class="col-4 smpl-step-step disabled" id="step_1">
<!-- error messge --> <div class="text-center smpl-step-num font-weight-bolder">Step 1</div>
<div class="text-center text-danger" id="error_message_activity" hidden> <div class="progress">
<p class="font-italic">No frames were found for this video</p> <div class="progress-bar"></div>
</div> </div>
<a class="smpl-step-icon text-center"><i class="fa fa-chart-line"
<!-- loader --> style="font-size: 40px; padding-top: 10px; color: white"></i></a>
<div class="text-center" id="loader_activity" hidden> <div class="smpl-step-info text-center">
<img src="{% static 'FirstApp/images/ajax-loader.gif' %}" alt="Loading image"> <span class="font-italic font-weight-bolder">Perform Activity Recognition</span>
</div> <br />
<img src="{% static 'FirstApp/images/ajax-loader.gif' %}" alt="Loader" class="mt-2" id="activity_loader" hidden>
</div>
<!--nav tabs--> </div>
<ul class="nav nav-tabs nav-fill" id="nav_bar_activity" role="tablist" hidden> <!-- end of step 1 -->
<li class="nav-item">
<a class="nav-link active" id="frame-tab_activity" data-toggle="tab" href="#frame_activity" role="tab" aria-controls="frame_activity" aria-selected="true">Frame</a> <!-- step 2 -->
</li> <div class="col-4 smpl-step-step disabled" id="step_2">
<li class="nav-item"> <div class="text-center smpl-step-num font-weight-bolder">Step 3</div>
<a class="nav-link" id="graph-tab_activity" data-toggle="tab" href="#graph_activity" role="tab" aria-controls="graph_activity" aria-selected="false">Graphs</a> <div class="progress">
</li> <div class="progress-bar"></div>
</ul> </div>
<a class="smpl-step-icon text-center"><i class="fa fa-user"
<!--tab content --> style="font-size: 50px; padding-top: 10px; color: white"></i></a>
<div class="tab-content" id="tabContentDetails_activity" hidden> <div class="smpl-step-info text-center">
<div class="tab-pane fade show active" id="frame_activity" role="tabpanel" aria-labelledby="frame-tab_activity"> <span class="font-italic font-weight-bolder">Study Student Emotions</span>
<div class="text-center p-4" id="activity_frames"> <br />
<!-- slide container --> <img src="{% static 'FirstApp/images/ajax-loader.gif' %}" alt="Loader" class="mt-2" id="emotion_loader" hidden>
<div class="slidecontainer_activity"> </div>
<div class="row"> </div>
<div class="col-1">0</div> <!-- end of step 2 -->
<div class="col-9"></div>
<div class="col-2">100</div> <!-- step 3 -->
</div> <div class="col-4 smpl-step-step disabled" id="step_3">
<!-- play/pause icon --> <div class="text-center smpl-step-num font-weight-bolder">Step 3</div>
<div class="row"> <div class="progress">
<span><i class="fas fa-play" id="play_pause_icon_activity"></i></span> <div class="progress-bar"></div>
</div> </div>
<input type="range" min="1" max="100" value="0" class="slider" id="myRange_activity"> <a class="smpl-step-icon">
<p>No of frames: <span id="demo_activity"></span></p> <i class="fa fa-eye"
</div> style="font-size: 60px; padding-left: 7px; padding-top: 5px; color: white;"></i>
</div>
</div>
<!-- graph content -->
<div class="tab-pane fade" id="graph_activity" role="tabpanel" aria-labelledby="graph-tab_gaze">
<!--card content -->
<div class="card shadow mb-4 p-3">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Activity Distribution</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button"
id="dropdownMenuLink" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
</a> </a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in" <div class="smpl-step-info text-center">
aria-labelledby="dropdownMenuLink"> <span class="font-italic font-weight-bolder">See students' Gazes</span>
<div class="dropdown-header">Graph options:</div> <br />
<a class="dropdown-item" href="#">Pie</a> <img src="{% static 'FirstApp/images/ajax-loader.gif' %}" alt="Loader" class="mt-2" id="gaze_loader" hidden>
<a class="dropdown-item" href="#">Bar</a>
<div class="dropdown-divider">Column</div>
<a class="dropdown-item" href="#">Line</a>
</div>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="chart-pie pt-4 pb-2">
<canvas id="myPieChart"></canvas>
</div>
<div class="mt-4 text-center small">
<span class="mr-2">
<i class="fas fa-circle text-primary"></i> Direct
</span>
<span class="mr-2">
<i class="fas fa-circle text-success"></i> Social
</span>
<span class="mr-2">
<i class="fas fa-circle text-info"></i> Referral
</span>
</div>
</div> </div>
</div> </div>
<!-- end of step 3 -->
</div> </div>
{# <!-- simulation button row -->#}
{# <div class="row">#}
{# <button type="button" class="btn btn-outline-danger" id="simulate_process">Simulate</button>#}
{# </div>#}
</div> </div>
<!-- end of container -->
</div> </div>
</div> </div>
</div> </div>
<!--end of student activity column --> <!-- end of 1st column -->
</div> </div>
<!--end of 3rd row --> <!-- end of progress row -->
</div> </div>
{% endblock %} {% endblock %}
......
...@@ -41,6 +41,9 @@ urlpatterns = [ ...@@ -41,6 +41,9 @@ urlpatterns = [
# tables view # tables view
path('tables', views.tables), path('tables', views.tables),
# test view (delete later)
path('test', views.test),
url(r'^register', views.RegisterViewSet), url(r'^register', views.RegisterViewSet),
# re_path('video/?video_name<str:video_name>', views.video), # re_path('video/?video_name<str:video_name>', views.video),
url(r'^teachers/', views.teachersList.as_view()), url(r'^teachers/', views.teachersList.as_view()),
...@@ -75,7 +78,6 @@ urlpatterns = [ ...@@ -75,7 +78,6 @@ urlpatterns = [
# timetable API # timetable API
url(r'^timetable', api.FacultyTimetableViewSet.as_view()), url(r'^timetable', api.FacultyTimetableViewSet.as_view()),
##### VIDEO Section ##### ##### VIDEO Section #####
# lecture video API # lecture video API
...@@ -84,7 +86,6 @@ urlpatterns = [ ...@@ -84,7 +86,6 @@ urlpatterns = [
# lecture video API (to retrieve a lecture) # lecture video API (to retrieve a lecture)
url(r'^get-lecture-video/$', api.GetLectureVideoViewSet.as_view()), url(r'^get-lecture-video/$', api.GetLectureVideoViewSet.as_view()),
##### ACTIVITIES API ##### ##### ACTIVITIES API #####
# lecture activity API (to retrieve lecture activities) # lecture activity API (to retrieve lecture activities)
...@@ -112,6 +113,9 @@ urlpatterns = [ ...@@ -112,6 +113,9 @@ urlpatterns = [
url(r'^get-lecture-activity-individual-student-evaluation/$', url(r'^get-lecture-activity-individual-student-evaluation/$',
api.GetLectureActivityIndividualStudentEvaluation.as_view()), api.GetLectureActivityIndividualStudentEvaluation.as_view()),
# lecture activity report generation
url(r'^lecture-activity-report-generation/$',
api.GenerateActivityReport.as_view()),
###### EMOTION Section ##### ###### EMOTION Section #####
# getting lecture emotion record availability # getting lecture emotion record availability
...@@ -133,7 +137,6 @@ urlpatterns = [ ...@@ -133,7 +137,6 @@ urlpatterns = [
# lecture emotion detection for frames API (to retrieve detections for each frame in lecture video) # lecture emotion detection for frames API (to retrieve detections for each frame in lecture video)
url(r'^get-lecture-emotion-for-frame/$', api.GetLectureEmotionRecognitionsForFrames.as_view()), url(r'^get-lecture-emotion-for-frame/$', api.GetLectureEmotionRecognitionsForFrames.as_view()),
###### POSE Section ##### ###### POSE Section #####
# lecture video API (for Pose estimation) # lecture video API (for Pose estimation)
url(r'^get-lecture-video-for-pose/$', api.GetLectureVideoForPose.as_view()), url(r'^get-lecture-video-for-pose/$', api.GetLectureVideoForPose.as_view()),
...@@ -147,6 +150,27 @@ urlpatterns = [ ...@@ -147,6 +150,27 @@ urlpatterns = [
# lecture video individual student process pose estimation API (for Pose estimation) # lecture video individual student process pose estimation API (for Pose estimation)
url(r'^process-lecture-video-individual-pose-estimation', api.ProcessIndividualStudentPoseEstimation.as_view()), url(r'^process-lecture-video-individual-pose-estimation', api.ProcessIndividualStudentPoseEstimation.as_view()),
##### GAZE Section #####
# lecture video Gaze estimation
url(r'^get-lecture-video-gaze-estimation-availability/$', api.GetLectureGazeEstimationAvailaibility.as_view()),
# process a lecture Gaze estimation
url(r'^process-lecture-gaze-estimation/$', api.ProcessLectureGazeEstimation.as_view()),
# retrieve a Lecture Gaze estimation
url(r'^get-lecture-gaze-estimation/$', api.GetLectureGazeEstimationViewSet.as_view()),
# lecture gaze estimation for frames API (to retrieve detections for each frame in lecture video)
url(r'^get-lecture-gaze-estimation-for-frame/$', api.GetLectureGazeEstimationForFrames.as_view()),
##### VIEW STUDENT BEHAVIOR SUMMARY SECTION #####
# retrieves student behavior summary for specified time period
url(r'^get-student-behavior-summary-for-period/$', api.GetStudentBehaviorSummaryForPeriod.as_view()),
# routers # routers
# path('', include(router.urls)), # path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')) path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
......
...@@ -20,7 +20,7 @@ from . logic import video_extraction ...@@ -20,7 +20,7 @@ from . logic import video_extraction
from . forms import * from . forms import *
import cv2 import cv2
import os import os
import datetime from datetime import datetime
# hashing # hashing
...@@ -113,27 +113,85 @@ class LectureViewSet(APIView): ...@@ -113,27 +113,85 @@ class LectureViewSet(APIView):
def hello(request): def hello(request):
username = request.user.username username = request.user.username
# retrieve the lecturer
lecturer = request.session['lecturer']
# retrieve the lecturer's timetable slots
lecturer_timetable = FacultyTimetable.objects.filter()
# serialize the timetable
lecturer_timetable_serialized = FacultyTimetableSerializer(lecturer_timetable, many=True)
lecturer_details = []
# loop through the serialized timetable
for timetable in lecturer_timetable_serialized.data:
# retrieve daily timetable
daily_timetable = timetable['timetable']
# loop through the daily timetable
for day_timetable in daily_timetable:
date = ''
lecture_index = 0
# loop through each timeslots
for slots in day_timetable:
if slots == "date":
date = day_timetable[slots]
elif slots == "time_slots":
slot = day_timetable[slots]
# loop through each slot
for lecture in slot:
# check whether the lecturer is the current lecturer
if lecturer == lecture['lecturer']['id']:
lecturer_lecture_details = {}
lecturer_lecture_details['date'] = date
lecturer_lecture_details['start_time'] = lecture['start_time']
lecturer_lecture_details['end_time'] = lecture['end_time']
lecturer_lecture_details['subject_name'] = lecture['subject']['name']
lecturer_lecture_details['index'] = lecture_index
lecturer_lecture_details['lecturer'] = lecture['lecturer']['id']
# append to the lecturer_details
lecturer_details.append(lecturer_lecture_details)
# increment the index
lecture_index += 1
# sorting the dates in lecturer_details list
# for details in lecturer_details:
lecturer_details.sort(key=lambda date: datetime.strptime(str(date['date']), "%Y-%m-%d"), reverse=True)
obj = {'Message': 'Student and Lecturer Performance Enhancement System', 'username': username} obj = {'Message': 'Student and Lecturer Performance Enhancement System', 'username': username}
folder = os.path.join(BASE_DIR, os.path.join('static\\FirstApp\\videos')) folder = os.path.join(BASE_DIR, os.path.join('static\\FirstApp\\videos'))
videoPaths = [os.path.join(folder, file) for file in os.listdir(folder)] videoPaths = [os.path.join(folder, file) for file in os.listdir(folder)]
videos = [] videos = []
durations = [] durations = []
#
for videoPath in videoPaths: # for videoPath in videoPaths:
video = Video() # video = Video()
cap = cv2.VideoCapture(videoPath) # cap = cv2.VideoCapture(videoPath)
fps = cap.get(cv2.CAP_PROP_FPS) # OpenCV2 version 2 used "CV_CAP_PROP_FPS" # fps = cap.get(cv2.CAP_PROP_FPS) # OpenCV2 version 2 used "CV_CAP_PROP_FPS"
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
duration = int(frame_count / fps) # duration = int(frame_count / fps)
durations.append(duration) # durations.append(duration)
videoName = os.path.basename(videoPath) # videoName = os.path.basename(videoPath)
# videoName = videos.append(os.path.basename(videoPath)) # # videoName = videos.append(os.path.basename(videoPath))
durationObj = datetime.timedelta(seconds=duration) # durationObj = datetime.timedelta(seconds=duration)
video.path = videoPath # video.path = videoPath
video.name = videoName # video.name = videoName
video.duration = str(durationObj) # video.duration = str(durationObj)
videos.append(video) # videos.append(video)
context = {'object': obj, 'Videos': videos, 'durations': durations, 'template_name': 'FirstApp/template.html'} context = {'object': obj, 'Videos': videos, 'durations': durations, 'template_name': 'FirstApp/template.html', 'lecturer_details': lecturer_details, "lecturer": lecturer}
return render(request, 'FirstApp/Home.html', context) return render(request, 'FirstApp/Home.html', context)
def view404(request): def view404(request):
...@@ -302,64 +360,87 @@ def child(request): ...@@ -302,64 +360,87 @@ def child(request):
# displaying video results # displaying video results
@login_required(login_url='/login') @login_required(login_url='/login')
def video_result(request): def video_result(request):
try: try:
# retrieving data from the db # retrieving data from the db
lecturer = request.session['lecturer'] lecturer = request.session['lecturer']
to_do_lecture_list = []
due_lecture_list = []
lecturer_videos = LectureVideo.objects.filter(lecturer_id=lecturer)
serializer = LectureVideoSerializer(lecturer_videos, many=True)
data = serializer.data
# iterate through the existing lecture videos for the lecturer
for video in data:
video_id = video['id']
date = video['date']
subject = video['subject']['id']
# check whether the video id exist in the Activity Recognition table
lec_activity = LectureActivity.objects.filter(lecture_video_id_id=video_id).exists()
if lec_activity == False:
to_do_lecture_list.append({
"lecturer": lecturer,
"date": date,
"subject": subject,
"video_id": video['id'],
"video_name": video['video_name']
})
# once the lectures that needs to be processed are found out, extract the corresponding timetable details
# retrieve the lecturer's timetable slots
lecturer_timetable = FacultyTimetable.objects.filter()
# serialize the timetable
lecturer_timetable_serialized = FacultyTimetableSerializer(lecturer_timetable, many=True)
# loop through the serialized timetable
for timetable in lecturer_timetable_serialized.data:
# retrieve daily timetable
daily_timetable = timetable['timetable']
# loop through the daily timetable
for day_timetable in daily_timetable:
# print('day timetable" ', day_timetable)
# loop through the to-do lecture list
for item in to_do_lecture_list:
isDate = item['date'] == str(day_timetable['date'])
# isLecturer = item['lecturer'] ==
# check for the particular lecture on the day
if isDate:
slots = day_timetable['time_slots']
# loop through the slots
for slot in slots:
# check for the lecturer and subject
isLecturer = item['lecturer'] == slot['lecturer']['id']
isSubject = item['subject'] == slot['subject']['id']
if isLecturer & isSubject:
obj = {}
obj['date'] = item['date']
obj['subject'] = slot['subject']['subject_code']
obj['subject_name'] = slot['subject']['name']
obj['start_time'] = slot['start_time']
obj['end_time'] = slot['end_time']
obj['video_id'] = item['video_id']
obj['video_name'] = item['video_name']
# append to the list
due_lecture_list.append(obj)
lecturer_subjects = LecturerSubject.objects.filter(lecturer_id_id=lecturer)
lec_sub_serilizer = LecturerSubjectSerializer(lecturer_subjects, many=True)
subject_list = []
subjects = lec_sub_serilizer.data[0]['subjects']
for sub in subjects:
subject = Subject.objects.filter(id=sub)
subject_serialized = SubjectSerializer(subject, many=True)
subject_list.append(subject_serialized.data)
folder = os.path.join(BASE_DIR, os.path.join('static\\FirstApp\\videos'))
videoPaths = [os.path.join(folder, file) for file in os.listdir(folder)]
videos = []
durations = []
# setting up the first video details except Exception as exc:
first_video_path = videoPaths[0] print('what is wrong?: ', exc)
first_video = Video()
cap = cv2.VideoCapture(first_video_path)
fps = cap.get(cv2.CAP_PROP_FPS) # OpenCV2 version 2 used "CV_CAP_PROP_FPS"
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
duration = int(frame_count / fps)
videoName = os.path.basename(first_video_path)
durationObj = datetime.timedelta(seconds=duration)
first_video.path = first_video_path
first_video.name = videoName
first_video.duration = str(durationObj)
for videoPath in videoPaths:
video = Video()
cap = cv2.VideoCapture(videoPath)
fps = cap.get(cv2.CAP_PROP_FPS) # OpenCV2 version 2 used "CV_CAP_PROP_FPS"
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
duration = int(frame_count / fps)
durations.append(duration)
videoName = os.path.basename(videoPath)
durationObj = datetime.timedelta(seconds=duration)
video.path = videoPath
video.name = videoName
video.duration = str(durationObj)
videos.append(video)
context = {'Videos': videos, 'firstVideo': first_video, 'durations': durations, 'lecturer_subjects': lecturer_subjects, 'subjects': subject_list,
'template_name': 'FirstApp/template.html'}
except Exception as ex:
return redirect('/500') return redirect('/500')
return render(request, 'FirstApp/video_results.html', context) return render(request, "FirstApp/video_results.html",
{"lecturer": lecturer, "due_lectures": due_lecture_list})
# view for emotion page # view for emotion page
...@@ -437,6 +518,7 @@ def view500(request): ...@@ -437,6 +518,7 @@ def view500(request):
def tables(request): def tables(request):
return render(request, "FirstApp/tables.html") return render(request, "FirstApp/tables.html")
@login_required(login_url='/login') @login_required(login_url='/login')
def activity(request): def activity(request):
try: try:
...@@ -460,3 +542,7 @@ def activity(request): ...@@ -460,3 +542,7 @@ def activity(request):
return redirect('/500') return redirect('/500')
return render(request, "FirstApp/activity.html", {"lecturer_subjects": lecturer_subjects, "subjects": subject_list, "lecturer": lecturer}) return render(request, "FirstApp/activity.html", {"lecturer_subjects": lecturer_subjects, "subjects": subject_list, "lecturer": lecturer})
def test(request):
return render(request, "FirstApp/pdf_template.html")
\ No newline at end of file
from django.templatetags.static import static
from django.urls import reverse
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
env.globals.update({
'static': static,
'url': reverse,
})
return env
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment