| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- """BFL FLUX HTTP 客户端 — 异步提交 + 轮询。
- 文档: https://docs.bfl.ai/quick_start/generating_images
- """
- from __future__ import annotations
- import os
- from typing import Any
- import httpx
- from dotenv import load_dotenv
- _ = load_dotenv()
- DEFAULT_API_BASE = "https://api.bfl.ai/v1"
- def _api_key() -> str:
- key = os.environ.get("BFL_API_KEY", "").strip()
- if not key:
- raise ValueError("缺少环境变量 BFL_API_KEY")
- return key
- def _headers() -> dict[str, str]:
- return {
- "accept": "application/json",
- "x-key": _api_key(),
- "Content-Type": "application/json",
- }
- def submit_generation(
- *,
- model: str,
- prompt: str,
- width: int | None = None,
- height: int | None = None,
- parameters: dict[str, Any] | None = None,
- ) -> dict[str, Any]:
- """POST {BFL_API_BASE}/{model},返回含 id、polling_url 等(以 BFL 响应为准)。"""
- base = os.environ.get("BFL_API_BASE", DEFAULT_API_BASE).rstrip("/")
- model_path = model.strip().lstrip("/")
- url = f"{base}/{model_path}"
- body: dict[str, Any] = dict(parameters) if parameters else {}
- body["prompt"] = prompt
- if width is not None:
- body["width"] = width
- if height is not None:
- body["height"] = height
- with httpx.Client(timeout=120.0) as client:
- r = client.post(url, headers=_headers(), json=body)
- try:
- data = r.json()
- except Exception:
- r.raise_for_status()
- raise RuntimeError(r.text[:2000]) from None
- if r.status_code >= 400:
- err = data.get("detail") if isinstance(data, dict) else None
- msg = err if err is not None else str(data)
- raise RuntimeError(f"BFL HTTP {r.status_code}: {msg}")
- if not isinstance(data, dict):
- raise RuntimeError("提交响应不是 JSON 对象")
- return data
- def poll_result(*, polling_url: str, request_id: str) -> dict[str, Any]:
- """GET polling_url,Query: id=request_id(与官方示例一致)。"""
- with httpx.Client(timeout=60.0) as client:
- r = client.get(
- polling_url.strip(),
- headers={
- "accept": "application/json",
- "x-key": _api_key(),
- },
- params={"id": request_id.strip()},
- )
- try:
- data = r.json()
- except Exception:
- r.raise_for_status()
- raise RuntimeError(r.text[:2000]) from None
- if r.status_code >= 400:
- msg = data if isinstance(data, dict) else str(data)
- raise RuntimeError(f"BFL poll HTTP {r.status_code}: {msg}")
- if not isinstance(data, dict):
- raise RuntimeError("轮询响应不是 JSON 对象")
- return data
|