124 lines
5.4 KiB
Python
124 lines
5.4 KiB
Python
import streamlit as st
|
|
from PIL import Image
|
|
from google import genai
|
|
import json
|
|
from io import BytesIO
|
|
from .email_helloween_image import send_email_with_attachment
|
|
|
|
|
|
def camera_photo():
|
|
st.markdown("<h1 style='text-align: center; color: #451002;'>🎃 Halloween Photo Booth 📸</h1>", unsafe_allow_html=True)
|
|
st.markdown("<h5 style='text-align: center;'> Capture your Halloween spirit with a festive photo! 👻 </h3>", unsafe_allow_html=True)
|
|
|
|
if 'image_response' not in st.session_state:
|
|
st.session_state.image_response = None
|
|
|
|
enable_camera = st.checkbox("Enable Camera")
|
|
if enable_camera:
|
|
st.info("📎Note: No photos are stored. The image is processed in-memory and deleted after refresh app.")
|
|
picture = st.camera_input("Take a Halloween-themed photo! 🎃👻🕸️")
|
|
|
|
if picture is not None:
|
|
image = Image.open(picture)
|
|
|
|
keep_dressing_style = st.checkbox("Keep original dressing style", value=False)
|
|
keep_body_pose = st.checkbox("Keep original body pose", value=False)
|
|
|
|
theme = st.selectbox(
|
|
"Select or Input a Halloween theme for your photo:",
|
|
[ "🎃 Classic Halloween",
|
|
"👻 Haunted House",
|
|
"⚗️ Science Experiment Gone Wrong",
|
|
"🎥 Horror Film Inspired",
|
|
"🕯️ Gothic",
|
|
"🧙♂️ Harry Potter",
|
|
"⚰️ Graveyard",
|
|
"🔮 Cult Horror Theme"
|
|
],
|
|
index=0,
|
|
key="theme_selector"
|
|
)
|
|
|
|
if st.button("AI Editing"):
|
|
edit_prompt = f"""
|
|
Retain original facial features (eyes, nose, mouth etc.) of any persons in the photo. The goal is to achieve a realistic, edited look, not an AI-generated or overly smoothed/perfected appearance. Avoid any artificial alterations to these features.
|
|
Keep the original dressing style: {str(keep_dressing_style)}
|
|
Keep the original body pose: {str(keep_body_pose)}
|
|
Theme: {theme}
|
|
If a person is already in costume, enhance the costume and add more Halloween elements and background to the scene.
|
|
If multiple persons are present, ensure all are included in the Halloween theme.
|
|
- Overall Style: The final image should be photorealistic.
|
|
Ensure the final image is vibrant, festive, and captures the Halloween spirit!
|
|
"""
|
|
with st.spinner("Editing image..."):
|
|
text_response, image_response = edit_image_with_ai(image, edit_prompt)
|
|
if text_response:
|
|
st.info(text_response)
|
|
if image_response:
|
|
st.session_state.image_response = image_response
|
|
# Rerun to display the generated image and send options
|
|
st.rerun()
|
|
|
|
if st.session_state.image_response:
|
|
st.image(st.session_state.image_response)
|
|
# Convert PIL image to bytes for download
|
|
img_byte_arr = BytesIO()
|
|
st.session_state.image_response.save(img_byte_arr, format="JPEG")
|
|
st.download_button(
|
|
label="Download Edited Image",
|
|
data=img_byte_arr.getvalue(),
|
|
file_name="edited_image.jpeg",
|
|
mime="image/jpeg"
|
|
)
|
|
send_image(st.session_state.image_response)
|
|
|
|
def send_image(image_response):
|
|
st.divider()
|
|
to_email = st.text_input("Enter your email to receive the photo:", key="email_input")
|
|
if st.button("Send Email"):
|
|
with st.spinner("Sending email..."):
|
|
if to_email and image_response:
|
|
with open('app_config.json') as config_file:
|
|
config = json.load(config_file)
|
|
sender_email = config["send_email"]["sender_email"]
|
|
password = config["send_email"]["password"]
|
|
subject = "Your Spooktacular Halloween Photo! 🎃👻"
|
|
send_email_with_attachment(sender_email, password, to_email, subject, image_response)
|
|
st.success("Email sent successfully!")
|
|
else:
|
|
st.error("Please enter a valid email address and ensure the image is generated.")
|
|
|
|
|
|
|
|
|
|
def edit_image_with_ai(image, description):
|
|
with open('app_config.json') as config_file:
|
|
config = json.load(config_file)
|
|
api_key = config["nano-banana"]["api_key"]
|
|
|
|
client = genai.Client(api_key=api_key)
|
|
|
|
prompt = description
|
|
|
|
response = client.models.generate_content(
|
|
model="gemini-2.5-flash-image-preview",
|
|
contents=[prompt, image],
|
|
)
|
|
|
|
text_response = None
|
|
image_response = None
|
|
|
|
# AttributeError: 'NoneType' object has no attribute 'parts'
|
|
if response.candidates and len(response.candidates) <= 0:
|
|
st.error("No response from AI model. Please try again.")
|
|
return text_response, image_response
|
|
|
|
for part in response.candidates[0].content.parts:
|
|
if part.text is not None:
|
|
text_response = part.text
|
|
|
|
if part.inline_data is not None:
|
|
image_response = Image.open(BytesIO(part.inline_data.data))
|
|
|
|
return text_response, image_response
|