MBG0903's picture
Update src/app.py
2821cf4 verified
import streamlit as st
import random
from io import BytesIO
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
# ------------------- BRAND CONFIG -------------------
BRAND = "#0F2C59" # Procelevate navy
ACCENT = "#00FFFF" # Cyan glow
PINK = "#FF00FF" # Magenta glow
st.set_page_config(
page_title="AI Name Magic - Procelevate",
page_icon="โœจ",
layout="centered",
)
# ------------------- SESSION STATE -------------------
if "gallery" not in st.session_state:
st.session_state.gallery = [] # list of dicts: {"img": bytes, "name": str, "fact": str}
if "current_name" not in st.session_state:
st.session_state.current_name = ""
if "current_fact" not in st.session_state:
st.session_state.current_fact = ""
if "current_card" not in st.session_state:
st.session_state.current_card = None
# ------------------- HEADER (CENTERED LOGO) -------------------
# Try a few common locations for the logo so path changes don't break the app.
logo_candidates = [
"src/procelevate_logo.png",
"src/assets/procelevate_logo.png",
"procelevate_logo.png",
]
logo_path = next((p for p in logo_candidates if Path(p).exists()), None)
if logo_path:
c1, c2, c3 = st.columns([1, 2, 1])
with c2:
st.image(logo_path, width=150)
st.markdown(
f"""
<div style="text-align:center; margin-top:4px;">
<h1 style="margin:0; color:{BRAND};">AI Name Magic โœจ</h1>
<div style="font-size:20px; color:#1f2937;">Powered by <b style="color:{BRAND};">Procelevate Consulting</b></div>
</div>
<hr style="opacity:.2;"/>
""",
unsafe_allow_html=True,
)
# ------------------- INPUT FORM -------------------
with st.form("name_form", clear_on_submit=False):
st.subheader("๐Ÿ”ฎ Type Your Name & See AI Magic")
name = st.text_input("Enter your name:")
submitted = st.form_submit_button("Show My AI Prediction ๐Ÿš€")
# ------------------- PREDICTION POOL -------------------
facts = [
"It's a beautiful name...AI predicts youโ€™ll be a Future Innovator. Keep rocking..! ๐Ÿš€",
"It's a beautiful name...Your curiosity will power the next big idea. Keep inspiring...! ๐Ÿ’ก",
"It's a beautiful name...You might be the Next Data Scientist / Data Engineer. Best Wishes for you....! ๐Ÿ“Š",
"It's a beautiful name...AI says youโ€™ll shape the Future of Tech. Thank you future CTO...! ๐Ÿค–",
"It's a beautiful name...Leadership and technology is in your DNA ๐ŸŒŸ",
"It's a beautiful name...AI foresees a potential CEO / CTO of a big company ๐ŸŒ",
]
def choose_new_fact(exclude=None):
pool = [f for f in facts if f != exclude] or facts
return random.choice(pool)
# ------------------- IMAGE GENERATOR (PNG CARD) -------------------
def _load_font(path_candidates, size):
"""Try to load a TTF font from common paths; fall back to default."""
for p in path_candidates:
if Path(p).exists():
try:
return ImageFont.truetype(p, size)
except Exception:
pass
return ImageFont.load_default()
def make_card(name_text: str, fact_text: str) -> bytes:
"""Create a branded 'Future Me Card' PNG and return bytes."""
W, H = 1200, 630
base = Image.new("RGB", (W, H), (15, 44, 89)) # #0F2C59
draw = ImageDraw.Draw(base)
# Subtle cyan gradient overlay
grad = Image.new("RGB", (W, H))
for y in range(H):
c = int(255 * (y / H) * 0.18)
grad.putpixel((0, y), (0, 180, 180 - c))
grad = grad.resize((W, H))
base = Image.blend(base, grad, 0.15)
draw = ImageDraw.Draw(base)
# Fonts: try DejaVu (available if installed), else default
dejavu_bold = [
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
"/usr/local/share/fonts/DejaVuSans-Bold.ttf",
]
dejavu = [
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
"/usr/local/share/fonts/DejaVuSans.ttf",
]
title_font = _load_font(dejavu_bold, 70)
name_font = _load_font(dejavu_bold, 120)
fact_font = _load_font(dejavu, 46)
foot_font = _load_font(dejavu, 28)
# Paste logo if available (resolve relative to this file)
try:
local_dir = Path(__file__).parent
lp = None
for cand in ["procelevate_logo.png", "assets/procelevate_logo.png", "../procelevate_logo.png"]:
p = (local_dir / cand).resolve()
if p.exists():
lp = p
break
if lp:
logo = Image.open(lp).convert("RGBA")
logo = logo.resize((140, 140))
base.paste(logo, (50, 50), logo)
except Exception:
pass # OK if logo missing
# Title pill
title = "YOUR AI PREDICTION"
tw = draw.textlength(title, font=title_font)
th = getattr(title_font, "size", 70)
draw.rounded_rectangle([(400, 70), (400 + tw + 60, 70 + th + 40)], radius=18, fill=(255, 255, 255))
draw.text((430, 90), title, font=title_font, fill=(15, 44, 89))
# Neon name
name_text = name_text.upper()
nx, ny = 120, 260
draw.text((nx + 6, ny + 6), name_text, font=name_font, fill=(255, 0, 255)) # magenta shadow
draw.text((nx - 6, ny - 6), name_text, font=name_font, fill=(0, 255, 255)) # cyan shadow
draw.text((nx, ny), name_text, font=name_font, fill=(255, 255, 255)) # white main
# Fact chip
fact_box_y = ny + 170
draw.rounded_rectangle([(80, fact_box_y), (W - 80, fact_box_y + 170)], radius=24, fill=(255, 255, 255))
draw.text((110, fact_box_y + 55), f"โœจ {fact_text}", font=fact_font, fill=(15, 44, 89))
# Footer
footer = "ยฉ Procelevate Consulting โ€ข Elevating Processes. Empowering People."
fw = draw.textlength(footer, font=foot_font)
draw.text(((W - fw) // 2, H - 60), footer, font=foot_font, fill=(230, 240, 245))
buf = BytesIO()
base.save(buf, format="PNG")
buf.seek(0)
return buf.getvalue()
# ------------------- RENDER RESULT BLOCK -------------------
def render_result(name_text: str, fact_text: str):
st.markdown(
f"""
<div style="
margin: 10px auto 0 auto;
max-width: 820px;
text-align:center;
padding: 18px 22px;
border-radius: 16px;
background:
radial-gradient(circle at 20% 10%, rgba(0,255,255,.25), transparent 40%),
radial-gradient(circle at 80% 0%, rgba(255,0,255,.25), transparent 35%),
linear-gradient(180deg, #ffffff 0%, #f7fbff 100%);
border: 2px solid #e6eef7;">
<div style="font-size:14px; letter-spacing:1px; color:{BRAND}; font-weight:700;
display:inline-block; padding:6px 12px; border-radius:999px; background:#e6f3ff; margin-bottom:8px;">
YOUR AI PREDICTION
</div>
<h1 style="margin:4px 0 8px 0; font-size:56px; color:{BRAND};
text-shadow: 2px 2px {ACCENT}, -2px -2px {PINK};">
{name_text.upper()}
</h1>
<div style="font-size:22px; color:#0b2239; padding:12px 16px; border-radius:12px;
background:#f0f9ff; display:inline-block;">
โœจ {fact_text}
</div>
</div>
""",
unsafe_allow_html=True,
)
# ------------------- HANDLE SUBMIT -------------------
if submitted and name.strip():
st.session_state.current_name = name.strip()
st.session_state.current_fact = choose_new_fact(None)
st.session_state.current_card = make_card(st.session_state.current_name, st.session_state.current_fact)
# Add to gallery (cap 5 latest)
st.session_state.gallery = (st.session_state.gallery + [{
"img": st.session_state.current_card,
"name": st.session_state.current_name,
"fact": st.session_state.current_fact
}])[-5:]
st.balloons()
elif submitted and not name.strip():
st.warning("Please enter your name first ๐Ÿ™‚")
# ------------------- TRY ANOTHER PREDICTION BUTTON -------------------
# Show only if we already have a name
if st.session_state.current_name:
try_another = st.button("๐Ÿ”„ Try another prediction")
if try_another:
st.session_state.current_fact = choose_new_fact(st.session_state.current_fact)
st.session_state.current_card = make_card(st.session_state.current_name, st.session_state.current_fact)
st.session_state.gallery = (st.session_state.gallery + [{
"img": st.session_state.current_card,
"name": st.session_state.current_name,
"fact": st.session_state.current_fact
}])[-5:]
# ------------------- SHOW RESULT (IF ANY) -------------------
if st.session_state.current_name and st.session_state.current_fact:
render_result(st.session_state.current_name, st.session_state.current_fact)
# Download button for the latest card
if st.session_state.current_card:
st.download_button(
"โฌ‡๏ธ Download My Future Me Card (PNG)",
data=st.session_state.current_card,
file_name=f"{st.session_state.current_name.replace(' ','_')}_future_me.png",
mime="image/png",
)
# ------------------- LIVE GALLERY (LAST 5) -------------------
if st.session_state.gallery:
st.markdown("<hr style='opacity:.15;'/>", unsafe_allow_html=True)
st.subheader("๐Ÿ“ธ Live Gallery (latest 5)")
items = list(reversed(st.session_state.gallery)) # newest first
cols = st.columns(len(items))
for col, item in zip(cols, items):
with col:
st.image(item["img"], caption=item["name"], use_container_width=True)
st.markdown("<hr style='opacity:.2;'/>", unsafe_allow_html=True)
st.markdown(
"<p style='text-align:center; font-size:14px;'>ยฉ 2025 Procelevate Consulting</p>",
unsafe_allow_html=True,
)