Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import requests
|
3 |
+
import base64
|
4 |
+
from io import BytesIO
|
5 |
+
from PIL import Image
|
6 |
+
import time
|
7 |
+
|
8 |
+
# Streamlit app title and description
|
9 |
+
st.title("SDXL Image Generation Wrapper")
|
10 |
+
st.markdown("""
|
11 |
+
This Streamlit app wraps the Google SDXL Gradio app to generate images from text prompts.
|
12 |
+
Enter a prompt, select a style, and adjust settings to create high-quality images.
|
13 |
+
""")
|
14 |
+
|
15 |
+
# Backend URL of the Gradio app (replace with actual endpoint if different)
|
16 |
+
BACKEND_URL = "https://google-sdxl.hf.space/api/predict/"
|
17 |
+
|
18 |
+
# Style options (mirroring the Gradio app's style_list)
|
19 |
+
STYLE_OPTIONS = [
|
20 |
+
"(No style)", "Cinematic", "Photographic", "Anime", "Manga",
|
21 |
+
"Digital Art", "Pixel art", "Fantasy art", "Neonpunk", "3D Model"
|
22 |
+
]
|
23 |
+
|
24 |
+
# Function to apply style (replicating the Gradio app's apply_style logic)
|
25 |
+
def apply_style(style_name, prompt, negative):
|
26 |
+
style_dict = {
|
27 |
+
"(No style)": ("{prompt}", ""),
|
28 |
+
"Cinematic": (
|
29 |
+
"cinematic still {prompt} . emotional, harmonious, vignette, highly detailed, high budget, bokeh, cinemascope, moody, epic, gorgeous, film grain, grainy",
|
30 |
+
"anime, cartoon, graphic, text, painting, crayon, graphite, abstract, glitch, deformed, mutated, ugly, disfigured"
|
31 |
+
),
|
32 |
+
"Photographic": (
|
33 |
+
"cinematic photo {prompt} . 35mm photograph, film, bokeh, professional, 4k, highly detailed",
|
34 |
+
"drawing, painting, crayon, sketch, graphite, impressionist, noisy, blurry, soft, deformed, ugly"
|
35 |
+
),
|
36 |
+
"Anime": (
|
37 |
+
"anime artwork {prompt} . anime style, key visual, vibrant, studio anime, highly detailed",
|
38 |
+
"photo, deformed, black and white, realism, disfigured, low contrast"
|
39 |
+
),
|
40 |
+
"Manga": (
|
41 |
+
"manga style {prompt} . vibrant, high-energy, detailed, iconic, Japanese comic style",
|
42 |
+
"ugly, deformed, noisy, blurry, low contrast, realism, photorealistic, Western comic style"
|
43 |
+
),
|
44 |
+
"Digital Art": (
|
45 |
+
"concept art {prompt} . digital artwork, illustrative, painterly, matte painting, highly detailed",
|
46 |
+
"photo, photorealistic, realism, ugly"
|
47 |
+
),
|
48 |
+
"Pixel art": (
|
49 |
+
"pixel-art {prompt} . low-res, blocky, pixel art style, 8-bit graphics",
|
50 |
+
"sloppy, messy, blurry, noisy, highly detailed, ultra textured, photo, realistic"
|
51 |
+
),
|
52 |
+
"Fantasy art": (
|
53 |
+
"ethereal fantasy concept art of {prompt} . magnificent, celestial, ethereal, painterly, epic, majestic, magical, fantasy art, cover art, dreamy",
|
54 |
+
"photographic, realistic, realism, 35mm film, dslr, cropped, frame, text, deformed, glitch, noise, noisy, off-center, deformed, cross-eyed, closed eyes, bad anatomy, ugly, disfigured, sloppy, duplicate, mutated, black and white"
|
55 |
+
),
|
56 |
+
"Neonpunk": (
|
57 |
+
"neonpunk style {prompt} . cyberpunk, vaporwave, neon, vibes, vibrant, stunningly beautiful, crisp, detailed, sleek, ultramodern, magenta highlights, dark purple shadows, high contrast, cinematic, ultra detailed, intricate, professional",
|
58 |
+
"painting, drawing, illustration, glitch, deformed, mutated, cross-eyed, ugly, disfigured"
|
59 |
+
),
|
60 |
+
"3D Model": (
|
61 |
+
"professional 3d model {prompt} . octane render, highly detailed, volumetric, dramatic lighting",
|
62 |
+
"ugly, deformed, noisy, low poly, blurry, painting"
|
63 |
+
)
|
64 |
+
}
|
65 |
+
positive, neg = style_dict.get(style_name, style_dict["(No style)"])
|
66 |
+
return positive.replace("{prompt}", prompt), neg + (negative or "")
|
67 |
+
|
68 |
+
# Function to call the Gradio backend
|
69 |
+
def generate_images(prompt, negative_prompt, guidance_scale, style_name):
|
70 |
+
try:
|
71 |
+
# Apply style to prompt and negative prompt
|
72 |
+
styled_prompt, styled_negative = apply_style(style_name, prompt, negative_prompt)
|
73 |
+
|
74 |
+
# Prepare payload (mimicking Gradio's infer function)
|
75 |
+
payload = {
|
76 |
+
"data": [
|
77 |
+
styled_prompt,
|
78 |
+
styled_negative,
|
79 |
+
guidance_scale,
|
80 |
+
style_name
|
81 |
+
]
|
82 |
+
}
|
83 |
+
|
84 |
+
# Send request to Gradio backend
|
85 |
+
start_time = time.time()
|
86 |
+
response = requests.post(BACKEND_URL, json=payload, timeout=60)
|
87 |
+
elapsed_time = time.time() - start_time
|
88 |
+
|
89 |
+
# Check response
|
90 |
+
if response.status_code != 200:
|
91 |
+
st.error(f"Error: Received status code {response.status_code}")
|
92 |
+
return None
|
93 |
+
|
94 |
+
# Parse response
|
95 |
+
json_data = response.json()
|
96 |
+
if "data" not in json_data or not json_data["data"]:
|
97 |
+
st.error("Error: No images returned from the backend.")
|
98 |
+
return None
|
99 |
+
|
100 |
+
# Extract images (assuming base64 strings)
|
101 |
+
images = []
|
102 |
+
for img_data in json_data["data"][0]: # Adjust based on actual response structure
|
103 |
+
if isinstance(img_data, str) and img_data.startswith("data:image"):
|
104 |
+
img_base64 = img_data.split(",")[1]
|
105 |
+
img_bytes = base64.b64decode(img_base64)
|
106 |
+
img = Image.open(BytesIO(img_bytes))
|
107 |
+
images.append(img)
|
108 |
+
else:
|
109 |
+
st.warning("Unexpected image data format.")
|
110 |
+
|
111 |
+
st.success(f"Images generated in {elapsed_time:.2f} seconds!")
|
112 |
+
return images
|
113 |
+
|
114 |
+
except requests.exceptions.RequestException as e:
|
115 |
+
st.error(f"Network error: {str(e)}")
|
116 |
+
return None
|
117 |
+
except ValueError as e:
|
118 |
+
st.error(f"Error decoding response: {str(e)}")
|
119 |
+
return None
|
120 |
+
except Exception as e:
|
121 |
+
st.error(f"Unexpected error: {str(e)}")
|
122 |
+
return None
|
123 |
+
|
124 |
+
# Streamlit UI components
|
125 |
+
with st.form(key="input_form"):
|
126 |
+
prompt = st.text_input("Enter your prompt", placeholder="A serious capybara at work, wearing a suit")
|
127 |
+
negative_prompt = st.text_input("Negative prompt (optional)", placeholder="low_quality")
|
128 |
+
guidance_scale = st.slider("Guidance Scale", min_value=0.0, max_value=50.0, value=7.5, step=0.1)
|
129 |
+
style_name = st.selectbox("Image Style", options=STYLE_OPTIONS, index=0)
|
130 |
+
submit_button = st.form_submit_button("Generate Images")
|
131 |
+
|
132 |
+
# Handle form submission
|
133 |
+
if submit_button:
|
134 |
+
if not prompt:
|
135 |
+
st.error("Please enter a prompt.")
|
136 |
+
else:
|
137 |
+
with st.spinner("Generating images..."):
|
138 |
+
images = generate_images(prompt, negative_prompt, guidance_scale, style_name)
|
139 |
+
if images:
|
140 |
+
# Display images in a gallery
|
141 |
+
st.subheader("Generated Images")
|
142 |
+
cols = st.columns(min(len(images), 3)) # Adjust columns based on number of images
|
143 |
+
for idx, img in enumerate(images):
|
144 |
+
with cols[idx % 3]:
|
145 |
+
st.image(img, use_column_width=True)
|