dphn/Dolphin3.0-Mistral-24B is the ungated mirror of the Dolphin 3.0 Mistral 24B — exactly what you asked for. It's ~48GB fp16, which needs GPU+CPU split (device_map="auto" with 32GB on GPU, ~16GB in RAM). Let me kick off the download and update the service in parallel.

This commit is contained in:
mike
2026-06-25 00:57:29 +02:00
parent ee7569f38c
commit 6d31826c29
3 changed files with 229 additions and 74 deletions

View File

@@ -2337,10 +2337,11 @@ def _extract_frame_at(video_path: str, t: float) -> Image.Image:
class SceneryRequest(BaseModel):
model_filename: str # person image in output_dir
scene_bytes: str | None = None # base64-encoded PNG/JPEG of the reference scene
model_filename: str # person image in output_dir → image2 (Picture 2)
scene_bytes: str | None = None # base64-encoded PNG/JPEG of the reference scene → image1
scene_video: str | None = None # wireframe video name to extract frame from
scene_time: float = 0.0 # timestamp (seconds) to extract from video
extra_filename: str | None = None # optional extra reference in output_dir → image3 (Picture 3)
prompt: str | None = None # override; auto-built if None
seed: int = -1
@@ -2361,18 +2362,19 @@ def _make_side_by_side(img1: Image.Image, img2: Image.Image,
def _scenery_worker(job_id: str, model_filename: str, scene_pil: Image.Image,
prompt: str, seed: int):
prompt: str, seed: int, extra_pils: list | None = None):
output_dir = _load_output_dir()
try:
model_path = os.path.join(output_dir, model_filename)
model_pil = Image.open(model_path).convert("RGB")
# image1=scene (→ Picture 1, output sized to scene), image2=person (→ Picture 2)
# The node prepends "Picture 1: <img> Picture 2: <img>" to the prompt so the
# model can reason about both images by name.
# image1=scene (→ Picture 1, output sized to scene), image2=person (→ Picture 2),
# image3=optional extra ref (→ Picture 3). The node prepends "Picture 1: <img>
# Picture 2: <img> ..." to the prompt so the model can reason about each by name.
extra_images = [model_pil] + list(extra_pils or [])
png_bytes = _run_pipeline(
scene_pil.convert("RGB"), prompt, seed, MAX_AREA,
extra_images=[model_pil],
extra_images=extra_images,
)
ts = time.strftime("%Y%m%d_%H%M%S")
base_name = naming.get_base_name(model_filename)
@@ -2396,6 +2398,10 @@ def _scenery_worker(job_id: str, model_filename: str, scene_pil: Image.Image,
print(f"[scenery] DB error: {db_err}")
jobs[job_id]["status"] = "done"
jobs[job_id]["output"] = out_name
# Regenerate the static JSON so the frontend's polling surfaces the new
# image immediately (matching _batch_worker / _multi_ref_worker). Without
# this the output only appeared after a server restart.
_invalidate_static()
except Exception as e:
print(f"[scenery] error: {e}")
jobs[job_id]["status"] = "error"
@@ -2427,19 +2433,28 @@ def generate_scenery(req: SceneryRequest):
else:
raise HTTPException(400, "Provide scene_bytes or scene_video")
# Optional image3 (Picture 3) — extra reference from output_dir
extra_pils = []
if req.extra_filename:
extra_path = os.path.join(output_dir, req.extra_filename)
if not os.path.exists(extra_path):
raise HTTPException(404, f"Extra reference not found: {req.extra_filename}")
extra_pils.append(Image.open(extra_path).convert("RGB"))
prompt = req.prompt or (
"Place the person from Picture 2 naturally inside the environment shown in Picture 1. "
"Keep the person's face, body proportions, clothing and pose exactly as in Picture 2. "
"Use the location, lighting and atmosphere from Picture 1 as the background. "
"Match the color temperature and shadows so it looks like one photograph taken on location. "
"Output a single photorealistic image. High quality, detailed."
+ ("Incorporate the reference from Picture 3 as well. " if extra_pils else "")
+ "Output a single photorealistic image. High quality, detailed."
)
job_id = uuid.uuid4().hex[:8]
jobs[job_id] = {"status": "running", "type": "scenery", "total": 1, "done": 0, "failed": 0}
threading.Thread(
target=_scenery_worker,
args=(job_id, req.model_filename, scene_pil, prompt, req.seed),
args=(job_id, req.model_filename, scene_pil, prompt, req.seed, extra_pils),
daemon=True,
).start()
return {"job_id": job_id, "model": req.model_filename}