Spaces:
Sleeping
Sleeping
File size: 7,003 Bytes
cd2942e dc71255 58c3956 cd2942e 58c3956 cd2942e 58c3956 cd2942e 58c3956 cd2942e 58c3956 cd2942e 58c3956 dc71255 58c3956 dc71255 6a9af1c cd2942e 58c3956 dc71255 cd2942e 58c3956 dc71255 58c3956 dc71255 58c3956 dc71255 58c3956 dc71255 cd2942e 58c3956 dc71255 58c3956 dc71255 58c3956 cd2942e 58c3956 dc71255 58c3956 dc71255 58c3956 cd2942e dc71255 58c3956 cd2942e dc71255 cd2942e dc71255 cd2942e 58c3956 cd2942e dc71255 58c3956 cd2942e 58c3956 cd2942e 58c3956 cd2942e 58c3956 cd2942e 58c3956 cd2942e dc71255 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
import os
import random
import time
import threading
import requests
import json
from flask import Flask, request, jsonify, send_file, make_response
from flask_cors import CORS
app = Flask(__name__)
# Enable CORS secara explicit dan permissive
CORS(app, resources={r"/*": {"origins": "*"}})
# --- TARGET CONFIG ---
# URL Space Flux kamu
BASE_URL = "https://black-forest-labs-flux-2-dev.hf.space"
# --- TOKEN LIST (HARDCODED) ---
RAW_TOKENS = [
"hf_+PiRCDDtPcPFMLWkTkVaZmzoleHOunXnLIA",
"hf_+BHvZXGICstaktSwycmwNmzHGrTNmKxnlRZ",
"hf_+ZdgawyTPzXIpwhnRYIteUKSMsWnEDtGKtM",
"hf_+nMiFYAFsINxAJWPwiCQlaunmdgmrcxKoaT",
"hf_+PccpUIbTckCiafwErDLkRlsvqhgtfZaBHL",
"hf_+faGyXBPfBkaHXDMUSJtxEggonhhZbomFIz",
"hf_+SndsPaRWsevDXCgZcSjTUlBYUJqOkSfFmn",
"hf_+CqobFdUpeVCeuhUaiuXwvdczBUmoUHXRGa",
"hf_+JKCQYUhhHPPkpucegqkNSyureLdXpmeXRF",
"hf_+tBYfslUwHNiNMufzwAYIlrDVovEWmOQulC",
"hf_+LKLdrdUxyUyKODSUthmqHXqDMfHrQueera",
"hf_+ivSBboJYQVcifWkCNcOTOnxUQrZOtOglnU"
]
class TokenManager:
def __init__(self, raw_tokens):
self.tokens = [t.replace("+", "").strip() for t in raw_tokens if t.strip()]
self.current_index = 0
self.lock = threading.Lock()
def get_token(self):
with self.lock:
if not self.tokens: raise Exception("No tokens available")
token = self.tokens[self.current_index]
self.current_index = (self.current_index + 1) % len(self.tokens)
return token
token_manager = TokenManager(RAW_TOKENS)
def request_flux_gradio4(prompt, width, height, guidance_scale, seed):
"""
Menangani request khusus untuk Gradio 4 (Flux Standard)
Endpoint: /gradio_api/call/infer
"""
max_retries = 5
attempt = 0
last_error = ""
# Endpoint Gradio 4 yang Benar
api_url = f"{BASE_URL}/gradio_api/call/infer"
while attempt < max_retries:
token = token_manager.get_token()
print(f"[LOG] Attempt {attempt+1} - Token: ...{token[-5:]}")
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
# Payload Gradio 4 (Tanpa fn_index, langsung data array)
payload = {
"data": [
prompt,
int(seed) if seed is not None else 0,
True if seed is None else False, # randomize_seed
int(width),
int(height),
float(guidance_scale),
28 # num_inference_steps
]
}
try:
# 1. Kirim Job ID Request
response = requests.post(api_url, headers=headers, json=payload, timeout=30)
if response.status_code != 200:
raise Exception(f"HTTP Error {response.status_code}: {response.text}")
resp_json = response.json()
# Gradio 4 mengembalikan { "event_id": "..." }
event_id = resp_json.get("event_id")
if not event_id:
raise Exception(f"No event_id returned: {resp_json}")
# 2. Polling Hasil (Gradio 4 butuh polling status request)
# Kita tembak endpoint result untuk event_id tersebut
result_url = f"{BASE_URL}/gradio_api/call/infer/{event_id}"
# Tunggu proses selesai (polling loop)
# Karena flux cepat, kita poll tiap 1 detik
for _ in range(60): # Max tunggu 60 detik
time.sleep(1)
poll_resp = requests.get(result_url, headers=headers, stream=True) # Stream true untuk jaga2
# Gradio 4 streaming response berbentuk text event stream
# Kita cari baris yang mengandung "complete" atau data url
content = poll_resp.text
if "process_completed" in content and "url" in content:
# Parsing manual dari format event-stream
# Biasanya format: event: complete \n data: [...]
lines = content.split('\n')
for line in lines:
if line.startswith('data:'):
try:
data_block = json.loads(line[5:])
# Cari URL output
if isinstance(data_block, list) and len(data_block) > 0:
file_info = data_block[0]
final_url = file_info.get("url")
if final_url:
# Download Gambar Akhir
print(f"[LOG] Downloading: {final_url}")
img_res = requests.get(final_url, timeout=60)
temp_filename = f"/tmp/flux_{int(time.time())}_{random.randint(0,999)}.webp"
with open(temp_filename, 'wb') as f:
f.write(img_res.content)
return temp_filename
except:
continue
raise Exception("Timeout waiting for Gradio 4 result")
except Exception as e:
err_msg = str(e)
print(f"[ERROR] {err_msg}")
if "429" in err_msg or "quota" in err_msg.lower():
print("Rate limit detected.")
else:
last_error = err_msg
attempt += 1
time.sleep(1)
raise Exception(f"Gagal Total: {last_error}")
# --- ROUTES ---
@app.route('/', methods=['GET'])
def home():
return jsonify({"status": "Online", "mode": "Gradio 4 Native"})
# Handle OPTIONS request manual untuk mencegah Failed to Fetch
@app.route('/generate', methods=['OPTIONS'])
def options_generate():
response = make_response()
response.headers.add("Access-Control-Allow-Origin", "*")
response.headers.add("Access-Control-Allow-Headers", "*")
response.headers.add("Access-Control-Allow-Methods", "POST, OPTIONS")
return response
@app.route('/generate', methods=['POST'])
def generate():
data = request.json
if not data or 'prompt' not in data:
return jsonify({"error": "Prompt required"}), 400
prompt = data.get('prompt')
width = data.get('width', 1024)
height = data.get('height', 1024)
guidance = data.get('guidance', 3.5)
seed = data.get('seed', None)
try:
image_path = request_flux_gradio4(prompt, width, height, guidance, seed)
return send_file(image_path, mimetype='image/webp')
except Exception as e:
# Return JSON error tapi dengan CORS header agar terbaca di frontend
resp = jsonify({"error": str(e)})
resp.headers.add("Access-Control-Allow-Origin", "*")
return resp, 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=7860)
|