Spaces:
Running
Running
| 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("<h1 id='lab-title'>AI Image Editing</h1><p id='lab-subtitle'>Let your imagination thrive !</p><p id='lab-disclaimer'>Do not submit personal information, nor images you do not hold the rights to.</p>") | |
| 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 <p id=\'privacy-footer\'>\n <a onclick="document.getElementById(\'privacy-modal\').classList.add(\'open\')">Privacy Policy</a>\n </p>\n\n <div id=\'privacy-modal\'>\n <div id=\'privacy-modal-box\'>\n <strong>Privacy Policy</strong><br><br>\n Please do not upload personal information, or images you do not have the right to use.<br><br>\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.<br><br>\n Data submitted to this Space is deleted at least monthly.<br><br>\n <br>\n <button onclick="document.getElementById(\'privacy-modal\').classList.remove(\'open\')">Close</button>\n </div>\n </div>\n ') | |
| K.queue(max_size=20,default_concurrency_limit=4) | |
| if __name__=='__main__':K.launch(css=a,share=False) |