atz21 commited on
Commit
c5806ce
Β·
verified Β·
1 Parent(s): c5c9486

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +189 -19
app.py CHANGED
@@ -3,6 +3,7 @@ import re
3
  import json
4
  import subprocess
5
  import time
 
6
  import img2pdf
7
  import gradio as gr
8
  from google import genai # NEW SDK
@@ -11,15 +12,110 @@ from PIL import Image, ImageDraw, ImageFont
11
  import cv2
12
  import numpy as np
13
  from PyPDF2 import PdfReader, PdfWriter
14
- from prompts import QP_MS_TRANSCRIPTION_PROMPT, get_grading_prompt
 
15
 
16
  # ---------------- CONFIG ----------------
17
  # Create client with new SDK
18
  client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))
19
- GRID_ROWS, GRID_COLS = 20, 14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
  # ---------------- PROMPTS ----------------
22
- # Prompts are now imported from prompts.py
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
 
25
 
@@ -1050,19 +1146,37 @@ def align_and_grade_pipeline(qp_path, ms_path, ans_path, subject="Maths", imprin
1050
  imprinted_pdf_path = imprint_marks_using_mapping(ans_path, grading_json, imprinted_pdf_path, extracted_ids)
1051
  print("βœ… Imprinting finished. Imprinted PDF at:", imprinted_pdf_path)
1052
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1053
  print("🏁 Pipeline finished successfully.")
1054
- return qpms_text, as_text, grading_text, grading_pdf_path, imprinted_pdf_path
1055
 
1056
  except Exception as e:
1057
  print("❌ Pipeline error:", e)
1058
  import traceback
1059
  traceback.print_exc()
1060
- return f"❌ Error: {e}", None, None, None, None
1061
 
1062
  # ---------------- GRADIO UI ----------------
1063
  with gr.Blocks(title="AI Grading (Pandoc + pdflatex)") as demo:
1064
  gr.Markdown("## πŸ“˜ AI Grading β€” Using Pandoc + pdflatex for PDF Generation")
1065
  gr.Markdown("**βœ… Now using Pandoc with pdflatex for professional-quality PDF outputs!**")
 
 
 
 
 
1066
 
1067
  with gr.Row():
1068
  qp_file = gr.File(label="πŸ“„ Upload Question Paper (PDF)")
@@ -1080,6 +1194,11 @@ with gr.Blocks(title="AI Grading (Pandoc + pdflatex)") as demo:
1080
 
1081
  run_button = gr.Button("πŸš€ Run Pipeline")
1082
 
 
 
 
 
 
1083
  with gr.Row():
1084
  qpms_box = gr.Textbox(label="πŸ“‘ QP+MS Transcript", lines=12)
1085
  as_box = gr.Textbox(label="πŸ“ AS Transcript", lines=12)
@@ -1090,23 +1209,74 @@ with gr.Blocks(title="AI Grading (Pandoc + pdflatex)") as demo:
1090
 
1091
  def run_pipeline(qp_file_obj, ms_file_obj, ans_file_obj, subject_choice, imprint_flag):
1092
  if not qp_file_obj or not ms_file_obj or not ans_file_obj:
1093
- return "❌ Please upload all three files", "", "", None, None
1094
-
1095
- qp_path = qp_file_obj.name
1096
- ms_path = ms_file_obj.name
1097
- ans_path = ans_file_obj.name
 
 
 
 
 
1098
 
1099
- qpms_text, as_text, grading_text, grading_pdf_path, imprinted_pdf_path = align_and_grade_pipeline(
 
1100
  qp_path, ms_path, ans_path, subject=subject_choice, imprint=imprint_flag
1101
- )
1102
-
1103
- return qpms_text or "", as_text or "", grading_text or "", grading_pdf_path, imprinted_pdf_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1104
 
1105
- run_button.click(
1106
- fn=run_pipeline,
1107
- inputs=[qp_file, ms_file, ans_file, subject_dropdown, imprint_toggle],
1108
- outputs=[qpms_box, as_box, grading_output_box, grading_pdf_file, imprint_pdf_file]
1109
- )
 
 
 
 
 
 
 
 
1110
 
1111
  if __name__ == "__main__":
1112
  demo.launch()
 
3
  import json
4
  import subprocess
5
  import time
6
+ import shutil
7
  import img2pdf
8
  import gradio as gr
9
  from google import genai # NEW SDK
 
12
  import cv2
13
  import numpy as np
14
  from PyPDF2 import PdfReader, PdfWriter
15
+ from prompts import QP_MS_TRANSCRIPTION_PROMPT, get_grading_prompt
16
+ from supabase import create_client, Client
17
 
18
  # ---------------- CONFIG ----------------
19
  # Create client with new SDK
20
  client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))
21
+ GRID_ROWS, GRID_COLS = 20, 14
22
+
23
+ # Supabase configuration
24
+ SUPABASE_URL = os.getenv("SUPABASE_URL")
25
+ SUPABASE_SERVICE_KEY = os.getenv("SUPABASE_SERVICE_KEY")
26
+ SUPABASE_BUCKET = "examfiles"
27
+
28
+ # Initialize Supabase client (only if credentials are available)
29
+ supabase_client = None
30
+ if SUPABASE_URL and SUPABASE_SERVICE_KEY:
31
+ try:
32
+ supabase_client = create_client(SUPABASE_URL, SUPABASE_SERVICE_KEY)
33
+ print("βœ… Supabase client initialized successfully")
34
+ except Exception as e:
35
+ print(f"⚠️ Supabase initialization failed: {e}")
36
+ else:
37
+ print("⚠️ Supabase credentials not found - file upload to storage disabled")
38
 
