Check each scene right after it is drawn and redraw failures immediately
This commit is contained in:
1 parent
7f26c406c7
commit
d2342e1bd0
1 file changed
+69
-37
@@ -931,7 +931,7 @@ def ensure_models(s, engine):
|
|||||||
raise RuntimeError(f"'{vm}' is a text model and cannot check images. Pick a vision model such as qwen2.5vl:7b in Settings")
|
raise RuntimeError(f"'{vm}' is a text model and cannot check images. Pick a vision model such as qwen2.5vl:7b in Settings")
|
||||||
|
|
||||||
|
|
||||||
def ollama_call(s, prompt, temperature=0.9, model=None, images=None, num_predict=2048, as_json=True):
|
def ollama_call(s, prompt, temperature=0.9, model=None, images=None, num_predict=2048, as_json=True, keep_alive="5m"):
|
||||||
url = f"{s['ollama_url'].rstrip('/')}/api/generate"
|
url = f"{s['ollama_url'].rstrip('/')}/api/generate"
|
||||||
model = model or s["ollama_model"]
|
model = model or s["ollama_model"]
|
||||||
timeout = max(30, int(s["ollama_timeout"]))
|
timeout = max(30, int(s["ollama_timeout"]))
|
||||||
@@ -939,7 +939,7 @@ def ollama_call(s, prompt, temperature=0.9, model=None, images=None, num_predict
|
|||||||
"model": model,
|
"model": model,
|
||||||
"prompt": prompt,
|
"prompt": prompt,
|
||||||
"stream": False,
|
"stream": False,
|
||||||
"keep_alive": "5m",
|
"keep_alive": keep_alive,
|
||||||
"options": {"temperature": temperature, "num_predict": num_predict, "num_ctx": 8192},
|
"options": {"temperature": temperature, "num_predict": num_predict, "num_ctx": 8192},
|
||||||
}
|
}
|
||||||
if as_json:
|
if as_json:
|
||||||
@@ -1347,10 +1347,10 @@ def kids_vision_check(s, clip_path):
|
|||||||
problems = []
|
problems = []
|
||||||
unclear = []
|
unclear = []
|
||||||
try:
|
try:
|
||||||
desc = ollama_call(s, "Describe this image in one short sentence.", temperature=0.1, model=model, images=images, num_predict=80, as_json=False).strip()
|
desc = ollama_call(s, "Describe this image in one short sentence.", temperature=0.1, model=model, images=images, num_predict=80, as_json=False, keep_alive="30s").strip()
|
||||||
def ask(q):
|
def ask(q):
|
||||||
for _ in range(2):
|
for _ in range(2):
|
||||||
a = yes_no(ollama_call(s, q, temperature=0.0, model=model, images=images, num_predict=10, as_json=False))
|
a = yes_no(ollama_call(s, q, temperature=0.0, model=model, images=images, num_predict=10, as_json=False, keep_alive="30s"))
|
||||||
if a is not None:
|
if a is not None:
|
||||||
return a
|
return a
|
||||||
return None
|
return None
|
||||||
@@ -1752,56 +1752,88 @@ def run_job(s):
|
|||||||
raise
|
raise
|
||||||
stop_event.wait(10)
|
stop_event.wait(10)
|
||||||
|
|
||||||
for i, scene in enumerate(script["scenes"], 1):
|
anatomy_flags = []
|
||||||
set_stage(f"generating scene {i}/{n}", step=2 + i)
|
batch_pending = []
|
||||||
path = job_dir / f"clip_{i:02d}.mp4"
|
inline = kids
|
||||||
build_scene(i, scene, path)
|
|
||||||
clips.append(path)
|
|
||||||
|
|
||||||
anatomy_note = ""
|
def judge(i, rnd):
|
||||||
safety_hits = set()
|
|
||||||
if kids:
|
|
||||||
pending = list(range(1, n + 1))
|
|
||||||
for rnd in range(1, 4):
|
|
||||||
unload_pipeline()
|
|
||||||
rejected = []
|
|
||||||
for i in pending:
|
|
||||||
check()
|
|
||||||
set_stage(f"vision check scene {i}/{n}", step=2 + n + i)
|
|
||||||
try:
|
try:
|
||||||
kids_vision_check(s, clips[i - 1])
|
kids_vision_check(s, clips[i - 1])
|
||||||
vision_log.append({"clip": i, "round": rnd, "result": "passed"})
|
vision_log.append({"clip": i, "round": rnd, "result": "passed"})
|
||||||
|
return "pass"
|
||||||
except Cancelled:
|
except Cancelled:
|
||||||
raise
|
raise
|
||||||
except VisionUnavailable as e:
|
except VisionUnavailable as e:
|
||||||
if s["kids_manual_review"]:
|
if s["kids_manual_review"]:
|
||||||
logger.warning("Scene %d: %s. Continuing, check this video manually before publishing", i, e)
|
logger.warning("Scene %d: %s. Continuing, check this video manually before publishing", i, e)
|
||||||
vision_log.append({"clip": i, "round": rnd, "result": f"skipped: {e}"[:300]})
|
vision_log.append({"clip": i, "round": rnd, "result": f"skipped: {e}"[:300]})
|
||||||
else:
|
return "pass"
|
||||||
raise RuntimeError(f"{e}. Frames were not verified, so nothing was uploaded")
|
raise
|
||||||
except Exception as e:
|
except VisionReject as e:
|
||||||
logger.warning("Scene %d rejected (round %d): %s", i, rnd, e)
|
logger.warning("Scene %d attempt %d rejected: %s", i, rnd, e)
|
||||||
vision_log.append({"clip": i, "round": rnd, "result": str(e)[:300]})
|
vision_log.append({"clip": i, "round": rnd, "result": str(e)[:300]})
|
||||||
rejected.append(i)
|
return "unsafe" if e.safety else "anatomy"
|
||||||
if getattr(e, "safety", True):
|
|
||||||
safety_hits.add(i)
|
def settle(i, verdict):
|
||||||
else:
|
if verdict == "unsafe":
|
||||||
safety_hits.discard(i)
|
raise RuntimeError(f"Scene {i} still failed the safety check after 3 attempts")
|
||||||
if not rejected:
|
if verdict == "anatomy":
|
||||||
|
logger.warning("Scene %d may still have an anatomy glitch after 3 attempts, keeping it. Check it before publishing", i)
|
||||||
|
anatomy_flags.append(i)
|
||||||
|
|
||||||
|
for i, scene in enumerate(script["scenes"], 1):
|
||||||
|
path = job_dir / f"clip_{i:02d}.mp4"
|
||||||
|
clips.append(path)
|
||||||
|
verdict = "pass"
|
||||||
|
for attempt in range(1, 4):
|
||||||
|
set_stage(f"generating scene {i}/{n}" + (f" (attempt {attempt})" if attempt > 1 else ""), step=(1 + 2 * i) if inline else (2 + i))
|
||||||
|
path.unlink(missing_ok=True)
|
||||||
|
build_scene(i, scene, path)
|
||||||
|
if not inline:
|
||||||
|
if kids:
|
||||||
|
batch_pending.append(i)
|
||||||
|
verdict = "pass"
|
||||||
|
break
|
||||||
|
set_stage(f"checking scene {i}/{n}" + (f" (attempt {attempt})" if attempt > 1 else ""), step=2 + 2 * i)
|
||||||
|
try:
|
||||||
|
verdict = judge(i, attempt)
|
||||||
|
except VisionUnavailable as e:
|
||||||
|
logger.warning("Checking scenes right after drawing failed (%s). Switching to checking after all scenes are drawn", e)
|
||||||
|
inline = False
|
||||||
|
batch_pending.append(i)
|
||||||
|
verdict = "pass"
|
||||||
|
break
|
||||||
|
if verdict == "pass":
|
||||||
|
break
|
||||||
|
if inline:
|
||||||
|
settle(i, verdict)
|
||||||
|
|
||||||
|
if batch_pending:
|
||||||
|
pending = batch_pending
|
||||||
|
for rnd in range(1, 4):
|
||||||
|
unload_pipeline()
|
||||||
|
results = {}
|
||||||
|
for i in pending:
|
||||||
|
check()
|
||||||
|
set_stage(f"checking scene {i}/{n}", step=2 + n + i)
|
||||||
|
try:
|
||||||
|
results[i] = judge(i, rnd)
|
||||||
|
except VisionUnavailable as e:
|
||||||
|
raise RuntimeError(f"{e}. Frames were not verified, so nothing was uploaded")
|
||||||
|
failed = [i for i, v in results.items() if v != "pass"]
|
||||||
|
if not failed:
|
||||||
break
|
break
|
||||||
if rnd == 3:
|
if rnd == 3:
|
||||||
unsafe = [i for i in rejected if i in safety_hits]
|
for i in failed:
|
||||||
if unsafe:
|
settle(i, results[i])
|
||||||
raise RuntimeError(f"Scenes {unsafe} still failed the safety check after 3 rounds")
|
|
||||||
flagged = ", ".join(str(i) for i in rejected)
|
|
||||||
logger.warning("Scenes %s may still have anatomy glitches after 3 redraws, keeping them. Check them before publishing", flagged)
|
|
||||||
anatomy_note = f"Possible anatomy glitches kept in scenes {flagged}"
|
|
||||||
break
|
break
|
||||||
for i in rejected:
|
for i in failed:
|
||||||
set_stage(f"regenerating scene {i}/{n}", step=2 + i)
|
set_stage(f"regenerating scene {i}/{n}", step=2 + i)
|
||||||
clips[i - 1].unlink(missing_ok=True)
|
clips[i - 1].unlink(missing_ok=True)
|
||||||
build_scene(i, script["scenes"][i - 1], clips[i - 1])
|
build_scene(i, script["scenes"][i - 1], clips[i - 1])
|
||||||
pending = rejected
|
pending = failed
|
||||||
|
|
||||||
|
anatomy_note = f"Possible anatomy glitches kept in scenes {', '.join(str(i) for i in anatomy_flags)}" if anatomy_flags else ""
|
||||||
if kids:
|
if kids:
|
||||||
compliance["vision_checks"] = vision_log
|
compliance["vision_checks"] = vision_log
|
||||||
if anatomy_note:
|
if anatomy_note:
|
||||||
|
|||||||
Reference in new issue
Block a user