refactor: replace blackforest package with custom async BFL client
Some checks failed
Continuous Integration / Build Package (push) Successful in 41s
Continuous Integration / Lint, Check & Test (push) Failing after 59s

Implement bulkgen/providers/bfl.py with a fully async httpx-based client
that supports all current and future BFL models (including flux-2-*).
Remove the blackforest dependency and simplify the image provider by
eliminating the asyncio.to_thread wrapper.
This commit is contained in:
Konstantin Fickel 2026-02-14 16:44:36 +01:00
parent fd09d127f2
commit cf73511876
Signed by: kfickel
GPG key ID: A793722F9933C1A5
5 changed files with 179 additions and 89 deletions

View file

@ -2,24 +2,15 @@
from __future__ import annotations
import asyncio
import base64
from pathlib import Path
from typing import override
import httpx
from blackforest import BFLClient # pyright: ignore[reportMissingTypeStubs]
from blackforest.types.general.client_config import ( # pyright: ignore[reportMissingTypeStubs]
ClientConfig,
)
from blackforest.types.responses.responses import ( # pyright: ignore[reportMissingTypeStubs]
SyncResponse,
)
from bulkgen.config import TargetConfig
from bulkgen.providers import Provider
_BFL_SYNC_CONFIG = ClientConfig(sync=True, timeout=300)
from bulkgen.providers.bfl import BFLClient
def _encode_image_b64(path: Path) -> str:
@ -61,24 +52,10 @@ class ImageProvider(Provider):
ctrl_path = project_dir / control_name
inputs["control_image"] = _encode_image_b64(ctrl_path)
result = await asyncio.to_thread(
self._client.generate, resolved_model, inputs, _BFL_SYNC_CONFIG
)
if not isinstance(result, SyncResponse):
msg = (
f"BFL API returned unexpected response type for target '{target_name}'"
)
raise RuntimeError(msg)
result_dict: dict[str, str] = result.result # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
image_url = result_dict.get("sample")
if not image_url:
msg = f"BFL API did not return an image URL for target '{target_name}'"
raise RuntimeError(msg)
result = await self._client.generate(resolved_model, inputs)
async with httpx.AsyncClient() as http:
response = await http.get(image_url)
response = await http.get(result.sample_url)
_ = response.raise_for_status()
_ = output_path.write_bytes(response.content)