Spaces:
Runtime error
Runtime error
| import streamlit as st | |
| import requests | |
| import io | |
| from PIL import Image | |
| st.set_page_config(page_title="dreamforge · AI Image Generator", page_icon="🔮", layout="wide") | |
| st.markdown(""" | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Syne:wght@400;700;800&family=Fira+Code&display=swap'); | |
| html, body, [class*="css"] { font-family: 'Syne', sans-serif; } | |
| .stApp { background: #0a0a0b; color: #f0f0f0; } | |
| h1 { font-size: 2.4rem !important; font-weight: 800 !important; letter-spacing: -1px; } | |
| .subtitle { color: #666; font-family: 'Fira Code', monospace; font-size: 13px; margin-top: -16px; margin-bottom: 28px; } | |
| .stButton > button { | |
| background: #e8ff47 !important; color: #000 !important; | |
| font-family: 'Syne', sans-serif !important; font-weight: 800 !important; | |
| font-size: 16px !important; border: none !important; | |
| border-radius: 12px !important; padding: 14px 0 !important; width: 100%; | |
| } | |
| .stButton > button:hover { box-shadow: 0 8px 30px rgba(232,255,71,0.3) !important; } | |
| .stTextArea textarea, .stTextInput input { | |
| background: #18181b !important; border: 1px solid rgba(255,255,255,0.06) !important; | |
| color: #f0f0f0 !important; border-radius: 10px !important; | |
| font-family: 'Fira Code', monospace !important; font-size: 13px !important; | |
| } | |
| label { color: #888 !important; font-size: 12px !important; letter-spacing: 1px !important; text-transform: uppercase !important; } | |
| .stImage img { border-radius: 16px; box-shadow: 0 24px 80px rgba(0,0,0,0.6); } | |
| hr { border-color: rgba(255,255,255,0.06) !important; } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| MODELS = { | |
| "⚡ FLUX Schnell (fastest)": "black-forest-labs/FLUX.1-schnell", | |
| "🎨 SDXL Base (high quality)": "stabilityai/stable-diffusion-xl-base-1.0", | |
| "🖼 SD 1.5 (classic)": "runwayml/stable-diffusion-v1-5", | |
| "🌅 Openjourney (Midjourney style)": "prompthero/openjourney-v4", | |
| } | |
| STYLES = { | |
| "None": "", "Cinematic": ", cinematic lighting, film grain, anamorphic lens", | |
| "Anime": ", anime style, vibrant colors, studio ghibli", | |
| "Oil Painting": ", oil painting, textured brushstrokes, classical art", | |
| "Neon Noir": ", neon noir, rain-slicked streets, cyberpunk", | |
| "Soft Dream": ", soft focus, dreamy, pastel tones, ethereal", | |
| "Raw Photo": ", photorealistic, RAW photo, DSLR, 85mm lens", | |
| } | |
| RATIOS = { | |
| "1:1 (512×512)": (512, 512), "3:2 (768×512)": (768, 512), | |
| "2:3 (512×768)": (512, 768), "16:9 (896×512)": (896, 512), | |
| } | |
| HF_API = "https://api-inference.huggingface.co/models/" | |
| st.markdown("# 🔮 dreamforge") | |
| st.markdown('<p class="subtitle">AI image generation · Hugging Face Inference API</p>', unsafe_allow_html=True) | |
| st.markdown("---") | |
| col_left, col_right = st.columns([1, 1], gap="large") | |
| with col_left: | |
| hf_token = st.text_input("🔑 Hugging Face Token", type="password", placeholder="hf_xxxxxxxxxxxxxxxxxxxxxxxx", help="Get yours free at huggingface.co/settings/tokens") | |
| prompt = st.text_area("✏️ Prompt", placeholder="A misty mountain at golden hour, oil on canvas…", height=120) | |
| neg_prompt = st.text_area("🚫 Negative Prompt", value="blurry, low quality, watermark, text, ugly, deformed", height=68) | |
| model_label = st.selectbox("🤖 Model", list(MODELS.keys())) | |
| c1, c2 = st.columns(2) | |
| with c1: style_label = st.selectbox("🎨 Style", list(STYLES.keys())) | |
| with c2: ratio_label = st.selectbox("📐 Ratio", list(RATIOS.keys())) | |
| c3, c4 = st.columns(2) | |
| with c3: steps = st.slider("Steps", 1, 50, 4) | |
| with c4: guidance = st.slider("Guidance Scale", 1.0, 20.0, 7.5, 0.5) | |
| generate = st.button("✦ Generate Image", use_container_width=True) | |
| with col_right: | |
| st.markdown("### Output") | |
| if generate: | |
| if not hf_token.strip(): | |
| st.error("🔑 Please enter your Hugging Face API token.") | |
| elif not prompt.strip(): | |
| st.error("✏️ Please enter a prompt.") | |
| else: | |
| model_id = MODELS[model_label] | |
| full_prompt = prompt + STYLES[style_label] | |
| width, height = RATIOS[ratio_label] | |
| headers = {"Authorization": f"Bearer {hf_token.strip()}"} | |
| payload = {"inputs": full_prompt} | |
| if "FLUX" in model_label: | |
| payload["parameters"] = {"num_inference_steps": steps, "width": width, "height": height} | |
| else: | |
| payload["parameters"] = {"negative_prompt": neg_prompt, "num_inference_steps": steps, "guidance_scale": guidance, "width": width, "height": height} | |
| with st.spinner("Synthesizing pixels…"): | |
| try: | |
| resp = requests.post(HF_API + model_id, headers=headers, json=payload, timeout=120) | |
| if resp.status_code == 503: | |
| st.warning("⏳ Model is loading — wait 20 seconds and try again.") | |
| elif not resp.ok: | |
| try: detail = resp.json().get("error", resp.text) | |
| except: detail = resp.text | |
| st.error(f"API error {resp.status_code}: {detail}") | |
| else: | |
| image = Image.open(io.BytesIO(resp.content)) | |
| st.image(image, use_container_width=True) | |
| buf = io.BytesIO() | |
| image.save(buf, format="PNG") | |
| st.download_button("⬇ Download PNG", data=buf.getvalue(), file_name="dreamforge_output.png", mime="image/png", use_container_width=True) | |
| st.caption(f"**Prompt:** {full_prompt}") | |
| except requests.exceptions.Timeout: | |
| st.error("⏱ Request timed out. Try fewer steps or a faster model.") | |
| except Exception as e: | |
| st.error(f"Something went wrong: {e}") | |
| else: | |
| st.markdown('<div style="border:1px dashed rgba(255,255,255,0.1);border-radius:16px;height:400px;display:flex;align-items:center;justify-content:center;color:#444;font-family:monospace;font-size:13px;">your image will appear here</div>', unsafe_allow_html=True) | |
| st.markdown("---") | |
| st.markdown('<p style="text-align:center;color:#444;font-size:12px;font-family:monospace;">dreamforge · <a href="https://huggingface.co/settings/tokens" style="color:#e8ff47">get your free HF token</a></p>', unsafe_allow_html=True) | |