L='PNG' D='RGB' C=max import base64 as M,io,json,math as F,os,random,sys,time,traceback as N,uuid,gradio as A,numpy as B from huggingface_hub import batch_bucket_files as O from PIL import Image as E,ImageDraw as P,ImageFilter as Q,ImageFont as G H=os.environ.get('HF_TOKEN','').strip() I=os.environ.get('BUCKET_ID','').strip() R=os.environ.get('DEEPINFRA_TOKEN','').strip() S='Wan-AI/Wan2.7-Image-Edit' T=bool(H and I) def U():return OpenAI(api_key=R,base_url='https://api.deepinfra.com/v1/openai') def f(image,prompt):A=io.BytesIO();image.convert(D).save(A,format=L);B=M.b64encode(A.getvalue()).decode();C=U();E=C.images.edit(model=S,image=f"data:image/png;base64,{B}",prompt=prompt,n=1);return E.data[0] def V(sample_id,image,prompt): A=sample_id if not T:return try:B=io.BytesIO();image.convert(D).save(B,format=L);C={'id':A,'prompt':prompt,'timestamp':time.time()};O(I,add=[(B.getvalue(),f"images/{A}.png"),(json.dumps(C).encode(),f"metadata/{A}.json")],token=H) except Exception:print(f"[DEBUG] log_request failed:\n{N.format_exc()}",file=sys.stderr) def W(size):A,C=size;return B.random.randint(0,256,(C,A,3)).astype(B.float32) def X(size,cell=28):A,F=size;G,H=C(2,A//cell),C(2,F//cell);I=B.random.randint(0,256,(H,G,3)).astype(B.uint8);return B.asarray(E.fromarray(I,D).resize((A,F),E.BICUBIC),dtype=B.float32) def Y(arr):return E.fromarray(B.clip(arr,0,255).astype(B.uint8),D) def g(target,t):G=target;E=.0;A=G.size;t=C(E,min(1.,t));K=C(.6,C(A)/6*F.exp(-3.2*t));L=B.asarray(G.filter(Q.GaussianBlur(radius=K)).convert(D),dtype=B.float32);H=.5*(1+F.cos(F.pi*t));I=C(E,1-2*t);J=2*t if t<.5 else C(E,2*(1-t));M=I+J or 1.;N=(I*W(A)+J*X(A))/M;O=L*(1-H)+N*H;return Y(O) def J(draw,y,text,font,fill,size):A=draw.textbbox((0,0),text,font=font);B,C=A[2]-A[0],A[3]-A[1];draw.text(((size[0]-B)/2-A[0],y-A[1]),text,fill=fill,font=font);return C def h(size):A=size;F=E.new(D,A,(243,239,230));B=P.Draw(F);B.rectangle([0,0,A[0]-1,A[1]-1],outline=(20,20,20),width=3);H=G.load_default(size=C(36,A[0]//9));I=G.load_default(size=C(18,A[0]//26));K=J(B,A[1]/2-A[0]//9,'ERROR',H,(163,39,44),A);J(B,A[1]/2-A[0]//9+K+16,'SYNTHESIS FAULT - RETRY',I,(40,40,40),A);return F def Z(image,prompt): C=image;B=prompt if C is None or not B or not B.strip():raise A.Error('Please provide both an image and a prompt.') D=uuid.uuid4().hex[:10];V(D,C,B.strip());raise A.Error('429: Rate limit reached.') a="\n@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap');\n\n:root {\n --paper: #ffffff;\n --ink: #0a0a0a;\n --line: #dcdcdc;\n --accent: #0a0a0a;\n}\n\n.gradio-container {\n background: var(--paper) !important;\n font-family: 'JetBrains Mono', monospace !important;\n color: var(--ink) !important;\n}\n\n#lab-title {\n font-family: 'JetBrains Mono', monospace;\n font-weight: 700;\n letter-spacing: 4px;\n text-transform: uppercase;\n text-align: center;\n color: var(--ink);\n border-bottom: 2px solid var(--ink);\n padding-bottom: 0.5rem;\n margin-bottom: 0;\n}\n\n#lab-subtitle {\n text-align: center;\n font-size: 0.85rem;\n color: #4d4d4d;\n margin-top: 0.4rem;\n letter-spacing: 0.5px;\n}\n\n#lab-disclaimer {\n text-align: center;\n font-size: 0.72rem;\n color: #8a8a8a;\n margin-top: 0.3rem;\n margin-bottom: 1rem;\n letter-spacing: 0.3px;\n text-transform: uppercase;\n}\n\n.gr-panel, .block, .form {\n background: var(--paper) !important;\n border: 1.5px solid var(--ink) !important;\n border-radius: 0 !important;\n box-shadow: none !important;\n}\n\ntextarea, input {\n background: var(--paper) !important;\n color: var(--ink) !important;\n font-family: 'JetBrains Mono', monospace !important;\n border: 1.5px solid var(--ink) !important;\n border-radius: 0 !important;\n}\n\nbutton {\n font-family: 'JetBrains Mono', monospace !important;\n font-weight: 700 !important;\n text-transform: uppercase;\n letter-spacing: 1.5px;\n background: var(--ink) !important;\n color: var(--paper) !important;\n border-radius: 0 !important;\n border: 1.5px solid var(--ink) !important;\n transition: all 0.15s ease-in-out;\n}\nbutton:hover {\n background: var(--paper) !important;\n color: var(--ink) !important;\n}\n\nlabel {\n color: var(--ink) !important;\n font-family: 'JetBrains Mono', monospace !important;\n font-size: 0.78rem !important;\n text-transform: uppercase;\n letter-spacing: 1px;\n}\n\nfooter {visibility: hidden}\n\n#privacy-footer {\n text-align: center;\n font-size: 0.72rem;\n color: #8a8a8a;\n margin-top: 2rem;\n letter-spacing: 0.3px;\n}\n#privacy-footer a {\n color: #8a8a8a;\n text-decoration: underline;\n cursor: pointer;\n}\n\n#privacy-modal {\n display: none;\n position: fixed;\n top: 0; left: 0; width: 100%; height: 100%;\n background: rgba(0,0,0,0.6);\n z-index: 9999;\n align-items: center;\n justify-content: center;\n}\n#privacy-modal.open { display: flex; }\n#privacy-modal-box {\n background: var(--paper);\n border: 1.5px solid var(--ink);\n padding: 2rem;\n max-width: 480px;\n font-family: 'JetBrains Mono', monospace;\n font-size: 0.8rem;\n line-height: 1.5;\n}\n#privacy-modal-box button { margin-top: 1rem; }\n" with A.Blocks(title='AI Image Editing')as K: A.HTML("

AI Image Editing

Let your imagination thrive !

Do not submit personal information, nor images you do not hold the rights to.

") with A.Row(): with A.Column():b=A.Image(type='pil',label='Input Image',height=340);c=A.Textbox(label='What changes would you like to make ?',placeholder='e.g. change the background to a forest at dusk',lines=3);d=A.Button('Submit') with A.Column():e=A.Image(label='Output',height=340) d.click(fn=Z,inputs=[b,c],outputs=[e]);A.HTML('\n

\n Privacy Policy\n

\n\n
\n
\n Privacy Policy

\n Please do not upload personal information, or images you do not have the right to use.

\n No personal data beyond what you submit is collected. Only the data required for the system to function — your prompt and the submitted image — is processed, for AI research purposes.

\n Data submitted to this Space is deleted at least monthly.

\n
\n \n
\n
\n ') K.queue(max_size=20,default_concurrency_limit=4) if __name__=='__main__':K.launch(css=a,share=False)