Commit
·
c1855f3
1
Parent(s):
2a626af
removing time out errro
Browse files- main.py +34 -2
- templates/index.html +113 -30
main.py
CHANGED
@@ -313,6 +313,15 @@ def validate_folder_structure(files):
|
|
313 |
@app.route('/compute_marks', methods=['POST'])
|
314 |
def compute_marks():
|
315 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
316 |
# Get correct answers
|
317 |
correct_answers = request.form.getlist('correct_answers[]')
|
318 |
log_print(f"Received correct answers: {correct_answers}")
|
@@ -346,6 +355,18 @@ def compute_marks():
|
|
346 |
"message": "No files uploaded"
|
347 |
}), 400
|
348 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
349 |
# Validate folder structure
|
350 |
is_valid, message = validate_folder_structure(files)
|
351 |
log_print(f"Folder structure validation: {message}")
|
@@ -641,8 +662,19 @@ if __name__ == '__main__':
|
|
641 |
for directory in essential_dirs:
|
642 |
ensure_directory(directory)
|
643 |
|
644 |
-
#
|
|
|
|
|
|
|
|
|
|
|
645 |
port = int(os.environ.get('PORT', 7860))
|
646 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
647 |
finally:
|
648 |
cleanup_temp_files()
|
|
|
313 |
@app.route('/compute_marks', methods=['POST'])
|
314 |
def compute_marks():
|
315 |
try:
|
316 |
+
# Wait for initialization to complete
|
317 |
+
if not initialization_complete.is_set():
|
318 |
+
wait_for_initialization()
|
319 |
+
if not initialization_complete.is_set():
|
320 |
+
return jsonify({
|
321 |
+
"error": "Server initialization",
|
322 |
+
"message": "Server is still initializing. Please try again in a moment."
|
323 |
+
}), 503
|
324 |
+
|
325 |
# Get correct answers
|
326 |
correct_answers = request.form.getlist('correct_answers[]')
|
327 |
log_print(f"Received correct answers: {correct_answers}")
|
|
|
355 |
"message": "No files uploaded"
|
356 |
}), 400
|
357 |
|
358 |
+
# Check total file size
|
359 |
+
total_size = sum(len(file.read()) for file in files)
|
360 |
+
for file in files:
|
361 |
+
file.seek(0) # Reset file pointers after reading
|
362 |
+
|
363 |
+
max_size = 15 * 1024 * 1024 # 15MB
|
364 |
+
if total_size > max_size:
|
365 |
+
return jsonify({
|
366 |
+
"error": "File size limit exceeded",
|
367 |
+
"message": f"Total file size must be less than 15MB (current size: {total_size / 1024 / 1024:.1f}MB)"
|
368 |
+
}), 413
|
369 |
+
|
370 |
# Validate folder structure
|
371 |
is_valid, message = validate_folder_structure(files)
|
372 |
log_print(f"Folder structure validation: {message}")
|
|
|
662 |
for directory in essential_dirs:
|
663 |
ensure_directory(directory)
|
664 |
|
665 |
+
# Configure server for long-running requests
|
666 |
+
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
|
667 |
+
app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024 # Increase to 50MB
|
668 |
+
|
669 |
+
# Start the Flask app with increased timeout
|
670 |
+
from werkzeug.serving import run_simple
|
671 |
port = int(os.environ.get('PORT', 7860))
|
672 |
+
run_simple('0.0.0.0', port, app,
|
673 |
+
use_reloader=False,
|
674 |
+
threaded=True,
|
675 |
+
request_handler=None,
|
676 |
+
passthrough_errors=True,
|
677 |
+
ssl_context=None,
|
678 |
+
socket_timeout=600) # 10 minute timeout
|
679 |
finally:
|
680 |
cleanup_temp_files()
|
templates/index.html
CHANGED
@@ -1177,17 +1177,19 @@
|
|
1177 |
return;
|
1178 |
}
|
1179 |
|
1180 |
-
notificationSystem.info(`Processing ${selectedFiles.size} student files...`);
|
1181 |
|
1182 |
const computeBtn = document.getElementById('compute-marks-btn');
|
1183 |
computeBtn.disabled = true;
|
1184 |
|
1185 |
const formData = new FormData();
|
1186 |
|
|
|
1187 |
answerValues.forEach((answer, index) => {
|
1188 |
formData.append('correct_answers[]', answer);
|
1189 |
});
|
1190 |
|
|
|
1191 |
let validFiles = 0;
|
1192 |
selectedFiles.forEach((fileInfo, path) => {
|
1193 |
if (fileInfo.file.type.startsWith('image/')) {
|
@@ -1200,46 +1202,62 @@
|
|
1200 |
throw new Error("No valid image files found in the uploaded folder");
|
1201 |
}
|
1202 |
|
1203 |
-
notificationSystem.info(`
|
1204 |
|
1205 |
-
|
1206 |
-
|
1207 |
-
|
1208 |
-
|
1209 |
-
|
1210 |
-
|
1211 |
-
});
|
1212 |
|
1213 |
-
const responseText = await response.text();
|
1214 |
-
let result;
|
1215 |
try {
|
1216 |
-
|
1217 |
-
|
1218 |
-
|
1219 |
-
|
1220 |
-
|
|
|
|
|
|
|
1221 |
|
1222 |
-
|
1223 |
-
|
1224 |
-
|
|
|
1225 |
|
1226 |
-
|
1227 |
-
|
1228 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1229 |
|
1230 |
-
|
1231 |
-
|
1232 |
|
1233 |
-
|
1234 |
-
|
1235 |
-
|
1236 |
-
|
1237 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1238 |
}
|
1239 |
|
1240 |
} catch (error) {
|
1241 |
console.error('Error details:', error);
|
1242 |
-
notificationSystem.error('Error computing marks
|
1243 |
} finally {
|
1244 |
hideLoading();
|
1245 |
const computeBtn = document.getElementById('compute-marks-btn');
|
@@ -1247,6 +1265,71 @@
|
|
1247 |
}
|
1248 |
}
|
1249 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1250 |
function displayMarks(results) {
|
1251 |
const tableBody = document.getElementById('marks-table-body');
|
1252 |
if (!tableBody) {
|
|
|
1177 |
return;
|
1178 |
}
|
1179 |
|
1180 |
+
notificationSystem.info(`Processing ${selectedFiles.size} student files. This may take several minutes...`);
|
1181 |
|
1182 |
const computeBtn = document.getElementById('compute-marks-btn');
|
1183 |
computeBtn.disabled = true;
|
1184 |
|
1185 |
const formData = new FormData();
|
1186 |
|
1187 |
+
// Add each answer as a separate correct_answers[] entry
|
1188 |
answerValues.forEach((answer, index) => {
|
1189 |
formData.append('correct_answers[]', answer);
|
1190 |
});
|
1191 |
|
1192 |
+
// Add files with their folder structure
|
1193 |
let validFiles = 0;
|
1194 |
selectedFiles.forEach((fileInfo, path) => {
|
1195 |
if (fileInfo.file.type.startsWith('image/')) {
|
|
|
1202 |
throw new Error("No valid image files found in the uploaded folder");
|
1203 |
}
|
1204 |
|
1205 |
+
notificationSystem.info(`Uploading and processing ${validFiles} files. Please be patient...`);
|
1206 |
|
1207 |
+
// Update loading message
|
1208 |
+
document.querySelector('.loading-text').innerHTML = `
|
1209 |
+
Processing ${validFiles} files...<br>
|
1210 |
+
This may take several minutes depending on the number of files.<br>
|
1211 |
+
Please keep this window open.
|
1212 |
+
`;
|
|
|
1213 |
|
|
|
|
|
1214 |
try {
|
1215 |
+
const controller = new AbortController();
|
1216 |
+
const response = await fetch('/compute_marks', {
|
1217 |
+
method: 'POST',
|
1218 |
+
body: formData,
|
1219 |
+
signal: controller.signal,
|
1220 |
+
// Remove timeout, let the browser handle connection timeouts
|
1221 |
+
keepalive: true
|
1222 |
+
});
|
1223 |
|
1224 |
+
if (!response.ok) {
|
1225 |
+
const errorData = await response.json();
|
1226 |
+
throw new Error(errorData.message || `Server error: ${response.status}`);
|
1227 |
+
}
|
1228 |
|
1229 |
+
const result = await response.json();
|
1230 |
+
|
1231 |
+
if (result.error) {
|
1232 |
+
throw new Error(result.message || result.error);
|
1233 |
+
}
|
1234 |
+
|
1235 |
+
if (!result.results) {
|
1236 |
+
throw new Error('No results found in server response');
|
1237 |
+
}
|
1238 |
|
1239 |
+
displayMarks(result.results);
|
1240 |
+
notificationSystem.success("Successfully computed marks!");
|
1241 |
|
1242 |
+
if (result.failed_files && result.failed_files.length > 0) {
|
1243 |
+
const failedMessage = result.failed_files
|
1244 |
+
.map(f => `${f.file}: ${f.error}`)
|
1245 |
+
.join('\n');
|
1246 |
+
notificationSystem.warning(`Some files failed to process:\n${failedMessage}`);
|
1247 |
+
}
|
1248 |
+
|
1249 |
+
} catch (fetchError) {
|
1250 |
+
console.error('Fetch error:', fetchError);
|
1251 |
+
if (!navigator.onLine) {
|
1252 |
+
throw new Error('No internet connection. Please check your connection and try again.');
|
1253 |
+
} else {
|
1254 |
+
throw new Error(`Server error: ${fetchError.message}`);
|
1255 |
+
}
|
1256 |
}
|
1257 |
|
1258 |
} catch (error) {
|
1259 |
console.error('Error details:', error);
|
1260 |
+
notificationSystem.error(error.message || 'Error computing marks. Please try again.');
|
1261 |
} finally {
|
1262 |
hideLoading();
|
1263 |
const computeBtn = document.getElementById('compute-marks-btn');
|
|
|
1265 |
}
|
1266 |
}
|
1267 |
|
1268 |
+
// Add this helper function to check file size
|
1269 |
+
function getFileSizeMB(file) {
|
1270 |
+
return file.size / (1024 * 1024);
|
1271 |
+
}
|
1272 |
+
|
1273 |
+
// Add this function to handle folder uploads
|
1274 |
+
async function handleFolderUpload(event) {
|
1275 |
+
try {
|
1276 |
+
const files = event.target.files;
|
1277 |
+
if (!files || files.length === 0) {
|
1278 |
+
notificationSystem.error("No files selected");
|
1279 |
+
return;
|
1280 |
+
}
|
1281 |
+
|
1282 |
+
// Clear previous files
|
1283 |
+
selectedFiles.clear();
|
1284 |
+
|
1285 |
+
let totalSize = 0;
|
1286 |
+
const maxTotalSize = 15; // Maximum total size in MB
|
1287 |
+
const maxFileSize = 2; // Maximum size per file in MB
|
1288 |
+
|
1289 |
+
// Process each file
|
1290 |
+
for (const file of files) {
|
1291 |
+
const fileSize = getFileSizeMB(file);
|
1292 |
+
|
1293 |
+
// Check individual file size
|
1294 |
+
if (fileSize > maxFileSize) {
|
1295 |
+
notificationSystem.warning(`File ${file.name} is too large (${fileSize.toFixed(1)}MB). Maximum size is ${maxFileSize}MB.`);
|
1296 |
+
continue;
|
1297 |
+
}
|
1298 |
+
|
1299 |
+
// Check total size
|
1300 |
+
if (totalSize + fileSize > maxTotalSize) {
|
1301 |
+
notificationSystem.warning(`Total file size limit of ${maxTotalSize}MB exceeded. Some files were not added.`);
|
1302 |
+
break;
|
1303 |
+
}
|
1304 |
+
|
1305 |
+
// Add file if it's an image
|
1306 |
+
if (file.type.startsWith('image/')) {
|
1307 |
+
const fullPath = file.webkitRelativePath || file.name;
|
1308 |
+
selectedFiles.set(fullPath, {
|
1309 |
+
file: file,
|
1310 |
+
fullPath: fullPath
|
1311 |
+
});
|
1312 |
+
totalSize += fileSize;
|
1313 |
+
} else {
|
1314 |
+
notificationSystem.warning(`File ${file.name} is not an image file and was skipped.`);
|
1315 |
+
}
|
1316 |
+
}
|
1317 |
+
|
1318 |
+
// Update UI with selected files
|
1319 |
+
updateFileTree();
|
1320 |
+
|
1321 |
+
if (selectedFiles.size > 0) {
|
1322 |
+
notificationSystem.success(`Successfully loaded ${selectedFiles.size} image files.`);
|
1323 |
+
} else {
|
1324 |
+
notificationSystem.error("No valid image files were found in the selected folder.");
|
1325 |
+
}
|
1326 |
+
|
1327 |
+
} catch (error) {
|
1328 |
+
console.error('Error handling folder upload:', error);
|
1329 |
+
notificationSystem.error('Error processing folder: ' + error.message);
|
1330 |
+
}
|
1331 |
+
}
|
1332 |
+
|
1333 |
function displayMarks(results) {
|
1334 |
const tableBody = document.getElementById('marks-table-body');
|
1335 |
if (!tableBody) {
|