Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -5,42 +5,45 @@ import fitz # PyMuPDF
|
|
| 5 |
from flask import Flask, request, render_template_string, send_file
|
| 6 |
from playwright.async_api import async_playwright
|
| 7 |
|
| 8 |
-
# --- Flask App Setup ---
|
| 9 |
app = Flask(__name__)
|
| 10 |
|
| 11 |
-
# --- UI
|
| 12 |
HTML_PAGE = """
|
| 13 |
<!DOCTYPE html>
|
| 14 |
<html>
|
| 15 |
<head>
|
| 16 |
<title>JNVU Admit Card Downloader</title>
|
|
|
|
| 17 |
<style>
|
| 18 |
-
body { font-family: 'Segoe UI',
|
| 19 |
-
.
|
| 20 |
-
h2 { color: #
|
| 21 |
-
input { width:
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
.
|
| 25 |
-
.
|
|
|
|
|
|
|
|
|
|
| 26 |
</style>
|
| 27 |
</head>
|
| 28 |
<body>
|
| 29 |
-
<div class="
|
| 30 |
-
<h2>JNVU Admit Card</h2>
|
| 31 |
<form method="POST">
|
| 32 |
-
<input type="text" name="form_number" placeholder="Enter Form Number" required>
|
| 33 |
-
<button type="submit">
|
| 34 |
</form>
|
| 35 |
-
|
|
|
|
|
|
|
| 36 |
{% if data %}
|
| 37 |
-
<div class="result">
|
| 38 |
-
<strong>
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
<hr>
|
| 43 |
-
<a href="/download/{{ filename }}" style="color: #27ae60; font-weight: bold;">📥 Click here to Save PDF</a>
|
| 44 |
</div>
|
| 45 |
{% endif %}
|
| 46 |
</div>
|
|
@@ -55,33 +58,31 @@ def extract_student_info(pdf_path):
|
|
| 55 |
doc = fitz.open(pdf_path)
|
| 56 |
text = "".join([page.get_text() for page in doc])
|
| 57 |
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
center_match = re.search(center_pattern, text, re.DOTALL)
|
| 62 |
|
| 63 |
-
if
|
| 64 |
-
if
|
| 65 |
-
if
|
| 66 |
-
|
| 67 |
doc.close()
|
| 68 |
-
except Exception as e:
|
| 69 |
-
print(f"Extraction Error: {e}")
|
| 70 |
return info
|
| 71 |
|
| 72 |
-
# --- Playwright
|
| 73 |
async def download_jnvu_pdf(form_number):
|
| 74 |
pdf_path = f"admit_card_{form_number}.pdf"
|
| 75 |
async with async_playwright() as p:
|
| 76 |
-
|
|
|
|
| 77 |
context = await browser.new_context(accept_downloads=True)
|
| 78 |
page = await context.new_page()
|
| 79 |
try:
|
| 80 |
url = "https://erp.jnvuiums.in/(S(biolzjtwlrcfmzwwzgs5uj5n))/Exam/Pre_Exam/Exam_ForALL_AdmitCard.aspx#"
|
| 81 |
-
await page.goto(url, wait_until="
|
| 82 |
await page.fill("#txtchallanNo", str(form_number))
|
| 83 |
|
| 84 |
-
async with page.expect_download(timeout=
|
| 85 |
await page.click("#btnGetResult")
|
| 86 |
|
| 87 |
download = await download_info.value
|
|
@@ -99,25 +100,26 @@ def index():
|
|
| 99 |
if request.method == 'POST':
|
| 100 |
form_number = request.form.get('form_number')
|
| 101 |
if not form_number.isdigit():
|
| 102 |
-
return render_template_string(HTML_PAGE, error="
|
| 103 |
|
| 104 |
-
# Run async download in sync Flask
|
| 105 |
file_path = asyncio.run(download_jnvu_pdf(form_number))
|
| 106 |
|
| 107 |
if file_path and os.path.exists(file_path):
|
| 108 |
data = extract_student_info(file_path)
|
| 109 |
return render_template_string(HTML_PAGE, data=data, filename=file_path)
|
| 110 |
else:
|
| 111 |
-
return render_template_string(HTML_PAGE, error="
|
| 112 |
|
| 113 |
return render_template_string(HTML_PAGE)
|
| 114 |
|
| 115 |
@app.route('/download/<filename>')
|
| 116 |
def download_file(filename):
|
|
|
|
| 117 |
if os.path.exists(filename):
|
| 118 |
return send_file(filename, as_attachment=True)
|
| 119 |
-
return "File
|
| 120 |
|
| 121 |
if __name__ == "__main__":
|
|
|
|
| 122 |
port = int(os.environ.get("PORT", 7860))
|
| 123 |
app.run(host='0.0.0.0', port=port)
|
|
|
|
| 5 |
from flask import Flask, request, render_template_string, send_file
|
| 6 |
from playwright.async_api import async_playwright
|
| 7 |
|
|
|
|
| 8 |
app = Flask(__name__)
|
| 9 |
|
| 10 |
+
# --- UI Design ---
|
| 11 |
HTML_PAGE = """
|
| 12 |
<!DOCTYPE html>
|
| 13 |
<html>
|
| 14 |
<head>
|
| 15 |
<title>JNVU Admit Card Downloader</title>
|
| 16 |
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
| 17 |
<style>
|
| 18 |
+
body { font-family: 'Segoe UI', Arial, sans-serif; background: #f0f2f5; display: flex; justify-content: center; padding-top: 50px; }
|
| 19 |
+
.card { background: white; padding: 30px; border-radius: 15px; box-shadow: 0 10px 25px rgba(0,0,0,0.1); width: 100%; max-width: 450px; text-align: center; }
|
| 20 |
+
h2 { color: #1a73e8; margin-bottom: 20px; }
|
| 21 |
+
input { width: 90%; padding: 12px; margin: 10px 0; border: 2px solid #dfe1e5; border-radius: 8px; font-size: 16px; outline: none; }
|
| 22 |
+
input:focus { border-color: #1a73e8; }
|
| 23 |
+
.btn-fetch { background: #1a73e8; color: white; border: none; padding: 12px 25px; border-radius: 8px; cursor: pointer; font-size: 16px; width: 95%; font-weight: bold; }
|
| 24 |
+
.btn-fetch:hover { background: #1557b0; }
|
| 25 |
+
.result-box { margin-top: 25px; padding: 20px; background: #f8f9fa; border-radius: 10px; text-align: left; border-left: 5px solid #34a853; }
|
| 26 |
+
.btn-download { display: block; text-align: center; background: #34a853; color: white; padding: 12px; text-decoration: none; border-radius: 8px; margin-top: 15px; font-weight: bold; }
|
| 27 |
+
.error { color: #d93025; background: #fce8e6; padding: 10px; border-radius: 5px; margin-top: 10px; }
|
| 28 |
+
.loading { color: #5f6368; font-style: italic; margin-top: 10px; }
|
| 29 |
</style>
|
| 30 |
</head>
|
| 31 |
<body>
|
| 32 |
+
<div class="card">
|
| 33 |
+
<h2>JNVU Admit Card Finder</h2>
|
| 34 |
<form method="POST">
|
| 35 |
+
<input type="text" name="form_number" placeholder="Enter Form Number (e.g. 128xxx)" required>
|
| 36 |
+
<button type="submit" class="btn-fetch">Fetch Admit Card</button>
|
| 37 |
</form>
|
| 38 |
+
|
| 39 |
+
{% if error %}<div class="error">{{ error }}</div>{% endif %}
|
| 40 |
+
|
| 41 |
{% if data %}
|
| 42 |
+
<div class="result-box">
|
| 43 |
+
<p><strong>👤 Name:</strong> {{ data.name }}</p>
|
| 44 |
+
<p><strong>🔢 Roll No:</strong> {{ data.roll }}</p>
|
| 45 |
+
<p><strong>🏫 Center:</strong> {{ data.center }}</p>
|
| 46 |
+
<a href="/download/{{ filename }}" class="btn-download">📥 Download PDF Now</a>
|
|
|
|
|
|
|
| 47 |
</div>
|
| 48 |
{% endif %}
|
| 49 |
</div>
|
|
|
|
| 58 |
doc = fitz.open(pdf_path)
|
| 59 |
text = "".join([page.get_text() for page in doc])
|
| 60 |
|
| 61 |
+
name_m = re.search(r"NAME OF CANDIDATE\s*:\s*(.*)", text)
|
| 62 |
+
roll_m = re.search(r"Roll no is\s+([\w\d]+)", text)
|
| 63 |
+
cent_m = re.search(r"Exam Centre is\s*(.*?)(?=Print Date|To,|The Centre|NAME OF EXAMINATION)", text, re.DOTALL)
|
|
|
|
| 64 |
|
| 65 |
+
if name_m: info["name"] = name_m.group(1).split('\n')[0].strip()
|
| 66 |
+
if roll_m: info["roll"] = roll_m.group(1).strip()
|
| 67 |
+
if cent_m: info["center"] = " ".join(cent_m.group(1).split())
|
|
|
|
| 68 |
doc.close()
|
| 69 |
+
except Exception as e: print(f"Error: {e}")
|
|
|
|
| 70 |
return info
|
| 71 |
|
| 72 |
+
# --- Playwright Logic ---
|
| 73 |
async def download_jnvu_pdf(form_number):
|
| 74 |
pdf_path = f"admit_card_{form_number}.pdf"
|
| 75 |
async with async_playwright() as p:
|
| 76 |
+
# Docker के लिए No-Sandbox बहुत जरूरी है
|
| 77 |
+
browser = await p.chromium.launch(headless=True, args=["--no-sandbox", "--disable-dev-shm-usage"])
|
| 78 |
context = await browser.new_context(accept_downloads=True)
|
| 79 |
page = await context.new_page()
|
| 80 |
try:
|
| 81 |
url = "https://erp.jnvuiums.in/(S(biolzjtwlrcfmzwwzgs5uj5n))/Exam/Pre_Exam/Exam_ForALL_AdmitCard.aspx#"
|
| 82 |
+
await page.goto(url, wait_until="load", timeout=40000)
|
| 83 |
await page.fill("#txtchallanNo", str(form_number))
|
| 84 |
|
| 85 |
+
async with page.expect_download(timeout=20000) as download_info:
|
| 86 |
await page.click("#btnGetResult")
|
| 87 |
|
| 88 |
download = await download_info.value
|
|
|
|
| 100 |
if request.method == 'POST':
|
| 101 |
form_number = request.form.get('form_number')
|
| 102 |
if not form_number.isdigit():
|
| 103 |
+
return render_template_string(HTML_PAGE, error="कृपया सही फॉर्म नंबर डालें।")
|
| 104 |
|
|
|
|
| 105 |
file_path = asyncio.run(download_jnvu_pdf(form_number))
|
| 106 |
|
| 107 |
if file_path and os.path.exists(file_path):
|
| 108 |
data = extract_student_info(file_path)
|
| 109 |
return render_template_string(HTML_PAGE, data=data, filename=file_path)
|
| 110 |
else:
|
| 111 |
+
return render_template_string(HTML_PAGE, error="एडमिट कार्ड नहीं मिला या JNVU सर्वर धीमा है।")
|
| 112 |
|
| 113 |
return render_template_string(HTML_PAGE)
|
| 114 |
|
| 115 |
@app.route('/download/<filename>')
|
| 116 |
def download_file(filename):
|
| 117 |
+
# सुरक्षा के लिए चेक करें कि फाइल मौजूद है
|
| 118 |
if os.path.exists(filename):
|
| 119 |
return send_file(filename, as_attachment=True)
|
| 120 |
+
return "File missing", 404
|
| 121 |
|
| 122 |
if __name__ == "__main__":
|
| 123 |
+
# Hugging Face PORT 7860 मांगता है
|
| 124 |
port = int(os.environ.get("PORT", 7860))
|
| 125 |
app.run(host='0.0.0.0', port=port)
|