Spaces:
Sleeping
Sleeping
Update server.py
Browse files
server.py
CHANGED
|
@@ -2,12 +2,12 @@ import io
|
|
| 2 |
import logging
|
| 3 |
import os
|
| 4 |
import threading
|
|
|
|
| 5 |
|
| 6 |
import torch
|
| 7 |
-
from flask import Flask, jsonify, request, send_file
|
| 8 |
from flask_cors import CORS
|
| 9 |
|
| 10 |
-
# CPU limits
|
| 11 |
os.environ["OMP_NUM_THREADS"] = "4"
|
| 12 |
os.environ["MKL_NUM_THREADS"] = "4"
|
| 13 |
torch.set_num_threads(4)
|
|
@@ -16,7 +16,6 @@ torch.set_num_interop_threads(1)
|
|
| 16 |
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s")
|
| 17 |
logger = logging.getLogger("sd-turbo-server")
|
| 18 |
|
| 19 |
-
# Config
|
| 20 |
DEFAULT_STEPS = int(os.environ.get("DEFAULT_STEPS", "4"))
|
| 21 |
DEFAULT_GUIDANCE = float(os.environ.get("DEFAULT_GUIDANCE", "1.0"))
|
| 22 |
DEFAULT_WIDTH = 768
|
|
@@ -68,9 +67,70 @@ def run_generation(prompt, width, height, steps, guidance):
|
|
| 68 |
return result.images[0]
|
| 69 |
|
| 70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
@app.route("/health")
|
| 72 |
def health():
|
| 73 |
-
return jsonify({"status": "ok"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
|
| 76 |
@app.route("/image", methods=["GET"])
|
|
@@ -99,7 +159,7 @@ def generate_image():
|
|
| 99 |
buf.seek(0)
|
| 100 |
return send_file(buf, mimetype="image/png")
|
| 101 |
except Exception as e:
|
| 102 |
-
logger.exception("
|
| 103 |
return str(e), 500
|
| 104 |
|
| 105 |
|
|
|
|
| 2 |
import logging
|
| 3 |
import os
|
| 4 |
import threading
|
| 5 |
+
import uuid
|
| 6 |
|
| 7 |
import torch
|
| 8 |
+
from flask import Flask, jsonify, request, send_file, redirect
|
| 9 |
from flask_cors import CORS
|
| 10 |
|
|
|
|
| 11 |
os.environ["OMP_NUM_THREADS"] = "4"
|
| 12 |
os.environ["MKL_NUM_THREADS"] = "4"
|
| 13 |
torch.set_num_threads(4)
|
|
|
|
| 16 |
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s")
|
| 17 |
logger = logging.getLogger("sd-turbo-server")
|
| 18 |
|
|
|
|
| 19 |
DEFAULT_STEPS = int(os.environ.get("DEFAULT_STEPS", "4"))
|
| 20 |
DEFAULT_GUIDANCE = float(os.environ.get("DEFAULT_GUIDANCE", "1.0"))
|
| 21 |
DEFAULT_WIDTH = 768
|
|
|
|
| 67 |
return result.images[0]
|
| 68 |
|
| 69 |
|
| 70 |
+
@app.route("/")
|
| 71 |
+
def index():
|
| 72 |
+
return "SD Turbo Server - Use /image or /v1/images/generations"
|
| 73 |
+
|
| 74 |
+
|
| 75 |
@app.route("/health")
|
| 76 |
def health():
|
| 77 |
+
return jsonify({"status": "ok", "model": "sd-turbo"})
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
@app.route("/v1/models")
|
| 81 |
+
def list_models():
|
| 82 |
+
return jsonify({
|
| 83 |
+
"object": "list",
|
| 84 |
+
"data": [{"id": "sd-turbo", "object": "model", "owned_by": "stabilityai"}]
|
| 85 |
+
})
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
@app.route("/v1/images/generations", methods=["POST"])
|
| 89 |
+
def images_generations():
|
| 90 |
+
"""OpenAI-compatible endpoint that returns a direct image URL"""
|
| 91 |
+
if not request.is_json:
|
| 92 |
+
return jsonify({"error": {"message": "JSON required"}}), 400
|
| 93 |
+
|
| 94 |
+
data = request.get_json()
|
| 95 |
+
prompt = data.get("prompt")
|
| 96 |
+
if not prompt:
|
| 97 |
+
return jsonify({"error": {"message": "prompt is required"}}), 400
|
| 98 |
+
|
| 99 |
+
size = data.get("size", "768x768")
|
| 100 |
+
n = data.get("n", 1)
|
| 101 |
+
steps = int(data.get("num_inference_steps", DEFAULT_STEPS))
|
| 102 |
+
guidance = float(data.get("guidance_scale", DEFAULT_GUIDANCE))
|
| 103 |
+
|
| 104 |
+
if steps > 6: steps = 6
|
| 105 |
+
if guidance > 2.0: guidance = 1.5
|
| 106 |
+
|
| 107 |
+
width = DEFAULT_WIDTH
|
| 108 |
+
height = DEFAULT_HEIGHT
|
| 109 |
+
if "x" in size:
|
| 110 |
+
try:
|
| 111 |
+
w, h = map(int, size.split("x"))
|
| 112 |
+
width, height = min(w, 768), min(h, 768)
|
| 113 |
+
except:
|
| 114 |
+
pass
|
| 115 |
+
|
| 116 |
+
request_id = uuid.uuid4().hex[:8]
|
| 117 |
+
logger.info(f"[{request_id}] OpenAI gen - prompt={prompt[:60]}... size={width}x{height}")
|
| 118 |
+
|
| 119 |
+
try:
|
| 120 |
+
image = run_generation(prompt, width, height, steps, guidance)
|
| 121 |
+
|
| 122 |
+
# Save to a temporary in-memory route so we can return a URL
|
| 123 |
+
img_id = uuid.uuid4().hex[:12]
|
| 124 |
+
# For simplicity we return a direct /image URL with the same prompt
|
| 125 |
+
image_url = f"https://cloudunity-sdturbolumi.hf.space/image?prompt={prompt.replace(' ', '+')}&width={width}&height={height}&steps={steps}&guidance={guidance}"
|
| 126 |
+
|
| 127 |
+
return jsonify({
|
| 128 |
+
"created": int(time.time()),
|
| 129 |
+
"data": [{"url": image_url}]
|
| 130 |
+
})
|
| 131 |
+
except Exception as e:
|
| 132 |
+
logger.exception("Generation failed")
|
| 133 |
+
return jsonify({"error": {"message": str(e)}}), 500
|
| 134 |
|
| 135 |
|
| 136 |
@app.route("/image", methods=["GET"])
|
|
|
|
| 159 |
buf.seek(0)
|
| 160 |
return send_file(buf, mimetype="image/png")
|
| 161 |
except Exception as e:
|
| 162 |
+
logger.exception("Image generation failed")
|
| 163 |
return str(e), 500
|
| 164 |
|
| 165 |
|