← back to Filibuster Marathon Cartoon
anim/edit.py
32 lines
import base64,json,os,time,urllib.request
tok=[l.split('=',1)[1].strip().strip('"\'') for l in open(os.path.expanduser('~/Projects/secrets-manager/.env')) if l.startswith('REPLICATE_API_TOKEN=')][0]
def api(url,data=None):
r=urllib.request.Request(url,data=json.dumps(data).encode() if data else None,headers={"Authorization":f"Bearer {tok}","Content-Type":"application/json","Prefer":"wait"})
return json.load(urllib.request.urlopen(r,timeout=300))
HERE=os.path.dirname(os.path.abspath(__file__)) # paths resolve from this file, not the cwd
def P(name): return os.path.join(HERE,name)
def poll(pr,interval,deadline_s):
# Replicate bills at create time: never lose the id, retry transient poll errors, bound the wait.
end=time.time()+deadline_s
while pr["status"] not in("succeeded","failed","canceled"):
if time.time()>end: raise SystemExit(f"TIMEOUT after {deadline_s}s — recover later: GET {pr['urls']['get']}")
time.sleep(interval)
for a in range(5):
try: pr=api(pr["urls"]["get"]); break
except Exception as e:
print(f"poll error (attempt {a+1}/5): {e}"); time.sleep(interval*(a+1))
else: raise SystemExit(f"poll failed 5x — recover later: GET {pr['urls']['get']}")
return pr
img="data:image/jpeg;base64,"+base64.b64encode(open(P('base.jpg'),'rb').read()).decode()
p=("Keep this exact pen-and-ink editorial cartoon, same style, same delegate, same lectern, same telephone directory, same composition. "
"Edit only: 1) the melted wall clock's minute hand slides off its face and hangs down the wall like a limp noodle all the way to the floor, its tip resting in the puddle on the floor at bottom right; "
"2) remove the tangled shape lying in the puddle at bottom right, replace it with plain floor and puddle; "
"3) the rows of legislators in the background are asleep, heads slumped forward onto their chests. No text added, no signature.")
pr=api("https://api.replicate.com/v1/models/black-forest-labs/flux-kontext-pro/predictions",{"input":{"prompt":p,"input_image":img,"aspect_ratio":"match_input_image","output_format":"jpg"}})
print("id",pr["id"],pr["status"])
pr=poll(pr,3,900)
print(pr["status"],pr.get("error"))
if pr["status"]!="succeeded": raise SystemExit(1)
out=pr["output"]; out=out[0] if isinstance(out,list) else out
urllib.request.urlretrieve(out,P('edited.jpg')); print('saved')