Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -40,13 +40,14 @@ else:
|
|
| 40 |
# Prompts are now imported from prompts.py
|
| 41 |
|
| 42 |
# ---------------- SUPABASE HELPERS ----------------
|
| 43 |
-
def upload_file_to_supabase(local_path, file_type="unknown"):
|
| 44 |
"""
|
| 45 |
Upload a file to Supabase Storage.
|
| 46 |
|
| 47 |
Args:
|
| 48 |
local_path (str): Local file path
|
| 49 |
file_type (str): Type of file (qp, ms, ans, graded, imprinted)
|
|
|
|
| 50 |
|
| 51 |
Returns:
|
| 52 |
str: Public URL of uploaded file or None if upload failed
|
|
@@ -56,9 +57,12 @@ def upload_file_to_supabase(local_path, file_type="unknown"):
|
|
| 56 |
return None
|
| 57 |
|
| 58 |
try:
|
| 59 |
-
timestamp
|
|
|
|
|
|
|
| 60 |
original_name = os.path.basename(local_path)
|
| 61 |
-
|
|
|
|
| 62 |
|
| 63 |
print(f"π€ Uploading {file_type} to Supabase: {remote_path}")
|
| 64 |
|
|
@@ -79,7 +83,7 @@ def upload_file_to_supabase(local_path, file_type="unknown"):
|
|
| 79 |
|
| 80 |
def process_and_upload_input_files(qp_file_obj, ms_file_obj, ans_file_obj):
|
| 81 |
"""
|
| 82 |
-
Process uploaded files and upload them to Supabase.
|
| 83 |
|
| 84 |
Args:
|
| 85 |
qp_file_obj: Gradio file object for Question Paper
|
|
@@ -87,12 +91,16 @@ def process_and_upload_input_files(qp_file_obj, ms_file_obj, ans_file_obj):
|
|
| 87 |
ans_file_obj: Gradio file object for Answer Sheet
|
| 88 |
|
| 89 |
Returns:
|
| 90 |
-
tuple: (qp_path, ms_path, ans_path, upload_urls_dict)
|
| 91 |
"""
|
| 92 |
print("\n" + "="*60)
|
| 93 |
print("π PROCESSING INPUT FILES")
|
| 94 |
print("="*60)
|
| 95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
upload_urls = {
|
| 97 |
"qp_url": None,
|
| 98 |
"ms_url": None,
|
|
@@ -104,18 +112,18 @@ def process_and_upload_input_files(qp_file_obj, ms_file_obj, ans_file_obj):
|
|
| 104 |
ms_path = ms_file_obj.name if ms_file_obj else None
|
| 105 |
ans_path = ans_file_obj.name if ans_file_obj else None
|
| 106 |
|
| 107 |
-
# Upload to Supabase if configured
|
| 108 |
if supabase_client:
|
| 109 |
if qp_path:
|
| 110 |
-
upload_urls["qp_url"] = upload_file_to_supabase(qp_path, "qp")
|
| 111 |
if ms_path:
|
| 112 |
-
upload_urls["ms_url"] = upload_file_to_supabase(ms_path, "ms")
|
| 113 |
if ans_path:
|
| 114 |
-
upload_urls["ans_url"] = upload_file_to_supabase(ans_path, "ans")
|
| 115 |
|
| 116 |
print("="*60 + "\n")
|
| 117 |
|
| 118 |
-
return qp_path, ms_path, ans_path, upload_urls
|
| 119 |
|
| 120 |
|
| 121 |
|
|
@@ -1051,9 +1059,17 @@ def extract_pdf_pages_as_images(pdf_path, page_numbers, prefix):
|
|
| 1051 |
return out_paths
|
| 1052 |
|
| 1053 |
# ---------------- PIPELINE ----------------
|
| 1054 |
-
def align_and_grade_pipeline(qp_path, ms_path, ans_path, subject="Maths", imprint=False):
|
| 1055 |
"""
|
| 1056 |
Final pipeline with graph-aware grading logic using NEW SDK.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1057 |
"""
|
| 1058 |
try:
|
| 1059 |
print("π Starting pipeline...")
|
|
@@ -1146,7 +1162,7 @@ def align_and_grade_pipeline(qp_path, ms_path, ans_path, subject="Maths", imprin
|
|
| 1146 |
imprinted_pdf_path = imprint_marks_using_mapping(ans_path, grading_json, imprinted_pdf_path, extracted_ids)
|
| 1147 |
print("β
Imprinting finished. Imprinted PDF at:", imprinted_pdf_path)
|
| 1148 |
|
| 1149 |
-
# Upload output files to Supabase
|
| 1150 |
output_urls = {
|
| 1151 |
"graded_pdf_url": None,
|
| 1152 |
"imprinted_pdf_url": None
|
|
@@ -1155,9 +1171,9 @@ def align_and_grade_pipeline(qp_path, ms_path, ans_path, subject="Maths", imprin
|
|
| 1155 |
if supabase_client:
|
| 1156 |
print("\nπ€ Uploading output files to Supabase...")
|
| 1157 |
if grading_pdf_path:
|
| 1158 |
-
output_urls["graded_pdf_url"] = upload_file_to_supabase(grading_pdf_path, "graded")
|
| 1159 |
if imprinted_pdf_path:
|
| 1160 |
-
output_urls["imprinted_pdf_url"] = upload_file_to_supabase(imprinted_pdf_path, "imprinted")
|
| 1161 |
|
| 1162 |
print("π Pipeline finished successfully.")
|
| 1163 |
return qpms_text, as_text, grading_text, grading_pdf_path, imprinted_pdf_path, output_urls
|
|
@@ -1215,20 +1231,20 @@ with gr.Blocks(title="AI Grading (Pandoc + pdflatex)") as demo:
|
|
| 1215 |
else:
|
| 1216 |
return error_msg, "", "", None, None
|
| 1217 |
|
| 1218 |
-
# Process and upload input files
|
| 1219 |
-
qp_path, ms_path, ans_path, input_urls = process_and_upload_input_files(
|
| 1220 |
qp_file_obj, ms_file_obj, ans_file_obj
|
| 1221 |
)
|
| 1222 |
|
| 1223 |
-
# Run the grading pipeline
|
| 1224 |
qpms_text, as_text, grading_text, grading_pdf_path, imprinted_pdf_path, output_urls = align_and_grade_pipeline(
|
| 1225 |
-
qp_path, ms_path, ans_path, subject=subject_choice, imprint=imprint_flag
|
| 1226 |
)
|
| 1227 |
|
| 1228 |
# Build URLs summary
|
| 1229 |
urls_summary = ""
|
| 1230 |
if supabase_client:
|
| 1231 |
-
urls_summary = "π€ UPLOADED FILES:\n\n"
|
| 1232 |
urls_summary += "INPUT FILES:\n"
|
| 1233 |
if input_urls.get("qp_url"):
|
| 1234 |
urls_summary += f"β’ Question Paper: {input_urls['qp_url']}\n"
|
|
@@ -1243,6 +1259,8 @@ with gr.Blocks(title="AI Grading (Pandoc + pdflatex)") as demo:
|
|
| 1243 |
if output_urls.get("imprinted_pdf_url"):
|
| 1244 |
urls_summary += f"β’ Imprinted PDF: {output_urls['imprinted_pdf_url']}\n"
|
| 1245 |
|
|
|
|
|
|
|
| 1246 |
if not any(input_urls.values()) and not any(output_urls.values()):
|
| 1247 |
urls_summary += "\nβ οΈ No files were uploaded to Supabase"
|
| 1248 |
|
|
|
|
| 40 |
# Prompts are now imported from prompts.py
|
| 41 |
|
| 42 |
# ---------------- SUPABASE HELPERS ----------------
|
| 43 |
+
def upload_file_to_supabase(local_path, file_type="unknown", timestamp=None):
|
| 44 |
"""
|
| 45 |
Upload a file to Supabase Storage.
|
| 46 |
|
| 47 |
Args:
|
| 48 |
local_path (str): Local file path
|
| 49 |
file_type (str): Type of file (qp, ms, ans, graded, imprinted)
|
| 50 |
+
timestamp (str): Unix timestamp for folder organization (optional)
|
| 51 |
|
| 52 |
Returns:
|
| 53 |
str: Public URL of uploaded file or None if upload failed
|
|
|
|
| 57 |
return None
|
| 58 |
|
| 59 |
try:
|
| 60 |
+
if timestamp is None:
|
| 61 |
+
timestamp = str(int(time.time()))
|
| 62 |
+
|
| 63 |
original_name = os.path.basename(local_path)
|
| 64 |
+
# Use original filename without prefix for cleaner storage
|
| 65 |
+
remote_path = f"{timestamp}/{original_name}"
|
| 66 |
|
| 67 |
print(f"π€ Uploading {file_type} to Supabase: {remote_path}")
|
| 68 |
|
|
|
|
| 83 |
|
| 84 |
def process_and_upload_input_files(qp_file_obj, ms_file_obj, ans_file_obj):
|
| 85 |
"""
|
| 86 |
+
Process uploaded files and upload them to Supabase using a shared timestamp.
|
| 87 |
|
| 88 |
Args:
|
| 89 |
qp_file_obj: Gradio file object for Question Paper
|
|
|
|
| 91 |
ans_file_obj: Gradio file object for Answer Sheet
|
| 92 |
|
| 93 |
Returns:
|
| 94 |
+
tuple: (qp_path, ms_path, ans_path, upload_urls_dict, timestamp)
|
| 95 |
"""
|
| 96 |
print("\n" + "="*60)
|
| 97 |
print("π PROCESSING INPUT FILES")
|
| 98 |
print("="*60)
|
| 99 |
|
| 100 |
+
# Generate single timestamp for this entire run
|
| 101 |
+
run_timestamp = str(int(time.time()))
|
| 102 |
+
print(f"π Run timestamp: {run_timestamp}")
|
| 103 |
+
|
| 104 |
upload_urls = {
|
| 105 |
"qp_url": None,
|
| 106 |
"ms_url": None,
|
|
|
|
| 112 |
ms_path = ms_file_obj.name if ms_file_obj else None
|
| 113 |
ans_path = ans_file_obj.name if ans_file_obj else None
|
| 114 |
|
| 115 |
+
# Upload to Supabase if configured (all files use same timestamp)
|
| 116 |
if supabase_client:
|
| 117 |
if qp_path:
|
| 118 |
+
upload_urls["qp_url"] = upload_file_to_supabase(qp_path, "qp", run_timestamp)
|
| 119 |
if ms_path:
|
| 120 |
+
upload_urls["ms_url"] = upload_file_to_supabase(ms_path, "ms", run_timestamp)
|
| 121 |
if ans_path:
|
| 122 |
+
upload_urls["ans_url"] = upload_file_to_supabase(ans_path, "ans", run_timestamp)
|
| 123 |
|
| 124 |
print("="*60 + "\n")
|
| 125 |
|
| 126 |
+
return qp_path, ms_path, ans_path, upload_urls, run_timestamp
|
| 127 |
|
| 128 |
|
| 129 |
|
|
|
|
| 1059 |
return out_paths
|
| 1060 |
|
| 1061 |
# ---------------- PIPELINE ----------------
|
| 1062 |
+
def align_and_grade_pipeline(qp_path, ms_path, ans_path, subject="Maths", imprint=False, run_timestamp=None):
|
| 1063 |
"""
|
| 1064 |
Final pipeline with graph-aware grading logic using NEW SDK.
|
| 1065 |
+
|
| 1066 |
+
Args:
|
| 1067 |
+
qp_path: Path to Question Paper PDF
|
| 1068 |
+
ms_path: Path to Markscheme PDF
|
| 1069 |
+
ans_path: Path to Answer Sheet PDF
|
| 1070 |
+
subject: Subject name (Maths or Science)
|
| 1071 |
+
imprint: Whether to generate imprinted PDF
|
| 1072 |
+
run_timestamp: Unix timestamp for organizing files in Supabase
|
| 1073 |
"""
|
| 1074 |
try:
|
| 1075 |
print("π Starting pipeline...")
|
|
|
|
| 1162 |
imprinted_pdf_path = imprint_marks_using_mapping(ans_path, grading_json, imprinted_pdf_path, extracted_ids)
|
| 1163 |
print("β
Imprinting finished. Imprinted PDF at:", imprinted_pdf_path)
|
| 1164 |
|
| 1165 |
+
# Upload output files to Supabase (using same timestamp as input files)
|
| 1166 |
output_urls = {
|
| 1167 |
"graded_pdf_url": None,
|
| 1168 |
"imprinted_pdf_url": None
|
|
|
|
| 1171 |
if supabase_client:
|
| 1172 |
print("\nπ€ Uploading output files to Supabase...")
|
| 1173 |
if grading_pdf_path:
|
| 1174 |
+
output_urls["graded_pdf_url"] = upload_file_to_supabase(grading_pdf_path, "graded", run_timestamp)
|
| 1175 |
if imprinted_pdf_path:
|
| 1176 |
+
output_urls["imprinted_pdf_url"] = upload_file_to_supabase(imprinted_pdf_path, "imprinted", run_timestamp)
|
| 1177 |
|
| 1178 |
print("π Pipeline finished successfully.")
|
| 1179 |
return qpms_text, as_text, grading_text, grading_pdf_path, imprinted_pdf_path, output_urls
|
|
|
|
| 1231 |
else:
|
| 1232 |
return error_msg, "", "", None, None
|
| 1233 |
|
| 1234 |
+
# Process and upload input files (generates shared timestamp)
|
| 1235 |
+
qp_path, ms_path, ans_path, input_urls, run_timestamp = process_and_upload_input_files(
|
| 1236 |
qp_file_obj, ms_file_obj, ans_file_obj
|
| 1237 |
)
|
| 1238 |
|
| 1239 |
+
# Run the grading pipeline (pass timestamp to keep all files together)
|
| 1240 |
qpms_text, as_text, grading_text, grading_pdf_path, imprinted_pdf_path, output_urls = align_and_grade_pipeline(
|
| 1241 |
+
qp_path, ms_path, ans_path, subject=subject_choice, imprint=imprint_flag, run_timestamp=run_timestamp
|
| 1242 |
)
|
| 1243 |
|
| 1244 |
# Build URLs summary
|
| 1245 |
urls_summary = ""
|
| 1246 |
if supabase_client:
|
| 1247 |
+
urls_summary = f"π€ UPLOADED FILES (Timestamp: {run_timestamp}):\n\n"
|
| 1248 |
urls_summary += "INPUT FILES:\n"
|
| 1249 |
if input_urls.get("qp_url"):
|
| 1250 |
urls_summary += f"β’ Question Paper: {input_urls['qp_url']}\n"
|
|
|
|
| 1259 |
if output_urls.get("imprinted_pdf_url"):
|
| 1260 |
urls_summary += f"β’ Imprinted PDF: {output_urls['imprinted_pdf_url']}\n"
|
| 1261 |
|
| 1262 |
+
urls_summary += f"\nπ All files stored in: examfiles/{run_timestamp}/\n"
|
| 1263 |
+
|
| 1264 |
if not any(input_urls.values()) and not any(output_urls.values()):
|
| 1265 |
urls_summary += "\nβ οΈ No files were uploaded to Supabase"
|
| 1266 |
|