image / Dockerfile
guydffdsdsfd's picture
Update Dockerfile
85a948d verified
FROM python:3.10-slim
ENV DEBIAN_FRONTEND=noninteractive
# ---------------- System deps ----------------
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
libgl1 \
libglib2.0-0 \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# ---------------- Python deps (PINNED & COMPATIBLE) ----------------
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir \
numpy<2 \
torch==2.0.1 \
torchvision==0.15.2 \
torchaudio==2.0.2 \
--index-url https://download.pytorch.org/whl/cpu
RUN pip install --no-cache-dir \
diffusers==0.24.0 \
transformers==4.36.2 \
accelerate==0.25.0 \
safetensors \
flask \
flask-cors \
pillow
# ---------------- Env ----------------
ENV HOME=/home/sd
ENV HF_HOME=/home/sd/.cache
ENV OMP_NUM_THREADS=1
ENV MKL_NUM_THREADS=1
ENV NUMPY_EXPERIMENTAL_ARRAY_FUNCTION=0
# ---------------- Storage ----------------
RUN mkdir -p /home/sd && chmod -R 777 /home/sd
# ---------------- App ----------------
RUN cat <<'EOF' > /app.py
from flask import Flask, request, jsonify, send_file
from flask_cors import CORS
from diffusers import DiffusionPipeline, LCMScheduler
import torch, os, json, secrets
from io import BytesIO
from datetime import datetime
app = Flask(__name__)
CORS(app)
BASE = "/home/sd"
WL_PATH = f"{BASE}/whitelist.txt"
USAGE_PATH = f"{BASE}/usage.json"
LIMITS_PATH = f"{BASE}/limits.json"
DEFAULT_LIMIT = 500
MODEL_ID = "SimianLuo/LCM_Dreamshaper_v7"
os.makedirs(BASE, exist_ok=True)
for p in [WL_PATH, USAGE_PATH, LIMITS_PATH]:
if not os.path.exists(p):
open(p, "w").write("{}" if p.endswith(".json") else "")
print(f"Loading model: {MODEL_ID}")
torch.set_grad_enabled(False)
pipe = DiffusionPipeline.from_pretrained(
MODEL_ID,
torch_dtype=torch.float32,
safety_checker=None
)
pipe.scheduler = LCMScheduler.from_config(pipe.scheduler.config)
pipe = pipe.to("cpu")
# ---- MEMORY + SPEED ----
pipe.enable_attention_slicing()
pipe.enable_vae_slicing()
print("Model loaded (CPU, optimized)")
def whitelist():
try:
return set(open(WL_PATH).read().split())
except:
return set()
def load_json(path):
try:
return json.load(open(path))
except:
return {}
def save_json(path, data):
json.dump(data, open(path, "w"))
@app.route("/", methods=["GET"])
def health():
return "LCM Image API Running", 200
@app.route("/generate-key", methods=["POST"])
def generate_key():
data = request.get_json() or {}
key = "sk-" + secrets.token_hex(16)
with open(WL_PATH, "a") as f:
f.write(key + "\n")
limits = load_json(LIMITS_PATH)
limits[key] = "unlimited" if data.get("unlimited") else int(data.get("limit", DEFAULT_LIMIT))
save_json(LIMITS_PATH, limits)
return jsonify({"key": key, "limit": limits[key]})
@app.route("/api/generate", methods=["POST"])
def generate():
key = request.headers.get("x-api-key", "")
if key not in whitelist():
return jsonify({"error": "Unauthorized"}), 401
data = request.get_json() or {}
prompt = data.get("prompt", "").strip()
if not prompt:
return jsonify({"error": "Prompt required"}), 400
limits = load_json(LIMITS_PATH)
usage = load_json(USAGE_PATH)
month = datetime.now().strftime("%Y-%m")
used = usage.get(key, {}).get(month, 0)
limit = limits.get(key, DEFAULT_LIMIT)
if limit != "unlimited" and used >= limit:
return jsonify({"error": "Monthly limit reached"}), 429
try:
image = pipe(
prompt=prompt,
num_inference_steps=4,
guidance_scale=1.5
).images[0]
usage.setdefault(key, {})[month] = used + 1
save_json(USAGE_PATH, usage)
buf = BytesIO()
image.save(buf, format="PNG")
buf.seek(0)
return send_file(buf, mimetype="image/png")
except Exception as e:
return jsonify({"error": str(e)}), 500
if __name__ == "__main__":
app.run(host="0.0.0.0", port=7860)
EOF
# ---------------- Start ----------------
RUN echo '#!/bin/bash\npython3 /app.py' > /start.sh && chmod +x /start.sh
EXPOSE 7860
ENTRYPOINT ["/bin/bash", "/start.sh"]