39
  # ---------------- PROMPTS ----------------
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
53
+ """
54
+ if not supabase_client:
55
+ print("⚠️ Supabase not configured - skipping upload")
56
+ return None
57
+
58
+ try:
59
+ timestamp = str(int(time.time()))
60
+ original_name = os.path.basename(local_path)
61
+ remote_path = f"{timestamp}/{file_type}_{original_name}"
62
+
63
+ print(f"πŸ“€ Uploading {file_type} to Supabase: {remote_path}")
64
+
65
+ with open(local_path, "rb") as f:
66
+ supabase_client.storage.from_(SUPABASE_BUCKET).upload(
67
+ remote_path,
68
+ f,
69
+ file_options={"upsert": "true"}
70
+ )
71
+
72
+ public_url = f"{SUPABASE_URL}/storage/v1/object/public/{SUPABASE_BUCKET}/{remote_path}"
73
+ print(f"βœ… Uploaded successfully: {public_url}")
74
+ return public_url
75
+
76
+ except Exception as e:
77
+ print(f"❌ Supabase upload failed for {file_type}: {e}")
78
+ return None
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
86
+ ms_file_obj: Gradio file object for Markscheme
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,
99
+ "ans_url": None
100
+ }
101
+
102
+ # Get local paths from Gradio file objects
103
+ qp_path = qp_file_obj.name if qp_file_obj else None
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
 
 
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
1153
+ }
1154
+
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
1164
 
1165
  except Exception as e:
1166
  print("❌ Pipeline error:", e)
1167
  import traceback
1168
  traceback.print_exc()
1169
+ return f"❌ Error: {e}", None, None, None, None, {}
1170
 
1171
  # ---------------- GRADIO UI ----------------
1172
  with gr.Blocks(title="AI Grading (Pandoc + pdflatex)") as demo:
1173
  gr.Markdown("## πŸ“˜ AI Grading β€” Using Pandoc + pdflatex for PDF Generation")
1174
  gr.Markdown("**βœ… Now using Pandoc with pdflatex for professional-quality PDF outputs!**")
1175
+
1176
+ if supabase_client:
1177
+ gr.Markdown("**☁️ Supabase Storage: Enabled** - All files will be uploaded to cloud storage")
1178
+ else:
1179
+ gr.Markdown("**⚠️ Supabase Storage: Disabled** - Files will only be processed locally")
1180
 
1181
  with gr.Row():
1182
  qp_file = gr.File(label="πŸ“„ Upload Question Paper (PDF)")
 
1194
 
1195
  run_button = gr.Button("πŸš€ Run Pipeline")
1196
 
1197
+ # File URLs section (only shown if Supabase is enabled)
1198
+ if supabase_client:
1199
+ with gr.Accordion("☁️ Uploaded File URLs", open=False):
1200
+ file_urls_box = gr.Textbox(label="Cloud Storage URLs", lines=8, interactive=False)
1201
+
1202
  with gr.Row():
1203
  qpms_box = gr.Textbox(label="πŸ“‘ QP+MS Transcript", lines=12)
1204
  as_box = gr.Textbox(label="πŸ“ AS Transcript", lines=12)
 
1209
 
1210
  def run_pipeline(qp_file_obj, ms_file_obj, ans_file_obj, subject_choice, imprint_flag):
1211
  if not qp_file_obj or not ms_file_obj or not ans_file_obj:
1212
+ error_msg = "❌ Please upload all three files"
1213
+ if supabase_client:
1214
+ return error_msg, "", "", None, None, ""
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"
1235
+ if input_urls.get("ms_url"):
1236
+ urls_summary += f"β€’ Markscheme: {input_urls['ms_url']}\n"
1237
+ if input_urls.get("ans_url"):
1238
+ urls_summary += f"β€’ Answer Sheet: {input_urls['ans_url']}\n"
1239
+
1240
+ urls_summary += "\nOUTPUT FILES:\n"
1241
+ if output_urls.get("graded_pdf_url"):
1242
+ urls_summary += f"β€’ Graded PDF: {output_urls['graded_pdf_url']}\n"
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
+
1249
+ if supabase_client:
1250
+ return (
1251
+ qpms_text or "",
1252
+ as_text or "",
1253
+ grading_text or "",
1254
+ grading_pdf_path,
1255
+ imprinted_pdf_path,
1256
+ urls_summary
1257
+ )
1258
+ else:
1259
+ return (
1260
+ qpms_text or "",
1261
+ as_text or "",
1262
+ grading_text or "",
1263
+ grading_pdf_path,
1264
+ imprinted_pdf_path
1265
+ )
1266
 
1267
+ # Set up the click handler based on whether Supabase is enabled
1268
+ if supabase_client:
1269
+ run_button.click(
1270
+ fn=run_pipeline,
1271
+ inputs=[qp_file, ms_file, ans_file, subject_dropdown, imprint_toggle],
1272
+ outputs=[qpms_box, as_box, grading_output_box, grading_pdf_file, imprint_pdf_file, file_urls_box]
1273
+ )
1274
+ else:
1275
+ run_button.click(
1276
+ fn=run_pipeline,
1277
+ inputs=[qp_file, ms_file, ans_file, subject_dropdown, imprint_toggle],
1278
+ outputs=[qpms_box, as_box, grading_output_box, grading_pdf_file, imprint_pdf_file]
1279
+ )
1280
 
1281
  if __name__ == "__main__":
1282
  demo.launch()