Abe
commited on
Commit
·
8247a04
1
Parent(s):
caf3333
initial copy
Browse files- .env.example +10 -0
- .gitignore +3 -0
- Project.md +46 -0
- api.py +98 -0
- api_example.py +88 -0
- app.py +100 -0
- config.py +22 -0
- inference.py +86 -0
- main.py +63 -0
- requirements.txt +6 -0
- spaces_config.json +23 -0
.env.example
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Hugging Face token
|
2 |
+
HF_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxxxxx
|
3 |
+
|
4 |
+
# API settings
|
5 |
+
API_HOST=0.0.0.0
|
6 |
+
API_PORT=8000
|
7 |
+
|
8 |
+
# Gradio settings
|
9 |
+
GRADIO_HOST=0.0.0.0
|
10 |
+
GRADIO_PORT=7860
|
.gitignore
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
.venv
|
2 |
+
*.pyc
|
3 |
+
__pycache__
|
Project.md
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Diffusion Models App
|
2 |
+
|
3 |
+
A Python application that uses Hugging Face inference endpoints for text-to-image and image-to-image generation with a Gradio UI and API endpoints.
|
4 |
+
|
5 |
+
## Features
|
6 |
+
|
7 |
+
- Text-to-image generation
|
8 |
+
- Image-to-image transformation with optional prompt
|
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 |
+
|
15 |
+
- `main.py` - Entry point that can run both UI and API
|
16 |
+
- `app.py` - Gradio UI implementation
|
17 |
+
- `api.py` - FastAPI server for API endpoints
|
18 |
+
- `inference.py` - Core functionality for HF inference
|
19 |
+
- `config.py` - Configuration and settings
|
20 |
+
- `requirements.txt` - Dependencies
|
21 |
+
|
22 |
+
## Setup & Usage
|
23 |
+
|
24 |
+
1. Clone the repository
|
25 |
+
2. Create a .env file with your Hugging Face token (copy from .env.example)
|
26 |
+
3. Install dependencies: `pip install -r requirements.txt`
|
27 |
+
4. Run the application: `python main.py`
|
28 |
+
|
29 |
+
## Running Options
|
30 |
+
|
31 |
+
- Run both UI and API: `python main.py`
|
32 |
+
- Run only the API: `python main.py --mode api`
|
33 |
+
- Run only the UI: `python main.py --mode ui`
|
34 |
+
|
35 |
+
## API Endpoints
|
36 |
+
|
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
|
43 |
+
- `API_HOST` - Host for the API server (default: 0.0.0.0)
|
44 |
+
- `API_PORT` - Port for the API server (default: 8000)
|
45 |
+
- `GRADIO_HOST` - Host for the Gradio UI (default: 0.0.0.0)
|
46 |
+
- `GRADIO_PORT` - Port for the Gradio UI (default: 7860)
|
api.py
ADDED
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI, File, UploadFile, Form, HTTPException
|
2 |
+
from fastapi.responses import Response
|
3 |
+
from PIL import Image
|
4 |
+
import io
|
5 |
+
import uvicorn
|
6 |
+
import config
|
7 |
+
from inference import DiffusionInference
|
8 |
+
|
9 |
+
app = FastAPI(title="Diffusion Models API")
|
10 |
+
|
11 |
+
# Initialize the inference class
|
12 |
+
inference = DiffusionInference()
|
13 |
+
|
14 |
+
@app.get("/")
|
15 |
+
async def root():
|
16 |
+
return {"message": "Diffusion Models API is running"}
|
17 |
+
|
18 |
+
@app.post("/text-to-image")
|
19 |
+
async def text_to_image(
|
20 |
+
prompt: str = Form(...),
|
21 |
+
model: str = Form(None),
|
22 |
+
negative_prompt: str = Form(None),
|
23 |
+
guidance_scale: float = Form(7.5),
|
24 |
+
num_inference_steps: int = Form(50)
|
25 |
+
):
|
26 |
+
"""
|
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,
|
37 |
+
model_name=model,
|
38 |
+
negative_prompt=negative_prompt,
|
39 |
+
guidance_scale=guidance_scale,
|
40 |
+
num_inference_steps=num_inference_steps
|
41 |
+
)
|
42 |
+
|
43 |
+
# Convert PIL image to bytes
|
44 |
+
img_byte_arr = io.BytesIO()
|
45 |
+
image.save(img_byte_arr, format='PNG')
|
46 |
+
img_byte_arr = img_byte_arr.getvalue()
|
47 |
+
|
48 |
+
return Response(content=img_byte_arr, media_type="image/png")
|
49 |
+
except Exception as e:
|
50 |
+
raise HTTPException(status_code=500, detail=str(e))
|
51 |
+
|
52 |
+
@app.post("/image-to-image")
|
53 |
+
async def image_to_image(
|
54 |
+
image: UploadFile = File(...),
|
55 |
+
prompt: str = Form(None),
|
56 |
+
model: str = Form(None),
|
57 |
+
negative_prompt: str = Form(None),
|
58 |
+
guidance_scale: float = Form(7.5),
|
59 |
+
num_inference_steps: int = Form(50)
|
60 |
+
):
|
61 |
+
"""
|
62 |
+
Generate a new image from an input image and optional prompt
|
63 |
+
"""
|
64 |
+
try:
|
65 |
+
# Read and convert input 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,
|
76 |
+
prompt=prompt,
|
77 |
+
model_name=model,
|
78 |
+
negative_prompt=negative_prompt,
|
79 |
+
guidance_scale=guidance_scale,
|
80 |
+
num_inference_steps=num_inference_steps
|
81 |
+
)
|
82 |
+
|
83 |
+
# Convert PIL image to bytes
|
84 |
+
img_byte_arr = io.BytesIO()
|
85 |
+
result.save(img_byte_arr, format='PNG')
|
86 |
+
img_byte_arr = img_byte_arr.getvalue()
|
87 |
+
|
88 |
+
return Response(content=img_byte_arr, media_type="image/png")
|
89 |
+
except Exception as e:
|
90 |
+
raise HTTPException(status_code=500, detail=str(e))
|
91 |
+
|
92 |
+
if __name__ == "__main__":
|
93 |
+
uvicorn.run(
|
94 |
+
"api:app",
|
95 |
+
host=config.API_HOST,
|
96 |
+
port=config.API_PORT,
|
97 |
+
reload=True
|
98 |
+
)
|
api_example.py
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import io
|
3 |
+
from PIL import Image
|
4 |
+
import os
|
5 |
+
from dotenv import load_dotenv
|
6 |
+
|
7 |
+
# Load environment variables from .env file
|
8 |
+
load_dotenv()
|
9 |
+
|
10 |
+
# Hugging Face API token (need to set in .env or environment)
|
11 |
+
HF_TOKEN = os.getenv("HF_TOKEN")
|
12 |
+
|
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 |
+
data = {
|
24 |
+
"prompt": prompt,
|
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)
|
35 |
+
|
36 |
+
if response.status_code == 200:
|
37 |
+
# Convert response to PIL image
|
38 |
+
image = Image.open(io.BytesIO(response.content))
|
39 |
+
return image
|
40 |
+
else:
|
41 |
+
print(f"Error: {response.status_code}")
|
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 and files
|
52 |
+
data = {}
|
53 |
+
if prompt:
|
54 |
+
data["prompt"] = prompt
|
55 |
+
|
56 |
+
if model:
|
57 |
+
data["model"] = model
|
58 |
+
|
59 |
+
files = {
|
60 |
+
"image": open(image_path, "rb")
|
61 |
+
}
|
62 |
+
|
63 |
+
# Make API request
|
64 |
+
response = requests.post(url, data=data, files=files)
|
65 |
+
|
66 |
+
if response.status_code == 200:
|
67 |
+
# Convert response to PIL image
|
68 |
+
image = Image.open(io.BytesIO(response.content))
|
69 |
+
return image
|
70 |
+
else:
|
71 |
+
print(f"Error: {response.status_code}")
|
72 |
+
print(response.text)
|
73 |
+
return None
|
74 |
+
|
75 |
+
if __name__ == "__main__":
|
76 |
+
# Example usage
|
77 |
+
print("Text to Image example:")
|
78 |
+
image = text_to_image("A beautiful mountain landscape at sunset")
|
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", "Turn this into a fantasy scene")
|
86 |
+
# if result:
|
87 |
+
# result.save("img2img_output.png")
|
88 |
+
# print("Image saved as img2img_output.png")
|
app.py
ADDED
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import config
|
3 |
+
from inference import DiffusionInference
|
4 |
+
from PIL import Image
|
5 |
+
import io
|
6 |
+
|
7 |
+
# Initialize the inference class
|
8 |
+
inference = DiffusionInference()
|
9 |
+
|
10 |
+
def text_to_image_fn(prompt, model, negative_prompt=None, guidance_scale=7.5, num_inference_steps=50):
|
11 |
+
"""
|
12 |
+
Handle text to image generation request
|
13 |
+
"""
|
14 |
+
try:
|
15 |
+
if not model:
|
16 |
+
model = config.DEFAULT_TEXT2IMG_MODEL
|
17 |
+
|
18 |
+
# Call the inference module
|
19 |
+
image = inference.text_to_image(
|
20 |
+
prompt=prompt,
|
21 |
+
model_name=model,
|
22 |
+
negative_prompt=negative_prompt,
|
23 |
+
guidance_scale=guidance_scale,
|
24 |
+
num_inference_steps=num_inference_steps
|
25 |
+
)
|
26 |
+
|
27 |
+
return image, None
|
28 |
+
except Exception as e:
|
29 |
+
return None, str(e)
|
30 |
+
|
31 |
+
def image_to_image_fn(image, prompt, model, negative_prompt=None, guidance_scale=7.5, num_inference_steps=50):
|
32 |
+
"""
|
33 |
+
Handle image to image transformation request
|
34 |
+
"""
|
35 |
+
try:
|
36 |
+
if not model:
|
37 |
+
model = config.DEFAULT_IMG2IMG_MODEL
|
38 |
+
|
39 |
+
# Call the inference module
|
40 |
+
result = inference.image_to_image(
|
41 |
+
image=image,
|
42 |
+
prompt=prompt,
|
43 |
+
model_name=model,
|
44 |
+
negative_prompt=negative_prompt,
|
45 |
+
guidance_scale=guidance_scale,
|
46 |
+
num_inference_steps=num_inference_steps
|
47 |
+
)
|
48 |
+
|
49 |
+
return result, None
|
50 |
+
except Exception as e:
|
51 |
+
return None, str(e)
|
52 |
+
|
53 |
+
# Create Gradio UI
|
54 |
+
with gr.Blocks(title="Diffusion Models") as app:
|
55 |
+
gr.Markdown("# Hugging Face Diffusion Models")
|
56 |
+
|
57 |
+
with gr.Tab("Text to Image"):
|
58 |
+
with gr.Row():
|
59 |
+
with gr.Column():
|
60 |
+
txt2img_prompt = gr.Textbox(label="Prompt", placeholder="Enter your prompt here...")
|
61 |
+
txt2img_negative = gr.Textbox(label="Negative Prompt (Optional)", placeholder="What to exclude from the image")
|
62 |
+
txt2img_model = gr.Textbox(label="Model", placeholder=f"Enter model name (default: {config.DEFAULT_TEXT2IMG_MODEL})")
|
63 |
+
txt2img_guidance = gr.Slider(minimum=1.0, maximum=20.0, value=7.5, step=0.5, label="Guidance Scale")
|
64 |
+
txt2img_steps = gr.Slider(minimum=10, maximum=100, value=50, step=1, label="Inference Steps")
|
65 |
+
txt2img_button = gr.Button("Generate Image")
|
66 |
+
|
67 |
+
with gr.Column():
|
68 |
+
txt2img_output = gr.Image(type="pil", label="Generated Image")
|
69 |
+
txt2img_error = gr.Textbox(label="Error", visible=True)
|
70 |
+
|
71 |
+
txt2img_button.click(
|
72 |
+
fn=text_to_image_fn,
|
73 |
+
inputs=[txt2img_prompt, txt2img_model, txt2img_negative, txt2img_guidance, txt2img_steps],
|
74 |
+
outputs=[txt2img_output, txt2img_error]
|
75 |
+
)
|
76 |
+
|
77 |
+
with gr.Tab("Image to Image"):
|
78 |
+
with gr.Row():
|
79 |
+
with gr.Column():
|
80 |
+
img2img_input = gr.Image(type="pil", label="Input Image")
|
81 |
+
img2img_prompt = gr.Textbox(label="Prompt", placeholder="Enter your prompt here...")
|
82 |
+
img2img_negative = gr.Textbox(label="Negative Prompt (Optional)", placeholder="What to exclude from the image")
|
83 |
+
img2img_model = gr.Textbox(label="Model", placeholder=f"Enter model name (default: {config.DEFAULT_IMG2IMG_MODEL})")
|
84 |
+
img2img_guidance = gr.Slider(minimum=1.0, maximum=20.0, value=7.5, step=0.5, label="Guidance Scale")
|
85 |
+
img2img_steps = gr.Slider(minimum=10, maximum=100, value=50, step=1, label="Inference Steps")
|
86 |
+
img2img_button = gr.Button("Transform Image")
|
87 |
+
|
88 |
+
with gr.Column():
|
89 |
+
img2img_output = gr.Image(type="pil", label="Generated Image")
|
90 |
+
img2img_error = gr.Textbox(label="Error", visible=True)
|
91 |
+
|
92 |
+
img2img_button.click(
|
93 |
+
fn=image_to_image_fn,
|
94 |
+
inputs=[img2img_input, img2img_prompt, img2img_model, img2img_negative, img2img_guidance, img2img_steps],
|
95 |
+
outputs=[img2img_output, img2img_error]
|
96 |
+
)
|
97 |
+
|
98 |
+
# Launch the Gradio app
|
99 |
+
if __name__ == "__main__":
|
100 |
+
app.launch(server_name=config.GRADIO_HOST, server_port=config.GRADIO_PORT)
|
config.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from dotenv import load_dotenv
|
3 |
+
|
4 |
+
# Load environment variables from .env file
|
5 |
+
load_dotenv()
|
6 |
+
|
7 |
+
# Hugging Face API token
|
8 |
+
HF_TOKEN = os.getenv("HF_TOKEN", "")
|
9 |
+
|
10 |
+
# Default model for text to image
|
11 |
+
DEFAULT_TEXT2IMG_MODEL = "stabilityai/stable-diffusion-2-1"
|
12 |
+
|
13 |
+
# Default model for image to image
|
14 |
+
DEFAULT_IMG2IMG_MODEL = "lllyasviel/sd-controlnet-depth"
|
15 |
+
|
16 |
+
# API settings
|
17 |
+
API_HOST = os.getenv("API_HOST", "0.0.0.0")
|
18 |
+
API_PORT = int(os.getenv("API_PORT", "8000"))
|
19 |
+
|
20 |
+
# Gradio settings
|
21 |
+
GRADIO_HOST = os.getenv("GRADIO_HOST", "0.0.0.0")
|
22 |
+
GRADIO_PORT = int(os.getenv("GRADIO_PORT", "7860"))
|
inference.py
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from huggingface_hub import InferenceClient
|
2 |
+
from PIL import Image
|
3 |
+
import io
|
4 |
+
import config
|
5 |
+
|
6 |
+
|
7 |
+
class DiffusionInference:
|
8 |
+
def __init__(self, api_key=None):
|
9 |
+
"""
|
10 |
+
Initialize the inference client with the Hugging Face API token.
|
11 |
+
"""
|
12 |
+
self.api_key = api_key or config.HF_TOKEN
|
13 |
+
self.client = InferenceClient(
|
14 |
+
provider="hf-inference",
|
15 |
+
api_key=self.api_key,
|
16 |
+
)
|
17 |
+
|
18 |
+
def text_to_image(self, prompt, model_name=None, negative_prompt=None, **kwargs):
|
19 |
+
"""
|
20 |
+
Generate an image from a text prompt.
|
21 |
+
|
22 |
+
Args:
|
23 |
+
prompt (str): The text prompt to guide image generation
|
24 |
+
model_name (str, optional): The model to use for inference
|
25 |
+
negative_prompt (str, optional): What not to include in the image
|
26 |
+
**kwargs: Additional parameters to pass to the model
|
27 |
+
|
28 |
+
Returns:
|
29 |
+
PIL.Image: The generated image
|
30 |
+
"""
|
31 |
+
model = model_name or config.DEFAULT_TEXT2IMG_MODEL
|
32 |
+
|
33 |
+
# Set up parameters dictionary
|
34 |
+
params = {"prompt": prompt}
|
35 |
+
|
36 |
+
if negative_prompt:
|
37 |
+
params["negative_prompt"] = negative_prompt
|
38 |
+
|
39 |
+
# Add any additional parameters
|
40 |
+
params.update(kwargs)
|
41 |
+
|
42 |
+
try:
|
43 |
+
image = self.client.text_to_image(model=model, **params)
|
44 |
+
return image
|
45 |
+
except Exception as e:
|
46 |
+
print(f"Error generating image: {e}")
|
47 |
+
raise
|
48 |
+
|
49 |
+
def image_to_image(self, image, prompt=None, model_name=None, negative_prompt=None, **kwargs):
|
50 |
+
"""
|
51 |
+
Generate a new image from an input image and optional prompt.
|
52 |
+
|
53 |
+
Args:
|
54 |
+
image (PIL.Image or str): Input image or path to image
|
55 |
+
prompt (str, optional): Text prompt to guide the transformation
|
56 |
+
model_name (str, optional): The model to use for inference
|
57 |
+
negative_prompt (str, optional): What not to include in the image
|
58 |
+
**kwargs: Additional parameters to pass to the model
|
59 |
+
|
60 |
+
Returns:
|
61 |
+
PIL.Image: The generated image
|
62 |
+
"""
|
63 |
+
model = model_name or config.DEFAULT_IMG2IMG_MODEL
|
64 |
+
|
65 |
+
# Convert image path to PIL Image if needed
|
66 |
+
if isinstance(image, str):
|
67 |
+
image = Image.open(image)
|
68 |
+
|
69 |
+
# Set up parameters dictionary
|
70 |
+
params = {"image": image}
|
71 |
+
|
72 |
+
if prompt:
|
73 |
+
params["prompt"] = prompt
|
74 |
+
|
75 |
+
if negative_prompt:
|
76 |
+
params["negative_prompt"] = negative_prompt
|
77 |
+
|
78 |
+
# Add any additional parameters
|
79 |
+
params.update(kwargs)
|
80 |
+
|
81 |
+
try:
|
82 |
+
result = self.client.image_to_image(model=model, **params)
|
83 |
+
return result
|
84 |
+
except Exception as e:
|
85 |
+
print(f"Error transforming image: {e}")
|
86 |
+
raise
|
main.py
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import argparse
|
2 |
+
import uvicorn
|
3 |
+
import threading
|
4 |
+
import os
|
5 |
+
import config
|
6 |
+
from app import app as gradio_app
|
7 |
+
from api import app as api_app
|
8 |
+
|
9 |
+
def run_api():
|
10 |
+
"""Run the FastAPI server"""
|
11 |
+
uvicorn.run(
|
12 |
+
api_app,
|
13 |
+
host=config.API_HOST,
|
14 |
+
port=config.API_PORT
|
15 |
+
)
|
16 |
+
|
17 |
+
def run_gradio():
|
18 |
+
"""Run the Gradio interface"""
|
19 |
+
gradio_app.launch(
|
20 |
+
server_name=config.GRADIO_HOST,
|
21 |
+
server_port=config.GRADIO_PORT,
|
22 |
+
share=False
|
23 |
+
)
|
24 |
+
|
25 |
+
def main():
|
26 |
+
parser = argparse.ArgumentParser(description="Run Diffusion Models App")
|
27 |
+
parser.add_argument(
|
28 |
+
"--mode",
|
29 |
+
type=str,
|
30 |
+
default="all",
|
31 |
+
choices=["all", "api", "ui"],
|
32 |
+
help="Which component to run: 'all' (default), 'api', or 'ui'"
|
33 |
+
)
|
34 |
+
|
35 |
+
args = parser.parse_args()
|
36 |
+
|
37 |
+
# Check if HF_TOKEN is set
|
38 |
+
if not config.HF_TOKEN:
|
39 |
+
print("Warning: HF_TOKEN environment variable is not set. Please set it for API access.")
|
40 |
+
print("You can create a .env file with HF_TOKEN=your_token or set it in your environment.")
|
41 |
+
|
42 |
+
if args.mode == "all":
|
43 |
+
# Run both API and UI in separate threads
|
44 |
+
api_thread = threading.Thread(target=run_api)
|
45 |
+
api_thread.daemon = True
|
46 |
+
api_thread.start()
|
47 |
+
|
48 |
+
print(f"API server running at http://{config.API_HOST}:{config.API_PORT}")
|
49 |
+
print(f"Starting Gradio UI at http://{config.GRADIO_HOST}:{config.GRADIO_PORT}")
|
50 |
+
|
51 |
+
# Run Gradio in the main thread
|
52 |
+
run_gradio()
|
53 |
+
|
54 |
+
elif args.mode == "api":
|
55 |
+
print(f"Starting API server at http://{config.API_HOST}:{config.API_PORT}")
|
56 |
+
run_api()
|
57 |
+
|
58 |
+
elif args.mode == "ui":
|
59 |
+
print(f"Starting Gradio UI at http://{config.GRADIO_HOST}:{config.GRADIO_PORT}")
|
60 |
+
run_gradio()
|
61 |
+
|
62 |
+
if __name__ == "__main__":
|
63 |
+
main()
|
requirements.txt
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gradio
|
2 |
+
huggingface_hub
|
3 |
+
Pillow
|
4 |
+
fastapi
|
5 |
+
uvicorn
|
6 |
+
python-dotenv
|
spaces_config.json
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"sdk": "gradio",
|
3 |
+
"sdk_version": "3.50.2",
|
4 |
+
"app_file": "app.py",
|
5 |
+
"models": [
|
6 |
+
{
|
7 |
+
"model_name": "stabilityai/stable-diffusion-2-1",
|
8 |
+
"model_class": "diffusers"
|
9 |
+
},
|
10 |
+
{
|
11 |
+
"model_name": "lllyasviel/sd-controlnet-depth",
|
12 |
+
"model_class": "diffusers"
|
13 |
+
}
|
14 |
+
],
|
15 |
+
"resources": {
|
16 |
+
"accelerator": "gpu",
|
17 |
+
"gpu": {
|
18 |
+
"count": 1,
|
19 |
+
"vendor": "nvidia",
|
20 |
+
"memory": "16GB"
|
21 |
+
}
|
22 |
+
}
|
23 |
+
}
|