【Stable Diffusion】APIで画像一括生成する際の「ConnectionError」と「パラメータ不整合」エラーの解決法

問題の概要:API一括生成時の接続エラーと予期せぬ出力

Stable Diffusion WebUI(以下、SD WebUI)は、直感的なWebインターフェースで画像生成が可能な優れたツールです。さらに、その内部APIを利用することで、Pythonスクリプトからプロンプトやパラメータをプログラムで制御し、大量の画像を自動生成するバッチ処理が可能になります。

しかし、APIを利用した一括生成スクリプトの作成・実行において、特に初心者から中級者の開発者が頻繁に遭遇する問題が2つあります。

1. APIサーバーへの接続エラー

スクリプト実行時に、SD WebUIのAPIサーバーに接続できないというエラーです。具体的には、以下のようなエラーメッセージが表示されます。

requests.exceptions.ConnectionError: HTTPConnectionPool(host='127.0.0.1', port=7860):
Max retries exceeded with url: /sdapi/v1/txt2img (Caused by NewConnectionError(':
Failed to establish a new connection: [WinError 10061] 対象のコンピューターによって拒否されたため、接続できませんでした。'))

2. パラメータ指定不整合によるエラーまたは期待しない出力

接続は成功したものの、APIに渡すリクエストボディのJSON形式やパラメータ名が正しくない場合に発生します。エラーが返されることもあれば、エラーなく処理が完了しても、期待した画質や構図の画像が生成されない「サイレント失敗」に陥ることがあります。

# エラーレスポンスの例
{
  "error": "Validation error: `steps` must be a positive integer",
  "detail": "..."
}
# または、エラーは出ないが、常に同じ画像しか生成されない、シードが効かないなどの不具合。

原因の解説

これらの問題が発生する主な原因は以下の通りです。

接続エラーの原因

1. SD WebUIの起動モード: デフォルトではWebUIはローカルネットワークからのみアクセス可能なモードで起動します。スクリプトから`localhost`や`127.0.0.1`でアクセスするためには、WebUIが確実に起動している必要があります。また、`–listen`オプションなしで起動すると、外部IPからのアクセスは拒否されます(スクリプトが同じPC上であれば問題ありません)。

2. ポート番号の不一致: WebUIの起動ポート(デフォルトは`7860`)と、スクリプト内で指定するポート番号が一致していない場合に接続できません。別のアプリケーションが同じポートを使用している可能性もあります。

パラメータ不整合の原因

1. API仕様のバージョン差異: SD WebUIはアップデートが頻繁で、APIのエンドポイントや利用可能なパラメータが変更されることがあります。古いチュートリアルに記載されたパラメータ名(例:`sampler_name`)が現在のバージョンでは非推奨になっているケースがあります。

2. JSON構造の誤り: `requests`ライブラリでデータを送信する際、Pythonの辞書型を正しくJSON形式に変換できていない、または必須パラメータが欠けている場合にエラーとなります。

3. シード(seed)管理の問題: バッチ生成で毎回異なる画像を生成したい場合、シード値を固定せず(`-1`にする)、またはループ内で動的に変更する必要があります。シードを固定したまま他のパラメータだけ変更しても、同じ画像が生成され続けることがあります。

解決方法:ステップバイステップガイド

ステップ1: SD WebUIの正しい起動

まず、APIを受け付ける状態でSD WebUIを起動します。コマンドラインまたは`webui-user.bat`(Windows)の設定を変更します。

# webui-user.bat 内の COMMANDLINE_ARGS を編集する例(Windows)
set COMMANDLINE_ARGS=--api --listen

# ターミナルから直接起動する例(Linux/macOS)
./webui.sh --api --listen

`–api`: API機能を有効化します。これが必須です。
`–listen`: ローカルホスト以外からの接続を許可します(同じマシン上のスクリプトの場合は必須ではありませんが、明示的に指定することをお勧めします)。
起動後、ブラウザで `http://127.0.0.1:7860` にアクセスできることを確認してください。

ステップ2: 最小限の動作確認スクリプトの作成

以下のシンプルなスクリプトで、API接続と基本的な画像生成が可能かテストします。

import requests
import json
import io
from PIL import Image

# 1. APIエンドポイントの設定
url = "http://127.0.0.1:7860"

# 2. テキストから画像生成するためのパラメータ
payload = {
    "prompt": "a beautiful sunset over mountains, masterpiece, high quality",
    "negative_prompt": "blurry, ugly, deformed",
    "steps": 20,
    "width": 512,
    "height": 512,
    "cfg_scale": 7,
    "sampler_name": "Euler a", # サンプラー名はWebUIの画面で確認可能
    "seed": -1, # -1 はランダムシード
}

# 3. APIリクエストの送信
try:
    response = requests.post(url=f'{url}/sdapi/v1/txt2img', json=payload)
    response.raise_for_status() # HTTPエラーがあれば例外を発生させる
except requests.exceptions.ConnectionError as e:
    print(f"接続エラー: {e}")
    print("SD WebUIが '--api' オプションを付けて起動しているか確認してください。")
    exit(1)
except requests.exceptions.RequestException as e:
    print(f"リクエストエラー: {e}")
    exit(1)

# 4. レスポンスの処理
r = response.json()
print("生成成功!")

# 5. 画像の保存 (レスポンスはBase64エンコードされた画像のリストを含む)
for i, img_base64 in enumerate(r['images']):
    image = Image.open(io.BytesIO(base64.b64decode(img_base64.split(",",1)[0])))
    image.save(f'test_output_{i}.png')
    print(f"画像を 'test_output_{i}.png' として保存しました。")

ステップ3: 一括生成スクリプトへの発展とエラー対策

テストスクリプトが動作したら、複数のプロンプトを処理するバッチスクリプトを作成します。この際、以下の点に注意して実装します。

import requests
import base64
import io
import time
from PIL import Image
import json

def generate_image(prompt, negative_prompt, seed=-1, index=0):
    """単一画像生成関数"""
    url = "http://127.0.0.1:7860"
    payload = {
        "prompt": prompt,
        "negative_prompt": negative_prompt,
        "steps": 28,
        "width": 768,
        "height": 512,
        "cfg_scale": 7.5,
        "sampler_name": "DPM++ 2M Karras",
        "seed": seed,
        "batch_size": 1
    }
    try:
        response = requests.post(url=f'{url}/sdapi/v1/txt2img', json=payload, timeout=60)
        # HTTPステータスコードのチェック
        if response.status_code != 200:
            print(f"エラー: HTTP {response.status_code}")
            print(response.text)
            return None

        r = response.json()
        # 実際のSD WebUIのAPIレスポンス構造を確認
        if 'images' not in r or len(r['images']) == 0:
            print("エラー: レスポンスに画像データが含まれていません。")
            print(json.dumps(r, indent=2)[:500]) # レスポンスの一部を表示
            return None

        img_data = base64.b64decode(r['images'][0].split(",",1)[0])
        return img_data

    except requests.exceptions.Timeout:
        print(f"タイムアウト: プロンプト '{prompt[:20]}...' の処理に時間がかかりすぎています。")
        return None
    except Exception as e:
        print(f"予期せぬエラー: {type(e).__name__} - {e}")
        return None

# メイン処理: プロンプトリストを一括処理
prompt_list = [
    ("1girl, in a cyberpunk city, neon lights", "low quality, monochrome"),
    ("ancient castle in a fantasy forest, digital art", "people, modern"),
    ("a cute cat wearing a wizard hat, detailed illustration", "dog, realistic"),
]

for idx, (prompt, neg_prompt) in enumerate(prompt_list):
    print(f"処理中 [{idx+1}/{len(prompt_list)}]: {prompt}")
    # シードをランダム(-1)またはインデックスに基づいて変更可能
    img_data = generate_image(prompt, neg_prompt, seed=-1, index=idx)

    if img_data:
        image = Image.open(io.BytesIO(img_data))
        filename = f"batch_output_{idx:03d}.png"
        image.save(filename)
        print(f"  -> 保存完了: {filename}")
    else:
        print(f"  -> 生成失敗")

    # サーバー負荷軽減のための短い間隔(オプション)
    time.sleep(1)

print("一括生成処理が完了しました。")

ステップ4: よくあるパラメータ関連のトラブルシューティング

サンプラー名が無効というエラーが出る場合: 使用可能なサンプラー名はAPIエンドポイント `/sdapi/v1/samplers` にGETリクエストを送ることで取得できます。

import requests
url = "http://127.0.0.1:7860"
samplers = requests.get(url=f'{url}/sdapi/v1/samplers').json()
print("利用可能なサンプラー:")
for sampler in samplers:
    print(f"  - {sampler['name']}")

常に同じ画像が生成される場合: `”seed”: -1` が設定されていることを確認してください。特定のシードから開始して変化させたい場合は、ループ内で `seed = initial_seed + i` のようにインクリメントします。

メモリ不足エラーが発生する場合: `”width”`、`”height”`、`”batch_size”` の値を小さくしてみてください。高解像度や大きなバッチサイズはVRAMを大量に消費します。

まとめ・補足情報

SD WebUIのAPIを利用した一括画像生成は、創作やデータセット作成の効率を飛躍的に高める強力な手法です。成功の鍵は以下の3点に集約されます。

1. 確実な接続環境の構築: `–api` オプションを付けたWebUIの起動を習慣化し、簡単なテストスクリプトで通信を確認することから始めましょう。
2. 正しいパラメータの把握: APIの仕様は更新されるため、利用しているWebUIのバージョンに対応したパラメータを、実際にAPIから取得する情報も参考にしながら使用しましょう。
3. 堅牢なエラーハンドリング: ネットワークタイムアウト、サーバーエラー、不正なレスポンスなど、様々な異常系を想定したコードを書くことで、長時間実行するバッチ処理を安定させられます。

さらに発展的な使い方として、`/sdapi/v1/options` エンドポイントにPOSTリクエストを送ることで、モデルの切り替え(`”sd_model_checkpoint”`)などWebUIの設定そのものをスクリプトから変更することも可能です。APIをマスターすることで、Stable Diffusionの可能性をさらに広げられるでしょう。

この記事は役に立ちましたか?