Skip to content

Commit 898ee6f

Browse files
authored
Merge pull request #99 from intel/update-branch
292 user story include stable diffusion xl in text to image generation microservice (#293)
2 parents 3c795d6 + a10a418 commit 898ee6f

File tree

14 files changed

+586
-23
lines changed

14 files changed

+586
-23
lines changed

usecases/ai/microservices/text-to-image/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Text-to-image generation microservice is a FastAPI-based API that interacts with
55
It provides endpoints for managing the pipeline, checking the pipeline status, retrieving the generated image, and performing a health check.
66

77
### Supported Models
8+
* Stable Diffusion XL
89
* Stable Diffusion v3.5
910
* Stable Diffusion v3
1011

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.venv
2+
stable-diffusion-3.5-medium
3+
kernel.errors.txt
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
git+https://github.com/huggingface/optimum-intel.git
2-
openvino>=2024.6
3-
openvino-tokenizers>=2024.6
4-
openvino-genai>=2024.6
5-
Pillow
6-
diffusers>=0.30.3
7-
gradio>=4.19
8-
typing_extensions>=4.9
9-
numpy<2.0.0; platform_system == "Darwin"
10-
IPython
2+
openvino==2024.6.0
3+
openvino-tokenizers==2024.6.0.0
4+
openvino-genai==2024.6.0.0
5+
Pillow==11.1.0
6+
diffusers==0.32.1
7+
gradio==5.11.0
8+
typing_extensions==4.12.2
9+
numpy==2.1.3
10+
IPython==8.31.0
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.venv
2+
stable-diffusion-3
3+
kernel.errors.txt

usecases/ai/microservices/text-to-image/stable-diffusion-v3/backend/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
class PipelineClient:
9-
def __init__(self, base_url="http://localhost:8000"):
9+
def __init__(self, base_url="http://localhost:8100"):
1010
"""
1111
Initialize the PipelineClient with the base URL.
1212
:param base_url: The base URL for the API.

usecases/ai/microservices/text-to-image/stable-diffusion-v3/backend/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,4 +318,4 @@ def health_check():
318318

319319
if __name__ == "__main__":
320320
api = Sdv3API()
321-
uvicorn.run(api.app, host="0.0.0.0", port=8000, reload=False)
321+
uvicorn.run(api.app, host="0.0.0.0", port=8100, reload=False)

usecases/ai/microservices/text-to-image/stable-diffusion-v3/requirements.txt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,22 @@
44
git+https://github.com/initml/diffusers.git@clement/feature/flash_sd3
55

66
# Dependencies with version specifications
7-
gradio>=4.19
8-
torch>=2.1
9-
transformers
10-
nncf>=2.12.0
11-
datasets>=2.14.6
12-
opencv-python
13-
pillow
14-
peft>=0.7.0
15-
ipywidgets
7+
gradio==5.11.0
8+
torch==2.5.1+cpu
9+
transformers==4.47.1
10+
nncf==2.14.1
11+
datasets==3.2.0
12+
opencv-python==4.10.0.84
13+
pillow==11.1.0
14+
peft==0.14.0
15+
ipywidgets==8.1.5
1616

1717
# Additional index URL for PyTorch dependencies
1818
--extra-index-url https://download.pytorch.org/whl/cpu
1919

2020
# OpenVINO with version specification
21-
openvino>=2024.3.0
21+
openvino==2024.6.0
2222

2323
# Server
24-
fastapi
25-
uvicorn
24+
fastapi==0.115.6
25+
uvicorn==0.34.0
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.venv
2+
openvino-sd-xl-base-1.0
3+
kernel.errors.txt
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Copyright (C) 2025 Intel Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
import time
5+
import requests
6+
7+
8+
class PipelineClient:
9+
def __init__(self, base_url="http://localhost:8100"):
10+
"""
11+
Initialize the PipelineClient with the base URL.
12+
:param base_url: The base URL for the API.
13+
"""
14+
self.base_url = base_url
15+
16+
def make_request(self, method, endpoint, data=None, timeout=100):
17+
"""
18+
Make a request to the API.
19+
:param method: HTTP method (GET, POST, etc.).
20+
:param endpoint: API endpoint.
21+
:param data: JSON payload for the request.
22+
:param timeout: Timeout in seconds.
23+
:return: Response object or None on failure.
24+
"""
25+
url = f"{self.base_url}{endpoint}"
26+
try:
27+
response = requests.request(method, url, json=data, timeout=timeout)
28+
response.raise_for_status()
29+
return response
30+
except requests.RequestException as e:
31+
print(f"Error while accessing {url}: {e}")
32+
return None
33+
34+
@staticmethod
35+
def save_image(content, filename):
36+
"""
37+
Save the content as an image file.
38+
:param content: Binary content of the image.
39+
:param filename: Filename to save the image.
40+
"""
41+
try:
42+
with open(filename, "wb") as file:
43+
file.write(content)
44+
print(f"Image saved as {filename}")
45+
except IOError as e:
46+
print(f"Failed to save image: {e}")
47+
48+
def wait_for_completion(self, timeout=300, poll_interval=2):
49+
"""
50+
Wait for the pipeline to complete.
51+
:param timeout: Maximum time to wait in seconds.
52+
:param poll_interval: Time between status checks.
53+
:return: True if completed, False otherwise.
54+
"""
55+
start_time = time.time()
56+
while time.time() - start_time < timeout:
57+
response = self.make_request("GET", "/pipeline/status", timeout=10)
58+
if response:
59+
status = response.json()
60+
print(f"Pipeline status: Running={status['running']}, Completed={status['completed']}")
61+
if status["completed"]:
62+
return True
63+
time.sleep(poll_interval)
64+
print("Timeout reached. Pipeline execution did not complete.")
65+
return False
66+
67+
def check_health(self):
68+
"""
69+
Check the health of the API.
70+
:return: True if the health check passes, False otherwise.
71+
"""
72+
response = self.make_request("GET", "/health")
73+
if response:
74+
health_status = response.json()
75+
print(f"Health status: {health_status['status']}")
76+
return health_status['status'] == "healthy"
77+
else:
78+
print("Failed to perform health check.")
79+
return False
80+
81+
82+
83+
def main():
84+
client = PipelineClient()
85+
86+
# Step 1: Health check
87+
if not client.check_health():
88+
print("Health check failed. Exiting.")
89+
return
90+
91+
# # Step 2: Select the device
92+
# response = client.make_request("POST", "/pipeline/select-device", {"device": "CPU"})
93+
# if response:
94+
# print(response.json())
95+
96+
# Step 3: Trigger the pipeline with additional parameters
97+
response = client.make_request(
98+
"POST",
99+
"/pipeline/run",
100+
{
101+
"prompt": "A raccoon trapped inside a glass jar full of colorful candies, the background is steamy with vivid colors",
102+
"width": 1024, # Additional parameter: width
103+
"height": 1024, # Additional parameter: height
104+
"num_inference_steps": 50 # Additional parameter: num_inference_steps
105+
},
106+
)
107+
if not response:
108+
print("Failed to trigger the pipeline.")
109+
return
110+
print(response.json())
111+
112+
# Step 4: Wait for completion
113+
if not client.wait_for_completion():
114+
return
115+
116+
# # Step 5: Retrieve the generated image
117+
# response = client.make_request("GET", "/pipeline/image")
118+
# if response:
119+
# client.save_image(response.content, "output_image.png")
120+
# else:
121+
# print("Failed to retrieve the generated image.")
122+
123+
124+
if __name__ == "__main__":
125+
main()
126+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Copyright (C) 2025 Intel Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
import subprocess # nosec - disable B404:import-subprocess check
5+
import sys
6+
from pathlib import Path
7+
from typing import Dict
8+
import platform
9+
10+
11+
def clone_repo(repo_url: str, revision: str = None, add_to_sys_path: bool = True) -> Path:
12+
repo_path = Path(repo_url.split("/")[-1].replace(".git", ""))
13+
14+
if not repo_path.exists():
15+
try:
16+
subprocess.run(["git", "clone", repo_url], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
17+
except Exception as exc:
18+
print(f"Failed to clone the repository: {exc.stderr}")
19+
raise
20+
21+
if revision:
22+
subprocess.Popen(["git", "checkout", revision], cwd=str(repo_path))
23+
if add_to_sys_path and str(repo_path.resolve()) not in sys.path:
24+
sys.path.insert(0, str(repo_path.resolve()))
25+
26+
return repo_path
27+
28+
29+
def optimum_cli(model_id, output_dir, show_command=True, additional_args: Dict[str, str] = None):
30+
export_command = f"optimum-cli export openvino --model {model_id} {output_dir}"
31+
if additional_args is not None:
32+
for arg, value in additional_args.items():
33+
export_command += f" --{arg}"
34+
if value:
35+
export_command += f" {value}"
36+
37+
if show_command:
38+
from IPython.display import Markdown, display
39+
40+
display(Markdown("**Export command:**"))
41+
display(Markdown(f"`{export_command}`"))
42+
43+
subprocess.run(export_command.split(" "), shell=(platform.system() == "Windows"), check=True)

0 commit comments

Comments
 (0)