|
|
|
|
|
import gradio as gr |
|
import torch |
|
import numpy as np |
|
import cv2 |
|
from PIL import Image |
|
import time |
|
import spaces |
|
import traceback |
|
import os |
|
|
|
from diffusers import StableDiffusionPipeline, ControlNetModel |
|
from insightface.app import FaceAnalysis |
|
|
|
print("--- アプリケーションの初期化を開始 ---") |
|
|
|
|
|
try: |
|
print("モデルのロードを開始...") |
|
is_cuda_available = torch.cuda.is_available() |
|
device = "cuda" if is_cuda_available else "cpu" |
|
dtype = torch.float16 if is_cuda_available else torch.float32 |
|
print(f"実行デバイス: {device}, データ型: {dtype}") |
|
|
|
print("InsightFaceのプロバイダーとコンテキストIDを設定...") |
|
providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] if is_cuda_available else ['CPUExecutionProvider'] |
|
ctx_id = 0 if is_cuda_available else -1 |
|
print(f"使用するプロバイダー: {providers}, ctx_id: {ctx_id}") |
|
|
|
face_app = FaceAnalysis(name='buffalo_l', root='./', providers=providers) |
|
face_app.prepare(ctx_id=ctx_id, det_size=(640, 640)) |
|
print("InsightFaceのロード完了。") |
|
|
|
source_repo = "InstantX/InstantID" |
|
|
|
print(f"ControlNetモデル ({source_repo}) のロード開始...") |
|
controlnet = ControlNetModel.from_pretrained( |
|
source_repo, |
|
subfolder="ControlNetModel", |
|
torch_dtype=dtype |
|
) |
|
print("ControlNetモデルのロード完了。") |
|
|
|
civitai_model_url = "https://civitai.com/api/download/models/90505?type=Model&format=SafeTensor&size=full&fp=fp32" |
|
local_model_path = "civitai_model.safetensors" |
|
|
|
if not os.path.exists(local_model_path): |
|
print(f"{local_model_path} が存在しないため、ダウンロードを開始します...") |
|
os.system(f'wget -q -O {local_model_path} "{civitai_model_url}"') |
|
else: |
|
print(f"{local_model_path} は既に存在するため、ダウンロードをスキップします。") |
|
|
|
print(f"ローカルパス ({local_model_path}) からパイプラインをロード開始...") |
|
pipe = StableDiffusionPipeline.from_single_file( |
|
local_model_path, |
|
torch_dtype=dtype, |
|
safety_checker=None, |
|
use_safetensors=True, |
|
) |
|
pipe.controlnet = controlnet |
|
pipe.to(device) |
|
print("Stable Diffusionパイプラインのロード完了。") |
|
|
|
|
|
|
|
ip_adapter_repo = "h94/IP-Adapter" |
|
print(f"IP-Adapter ({ip_adapter_repo}) のロード開始...") |
|
pipe.load_ip_adapter( |
|
ip_adapter_repo, |
|
subfolder="models", |
|
weight_name="ip-adapter-plus_v2_sd15.bin" |
|
) |
|
print("IP-Adapter V2のロード完了。") |
|
|
|
print("★★全てのモデルのロードが正常に完了しました★★") |
|
MODELS_LOADED = True |
|
except Exception: |
|
error_details = traceback.format_exc() |
|
print("モデルのロード中に詳細なエラーが発生しました:") |
|
print(error_details) |
|
MODELS_LOADED = False |
|
|
|
|
|
@spaces.GPU(duration=300) |
|
def generate_image( |
|
face_image, prompt, negative_prompt, guidance_scale, ip_adapter_scale, num_steps, |
|
progress=gr.Progress(track_tqdm=True) |
|
): |
|
if not MODELS_LOADED: |
|
raise gr.Error("モデルがロードされていないため、画像を生成できません。ログを確認してください。") |
|
if face_image is None: |
|
raise gr.Error("顔画像をアップロードしてください。") |
|
if not prompt: |
|
raise gr.Error("プロンプトを入力してください。") |
|
|
|
face_image = Image.fromarray(face_image) |
|
face_info = face_app.get(cv2.cvtColor(np.array(face_image), cv2.COLOR_RGB2BGR)) |
|
if not face_info: |
|
raise gr.Error("アップロードされた画像から顔を検出できませんでした。") |
|
|
|
face_info = sorted(face_info, key=lambda x: (x['bbox'][2] - x['bbox'][0]) * (x['bbox'][3] - x['bbox'][1]))[-1] |
|
face_emb = face_info['embedding'] |
|
pipe.set_ip_adapter_scale(ip_adapter_scale) |
|
images = pipe( |
|
prompt=prompt, negative_prompt=negative_prompt, image_embeds=[face_emb], image=face_image, |
|
controlnet_conditioning_scale=ip_adapter_scale, num_inference_steps=int(num_steps), guidance_scale=guidance_scale, |
|
).images |
|
return images[0] |
|
|
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown("# InstantID 画像生成アプリ") |
|
with gr.Row(): |
|
with gr.Column(): |
|
face_image_input = gr.Image(label="顔写真", type="numpy") |
|
prompt_input = gr.Textbox(label="プロンプト (例: 1girl, a photo of a cute girl in a suit)") |
|
negative_prompt_input = gr.Textbox(label="ネガティブプロンプト", value="(lowres, low quality, worst quality:1.2), ugly") |
|
with gr.Accordion("詳細設定", open=False): |
|
ip_adapter_scale_slider = gr.Slider(minimum=0, maximum=1.5, step=0.1, value=0.8, label="顔の忠実度 (IP Adapter Scale)") |
|
guidance_scale_slider = gr.Slider(minimum=1, maximum=10, step=0.5, value=5.0, label="プロンプトへの忠実度 (Guidance Scale)") |
|
num_steps_slider = gr.Slider(minimum=10, maximum=50, step=1, value=30, label="生成ステップ数 (Steps)") |
|
generate_button = gr.Button("画像を生成", variant="primary") |
|
with gr.Column(): |
|
output_image = gr.Image(label="生成結果") |
|
generate_button.click( |
|
fn=generate_image, |
|
inputs=[ |
|
face_image_input, prompt_input, negative_prompt_input, guidance_scale_slider, |
|
ip_adapter_scale_slider, num_steps_slider |
|
], |
|
outputs=[output_image], |
|
api_name="generate" |
|
) |
|
|
|
demo.queue().launch() |
|
print("--- Gradioアプリの起動準備完了 ---") |