Dreamforge / app.py
spxxtu's picture
Upload 3 files
64c0f9c verified
Raw
History Blame Contribute Delete
6.34 kB
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)