toby007
commited on
Commit
·
63f6eb9
1
Parent(s):
e51059c
update code
Browse files- README.md +10 -32
- handler.py +14 -40
- requirements.txt +5 -5
README.md
CHANGED
@@ -1,42 +1,20 @@
|
|
1 |
-
#
|
2 |
|
3 |
-
|
4 |
|
5 |
-
|
6 |
-
- 风格转换
|
7 |
-
- 商务形象照生成
|
8 |
|
9 |
-
|
10 |
-
|
11 |
-
接口输入格式(JSON):
|
12 |
|
|
|
13 |
```json
|
14 |
{
|
15 |
"inputs": {
|
16 |
-
"prompt": "
|
17 |
-
"image": "<base64
|
18 |
-
"
|
|
|
|
|
19 |
}
|
20 |
}
|
21 |
```
|
22 |
-
|
23 |
-
返回格式:
|
24 |
-
|
25 |
-
```json
|
26 |
-
{
|
27 |
-
"image": "<base64 PNG 图像>"
|
28 |
-
}
|
29 |
-
```
|
30 |
-
|
31 |
-
## 💡 掩码说明
|
32 |
-
- 图像和掩码需为相同尺寸
|
33 |
-
- 掩码中**白色部分为需要替换的区域**
|
34 |
-
|
35 |
-
## 🚀 示例场景
|
36 |
-
|
37 |
-
- 用户上传自拍照片,并通过 mask 指定区域(如衣服、背景)
|
38 |
-
- 后端根据 prompt 生成对应风格的合成图
|
39 |
-
|
40 |
-
---
|
41 |
-
|
42 |
-
本部署服务基于 diffusers 实现,更多信息参考:https://huggingface.co/black-forest-labs/FLUX.1-Fill-dev
|
|
|
1 |
+
# FLUX.1-Fill-dev Custom Inference Endpoint
|
2 |
|
3 |
+
This repository is set up to deploy a custom Hugging Face Inference Endpoint using the StableDiffusionInstructPix2PixPipeline, enabling image-to-image transformation with prompt guidance.
|
4 |
|
5 |
+
## How to Use
|
|
|
|
|
6 |
|
7 |
+
Send a POST request with base64-encoded `image` and your `prompt` to get an enhanced version of the image.
|
|
|
|
|
8 |
|
9 |
+
## Input example:
|
10 |
```json
|
11 |
{
|
12 |
"inputs": {
|
13 |
+
"prompt": "高清艺术风格头像",
|
14 |
+
"image": "<base64-encoded-image>",
|
15 |
+
"steps": 30,
|
16 |
+
"guidance_scale": 7.5,
|
17 |
+
"image_guidance_scale": 1.5
|
18 |
}
|
19 |
}
|
20 |
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handler.py
CHANGED
@@ -1,21 +1,17 @@
|
|
1 |
-
from diffusers import
|
2 |
from PIL import Image
|
3 |
import torch
|
4 |
import base64
|
5 |
from io import BytesIO
|
6 |
|
7 |
-
|
8 |
-
|
9 |
-
"shangguanyanyan/flux1-fill-dev-custom", # 请确认仓库ID无误
|
10 |
torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
|
11 |
).to("cuda" if torch.cuda.is_available() else "cpu")
|
12 |
|
13 |
def decode_image(b64_string):
|
14 |
-
|
15 |
-
|
16 |
-
return Image.open(BytesIO(image_data)).convert("RGB")
|
17 |
-
except Exception as e:
|
18 |
-
raise ValueError(f"解码图像失败: {str(e)}")
|
19 |
|
20 |
def encode_image(image):
|
21 |
buffer = BytesIO()
|
@@ -25,45 +21,23 @@ def encode_image(image):
|
|
25 |
def handler(data):
|
26 |
try:
|
27 |
inputs = data.get("inputs", {})
|
28 |
-
prompt = inputs.get("prompt", "
|
29 |
-
|
30 |
image_b64 = inputs.get("image")
|
31 |
-
mask_b64 = inputs.get("mask")
|
32 |
-
if not image_b64 or not mask_b64:
|
33 |
-
raise ValueError("缺少必要的 image 或 mask 参数")
|
34 |
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
# 默认参数(支持调整)
|
39 |
-
height = int(inputs.get("height", image.height))
|
40 |
-
width = int(inputs.get("width", image.width))
|
41 |
-
steps = int(inputs.get("num_inference_steps", 30))
|
42 |
-
cfg_scale = float(inputs.get("guidance_scale", 7.5))
|
43 |
|
44 |
-
image =
|
45 |
-
mask = mask.resize((width, height))
|
46 |
|
47 |
result = pipe(
|
48 |
prompt=prompt,
|
49 |
image=image,
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
num_inference_steps=steps,
|
54 |
-
guidance_scale=cfg_scale
|
55 |
).images[0]
|
56 |
|
57 |
-
return {
|
58 |
-
"status": "success",
|
59 |
-
"image": encode_image(result),
|
60 |
-
"meta": {
|
61 |
-
"prompt": prompt,
|
62 |
-
"size": f"{width}x{height}",
|
63 |
-
"steps": steps,
|
64 |
-
"cfg_scale": cfg_scale
|
65 |
-
}
|
66 |
-
}
|
67 |
|
68 |
except Exception as e:
|
69 |
-
return {"
|
|
|
1 |
+
from diffusers import StableDiffusionInstructPix2PixPipeline
|
2 |
from PIL import Image
|
3 |
import torch
|
4 |
import base64
|
5 |
from io import BytesIO
|
6 |
|
7 |
+
pipe = StableDiffusionInstructPix2PixPipeline.from_pretrained(
|
8 |
+
"shangguanyanyan/flux1-fill-dev-custom",
|
|
|
9 |
torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
|
10 |
).to("cuda" if torch.cuda.is_available() else "cpu")
|
11 |
|
12 |
def decode_image(b64_string):
|
13 |
+
image_data = base64.b64decode(b64_string)
|
14 |
+
return Image.open(BytesIO(image_data)).convert("RGB")
|
|
|
|
|
|
|
15 |
|
16 |
def encode_image(image):
|
17 |
buffer = BytesIO()
|
|
|
21 |
def handler(data):
|
22 |
try:
|
23 |
inputs = data.get("inputs", {})
|
24 |
+
prompt = inputs.get("prompt", "写实风格形象照")
|
|
|
25 |
image_b64 = inputs.get("image")
|
|
|
|
|
|
|
26 |
|
27 |
+
if not image_b64:
|
28 |
+
return {"error": "缺少 image 参数", "status": "failed"}
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
|
30 |
+
image = decode_image(image_b64)
|
|
|
31 |
|
32 |
result = pipe(
|
33 |
prompt=prompt,
|
34 |
image=image,
|
35 |
+
num_inference_steps=int(inputs.get("steps", 30)),
|
36 |
+
guidance_scale=float(inputs.get("guidance_scale", 7.5)),
|
37 |
+
image_guidance_scale=float(inputs.get("image_guidance_scale", 1.5))
|
|
|
|
|
38 |
).images[0]
|
39 |
|
40 |
+
return {"image": encode_image(result), "status": "success"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
|
42 |
except Exception as e:
|
43 |
+
return {"error": str(e), "status": "failed"}
|
requirements.txt
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
-
|
2 |
-
transformers
|
3 |
-
|
4 |
-
accelerate
|
5 |
-
|
|
|
1 |
+
diffusers>=0.14.0
|
2 |
+
transformers
|
3 |
+
torch
|
4 |
+
accelerate
|
5 |
+
safetensors
|