Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions backend/routers/exam.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,18 +306,17 @@ async def submit_answer(
db.add(answer_db)

# Update session data
answers_data = session.answers_data or []
answers_data.append({
existing_answers = session.answers_data or []
session.answers_data = existing_answers + [{
"question_id": current_question['id'],
"answer": answer.answer,
"confidence_level": answer.confidence_level,
"time_taken": answer.time_taken,
"is_correct": is_correct,
"score": ai_score,
"feedback": ai_feedback
})
}]

session.answers_data = answers_data
session.current_question += 1
session.status = ExamStatus.IN_PROGRESS.value

Expand Down
14 changes: 7 additions & 7 deletions frontend/src/components/ConversationLogDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,28 +137,28 @@ function ConversationLogDisplay({ sessionId, logFilePath, isVisible, onClose }:

return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-lg shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-hidden">
<div className="bg-white rounded-lg shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-hidden flex flex-col">
{/* Header */}
<div className="bg-gradient-to-r from-blue-600 to-indigo-600 text-white p-6">
<div className="bg-gradient-to-r from-blue-600 to-indigo-600 text-white p-6 flex-shrink-0">
<div className="flex justify-between items-center">
<div>
<div className="min-w-0">
<h2 className="text-2xl font-bold mb-2">Exam Conversation Log</h2>
<p className="text-blue-100">Session ID: {sessionId}</p>
{logFilePath && (
<p className="text-blue-100 text-sm mt-1">Saved to: {logFilePath}</p>
<p className="text-blue-100 text-sm mt-1 break-words">Saved to: {logFilePath}</p>
)}
</div>
<button
onClick={onClose}
className="text-white hover:text-blue-200 text-2xl font-bold"
className="text-white hover:text-blue-200 text-2xl font-bold hidden md:block"
>
×
</button>
</div>
</div>

{/* Content */}
<div className="overflow-y-auto max-h-[calc(90vh-120px)]">
<div className="overflow-y-auto flex-1 min-h-0">
{isLoading && (
<div className="flex items-center justify-center p-8">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
Expand Down Expand Up @@ -316,7 +316,7 @@ function ConversationLogDisplay({ sessionId, logFilePath, isVisible, onClose }:
</div>

{/* Footer */}
<div className="bg-gray-50 px-6 py-4 border-t border-gray-200">
<div className="bg-gray-50 px-6 py-4 border-t border-gray-200 flex-shrink-0">
<div className="flex justify-end">
<button
onClick={onClose}
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/contexts/ExamContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ export function ExamProvider({ children }: ExamProviderProps) {
setError(null)

const response = await examAPI.getMaterials()
setMaterials(response.materials || [])
const sortedMaterials = response.materials.sort((a: Material, b: Material) => b.upload_time.localeCompare(a.upload_time))
setMaterials(sortedMaterials || [])
} catch (err) {
console.error('Failed to load materials:', err)
setError('Failed to load study materials')
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/pages/ExamPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -971,9 +971,9 @@ function ExamPage() {
📋 View Exam Transcript
</button>
{conversationLogPath && (
<p className="text-sm text-gray-600 mt-3 flex items-center">
<span className="mr-2">💾</span>
Saved to: {conversationLogPath}
<p className="text-sm text-gray-600 mt-3 flex items-start w-full">
<span className="mr-2 flex-shrink-0">💾</span>
<span className="break-words min-w-0 flex-1">Saved to: {conversationLogPath}</span>
</p>
)}
</div>
Expand Down
28 changes: 26 additions & 2 deletions frontend/src/pages/UploadPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { useState, useCallback } from 'react'
import { useDropzone } from 'react-dropzone'
import { useNavigate } from 'react-router-dom'
import { useExamContext } from '../contexts/ExamContext'
import { uploadMaterial, isValidFileType, formatFileSize, getFileTypeDisplayName } from '../services/examAPI'
import { uploadMaterial, isValidFileType, formatFileSize, getFileTypeDisplayName, getQuestionCount } from '../services/examAPI'
import LoadingSpinner from '../components/LoadingSpinner'
import QuestionsPopup from '../components/QuestionsPopup'
import toast from 'react-hot-toast'
Expand Down Expand Up @@ -42,6 +42,7 @@ function UploadPage() {
// Questions popup state
const [showQuestionsPopup, setShowQuestionsPopup] = useState(false)
const [questionsPopupMaterial, setQuestionsPopupMaterial] = useState<any>(null)
const [shouldStartExam, setShouldStartExam] = useState(false)

// Delete confirmation state
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
Expand Down Expand Up @@ -152,15 +153,24 @@ function UploadPage() {

if (success) {
toast.success(`${questionCount} questions generated successfully!`)

// If shouldStartExam, start the exam immediately
if (shouldStartExam) {
setShouldStartExam(false)
handleStartExam(selectedMaterial)
}

setShowQuestionModal(false)
setSelectedMaterial(null)
setCustomQuestionCount('10') // Reset to default
} else {
toast.error('Failed to generate questions. Please check your OpenAI API key.')
setShouldStartExam(false)
}
} catch (error) {
console.error('Question generation failed:', error)
toast.error('Failed to generate questions. Please try again.')
setShouldStartExam(false)
}
}

Expand All @@ -175,6 +185,14 @@ function UploadPage() {
// Handle material selection for exam
const handleStartExam = async (material: any) => {
try {
// Check if the material has questions
const questionCount = await getQuestionCount(material.id)
if (questionCount.total_questions === 0 && !shouldStartExam) {
setShouldStartExam(true)
handleGenerateQuestions(material)
return
}

selectMaterial(material)
const success = await startExam(material.id)

Expand Down Expand Up @@ -570,7 +588,9 @@ function UploadPage() {
<button
onClick={() => {
setShowQuestionModal(false)
setSelectedMaterial(null)
setCustomQuestionCount('10') // Reset to default
setShouldStartExam(false)
}}
className="btn-secondary flex-1"
disabled={isGeneratingQuestions}
Expand Down Expand Up @@ -606,7 +626,11 @@ function UploadPage() {
{/* Questions Popup */}
<QuestionsPopup
isVisible={showQuestionsPopup}
onClose={() => setShowQuestionsPopup(false)}
onClose={() => {
setShowQuestionsPopup(false);
setShouldStartExam(false);
setShouldStartExam(false);
}}
material={questionsPopupMaterial}
/>

Expand Down