IMAGPRO / api.py
webnowa's picture
Update api.py
e993d4e verified
import os
import io
import torch
from flask import Flask, request, jsonify, send_file, render_template_string
from diffusers import StableDiffusionPipeline, StableDiffusionImg2ImgPipeline
from PIL import Image, ImageFilter
from deep_translator import GoogleTranslator
from datetime import datetime
print("STARTING IMAGE PRO AI")
OUTPUT_DIR = "outputs"
os.makedirs(OUTPUT_DIR, exist_ok=True)
progress_value = 0
# ======================
# TRANSLATE & PROMPT ENHANCE
# ======================
def translate(text):
try:
return GoogleTranslator(source="auto", target="en").translate(text)
except:
return text
STYLE_PRESETS = {
"cinematic": "cinematic lighting, ultra realistic, 8k, film still, depth of field",
"anime": "anime style, clean lines, vibrant colors, detailed illustration",
"realistic": "photo realistic, natural lighting, high detail, 8k",
"neon": "neon lights, cyberpunk, glowing colors, night city",
"cartoon": "cartoon style, bold outlines, flat colors, playful",
}
def enhance(text, style: str | None = None):
base = "high detail, professional, sharp focus"
extra = base
if style and style in STYLE_PRESETS:
extra = STYLE_PRESETS[style] + ", " + base
return text + ", " + extra
# ======================
# MODEL (SZYBSZY: SD-TURBO)
# ======================
print("Loading Stable Diffusion Turbo...")
MODEL_ID = os.getenv("MODEL_ID", "stabilityai/sd-turbo")
pipe = StableDiffusionPipeline.from_pretrained(
MODEL_ID,
torch_dtype=torch.float32
)
pipe = pipe.to("cpu")
pipe.enable_attention_slicing()
img2img_pipe = StableDiffusionImg2ImgPipeline.from_pretrained(
MODEL_ID,
torch_dtype=torch.float32
)
img2img_pipe = img2img_pipe.to("cpu")
img2img_pipe.enable_attention_slicing()
print("MODEL READY")
# ======================
# API
# ======================
api = Flask(__name__)
# ======================
# HTML UI (ODŚWIEŻONY)
# ======================
HTML = """
<html>
<head>
<title>IMAGE PRO AI STUDIO</title>
<style>
body{
background:#05060a;
color:#f5f5f5;
text-align:center;
font-family:Arial, sans-serif;
}
h1{
margin-top:20px;
letter-spacing:2px;
}
.container{
max-width:900px;
margin:0 auto;
padding:20px;
}
button{
background:#ff8c00;
border:none;
padding:10px 16px;
margin:5px;
cursor:pointer;
font-weight:bold;
border-radius:6px;
color:#111;
}
button:hover{
background:#ffb347;
}
input, select{
width:420px;
padding:10px;
border-radius:6px;
border:1px solid #333;
background:#111;
color:#f5f5f5;
}
img{
max-width:650px;
margin-top:20px;
border:2px solid #ff8c00;
border-radius:8px;
}
#bar{
width:0%;
height:20px;
background:#ff8c00;
border-radius:10px;
}
#progress{
width:400px;
background:#222;
margin:10px auto;
display:none;
border-radius:10px;
padding:2px;
}
.section-title{
margin-top:25px;
font-size:18px;
text-transform:uppercase;
letter-spacing:1px;
color:#ffb347;
}
</style>
</head>
<body>
<div class="container">
<h1>IMAGE PRO AI STUDIO</h1>
<div>
<input id="prompt" placeholder="Enter prompt">
</div>
<div class="section-title">Styles</div>
<div>
<button onclick="stylePreset('cinematic')">CINEMATIC</button>
<button onclick="stylePreset('anime')">ANIME</button>
<button onclick="stylePreset('realistic')">REALISTIC</button>
<button onclick="stylePreset('neon')">NEON</button>
<button onclick="stylePreset('cartoon')">CARTOON</button>
</div>
<div class="section-title">Generate</div>
<div>
<button onclick="generate()">IMAGE</button>
<button onclick="product()">PRODUCT</button>
<button onclick="logo()">LOGO</button>
<button onclick="banner()">BANNER</button>
<button onclick="social()">SOCIAL</button>
</div>
<div class="section-title">Image Tools</div>
<div>
<input type="file" id="file">
</div>
<div>
<button onclick="restore()">RESTORE</button>
<button onclick="upscale()">UPSCALE</button>
<button onclick="color()">COLORIZE</button>
</div>
<div class="section-title">Blend PRO</div>
<div>
<input type="file" id="blendA">
<input type="file" id="blendB">
</div>
<div>
<label>Mix: <span id="mixLabel">0.5</span></label><br>
<input type="range" id="mixRange" min="0" max="1" step="0.05" value="0.5" style="width:300px" oninput="updateMix()">
</div>
<div>
<button onclick="runBlend()">BLEND</button>
<button onclick="runBlendPro()">BLEND PRO (AI)</button>
</div>
<h3>GENERATING</h3>
<div id="progress">
<div id="bar"></div>
</div>
<p id="percent">0%</p>
<h2>RESULT</h2>
<img id="result">
</div>
<script>
let progressTimer
let currentStyle = null
function startProgress(){
document.getElementById("progress").style.display="block"
document.getElementById("bar").style.width="0%"
document.getElementById("percent").innerText="0%"
progressTimer=setInterval(updateProgress,500)
}
function updateProgress(){
fetch("/progress")
.then(r=>r.json())
.then(data=>{
let p=data.progress
document.getElementById("bar").style.width=p+"%"
document.getElementById("percent").innerText=p+"%"
if(p>=100){
clearInterval(progressTimer)
}
})
}
function show(blob){
document.getElementById("result").src=URL.createObjectURL(blob)
}
function sendPrompt(endpoint, extraBody){
startProgress()
let body = {
prompt: document.getElementById("prompt").value,
style: currentStyle
}
if(extraBody){
Object.assign(body, extraBody)
}
fetch("/"+endpoint,{
method:"POST",
headers:{"Content-Type":"application/json"},
body:JSON.stringify(body)
})
.then(r=>r.blob())
.then(show)
}
function generate(){sendPrompt("generate")}
function product(){sendPrompt("product")}
function logo(){sendPrompt("logo")}
function banner(){sendPrompt("banner")}
function social(){sendPrompt("social")}
function sendImage(endpoint){
let file=document.getElementById("file").files[0]
if(!file){
alert("Select image first")
return
}
let data=new FormData()
data.append("image",file)
startProgress()
fetch("/"+endpoint,{method:"POST",body:data})
.then(r=>r.blob())
.then(show)
}
function restore(){sendImage("restore")}
function upscale(){sendImage("upscale")}
function color(){sendImage("colorize")}
function stylePreset(style){
currentStyle = style
alert("Style set: "+style.toUpperCase())
}
function updateMix(){
const v = document.getElementById("mixRange").value
document.getElementById("mixLabel").innerText = v
}
function runBlendCore(endpoint){
let a=document.getElementById("blendA").files[0]
let b=document.getElementById("blendB").files[0]
if(!a || !b){
alert("Select both images (A and B)")
return
}
let data=new FormData()
data.append("image_a",a)
data.append("image_b",b)
data.append("mix",document.getElementById("mixRange").value)
if(currentStyle){
data.append("style", currentStyle)
}
startProgress()
fetch("/"+endpoint,{method:"POST",body:data})
.then(r=>r.blob())
.then(show)
}
function runBlend(){runBlendCore("blend")}
function runBlendPro(){runBlendCore("blend-pro")}
</script>
</body>
</html>
"""
@api.route("/")
def home():
return render_template_string(HTML)
# ======================
# PROGRESS
# ======================
@api.route("/progress")
def progress():
global progress_value
return jsonify({"progress": progress_value})
# ======================
# GENERATE IMAGE
# ======================
def generate_image(prompt, style: str | None = None):
global progress_value
steps = 8 # szybciej
prompt = translate(prompt)
prompt = enhance(prompt, style)
def callback(step, timestep, latents):
global progress_value
progress_value = int((step/steps)*100)
image = pipe(
prompt,
num_inference_steps=steps,
guidance_scale=1.5,
callback=callback,
callback_steps=1
).images[0]
progress_value = 100
filename = datetime.now().strftime("%Y%m%d%H%M%S") + ".png"
path = os.path.join(OUTPUT_DIR, filename)
image.save(path)
return path
# ======================
# GENERATE
# ======================
@api.route("/generate", methods=["POST"])
def generate():
try:
data = request.get_json(force=True)
prompt = data.get("prompt", "")
style = data.get("style")
path = generate_image(prompt, style)
return send_file(path, mimetype="image/png")
except Exception as e:
return jsonify({"error": str(e)})
# ======================
# PRODUCT
# ======================
@api.route("/product", methods=["POST"])
def product():
data = request.get_json(force=True)
prompt = data.get("prompt", "")
style = data.get("style") or "realistic"
prompt = translate(prompt) + ", product photography, studio lighting, white background"
path = generate_image(prompt, style)
return send_file(path, mimetype="image/png")
# ======================
# LOGO
# ======================
@api.route("/logo", methods=["POST"])
def logo():
data = request.get_json(force=True)
prompt = data.get("prompt", "")
style = data.get("style") or "cartoon"
prompt = translate(prompt) + ", minimalist vector logo"
path = generate_image(prompt, style)
return send_file(path, mimetype="image/png")
# ======================
# BANNER
# ======================
@api.route("/banner", methods=["POST"])
def banner():
data = request.get_json(force=True)
prompt = data.get("prompt", "")
style = data.get("style") or "cinematic"
prompt = translate(prompt) + ", modern website banner design"
path = generate_image(prompt, style)
return send_file(path, mimetype="image/png")
# ======================
# SOCIAL
# ======================
@api.route("/social", methods=["POST"])
def social():
data = request.get_json(force=True)
prompt = data.get("prompt", "")
style = data.get("style") or "neon"
prompt = translate(prompt) + ", instagram social media post"
path = generate_image(prompt, style)
return send_file(path, mimetype="image/png")
# ======================
# RESTORE
# ======================
@api.route("/restore", methods=["POST"])
def restore():
if "image" not in request.files:
return "no image", 400
file = request.files["image"]
img = Image.open(file.stream)
img = img.filter(ImageFilter.SHARPEN)
path = os.path.join(OUTPUT_DIR, "restore.png")
img.save(path)
return send_file(path, mimetype="image/png")
# ======================
# UPSCALE
# ======================
@api.route("/upscale", methods=["POST"])
def upscale():
if "image" not in request.files:
return "no image", 400
file = request.files["image"]
img = Image.open(file.stream)
w, h = img.size
img = img.resize((w * 2, h * 2), Image.LANCZOS)
path = os.path.join(OUTPUT_DIR, "upscale.png")
img.save(path)
return send_file(path, mimetype="image/png")
# ======================
# COLORIZE
# ======================
@api.route("/colorize", methods=["POST"])
def colorize():
if "image" not in request.files:
return "no image", 400
file = request.files["image"]
img = Image.open(file.stream)
img = img.convert("RGB")
path = os.path.join(OUTPUT_DIR, "color.png")
img.save(path)
return send_file(path, mimetype="image/png")
# ======================
# BLEND (KLASYCZNY)
# ======================
def _blend_simple(file_a, file_b, mix: float, style: str | None = None):
img_a = Image.open(file_a.stream).convert("RGBA")
img_b = Image.open(file_b.stream).convert("RGBA")
img_b = img_b.resize(img_a.size)
mix = max(0.0, min(1.0, mix))
blended = Image.blend(img_a, img_b, mix)
path = os.path.join(OUTPUT_DIR, "blend.png")
blended.save(path)
return path
# ======================
# BLEND PRO (AI IMG2IMG)
# ======================
def _blend_ai(file_a, file_b, mix: float, style: str | None = None):
img_a = Image.open(file_a.stream).convert("RGBA")
img_b = Image.open(file_b.stream).convert("RGBA")
img_b = img_b.resize(img_a.size)
mix = max(0.0, min(1.0, mix))
base = Image.blend(img_a, img_b, mix).convert("RGB")
prompt = "high quality artistic blend of two images"
if style and style in STYLE_PRESETS:
prompt += ", " + STYLE_PRESETS[style]
images = img2img_pipe(
prompt=prompt,
image=base,
strength=0.6,
num_inference_steps=8,
guidance_scale=1.5,
).images
result = images[0]
path = os.path.join(OUTPUT_DIR, "blend_pro.png")
result.save(path)
return path
@api.route("/blend", methods=["POST"])
def blend():
if "image_a" not in request.files or "image_b" not in request.files:
return "need image_a and image_b", 400
file_a = request.files["image_a"]
file_b = request.files["image_b"]
try:
mix = float(request.form.get("mix", 0.5))
except:
mix = 0.5
style = request.form.get("style")
path = _blend_simple(file_a, file_b, mix, style)
return send_file(path, mimetype="image/png")
@api.route("/blend-pro", methods=["POST"])
def blend_pro():
if "image_a" not in request.files or "image_b" not in request.files:
return "need image_a and image_b", 400
file_a = request.files["image_a"]
file_b = request.files["image_b"]
try:
mix = float(request.form.get("mix", 0.5))
except:
mix = 0.5
style = request.form.get("style")
path = _blend_ai(file_a, file_b, mix, style)
return send_file(path, mimetype="image/png")
# ======================
if __name__ == "__main__":
api.run(host="0.0.0.0", port=7860)