File size: 6,227 Bytes
114c45d
1307279
114c45d
 
b253396
 
1307279
b253396
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf5a25f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b253396
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3c20bbd
b253396
3c20bbd
b253396
3c20bbd
 
 
b253396
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6c59c0b
114c45d
 
 
 
 
f12470b
114c45d
6c59c0b
 
114c45d
 
b253396
 
6c59c0b
b253396
114c45d
 
f12470b
114c45d
 
f12470b
6c59c0b
114c45d
 
 
6c59c0b
114c45d
 
 
 
 
 
 
 
 
 
 
 
 
44ad335
 
114c45d
f12470b
114c45d
 
 
 
 
 
3c20bbd
114c45d
f12470b
 
114c45d
 
 
 
 
 
 
 
 
f12470b
 
b253396
 
114c45d
 
6c59c0b
114c45d
6c59c0b
 
f12470b
114c45d
 
f12470b
114c45d
 
 
 
 
 
 
 
 
586a4a6
114c45d
 
 
f12470b
114c45d
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
import os
import gradio as gr
from PIL import Image
import io
import requests
from typing import Optional, Tuple

def load_environment():
    """
    Attempt to load environment variables with error handling.
    
    Returns:
        Optional[str]: Hugging Face Token or None
    """
    try:
        from dotenv import load_dotenv
        load_dotenv()
    except ImportError:
        print("python-dotenv not installed. Ensure HF_TOKEN is set in environment.")
    
    return os.getenv("HF_TOKEN")

def craft_realistic_prompt(base_prompt: str) -> str:
    """
    Enhance prompts for more photorealistic results
    
    Args:
        base_prompt (str): Original user prompt
    
    Returns:
        str: Enhanced, detailed prompt
    """
    realistic_modifiers = [
        "photorealistic",
        "high resolution",
        "sharp focus",
        "professional photography",
        "natural lighting",
        "detailed textures"
    ]
    
    # Combine base prompt with realistic modifiers
    enhanced_prompt = f"{' '.join(realistic_modifiers)}, {base_prompt}, shot on professional camera, 8k resolution"
    
    return enhanced_prompt

def query_hf_api(
    prompt: str, 
    model_url: str = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0",
    max_retries: int = 3
) -> Optional[bytes]:
    """
    Query the Hugging Face Inference API with robust error handling and retry mechanism.
    
    Args:
        prompt (str): Text prompt for image generation
        model_url (str): URL of the Hugging Face model
        max_retries (int): Maximum number of retry attempts
    
    Returns:
        Optional[bytes]: Generated image bytes or None
    """
    # Validate inputs
    if not prompt or not prompt.strip():
        raise ValueError("Prompt cannot be empty")
    
    # Load token
    HF_TOKEN = load_environment()
    if not HF_TOKEN:
        raise ValueError("Hugging Face token not found. Set HF_TOKEN in .env or environment variables.")
    
    # Prepare headers
    headers = {
        "Authorization": f"Bearer {HF_TOKEN}",
        "Content-Type": "application/json"
    }
    
    # Payload with enhanced configuration for realism
    payload = {
        "inputs": craft_realistic_prompt(prompt),
        "parameters": {
            "negative_prompt": "cartoon, anime, low quality, bad anatomy, blurry, unrealistic, painting, drawing, sketch",
            "num_inference_steps": 75,  # Increased steps
            "guidance_scale": 8.5,      # Higher guidance
        }
    }
    
    # Retry mechanism
    for attempt in range(max_retries):
        try:
            response = requests.post(
                model_url, 
                headers=headers, 
                json=payload,
                timeout=120  # 2-minute timeout
            )
            
            response.raise_for_status()  # Raise exception for bad status codes
            
            return response.content
        
        except requests.exceptions.RequestException as e:
            print(f"Request error (Attempt {attempt + 1}/{max_retries}): {e}")
            
            if attempt == max_retries - 1:
                raise RuntimeError(f"Failed to generate image after {max_retries} attempts: {e}")

    raise RuntimeError("Unexpected error in image generation")

def generate_image(prompt: str) -> Tuple[Optional[Image.Image], str]:
    """
    Generate an image from a text prompt.
    
    Args:
        prompt (str): Text description for image generation
    
    Returns:
        Tuple[Optional[Image.Image], str]: 
        Generated PIL Image and status message
    """
    try:
        # Validate prompt
        if not prompt or not prompt.strip():
            return None, "Error: Prompt cannot be empty"
        
        # Generate image bytes
        image_bytes = query_hf_api(prompt)
        
        # Convert to PIL Image
        image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
        
        return image, "Image generated successfully!"
    
    except Exception as e:
        print(f"Image generation error: {e}")
        return None, f"Error: {str(e)}"

def create_gradio_interface():
    """
    Create and configure the Gradio interface.
    
    Returns:
        gr.Blocks: Configured Gradio interface
    """
    with gr.Blocks(
        theme=gr.themes.Soft(), 
        title="🎨 AI Image Generator"
    ) as demo:
        # Title and Description
        gr.Markdown("# 🎨 AI Image Generator ")
        gr.Markdown("This webapp is created with ❀ by Sumit Yadav as GenAI project. Credits to HuggingFace Spaces and StabilityAI")
        gr.Markdown("Generate stunning images from your text prompts using AI!")
        
        # Input and Output Components
        with gr.Row():
            with gr.Column(scale=3):
                # Prompt Input
                text_input = gr.Textbox(
                    label="Enter your image prompt", 
                    placeholder="e.g., 'Photorealistic portrait of a woman in natural light'",
                    lines=3
                )
                
                # Generate Button
                generate_button = gr.Button("✨ Generate Image", variant="primary")
            
            # Output Image Display
            with gr.Column(scale=4):
                output_image = gr.Image(
                    label="Generated Image", 
                    type="pil", 
                    interactive=False
                )
        
        # Status Output
        status_output = gr.Textbox(label="Status")
        
        # Event Handlers
        generate_button.click(
            fn=generate_image,
            inputs=[text_input],
            outputs=[output_image, status_output]
        )
    
    return demo

def main():
    """
    Main entry point for the Gradio application.
    """
    try:
        demo = create_gradio_interface()
        demo.launch(
            server_name="0.0.0.0",  # Listen on all network interfaces
            server_port=7860,  # Default Gradio port
            share=True  # Set to True for a public link
        )
    except Exception as e:
        print(f"Error launching Gradio app: {e}")

if __name__ == "__main__":
    main()