Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
import re
|
| 3 |
import json
|
| 4 |
import subprocess
|
| 5 |
-
import tempfile
|
| 6 |
import time
|
| 7 |
import img2pdf
|
| 8 |
import gradio as gr
|
| 9 |
-
|
| 10 |
from markdown_pdf import MarkdownPdf, Section
|
| 11 |
from pdf2image import convert_from_path
|
| 12 |
from PIL import Image, ImageDraw, ImageFont
|
| 13 |
import cv2
|
| 14 |
import numpy as np
|
| 15 |
-
from concurrent.futures import ThreadPoolExecutor, as_completed
|
| 16 |
from PyPDF2 import PdfReader, PdfWriter
|
| 17 |
|
| 18 |
# ---------------- CONFIG ----------------
|
| 19 |
-
|
|
|
|
| 20 |
GRID_ROWS, GRID_COLS = 20, 14
|
| 21 |
|
| 22 |
# ---------------- PROMPTS ----------------
|
|
@@ -144,37 +148,24 @@ def compress_pdf(input_path, output_path=None, max_size=20*1024*1024):
|
|
| 144 |
print("β Compression error:", e)
|
| 145 |
return input_path
|
| 146 |
|
| 147 |
-
def create_model():
|
| 148 |
-
"""
|
| 149 |
-
Create the Gemini model and print which model is selected.
|
| 150 |
-
"""
|
| 151 |
-
try:
|
| 152 |
-
print("β‘ Attempting to use gemini-2.0-flash-exp model")
|
| 153 |
-
model = genai.GenerativeModel("gemini-2.0-flash-exp", generation_config={"temperature": 0})
|
| 154 |
-
print("β
Selected model: gemini-2.0-flash-exp")
|
| 155 |
-
return model
|
| 156 |
-
except Exception as e:
|
| 157 |
-
print("β οΈ Could not use gemini-2.0-flash-exp:", e)
|
| 158 |
-
try:
|
| 159 |
-
print("β‘ Falling back to gemini-1.5-flash model")
|
| 160 |
-
model = genai.GenerativeModel("gemini-1.5-flash", generation_config={"temperature": 0})
|
| 161 |
-
print("β
Selected model: gemini-1.5-flash")
|
| 162 |
-
return model
|
| 163 |
-
except Exception as e:
|
| 164 |
-
print("β Failed to create any Gemini model:", e)
|
| 165 |
-
raise
|
| 166 |
-
|
| 167 |
def upload_to_gemini(path, display_name=None):
|
| 168 |
"""
|
| 169 |
-
Upload a file to Gemini using the
|
| 170 |
"""
|
| 171 |
print(f"π€ Uploading {path} to Gemini...")
|
| 172 |
try:
|
| 173 |
-
uploaded_file =
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
)
|
| 177 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
return uploaded_file
|
| 179 |
except Exception as e:
|
| 180 |
print(f"β Upload failed for {path}: {e}")
|
|
@@ -190,37 +181,56 @@ def merge_pdfs(paths, output_path):
|
|
| 190 |
writer.write(f)
|
| 191 |
return output_path
|
| 192 |
|
| 193 |
-
def gemini_generate_content(
|
| 194 |
"""
|
| 195 |
-
Send prompt_text and optionally an uploaded file (or an image object/list) to the model
|
| 196 |
Returns textual response and prints progress.
|
| 197 |
"""
|
| 198 |
-
|
|
|
|
| 199 |
if file_upload_obj:
|
| 200 |
-
|
|
|
|
| 201 |
if image_obj:
|
| 202 |
if isinstance(image_obj, list):
|
| 203 |
for img_path in image_obj:
|
| 204 |
if isinstance(img_path, str):
|
| 205 |
pil_img = Image.open(img_path)
|
| 206 |
-
|
| 207 |
else:
|
| 208 |
-
|
| 209 |
else:
|
| 210 |
if isinstance(image_obj, str):
|
| 211 |
pil_img = Image.open(image_obj)
|
| 212 |
-
|
| 213 |
else:
|
| 214 |
-
|
|
|
|
| 215 |
print("π‘ Sending request to Gemini (prompt length:", len(prompt_text), "chars )")
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
|
| 225 |
# ---------------- PARSERS ----------------
|
| 226 |
def extract_question_ids_from_qpms(text: str):
|
|
@@ -336,7 +346,7 @@ def extract_marks_from_grading(grading_text):
|
|
| 336 |
return grading_json
|
| 337 |
|
| 338 |
# ---------------- MAPPING/IMPRINT HELPERS ----------------
|
| 339 |
-
def ask_gemini_for_mapping_batch(
|
| 340 |
"""
|
| 341 |
Send multiple page images together to Gemini for batch mapping processing.
|
| 342 |
"""
|
|
@@ -363,13 +373,22 @@ Grading JSON:
|
|
| 363 |
images = [Image.open(p) for p in image_paths]
|
| 364 |
|
| 365 |
print(f"π‘ Sending batch mapping request for {len(image_paths)} pages to Gemini...")
|
| 366 |
-
response = model.generate_content([prompt, *images])
|
| 367 |
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 373 |
|
| 374 |
print("π₯ Batch mapping response (chars):", len(raw_text))
|
| 375 |
print("π Gemini raw batch output:")
|
|
@@ -388,7 +407,7 @@ Grading JSON:
|
|
| 388 |
print(f"β Failed to parse Gemini JSON mapping: {e}")
|
| 389 |
return []
|
| 390 |
|
| 391 |
-
def imprint_marks_using_mapping(pdf_path, grading_json, output_pdf,
|
| 392 |
"""
|
| 393 |
Convert PDF to images, create grid-numbered images for batch sending to Gemini,
|
| 394 |
then annotate and produce imprinted PDF.
|
|
@@ -432,7 +451,7 @@ def imprint_marks_using_mapping(pdf_path, grading_json, output_pdf, model, expec
|
|
| 432 |
|
| 433 |
for start in range(0, len(temp_grid_images), batch_size):
|
| 434 |
batch_paths = temp_grid_images[start:start+batch_size]
|
| 435 |
-
batch_mapping = ask_gemini_for_mapping_batch(
|
| 436 |
all_mappings.extend(batch_mapping)
|
| 437 |
print(f"β
Processed batch {start//batch_size + 1}: pages {start+1}-{start+len(batch_paths)}")
|
| 438 |
|
|
@@ -504,7 +523,7 @@ def extract_pdf_pages_as_images(pdf_path, page_numbers, prefix):
|
|
| 504 |
# ---------------- PIPELINE ----------------
|
| 505 |
def align_and_grade_pipeline(qp_path, ms_path, ans_path, imprint=False):
|
| 506 |
"""
|
| 507 |
-
Final pipeline with graph-aware grading logic.
|
| 508 |
"""
|
| 509 |
try:
|
| 510 |
print("π Starting pipeline...")
|
|
@@ -517,15 +536,13 @@ def align_and_grade_pipeline(qp_path, ms_path, ans_path, imprint=False):
|
|
| 517 |
print("π Merged QP + MS ->", merged_qpms_path)
|
| 518 |
|
| 519 |
print("πΌ Uploading files to Gemini...")
|
| 520 |
-
merged_uploaded = upload_to_gemini(merged_qpms_path
|
| 521 |
-
ans_uploaded = upload_to_gemini(ans_path
|
| 522 |
print("β
Upload complete.")
|
| 523 |
|
| 524 |
-
model = create_model()
|
| 525 |
-
|
| 526 |
print("1.i) Transcribing QP+MS (questions first, then full markscheme, with graph detection)...")
|
| 527 |
qpms_prompt = PROMPTS["QP_MS_TRANSCRIPTION"]["content"] + "\nAt the end, also list all questions in the markscheme where a graph is expected, in the format:\nGraph expected in:\n- Question <number> β Page <number>\n(One per line, after ==== MARKSCHEME END ====)"
|
| 528 |
-
qpms_text = gemini_generate_content(
|
| 529 |
print("π QP+MS transcription received. Saving debug file: debug_qpms_transcript.txt")
|
| 530 |
with open("debug_qpms_transcript.txt", "w", encoding="utf-8") as f:
|
| 531 |
f.write(qpms_text)
|
|
@@ -543,7 +560,7 @@ def align_and_grade_pipeline(qp_path, ms_path, ans_path, imprint=False):
|
|
| 543 |
|
| 544 |
print("1.ii) Building AS transcription prompt with expected question IDs and graph detection, sending to Gemini...")
|
| 545 |
as_prompt = build_as_prompt_with_expected_ids(extracted_ids, qpms_text) + "\nAt the end, also list all answers where a graph is found, in the format:\nGraph found in:\n- Answer <number> β Page <number>\n(One per line, after all answers)"
|
| 546 |
-
as_text = gemini_generate_content(
|
| 547 |
print("π AS transcription received. Saving debug file: debug_as_transcript.txt")
|
| 548 |
with open("debug_as_transcript.txt", "w", encoding="utf-8") as f:
|
| 549 |
f.write(as_text)
|
|
@@ -569,7 +586,7 @@ def align_and_grade_pipeline(qp_path, ms_path, ans_path, imprint=False):
|
|
| 569 |
grading_input += graph_note
|
| 570 |
grading_prompt_system = PROMPTS["GRADING_PROMPT"]["content"]
|
| 571 |
grading_images = ms_graph_images + as_graph_images
|
| 572 |
-
grading_text = gemini_generate_content(
|
| 573 |
print("π§Ύ Grading output received. Saving debug file: debug_grading.md")
|
| 574 |
with open("debug_grading.md", "w", encoding="utf-8") as f:
|
| 575 |
f.write(grading_text)
|
|
@@ -585,9 +602,9 @@ def align_and_grade_pipeline(qp_path, ms_path, ans_path, imprint=False):
|
|
| 585 |
|
| 586 |
imprinted_pdf_path = None
|
| 587 |
if imprint:
|
| 588 |
-
print("β Imprint option enabled. Starting imprinting process
|
| 589 |
imprinted_pdf_path = f"{base_name}_imprinted.pdf"
|
| 590 |
-
imprinted_pdf_path = imprint_marks_using_mapping(ans_path, grading_json, imprinted_pdf_path,
|
| 591 |
print("β
Imprinting finished. Imprinted PDF at:", imprinted_pdf_path)
|
| 592 |
|
| 593 |
print("π Pipeline finished successfully.")
|
|
@@ -600,8 +617,9 @@ def align_and_grade_pipeline(qp_path, ms_path, ans_path, imprint=False):
|
|
| 600 |
return f"β Error: {e}", None, None, None, None
|
| 601 |
|
| 602 |
# ---------------- GRADIO UI ----------------
|
| 603 |
-
with gr.Blocks(title="AI Grading (
|
| 604 |
-
gr.Markdown("## π AI Grading β
|
|
|
|
| 605 |
|
| 606 |
with gr.Row():
|
| 607 |
qp_file = gr.File(label="π Upload Question Paper (PDF)")
|
|
@@ -620,6 +638,9 @@ with gr.Blocks(title="AI Grading (Final Flow)") as demo:
|
|
| 620 |
imprint_pdf_file = gr.File(label="π₯ Download Imprinted PDF (Optional)")
|
| 621 |
|
| 622 |
def run_pipeline(qp_file_obj, ms_file_obj, ans_file_obj, imprint_flag):
|
|
|
|
|
|
|
|
|
|
| 623 |
qp_path = qp_file_obj.name
|
| 624 |
ms_path = ms_file_obj.name
|
| 625 |
ans_path = ans_file_obj.name
|
|
|
|
| 1 |
+
Based on this new information, the issue is even clearer! The `google-generativeai` library has breaking changes that route requests to Vertex AI incorrectly. The solution is to migrate to the new `google-genai` SDK.
|
| 2 |
+
|
| 3 |
+
Here's your code completely rewritten using the **new official `google-genai` SDK**:
|
| 4 |
+
|
| 5 |
+
```python
|
| 6 |
import os
|
| 7 |
import re
|
| 8 |
import json
|
| 9 |
import subprocess
|
|
|
|
| 10 |
import time
|
| 11 |
import img2pdf
|
| 12 |
import gradio as gr
|
| 13 |
+
from google import genai # NEW SDK
|
| 14 |
from markdown_pdf import MarkdownPdf, Section
|
| 15 |
from pdf2image import convert_from_path
|
| 16 |
from PIL import Image, ImageDraw, ImageFont
|
| 17 |
import cv2
|
| 18 |
import numpy as np
|
|
|
|
| 19 |
from PyPDF2 import PdfReader, PdfWriter
|
| 20 |
|
| 21 |
# ---------------- CONFIG ----------------
|
| 22 |
+
# Create client with new SDK
|
| 23 |
+
client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))
|
| 24 |
GRID_ROWS, GRID_COLS = 20, 14
|
| 25 |
|
| 26 |
# ---------------- PROMPTS ----------------
|
|
|
|
| 148 |
print("β Compression error:", e)
|
| 149 |
return input_path
|
| 150 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
def upload_to_gemini(path, display_name=None):
|
| 152 |
"""
|
| 153 |
+
Upload a file to Gemini using the NEW google-genai SDK.
|
| 154 |
"""
|
| 155 |
print(f"π€ Uploading {path} to Gemini...")
|
| 156 |
try:
|
| 157 |
+
uploaded_file = client.files.upload(file=path)
|
| 158 |
+
|
| 159 |
+
# Wait for processing to complete
|
| 160 |
+
print(f"β³ Waiting for file processing: {uploaded_file.name}")
|
| 161 |
+
while uploaded_file.state.name == "PROCESSING":
|
| 162 |
+
time.sleep(2)
|
| 163 |
+
uploaded_file = client.files.get(name=uploaded_file.name)
|
| 164 |
+
|
| 165 |
+
if uploaded_file.state.name == "FAILED":
|
| 166 |
+
raise Exception(f"File processing failed: {uploaded_file.name}")
|
| 167 |
+
|
| 168 |
+
print(f"β
Uploaded and processed: {uploaded_file.name}")
|
| 169 |
return uploaded_file
|
| 170 |
except Exception as e:
|
| 171 |
print(f"β Upload failed for {path}: {e}")
|
|
|
|
| 181 |
writer.write(f)
|
| 182 |
return output_path
|
| 183 |
|
| 184 |
+
def gemini_generate_content(prompt_text, file_upload_obj=None, image_obj=None, model_name="gemini-2.0-flash-exp"):
|
| 185 |
"""
|
| 186 |
+
Send prompt_text and optionally an uploaded file (or an image object/list) to the model using NEW SDK.
|
| 187 |
Returns textual response and prints progress.
|
| 188 |
"""
|
| 189 |
+
contents = [prompt_text]
|
| 190 |
+
|
| 191 |
if file_upload_obj:
|
| 192 |
+
contents.append(file_upload_obj)
|
| 193 |
+
|
| 194 |
if image_obj:
|
| 195 |
if isinstance(image_obj, list):
|
| 196 |
for img_path in image_obj:
|
| 197 |
if isinstance(img_path, str):
|
| 198 |
pil_img = Image.open(img_path)
|
| 199 |
+
contents.append(pil_img)
|
| 200 |
else:
|
| 201 |
+
contents.append(img_path)
|
| 202 |
else:
|
| 203 |
if isinstance(image_obj, str):
|
| 204 |
pil_img = Image.open(image_obj)
|
| 205 |
+
contents.append(pil_img)
|
| 206 |
else:
|
| 207 |
+
contents.append(image_obj)
|
| 208 |
+
|
| 209 |
print("π‘ Sending request to Gemini (prompt length:", len(prompt_text), "chars )")
|
| 210 |
+
|
| 211 |
+
try:
|
| 212 |
+
response = client.models.generate_content(
|
| 213 |
+
model=model_name,
|
| 214 |
+
contents=contents
|
| 215 |
+
)
|
| 216 |
+
raw_text = response.text
|
| 217 |
+
print("π₯ Received response (chars):", len(raw_text))
|
| 218 |
+
return raw_text
|
| 219 |
+
except Exception as e:
|
| 220 |
+
print(f"β Generation failed: {e}")
|
| 221 |
+
# Try fallback model
|
| 222 |
+
print("β‘ Trying fallback model: gemini-1.5-flash")
|
| 223 |
+
try:
|
| 224 |
+
response = client.models.generate_content(
|
| 225 |
+
model="gemini-1.5-flash",
|
| 226 |
+
contents=contents
|
| 227 |
+
)
|
| 228 |
+
raw_text = response.text
|
| 229 |
+
print("π₯ Received response (chars):", len(raw_text))
|
| 230 |
+
return raw_text
|
| 231 |
+
except Exception as e2:
|
| 232 |
+
print(f"β Fallback also failed: {e2}")
|
| 233 |
+
raise
|
| 234 |
|
| 235 |
# ---------------- PARSERS ----------------
|
| 236 |
def extract_question_ids_from_qpms(text: str):
|
|
|
|
| 346 |
return grading_json
|
| 347 |
|
| 348 |
# ---------------- MAPPING/IMPRINT HELPERS ----------------
|
| 349 |
+
def ask_gemini_for_mapping_batch(image_paths, grading_json, expected_ids=None, rows=GRID_ROWS, cols=GRID_COLS):
|
| 350 |
"""
|
| 351 |
Send multiple page images together to Gemini for batch mapping processing.
|
| 352 |
"""
|
|
|
|
| 373 |
images = [Image.open(p) for p in image_paths]
|
| 374 |
|
| 375 |
print(f"π‘ Sending batch mapping request for {len(image_paths)} pages to Gemini...")
|
|
|
|
| 376 |
|
| 377 |
+
try:
|
| 378 |
+
contents = [prompt] + images
|
| 379 |
+
response = client.models.generate_content(
|
| 380 |
+
model="gemini-2.0-flash-exp",
|
| 381 |
+
contents=contents
|
| 382 |
+
)
|
| 383 |
+
raw_text = response.text
|
| 384 |
+
except:
|
| 385 |
+
print("β οΈ Trying fallback model for mapping...")
|
| 386 |
+
contents = [prompt] + images
|
| 387 |
+
response = client.models.generate_content(
|
| 388 |
+
model="gemini-1.5-flash",
|
| 389 |
+
contents=contents
|
| 390 |
+
)
|
| 391 |
+
raw_text = response.text
|
| 392 |
|
| 393 |
print("π₯ Batch mapping response (chars):", len(raw_text))
|
| 394 |
print("π Gemini raw batch output:")
|
|
|
|
| 407 |
print(f"β Failed to parse Gemini JSON mapping: {e}")
|
| 408 |
return []
|
| 409 |
|
| 410 |
+
def imprint_marks_using_mapping(pdf_path, grading_json, output_pdf, expected_ids=None, rows=GRID_ROWS, cols=GRID_COLS):
|
| 411 |
"""
|
| 412 |
Convert PDF to images, create grid-numbered images for batch sending to Gemini,
|
| 413 |
then annotate and produce imprinted PDF.
|
|
|
|
| 451 |
|
| 452 |
for start in range(0, len(temp_grid_images), batch_size):
|
| 453 |
batch_paths = temp_grid_images[start:start+batch_size]
|
| 454 |
+
batch_mapping = ask_gemini_for_mapping_batch(batch_paths, grading_json, expected_ids, rows, cols)
|
| 455 |
all_mappings.extend(batch_mapping)
|
| 456 |
print(f"β
Processed batch {start//batch_size + 1}: pages {start+1}-{start+len(batch_paths)}")
|
| 457 |
|
|
|
|
| 523 |
# ---------------- PIPELINE ----------------
|
| 524 |
def align_and_grade_pipeline(qp_path, ms_path, ans_path, imprint=False):
|
| 525 |
"""
|
| 526 |
+
Final pipeline with graph-aware grading logic using NEW SDK.
|
| 527 |
"""
|
| 528 |
try:
|
| 529 |
print("π Starting pipeline...")
|
|
|
|
| 536 |
print("π Merged QP + MS ->", merged_qpms_path)
|
| 537 |
|
| 538 |
print("πΌ Uploading files to Gemini...")
|
| 539 |
+
merged_uploaded = upload_to_gemini(merged_qpms_path)
|
| 540 |
+
ans_uploaded = upload_to_gemini(ans_path)
|
| 541 |
print("β
Upload complete.")
|
| 542 |
|
|
|
|
|
|
|
| 543 |
print("1.i) Transcribing QP+MS (questions first, then full markscheme, with graph detection)...")
|
| 544 |
qpms_prompt = PROMPTS["QP_MS_TRANSCRIPTION"]["content"] + "\nAt the end, also list all questions in the markscheme where a graph is expected, in the format:\nGraph expected in:\n- Question <number> β Page <number>\n(One per line, after ==== MARKSCHEME END ====)"
|
| 545 |
+
qpms_text = gemini_generate_content(qpms_prompt, file_upload_obj=merged_uploaded)
|
| 546 |
print("π QP+MS transcription received. Saving debug file: debug_qpms_transcript.txt")
|
| 547 |
with open("debug_qpms_transcript.txt", "w", encoding="utf-8") as f:
|
| 548 |
f.write(qpms_text)
|
|
|
|
| 560 |
|
| 561 |
print("1.ii) Building AS transcription prompt with expected question IDs and graph detection, sending to Gemini...")
|
| 562 |
as_prompt = build_as_prompt_with_expected_ids(extracted_ids, qpms_text) + "\nAt the end, also list all answers where a graph is found, in the format:\nGraph found in:\n- Answer <number> β Page <number>\n(One per line, after all answers)"
|
| 563 |
+
as_text = gemini_generate_content(as_prompt, file_upload_obj=ans_uploaded)
|
| 564 |
print("π AS transcription received. Saving debug file: debug_as_transcript.txt")
|
| 565 |
with open("debug_as_transcript.txt", "w", encoding="utf-8") as f:
|
| 566 |
f.write(as_text)
|
|
|
|
| 586 |
grading_input += graph_note
|
| 587 |
grading_prompt_system = PROMPTS["GRADING_PROMPT"]["content"]
|
| 588 |
grading_images = ms_graph_images + as_graph_images
|
| 589 |
+
grading_text = gemini_generate_content(grading_prompt_system + "\n\nPlease grade the following transcripts:\n" + grading_input, image_obj=grading_images if grading_images else None)
|
| 590 |
print("π§Ύ Grading output received. Saving debug file: debug_grading.md")
|
| 591 |
with open("debug_grading.md", "w", encoding="utf-8") as f:
|
| 592 |
f.write(grading_text)
|
|
|
|
| 602 |
|
| 603 |
imprinted_pdf_path = None
|
| 604 |
if imprint:
|
| 605 |
+
print("β Imprint option enabled. Starting imprinting process...")
|
| 606 |
imprinted_pdf_path = f"{base_name}_imprinted.pdf"
|
| 607 |
+
imprinted_pdf_path = imprint_marks_using_mapping(ans_path, grading_json, imprinted_pdf_path, extracted_ids)
|
| 608 |
print("β
Imprinting finished. Imprinted PDF at:", imprinted_pdf_path)
|
| 609 |
|
| 610 |
print("π Pipeline finished successfully.")
|
|
|
|
| 617 |
return f"β Error: {e}", None, None, None, None
|
| 618 |
|
| 619 |
# ---------------- GRADIO UI ----------------
|
| 620 |
+
with gr.Blocks(title="AI Grading (Fixed - google-genai SDK)") as demo:
|
| 621 |
+
gr.Markdown("## π AI Grading β Fixed with google-genai SDK")
|
| 622 |
+
gr.Markdown("**β
Now using the new official `google-genai` SDK (no more ragStoreName errors!)**")
|
| 623 |
|
| 624 |
with gr.Row():
|
| 625 |
qp_file = gr.File(label="π Upload Question Paper (PDF)")
|
|
|
|
| 638 |
imprint_pdf_file = gr.File(label="π₯ Download Imprinted PDF (Optional)")
|
| 639 |
|
| 640 |
def run_pipeline(qp_file_obj, ms_file_obj, ans_file_obj, imprint_flag):
|
| 641 |
+
if not qp_file_obj or not ms_file_obj or not ans_file_obj:
|
| 642 |
+
return "β Please upload all three files", "", "", None, None
|
| 643 |
+
|
| 644 |
qp_path = qp_file_obj.name
|
| 645 |
ms_path = ms_file_obj.name
|
| 646 |
ans_path = ans_file_obj.name
|