updated
Browse files
app.py
CHANGED
|
@@ -20,6 +20,44 @@ def load_environment():
|
|
| 20 |
|
| 21 |
return os.getenv("HF_TOKEN")
|
| 22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
def craft_realistic_prompt(base_prompt: str) -> str:
|
| 24 |
"""
|
| 25 |
Enhance prompts for more photorealistic results
|
|
@@ -49,16 +87,6 @@ def query_hf_api(
|
|
| 49 |
model_url: str = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0",
|
| 50 |
max_retries: int = 3
|
| 51 |
) -> Optional[bytes]:
|
| 52 |
-
|
| 53 |
-
# Enhanced configuration for realism
|
| 54 |
-
payload = {
|
| 55 |
-
"inputs": craft_realistic_prompt(prompt),
|
| 56 |
-
"parameters": {
|
| 57 |
-
"negative_prompt": "cartoon, anime, low quality, bad anatomy, blurry, unrealistic, painting, drawing, sketch",
|
| 58 |
-
"num_inference_steps": 75, # Increased steps
|
| 59 |
-
"guidance_scale": 8.5, # Higher guidance
|
| 60 |
-
}
|
| 61 |
-
}
|
| 62 |
"""
|
| 63 |
Query the Hugging Face Inference API with robust error handling and retry mechanism.
|
| 64 |
|
|
@@ -85,12 +113,13 @@ def query_hf_api(
|
|
| 85 |
"Content-Type": "application/json"
|
| 86 |
}
|
| 87 |
|
| 88 |
-
# Payload with
|
| 89 |
payload = {
|
| 90 |
-
"inputs": prompt,
|
| 91 |
"parameters": {
|
| 92 |
-
"negative_prompt": "low quality, bad anatomy, blurry",
|
| 93 |
-
"num_inference_steps":
|
|
|
|
| 94 |
}
|
| 95 |
}
|
| 96 |
|
|
@@ -116,20 +145,22 @@ def query_hf_api(
|
|
| 116 |
|
| 117 |
raise RuntimeError("Unexpected error in image generation")
|
| 118 |
|
| 119 |
-
def generate_image(prompt: str) -> Tuple[Optional[Image.Image], str]:
|
| 120 |
"""
|
| 121 |
Generate an image from a text prompt.
|
| 122 |
|
| 123 |
Args:
|
| 124 |
prompt (str): Text description for image generation
|
|
|
|
| 125 |
|
| 126 |
Returns:
|
| 127 |
-
Tuple[Optional[Image.Image], str]:
|
|
|
|
| 128 |
"""
|
| 129 |
try:
|
| 130 |
# Validate prompt
|
| 131 |
if not prompt or not prompt.strip():
|
| 132 |
-
return None, "Error: Prompt cannot be empty"
|
| 133 |
|
| 134 |
# Generate image bytes
|
| 135 |
image_bytes = query_hf_api(prompt)
|
|
@@ -137,11 +168,14 @@ def generate_image(prompt: str) -> Tuple[Optional[Image.Image], str]:
|
|
| 137 |
# Convert to PIL Image
|
| 138 |
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
|
| 139 |
|
| 140 |
-
|
|
|
|
|
|
|
|
|
|
| 141 |
|
| 142 |
except Exception as e:
|
| 143 |
print(f"Image generation error: {e}")
|
| 144 |
-
return None, f"Error: {str(e)}"
|
| 145 |
|
| 146 |
def create_gradio_interface():
|
| 147 |
"""
|
|
@@ -164,10 +198,17 @@ def create_gradio_interface():
|
|
| 164 |
# Prompt Input
|
| 165 |
text_input = gr.Textbox(
|
| 166 |
label="Enter your image prompt",
|
| 167 |
-
placeholder="e.g., '
|
| 168 |
lines=3
|
| 169 |
)
|
| 170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
# Generate Button
|
| 172 |
generate_button = gr.Button("✨ Generate Image", variant="primary")
|
| 173 |
|
|
@@ -182,12 +223,18 @@ def create_gradio_interface():
|
|
| 182 |
# Status Output
|
| 183 |
status_output = gr.Textbox(label="Status")
|
| 184 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 185 |
# Event Handlers
|
| 186 |
-
generate_button.click(
|
| 187 |
fn=generate_image,
|
| 188 |
-
inputs=[text_input],
|
| 189 |
-
outputs=[output_image, status_output]
|
| 190 |
-
api_name="generate"
|
| 191 |
)
|
| 192 |
|
| 193 |
return demo
|
|
|
|
| 20 |
|
| 21 |
return os.getenv("HF_TOKEN")
|
| 22 |
|
| 23 |
+
def convert_image(image: Image.Image, format: str = 'png') -> bytes:
|
| 24 |
+
"""
|
| 25 |
+
Convert PIL Image to specified format in memory.
|
| 26 |
+
|
| 27 |
+
Args:
|
| 28 |
+
image (Image.Image): Input PIL Image
|
| 29 |
+
format (str): Desired output format (png, jpg, webp)
|
| 30 |
+
|
| 31 |
+
Returns:
|
| 32 |
+
bytes: Image converted to specified format
|
| 33 |
+
"""
|
| 34 |
+
# Supported formats with their MIME types
|
| 35 |
+
supported_formats = {
|
| 36 |
+
'png': 'image/png',
|
| 37 |
+
'jpg': 'image/jpeg',
|
| 38 |
+
'jpeg': 'image/jpeg',
|
| 39 |
+
'webp': 'image/webp'
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
# Normalize format
|
| 43 |
+
format = format.lower()
|
| 44 |
+
|
| 45 |
+
# Validate format
|
| 46 |
+
if format not in supported_formats:
|
| 47 |
+
raise ValueError(f"Unsupported format. Choose from: {', '.join(supported_formats.keys())}")
|
| 48 |
+
|
| 49 |
+
# Convert image
|
| 50 |
+
byte_array = io.BytesIO()
|
| 51 |
+
|
| 52 |
+
# Special handling for JPEG to ensure no alpha channel
|
| 53 |
+
if format in ['jpg', 'jpeg']:
|
| 54 |
+
image = image.convert('RGB')
|
| 55 |
+
|
| 56 |
+
# Save image to byte array
|
| 57 |
+
image.save(byte_array, format=format)
|
| 58 |
+
|
| 59 |
+
return byte_array.getvalue()
|
| 60 |
+
|
| 61 |
def craft_realistic_prompt(base_prompt: str) -> str:
|
| 62 |
"""
|
| 63 |
Enhance prompts for more photorealistic results
|
|
|
|
| 87 |
model_url: str = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0",
|
| 88 |
max_retries: int = 3
|
| 89 |
) -> Optional[bytes]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
"""
|
| 91 |
Query the Hugging Face Inference API with robust error handling and retry mechanism.
|
| 92 |
|
|
|
|
| 113 |
"Content-Type": "application/json"
|
| 114 |
}
|
| 115 |
|
| 116 |
+
# Payload with enhanced configuration for realism
|
| 117 |
payload = {
|
| 118 |
+
"inputs": craft_realistic_prompt(prompt),
|
| 119 |
"parameters": {
|
| 120 |
+
"negative_prompt": "cartoon, anime, low quality, bad anatomy, blurry, unrealistic, painting, drawing, sketch",
|
| 121 |
+
"num_inference_steps": 75, # Increased steps
|
| 122 |
+
"guidance_scale": 8.5, # Higher guidance
|
| 123 |
}
|
| 124 |
}
|
| 125 |
|
|
|
|
| 145 |
|
| 146 |
raise RuntimeError("Unexpected error in image generation")
|
| 147 |
|
| 148 |
+
def generate_image(prompt: str, output_format: str = 'png') -> Tuple[Optional[Image.Image], str, Optional[bytes]]:
|
| 149 |
"""
|
| 150 |
Generate an image from a text prompt.
|
| 151 |
|
| 152 |
Args:
|
| 153 |
prompt (str): Text description for image generation
|
| 154 |
+
output_format (str): Desired output format
|
| 155 |
|
| 156 |
Returns:
|
| 157 |
+
Tuple[Optional[Image.Image], str, Optional[bytes]]:
|
| 158 |
+
Generated PIL Image, status message, and downloadable image bytes
|
| 159 |
"""
|
| 160 |
try:
|
| 161 |
# Validate prompt
|
| 162 |
if not prompt or not prompt.strip():
|
| 163 |
+
return None, "Error: Prompt cannot be empty", None
|
| 164 |
|
| 165 |
# Generate image bytes
|
| 166 |
image_bytes = query_hf_api(prompt)
|
|
|
|
| 168 |
# Convert to PIL Image
|
| 169 |
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
|
| 170 |
|
| 171 |
+
# Convert image to specified format
|
| 172 |
+
downloadable_image = convert_image(image, output_format)
|
| 173 |
+
|
| 174 |
+
return image, "Image generated successfully!", downloadable_image
|
| 175 |
|
| 176 |
except Exception as e:
|
| 177 |
print(f"Image generation error: {e}")
|
| 178 |
+
return None, f"Error: {str(e)}", None
|
| 179 |
|
| 180 |
def create_gradio_interface():
|
| 181 |
"""
|
|
|
|
| 198 |
# Prompt Input
|
| 199 |
text_input = gr.Textbox(
|
| 200 |
label="Enter your image prompt",
|
| 201 |
+
placeholder="e.g., 'Photorealistic portrait of a woman in natural light'",
|
| 202 |
lines=3
|
| 203 |
)
|
| 204 |
|
| 205 |
+
# Format Selection Dropdown
|
| 206 |
+
format_dropdown = gr.Dropdown(
|
| 207 |
+
choices=['PNG', 'JPEG', 'WebP'],
|
| 208 |
+
value='PNG',
|
| 209 |
+
label="Output Image Format"
|
| 210 |
+
)
|
| 211 |
+
|
| 212 |
# Generate Button
|
| 213 |
generate_button = gr.Button("✨ Generate Image", variant="primary")
|
| 214 |
|
|
|
|
| 223 |
# Status Output
|
| 224 |
status_output = gr.Textbox(label="Status")
|
| 225 |
|
| 226 |
+
# Download Button
|
| 227 |
+
download_button = gr.File(
|
| 228 |
+
label="Download Image",
|
| 229 |
+
file_count="single",
|
| 230 |
+
type="file"
|
| 231 |
+
)
|
| 232 |
+
|
| 233 |
# Event Handlers
|
| 234 |
+
generate_result = generate_button.click(
|
| 235 |
fn=generate_image,
|
| 236 |
+
inputs=[text_input, format_dropdown],
|
| 237 |
+
outputs=[output_image, status_output, download_button]
|
|
|
|
| 238 |
)
|
| 239 |
|
| 240 |
return demo
|