File size: 6,233 Bytes
aa52cca
 
 
 
 
e14c7dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aa52cca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ce426de
 
 
 
 
 
588d12a
 
 
 
 
ce426de
588d12a
 
 
 
 
b7a086c
aa52cca
 
 
 
 
 
 
 
 
 
 
ce426de
 
 
 
 
 
aa52cca
ce426de
aa52cca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f02c7c0
aa52cca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83289b3
 
 
 
aa52cca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
feb3cd8
 
aa52cca
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
203
204
205
206
207
208
209
210
"""
Indian Art SD LoRA API
Main application entry point
Optimized for HuggingFace Spaces ZeroGPU
"""
import gradio_client.utils as client_utils
import functools

_original_json_schema_to_python_type = client_utils._json_schema_to_python_type

@functools.wraps(_original_json_schema_to_python_type)
def _patched_json_schema_to_python_type(schema, defs=None):
    # Handle bool schema case that causes "argument of type 'bool' is not iterable"
    if isinstance(schema, bool):
        return "Any"
    # Handle case where schema might be None or other non-dict types
    if schema is None:
        return "Any"
    if not isinstance(schema, dict):
        return str(type(schema).__name__)
    return _original_json_schema_to_python_type(schema, defs)

client_utils._json_schema_to_python_type = _patched_json_schema_to_python_type
# Also patch the public function if it exists
if hasattr(client_utils, 'json_schema_to_python_type'):
    client_utils.json_schema_to_python_type = _patched_json_schema_to_python_type

import os
import sys
import json
import gradio as gr
from PIL import Image

# Add src to path
sys.path.insert(0, os.path.dirname(__file__))

from src.config import Config
from src.model import IndianArtGenerator
from src.utils import ensure_directories

# Global generator instance
generator = IndianArtGenerator()

# Hardcoded generation settings
DEFAULT_WIDTH = 512
DEFAULT_HEIGHT = 512
DEFAULT_STEPS = 30
DEFAULT_GUIDANCE = 7.5
DEFAULT_LORA_SCALE = 0.8
DEFAULT_SEED = -1  # Random


# def get_generator():
#     """Lazy initialization of model"""
#     if generator.pipe is None:
#         generator.load_model()
#     return generator

try:
    import spaces
    ZERO_GPU_AVAILABLE = True
except ImportError:
    ZERO_GPU_AVAILABLE = False

def conditional_gpu_decorator(fn):
    if ZERO_GPU_AVAILABLE:
        return spaces.GPU(duration=60)(fn)
    return fn

@conditional_gpu_decorator
def generate_api(prompt: str, art_style: str):
    """
    Generate image from prompt and art style.
    All generation parameters are hardcoded constants.
    """

    if not prompt or not prompt.strip():
        raise gr.Error("Prompt cannot be empty")
    if len(prompt) > 1000:
        raise gr.Error("Prompt too long (max 1000 chars)")

    # gen = get_generator()

    #Lazy-load inside GPU context, so ZEROGPU can map weights onto GPU
    if generator.pipe is None:
        generator.load_model() 
    

    image, metadata = generator.generate(
        prompt=prompt,
        negative_prompt="",  # Uses default negatives from config
        art_style=art_style,
        width=DEFAULT_WIDTH,
        height=DEFAULT_HEIGHT,
        num_inference_steps=DEFAULT_STEPS,
        guidance_scale=DEFAULT_GUIDANCE,
        lora_scale=DEFAULT_LORA_SCALE,
        seed=DEFAULT_SEED,
        num_images=1
    )

    return image, json.dumps(metadata, indent=2)


def create_ui():
    """Create minimal Gradio interface"""

    css = """
    .gradio-container {max-width: 800px !important;}
    .image-output {height: auto !important; max-height: 600px;}
    """

    with gr.Blocks(
        title="Indian Art Generator",
        theme=gr.themes.Soft(),
        css=css
    ) as demo:

        gr.Markdown("""
        <div style="text-align: center;">
        <h1>Indian Traditional Art Generator</h1>
        <p>Describe your scene and select an art style</p>
        </div>
        """)

        with gr.Row():
            with gr.Column(scale=1):
                prompt = gr.Textbox(
                    label="Prompt",
                    placeholder="peacock surrounded by floral patterns",
                    lines=3
                )

                art_style = gr.Dropdown(
                    choices=list(Config.ART_STYLES.keys()),
                    value="none",
                    label="Art Style Prefix",
                    info="Select a style to enhance your prompt, or 'none' for raw prompt"
                )

                generate_btn = gr.Button(
                    "Generate",
                    variant="primary",
                    size="lg"
                )

                # Hidden constants display
                with gr.Accordion("Generation Settings"):
                    gr.Markdown(f"""
                    - Resolution: {DEFAULT_WIDTH}x{DEFAULT_HEIGHT}
                    - Steps: {DEFAULT_STEPS}
                    - Guidance: {DEFAULT_GUIDANCE}
                    - LoRA Scale: {DEFAULT_LORA_SCALE}
                    - Seed: Random
                    """)

            with gr.Column(scale=1):
                output_image = gr.Image(
                    label="Generated Artwork",
                    type="pil",
                    elem_classes=["image-output"],
                    format="png"
                )

                output_metadata = gr.Textbox(
                    label="Metadata (JSON)",
                    lines=8,
                    interactive=False,
                )

        # Examples
        gr.Examples(
            examples=[
                ["peacock with elaborate geometric feathers", "madhubani"],
                ["village scene with farmers and traditional huts", "warli"],
                ["tiger in dense jungle with dotted patterns", "gond"],
                ["radha krishna under flowering tree", "pattachitra"],
                ["goddess lakshmi with gold ornaments", "tanjore"],
                ["elephant decorated for festival procession", "miniature"],
            ],
            inputs=[prompt, art_style],
            label="Example Prompts"
        )

        generate_btn.click(
            fn=generate_api,
            inputs=[prompt, art_style],
            outputs=[output_image, output_metadata]
        )

    return demo


if __name__ == "__main__":
    ensure_directories()
    Config.validate()

    print("Starting Indian Art Generator...")
    print(f"Base Model: {Config.BASE_MODEL}")
    print(f"LoRA Path: {Config.LORA_PATH or 'Not configured'}")
    print(f"Hardcoded settings: {DEFAULT_WIDTH}x{DEFAULT_HEIGHT}, {DEFAULT_STEPS} steps")

    demo = create_ui()

    demo.launch(
        server_name="0.0.0.0",
        server_port=int(os.getenv("PORT", 7860)),
        share=True,
        show_error=True,
    )