working system
Browse files- Project.md +10 -0
- api.py +22 -10
- api_example.py +39 -13
- app.py +13 -11
- config.py +9 -2
Project.md
CHANGED
@@ -9,6 +9,7 @@ A Python application that uses Hugging Face inference endpoints for text-to-imag
|
|
9 |
- Gradio UI for interactive use
|
10 |
- API endpoints for integration with other applications
|
11 |
- Configurable models via text input
|
|
|
12 |
|
13 |
## Project Structure
|
14 |
|
@@ -37,6 +38,15 @@ A Python application that uses Hugging Face inference endpoints for text-to-imag
|
|
37 |
- `POST /text-to-image` - Generate an image from text
|
38 |
- `POST /image-to-image` - Transform an image with optional prompt
|
39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
## Environment Variables
|
41 |
|
42 |
- `HF_TOKEN` - Your Hugging Face API token
|
|
|
9 |
- Gradio UI for interactive use
|
10 |
- API endpoints for integration with other applications
|
11 |
- Configurable models via text input
|
12 |
+
- Default values for prompts, negative prompts, and models
|
13 |
|
14 |
## Project Structure
|
15 |
|
|
|
38 |
- `POST /text-to-image` - Generate an image from text
|
39 |
- `POST /image-to-image` - Transform an image with optional prompt
|
40 |
|
41 |
+
## Default Values
|
42 |
+
|
43 |
+
The application includes defaults for:
|
44 |
+
- Sample prompts for text-to-image and image-to-image
|
45 |
+
- Negative prompts to exclude unwanted elements
|
46 |
+
- Pre-filled model names for both text-to-image and image-to-image
|
47 |
+
|
48 |
+
These defaults are applied to both the Gradio UI and API endpoints for consistency.
|
49 |
+
|
50 |
## Environment Variables
|
51 |
|
52 |
- `HF_TOKEN` - Your Hugging Face API token
|
api.py
CHANGED
@@ -17,9 +17,9 @@ async def root():
|
|
17 |
|
18 |
@app.post("/text-to-image")
|
19 |
async def text_to_image(
|
20 |
-
prompt: str = Form(
|
21 |
-
model: str = Form(
|
22 |
-
negative_prompt: str = Form(
|
23 |
guidance_scale: float = Form(7.5),
|
24 |
num_inference_steps: int = Form(50)
|
25 |
):
|
@@ -27,10 +27,14 @@ async def text_to_image(
|
|
27 |
Generate an image from a text prompt
|
28 |
"""
|
29 |
try:
|
30 |
-
# Use default model if not specified
|
31 |
-
if not model:
|
32 |
model = config.DEFAULT_TEXT2IMG_MODEL
|
33 |
|
|
|
|
|
|
|
|
|
34 |
# Call the inference module
|
35 |
image = inference.text_to_image(
|
36 |
prompt=prompt,
|
@@ -52,9 +56,9 @@ async def text_to_image(
|
|
52 |
@app.post("/image-to-image")
|
53 |
async def image_to_image(
|
54 |
image: UploadFile = File(...),
|
55 |
-
prompt: str = Form(
|
56 |
-
model: str = Form(
|
57 |
-
negative_prompt: str = Form(
|
58 |
guidance_scale: float = Form(7.5),
|
59 |
num_inference_steps: int = Form(50)
|
60 |
):
|
@@ -66,10 +70,18 @@ async def image_to_image(
|
|
66 |
contents = await image.read()
|
67 |
input_image = Image.open(io.BytesIO(contents))
|
68 |
|
69 |
-
# Use default model if not specified
|
70 |
-
if not model:
|
71 |
model = config.DEFAULT_IMG2IMG_MODEL
|
72 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
# Call the inference module
|
74 |
result = inference.image_to_image(
|
75 |
image=input_image,
|
|
|
17 |
|
18 |
@app.post("/text-to-image")
|
19 |
async def text_to_image(
|
20 |
+
prompt: str = Form(config.DEFAULT_TEXT2IMG_PROMPT),
|
21 |
+
model: str = Form(config.DEFAULT_TEXT2IMG_MODEL),
|
22 |
+
negative_prompt: str = Form(config.DEFAULT_NEGATIVE_PROMPT),
|
23 |
guidance_scale: float = Form(7.5),
|
24 |
num_inference_steps: int = Form(50)
|
25 |
):
|
|
|
27 |
Generate an image from a text prompt
|
28 |
"""
|
29 |
try:
|
30 |
+
# Use default model if not specified or empty
|
31 |
+
if not model or model.strip() == '':
|
32 |
model = config.DEFAULT_TEXT2IMG_MODEL
|
33 |
|
34 |
+
# Use default negative prompt if not specified or empty
|
35 |
+
if not negative_prompt or negative_prompt.strip() == '':
|
36 |
+
negative_prompt = config.DEFAULT_NEGATIVE_PROMPT
|
37 |
+
|
38 |
# Call the inference module
|
39 |
image = inference.text_to_image(
|
40 |
prompt=prompt,
|
|
|
56 |
@app.post("/image-to-image")
|
57 |
async def image_to_image(
|
58 |
image: UploadFile = File(...),
|
59 |
+
prompt: str = Form(config.DEFAULT_IMG2IMG_PROMPT),
|
60 |
+
model: str = Form(config.DEFAULT_IMG2IMG_MODEL),
|
61 |
+
negative_prompt: str = Form(config.DEFAULT_NEGATIVE_PROMPT),
|
62 |
guidance_scale: float = Form(7.5),
|
63 |
num_inference_steps: int = Form(50)
|
64 |
):
|
|
|
70 |
contents = await image.read()
|
71 |
input_image = Image.open(io.BytesIO(contents))
|
72 |
|
73 |
+
# Use default model if not specified or empty
|
74 |
+
if not model or model.strip() == '':
|
75 |
model = config.DEFAULT_IMG2IMG_MODEL
|
76 |
|
77 |
+
# Use default prompt if not specified or empty
|
78 |
+
if not prompt or prompt.strip() == '':
|
79 |
+
prompt = config.DEFAULT_IMG2IMG_PROMPT
|
80 |
+
|
81 |
+
# Use default negative prompt if not specified or empty
|
82 |
+
if not negative_prompt or negative_prompt.strip() == '':
|
83 |
+
negative_prompt = config.DEFAULT_NEGATIVE_PROMPT
|
84 |
+
|
85 |
# Call the inference module
|
86 |
result = inference.image_to_image(
|
87 |
image=input_image,
|
api_example.py
CHANGED
@@ -13,22 +13,31 @@ HF_TOKEN = os.getenv("HF_TOKEN")
|
|
13 |
# API base URL
|
14 |
API_BASE = "http://localhost:8000"
|
15 |
|
16 |
-
def text_to_image(prompt, model=None, negative_prompt=None):
|
17 |
"""
|
18 |
Generate image from text using the API
|
|
|
19 |
"""
|
20 |
url = f"{API_BASE}/text-to-image"
|
21 |
|
22 |
-
# Prepare form data
|
23 |
-
|
24 |
-
|
25 |
-
|
|
|
|
|
26 |
|
27 |
-
if model:
|
28 |
data["model"] = model
|
29 |
|
30 |
-
if negative_prompt:
|
31 |
data["negative_prompt"] = negative_prompt
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
|
33 |
# Make API request
|
34 |
response = requests.post(url, data=data)
|
@@ -42,20 +51,33 @@ def text_to_image(prompt, model=None, negative_prompt=None):
|
|
42 |
print(response.text)
|
43 |
return None
|
44 |
|
45 |
-
def image_to_image(image_path, prompt=None, model=None
|
|
|
46 |
"""
|
47 |
Transform image using the API
|
|
|
48 |
"""
|
49 |
url = f"{API_BASE}/image-to-image"
|
50 |
|
51 |
-
# Prepare form data
|
52 |
data = {}
|
53 |
-
|
|
|
54 |
data["prompt"] = prompt
|
55 |
|
56 |
-
if model:
|
57 |
data["model"] = model
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
|
|
|
59 |
files = {
|
60 |
"image": open(image_path, "rb")
|
61 |
}
|
@@ -75,14 +97,18 @@ def image_to_image(image_path, prompt=None, model=None):
|
|
75 |
if __name__ == "__main__":
|
76 |
# Example usage
|
77 |
print("Text to Image example:")
|
78 |
-
|
|
|
79 |
if image:
|
80 |
image.save("text2img_output.png")
|
81 |
print("Image saved as text2img_output.png")
|
82 |
|
|
|
|
|
|
|
83 |
print("Image to Image example (requires an input image):")
|
84 |
# Uncomment and modify path to run:
|
85 |
-
# result = image_to_image("input.png"
|
86 |
# if result:
|
87 |
# result.save("img2img_output.png")
|
88 |
# print("Image saved as img2img_output.png")
|
|
|
13 |
# API base URL
|
14 |
API_BASE = "http://localhost:8000"
|
15 |
|
16 |
+
def text_to_image(prompt=None, model=None, negative_prompt=None, guidance_scale=None, num_inference_steps=None):
|
17 |
"""
|
18 |
Generate image from text using the API
|
19 |
+
All parameters are optional and will use server defaults if not provided
|
20 |
"""
|
21 |
url = f"{API_BASE}/text-to-image"
|
22 |
|
23 |
+
# Prepare form data - only add parameters that are provided
|
24 |
+
# (otherwise use server defaults)
|
25 |
+
data = {}
|
26 |
+
|
27 |
+
if prompt is not None:
|
28 |
+
data["prompt"] = prompt
|
29 |
|
30 |
+
if model is not None:
|
31 |
data["model"] = model
|
32 |
|
33 |
+
if negative_prompt is not None:
|
34 |
data["negative_prompt"] = negative_prompt
|
35 |
+
|
36 |
+
if guidance_scale is not None:
|
37 |
+
data["guidance_scale"] = guidance_scale
|
38 |
+
|
39 |
+
if num_inference_steps is not None:
|
40 |
+
data["num_inference_steps"] = num_inference_steps
|
41 |
|
42 |
# Make API request
|
43 |
response = requests.post(url, data=data)
|
|
|
51 |
print(response.text)
|
52 |
return None
|
53 |
|
54 |
+
def image_to_image(image_path, prompt=None, model=None, negative_prompt=None,
|
55 |
+
guidance_scale=None, num_inference_steps=None):
|
56 |
"""
|
57 |
Transform image using the API
|
58 |
+
Only image_path is required, other parameters are optional and will use server defaults
|
59 |
"""
|
60 |
url = f"{API_BASE}/image-to-image"
|
61 |
|
62 |
+
# Prepare form data - only add parameters that are provided
|
63 |
data = {}
|
64 |
+
|
65 |
+
if prompt is not None:
|
66 |
data["prompt"] = prompt
|
67 |
|
68 |
+
if model is not None:
|
69 |
data["model"] = model
|
70 |
+
|
71 |
+
if negative_prompt is not None:
|
72 |
+
data["negative_prompt"] = negative_prompt
|
73 |
+
|
74 |
+
if guidance_scale is not None:
|
75 |
+
data["guidance_scale"] = guidance_scale
|
76 |
+
|
77 |
+
if num_inference_steps is not None:
|
78 |
+
data["num_inference_steps"] = num_inference_steps
|
79 |
|
80 |
+
# Prepare the image file
|
81 |
files = {
|
82 |
"image": open(image_path, "rb")
|
83 |
}
|
|
|
97 |
if __name__ == "__main__":
|
98 |
# Example usage
|
99 |
print("Text to Image example:")
|
100 |
+
# Can call without arguments to use server defaults
|
101 |
+
image = text_to_image()
|
102 |
if image:
|
103 |
image.save("text2img_output.png")
|
104 |
print("Image saved as text2img_output.png")
|
105 |
|
106 |
+
# Or with specific parameters
|
107 |
+
# image = text_to_image("A beautiful mountain landscape at sunset")
|
108 |
+
|
109 |
print("Image to Image example (requires an input image):")
|
110 |
# Uncomment and modify path to run:
|
111 |
+
# result = image_to_image("input.png") # Uses default prompt
|
112 |
# if result:
|
113 |
# result.save("img2img_output.png")
|
114 |
# print("Image saved as img2img_output.png")
|
app.py
CHANGED
@@ -12,7 +12,8 @@ def text_to_image_fn(prompt, model, negative_prompt=None, guidance_scale=7.5, nu
|
|
12 |
Handle text to image generation request
|
13 |
"""
|
14 |
try:
|
15 |
-
if
|
|
|
16 |
model = config.DEFAULT_TEXT2IMG_MODEL
|
17 |
|
18 |
# Call the inference module
|
@@ -40,12 +41,13 @@ def image_to_image_fn(image, prompt, model, negative_prompt=None, guidance_scale
|
|
40 |
if image is None:
|
41 |
return None, "No input image provided."
|
42 |
|
43 |
-
if
|
|
|
44 |
model = config.DEFAULT_IMG2IMG_MODEL
|
45 |
|
46 |
-
# Handle empty prompt
|
47 |
-
if prompt == "":
|
48 |
-
prompt =
|
49 |
|
50 |
try:
|
51 |
# Call the inference module with explicit parameters
|
@@ -77,9 +79,9 @@ with gr.Blocks(title="Diffusion Models") as app:
|
|
77 |
with gr.Tab("Text to Image"):
|
78 |
with gr.Row():
|
79 |
with gr.Column():
|
80 |
-
txt2img_prompt = gr.Textbox(label="Prompt", placeholder="Enter your prompt here...")
|
81 |
-
txt2img_negative = gr.Textbox(label="Negative Prompt (Optional)", placeholder="What to exclude from the image")
|
82 |
-
txt2img_model = gr.Textbox(label="Model", placeholder=f"Enter model name
|
83 |
txt2img_guidance = gr.Slider(minimum=1.0, maximum=20.0, value=7.5, step=0.5, label="Guidance Scale")
|
84 |
txt2img_steps = gr.Slider(minimum=10, maximum=100, value=50, step=1, label="Inference Steps")
|
85 |
txt2img_button = gr.Button("Generate Image")
|
@@ -98,9 +100,9 @@ with gr.Blocks(title="Diffusion Models") as app:
|
|
98 |
with gr.Row():
|
99 |
with gr.Column():
|
100 |
img2img_input = gr.Image(type="pil", label="Input Image")
|
101 |
-
img2img_prompt = gr.Textbox(label="Prompt", placeholder="Enter your prompt here...")
|
102 |
-
img2img_negative = gr.Textbox(label="Negative Prompt (Optional)", placeholder="What to exclude from the image")
|
103 |
-
img2img_model = gr.Textbox(label="Model", placeholder=f"Enter model name
|
104 |
img2img_guidance = gr.Slider(minimum=1.0, maximum=20.0, value=7.5, step=0.5, label="Guidance Scale")
|
105 |
img2img_steps = gr.Slider(minimum=10, maximum=100, value=50, step=1, label="Inference Steps")
|
106 |
img2img_button = gr.Button("Transform Image")
|
|
|
12 |
Handle text to image generation request
|
13 |
"""
|
14 |
try:
|
15 |
+
# Model validation - fallback to default if empty
|
16 |
+
if not model or model.strip() == '':
|
17 |
model = config.DEFAULT_TEXT2IMG_MODEL
|
18 |
|
19 |
# Call the inference module
|
|
|
41 |
if image is None:
|
42 |
return None, "No input image provided."
|
43 |
|
44 |
+
# Model validation - fallback to default if empty
|
45 |
+
if not model or model.strip() == '':
|
46 |
model = config.DEFAULT_IMG2IMG_MODEL
|
47 |
|
48 |
+
# Handle empty prompt - use default if completely empty
|
49 |
+
if prompt is None or prompt.strip() == "":
|
50 |
+
prompt = config.DEFAULT_IMG2IMG_PROMPT
|
51 |
|
52 |
try:
|
53 |
# Call the inference module with explicit parameters
|
|
|
79 |
with gr.Tab("Text to Image"):
|
80 |
with gr.Row():
|
81 |
with gr.Column():
|
82 |
+
txt2img_prompt = gr.Textbox(label="Prompt", placeholder="Enter your prompt here...", value=config.DEFAULT_TEXT2IMG_PROMPT)
|
83 |
+
txt2img_negative = gr.Textbox(label="Negative Prompt (Optional)", placeholder="What to exclude from the image", value=config.DEFAULT_NEGATIVE_PROMPT)
|
84 |
+
txt2img_model = gr.Textbox(label="Model", placeholder=f"Enter model name", value=config.DEFAULT_TEXT2IMG_MODEL)
|
85 |
txt2img_guidance = gr.Slider(minimum=1.0, maximum=20.0, value=7.5, step=0.5, label="Guidance Scale")
|
86 |
txt2img_steps = gr.Slider(minimum=10, maximum=100, value=50, step=1, label="Inference Steps")
|
87 |
txt2img_button = gr.Button("Generate Image")
|
|
|
100 |
with gr.Row():
|
101 |
with gr.Column():
|
102 |
img2img_input = gr.Image(type="pil", label="Input Image")
|
103 |
+
img2img_prompt = gr.Textbox(label="Prompt", placeholder="Enter your prompt here...", value=config.DEFAULT_IMG2IMG_PROMPT)
|
104 |
+
img2img_negative = gr.Textbox(label="Negative Prompt (Optional)", placeholder="What to exclude from the image", value=config.DEFAULT_NEGATIVE_PROMPT)
|
105 |
+
img2img_model = gr.Textbox(label="Model", placeholder=f"Enter model name", value=config.DEFAULT_IMG2IMG_MODEL)
|
106 |
img2img_guidance = gr.Slider(minimum=1.0, maximum=20.0, value=7.5, step=0.5, label="Guidance Scale")
|
107 |
img2img_steps = gr.Slider(minimum=10, maximum=100, value=50, step=1, label="Inference Steps")
|
108 |
img2img_button = gr.Button("Transform Image")
|
config.py
CHANGED
@@ -8,10 +8,17 @@ load_dotenv()
|
|
8 |
HF_TOKEN = os.getenv("HF_TOKEN", "")
|
9 |
|
10 |
# Default model for text to image
|
11 |
-
DEFAULT_TEXT2IMG_MODEL = "stabilityai/stable-diffusion-
|
12 |
|
13 |
# Default model for image to image
|
14 |
-
DEFAULT_IMG2IMG_MODEL = "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
16 |
# API settings
|
17 |
API_HOST = os.getenv("API_HOST", "0.0.0.0")
|
|
|
8 |
HF_TOKEN = os.getenv("HF_TOKEN", "")
|
9 |
|
10 |
# Default model for text to image
|
11 |
+
DEFAULT_TEXT2IMG_MODEL = "stabilityai/stable-diffusion-3-medium-diffusers"
|
12 |
|
13 |
# Default model for image to image
|
14 |
+
DEFAULT_IMG2IMG_MODEL = "stabilityai/stable-diffusion-xl-refiner-1.0"
|
15 |
+
|
16 |
+
# Default prompts - used as placeholders in UI and defaults in API
|
17 |
+
DEFAULT_TEXT2IMG_PROMPT = "A beautiful landscape with mountains and a lake"
|
18 |
+
DEFAULT_IMG2IMG_PROMPT = "Transform this image with fantasy elements"
|
19 |
+
|
20 |
+
# Default negative prompts - used to improve image quality by avoiding common issues
|
21 |
+
DEFAULT_NEGATIVE_PROMPT = "blurry, low quality, distorted, deformed, ugly, pixelated, noise, grain, text, watermark, poor composition, bad proportions, disfigured, mutation, mutated, extra limbs, extra fingers, fused fingers, malformed hands, poorly drawn face, bad anatomy, amateur drawing, low resolution, duplicate, cropped, out of frame, worst quality, jpeg artifacts, compression artifacts, glitch, overexposed, underexposed, low contrast, washed out colors, oversaturated, signature, username, artist name, logo, unnatural lighting, uneven lighting, harsh shadows, motion blur, out of focus, chromatic aberration, film grain, scratches, stains, dark spots, light leaks, fuzzy edges, jagged edges, broken lines, stretched image, elongated features, asymmetrical eyes, misaligned features, missing details, incomplete rendering"
|
22 |
|
23 |
# API settings
|
24 |
API_HOST = os.getenv("API_HOST", "0.0.0.0")
|