Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -14,9 +14,7 @@ GRADE_LIST = ["KG1", "KG2"] + [f"Grade {i}" for i in range(1, 13)]
|
|
| 14 |
SECTION_LIST = ["A", "B", "C", "D"]
|
| 15 |
current_year = 2025
|
| 16 |
AY_LIST = [f"AY {y}-{str(y+1)[2:]}" for y in range(current_year, current_year + 6)]
|
| 17 |
-
|
| 18 |
GOLD_COLOR = (184, 134, 11)
|
| 19 |
-
DARK_BLUE = (0, 31, 63)
|
| 20 |
|
| 21 |
# --- Loading Logic ---
|
| 22 |
if 'ai_loaded' not in st.session_state:
|
|
@@ -65,67 +63,69 @@ with tab1:
|
|
| 65 |
pdf = FPDF()
|
| 66 |
for student in data:
|
| 67 |
pdf.add_page()
|
| 68 |
-
|
| 69 |
-
# 1. Border
|
| 70 |
pdf.set_draw_color(*border_rgb)
|
| 71 |
pdf.set_line_width(5)
|
| 72 |
pdf.rect(10, 10, 190, 277)
|
| 73 |
|
| 74 |
-
# 2. Logo
|
| 75 |
if os.path.exists(LOGO_PATH):
|
| 76 |
pdf.image(LOGO_PATH, x=170, y=12, w=20)
|
| 77 |
|
| 78 |
-
# 3. Header Info
|
| 79 |
pdf.set_xy(15, 15)
|
| 80 |
pdf.set_font("Arial", 'B', 11)
|
| 81 |
pdf.set_text_color(160, 160, 160)
|
| 82 |
pdf.cell(0, 10, f"{term} | {week} | {ay}", ln=True)
|
| 83 |
|
| 84 |
-
#
|
| 85 |
raw_img = Image.open(student["image"])
|
| 86 |
-
processed_img = st.session_state['remove_fn'](raw_img)
|
| 87 |
-
processed_img = processed_img.convert("RGBA")
|
| 88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp:
|
| 90 |
processed_img.save(tmp.name, format='PNG')
|
| 91 |
temp_path = tmp.name
|
| 92 |
|
| 93 |
-
#
|
| 94 |
pdf.set_y(28)
|
| 95 |
pdf.set_font("Arial", 'B', 32)
|
| 96 |
pdf.set_text_color(*GOLD_COLOR)
|
| 97 |
pdf.cell(200, 20, "STAR OF THE WEEK", ln=True, align='C')
|
| 98 |
|
| 99 |
-
# 6. Student Name (NEW POSITION: Top, after title)
|
| 100 |
-
# Size reduced from 40 to 32 for better header integration
|
| 101 |
pdf.set_y(48)
|
| 102 |
pdf.set_font("Arial", 'B', 32)
|
| 103 |
pdf.set_text_color(*border_rgb)
|
| 104 |
pdf.cell(200, 12, student["name"].upper(), ln=True, align='C')
|
| 105 |
|
| 106 |
-
# 7. Grade-Section (NEW POSITION: Top, after name)
|
| 107 |
pdf.set_font("Arial", '', 22)
|
| 108 |
pdf.set_text_color(100, 100, 100)
|
| 109 |
pdf.cell(200, 10, f"{student['grade']}-{student['section']}", ln=True, align='C')
|
| 110 |
|
| 111 |
-
#
|
| 112 |
-
|
| 113 |
-
pdf.image(temp_path, x=32, y=75, w=145, h=0)
|
| 114 |
os.unlink(temp_path)
|
| 115 |
|
| 116 |
return pdf.output(dest='S').encode('latin-1')
|
| 117 |
|
|
|
|
| 118 |
if st.button("β¨ Generate Star of the Week Photos"):
|
| 119 |
if not students_data:
|
| 120 |
st.warning("Please fill in student details.")
|
| 121 |
else:
|
| 122 |
-
|
|
|
|
| 123 |
pdf_out = create_pdf(students_data, rgb_border, selected_term, selected_week, selected_ay)
|
| 124 |
-
status.update(label="Photos Ready!", state="complete", expanded=False)
|
| 125 |
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
SECTION_LIST = ["A", "B", "C", "D"]
|
| 15 |
current_year = 2025
|
| 16 |
AY_LIST = [f"AY {y}-{str(y+1)[2:]}" for y in range(current_year, current_year + 6)]
|
|
|
|
| 17 |
GOLD_COLOR = (184, 134, 11)
|
|
|
|
| 18 |
|
| 19 |
# --- Loading Logic ---
|
| 20 |
if 'ai_loaded' not in st.session_state:
|
|
|
|
| 63 |
pdf = FPDF()
|
| 64 |
for student in data:
|
| 65 |
pdf.add_page()
|
|
|
|
|
|
|
| 66 |
pdf.set_draw_color(*border_rgb)
|
| 67 |
pdf.set_line_width(5)
|
| 68 |
pdf.rect(10, 10, 190, 277)
|
| 69 |
|
|
|
|
| 70 |
if os.path.exists(LOGO_PATH):
|
| 71 |
pdf.image(LOGO_PATH, x=170, y=12, w=20)
|
| 72 |
|
|
|
|
| 73 |
pdf.set_xy(15, 15)
|
| 74 |
pdf.set_font("Arial", 'B', 11)
|
| 75 |
pdf.set_text_color(160, 160, 160)
|
| 76 |
pdf.cell(0, 10, f"{term} | {week} | {ay}", ln=True)
|
| 77 |
|
| 78 |
+
# AI Smart Crop & Background Removal
|
| 79 |
raw_img = Image.open(student["image"])
|
| 80 |
+
processed_img = st.session_state['remove_fn'](raw_img, alpha_matting=True)
|
|
|
|
| 81 |
|
| 82 |
+
# Tight crop to remove empty space around head
|
| 83 |
+
bbox = processed_img.getbbox()
|
| 84 |
+
if bbox:
|
| 85 |
+
processed_img = processed_img.crop(bbox)
|
| 86 |
+
|
| 87 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp:
|
| 88 |
processed_img.save(tmp.name, format='PNG')
|
| 89 |
temp_path = tmp.name
|
| 90 |
|
| 91 |
+
# Title, Name, Grade
|
| 92 |
pdf.set_y(28)
|
| 93 |
pdf.set_font("Arial", 'B', 32)
|
| 94 |
pdf.set_text_color(*GOLD_COLOR)
|
| 95 |
pdf.cell(200, 20, "STAR OF THE WEEK", ln=True, align='C')
|
| 96 |
|
|
|
|
|
|
|
| 97 |
pdf.set_y(48)
|
| 98 |
pdf.set_font("Arial", 'B', 32)
|
| 99 |
pdf.set_text_color(*border_rgb)
|
| 100 |
pdf.cell(200, 12, student["name"].upper(), ln=True, align='C')
|
| 101 |
|
|
|
|
| 102 |
pdf.set_font("Arial", '', 22)
|
| 103 |
pdf.set_text_color(100, 100, 100)
|
| 104 |
pdf.cell(200, 10, f"{student['grade']}-{student['section']}", ln=True, align='C')
|
| 105 |
|
| 106 |
+
# Photo Placement
|
| 107 |
+
pdf.image(temp_path, x=32, y=75, w=145, h=190)
|
|
|
|
| 108 |
os.unlink(temp_path)
|
| 109 |
|
| 110 |
return pdf.output(dest='S').encode('latin-1')
|
| 111 |
|
| 112 |
+
# --- Generation and Auto-Visible Button ---
|
| 113 |
if st.button("β¨ Generate Star of the Week Photos"):
|
| 114 |
if not students_data:
|
| 115 |
st.warning("Please fill in student details.")
|
| 116 |
else:
|
| 117 |
+
# We use a standard spinner so the output isn't nested inside a box
|
| 118 |
+
with st.spinner("π¨ AI is Smart-Cropping and generating..."):
|
| 119 |
pdf_out = create_pdf(students_data, rgb_border, selected_term, selected_week, selected_ay)
|
|
|
|
| 120 |
|
| 121 |
+
# These lines execute immediately after the spinner finishes
|
| 122 |
+
# No more drop-down arrow!
|
| 123 |
+
st.balloons() # Added a celebratory effect
|
| 124 |
+
st.success("β
Photos Ready!")
|
| 125 |
+
st.download_button(
|
| 126 |
+
label="π₯ Download Photos PDF",
|
| 127 |
+
data=pdf_out,
|
| 128 |
+
file_name=f"Star_of_the_Week_{selected_ay}_{selected_term}_{selected_week}.pdf",
|
| 129 |
+
mime="application/pdf",
|
| 130 |
+
use_container_width=True # Makes the button large and easy to click
|
| 131 |
+
)
|