localhost-llm commited on
Commit
f011a54
·
verified ·
1 Parent(s): e2a9424

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +63 -71
app.py CHANGED
@@ -154,34 +154,38 @@ async def v1_chat(request: Request, authorization: str = Header(None)):
154
  # ---------------------------------------------------------------------
155
  @api.post("/v1/images/generations")
156
  async def v1_images_generations(request: Request, authorization: str = Header(None)):
157
- import base64
158
-
 
159
  check_key(authorization)
160
 
161
  if not BYTEZ_AUTH:
162
  raise HTTPException(status_code=500, detail="Server BYTEZ_API_KEY not configured")
163
 
164
- # ---------------- parse request ----------------
165
  try:
166
  payload = await request.json()
167
  except json.JSONDecodeError:
168
  raise HTTPException(status_code=400, detail="Invalid JSON")
169
 
170
- prompt = payload.get("prompt") or payload.get("text")
171
- if not prompt or not str(prompt).strip():
172
  raise HTTPException(status_code=400, detail="Field 'prompt' is required")
173
 
174
  n = int(payload.get("n", 1))
175
- response_format = payload.get("response_format", "b64_json") # ignored; we always return b64_json
176
 
177
- # ---------------- Bytez request ----------------
178
- bytez_payload = { "text": prompt }
 
 
179
 
180
  headers = {
181
- "Authorization": BYTEZ_AUTH,
182
  "Content-Type": "application/json",
183
  }
184
 
 
185
  async with httpx.AsyncClient(timeout=200) as client:
186
  try:
187
  resp = await client.post(BYTEZ_IMAGE_URL, json=bytez_payload, headers=headers)
@@ -193,76 +197,64 @@ async def v1_images_generations(request: Request, authorization: str = Header(No
193
  except:
194
  detail = e.response.text
195
  raise HTTPException(status_code=e.response.status_code, detail={"upstream_error": detail})
196
- except Exception as e:
197
- raise HTTPException(status_code=502, detail=f"Bytez unreachable: {str(e)}")
198
 
199
  try:
200
  bytez_data = resp.json()
201
- except json.JSONDecodeError:
202
  raise HTTPException(status_code=502, detail="Bytez returned invalid JSON")
203
 
204
- # ---------------- normalize Bytez → list of images ----------------
205
- images = []
206
-
207
- if isinstance(bytez_data, dict) and "images" in bytez_data:
208
- images = bytez_data["images"]
209
-
210
- elif isinstance(bytez_data, dict) and "data" in bytez_data:
211
- for item in bytez_data["data"]:
212
- images.append(item.get("url") or item.get("b64_json") or str(item))
213
-
214
- elif isinstance(bytez_data, str):
215
- images = [bytez_data]
216
-
217
- else:
218
- images = [str(bytez_data)]
219
-
220
- if not images:
221
- raise HTTPException(status_code=500, detail="No images returned from Bytez")
222
-
223
- images = images[:n]
224
-
225
- # ---------------- ALWAYS RETURN BASE64 ----------------
 
226
  openai_data = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
 
228
- async def fetch_and_b64(url: str) -> str:
229
- async with httpx.AsyncClient(timeout=60) as client:
230
- r = await client.get(url)
231
- r.raise_for_status()
232
- return base64.b64encode(r.content).decode("utf-8")
233
-
234
- for img in images:
235
-
236
- # Case 1: data:image/...;base64,...
237
- if isinstance(img, str) and img.startswith("data:image"):
238
- b64 = img.split("base64,", 1)[1]
239
- openai_data.append({"b64_json": b64})
240
- continue
241
-
242
- # Case 2: pure base64
243
- if isinstance(img, str) and not img.startswith("http"):
244
- openai_data.append({"b64_json": img})
245
- continue
246
 
247
- # Case 3: URL → fetch + convert
248
- if isinstance(img, str) and img.startswith("http"):
249
- try:
250
- b64 = await fetch_and_b64(img)
251
- openai_data.append({"b64_json": b64})
252
- except Exception as e:
253
- raise HTTPException(
254
- status_code=502,
255
- detail=f"Failed to fetch image from URL returned by Bytez: {str(e)}"
256
- )
257
-
258
- # ---------------- return clean OpenAI-style result ----------------
259
- return JSONResponse(
260
- {
261
- "created": int(time.time()),
262
- "data": openai_data
263
- },
264
- headers={"Access-Control-Allow-Origin": "*"}
265
- )
266
 
267
 
268
 
 
154
  # ---------------------------------------------------------------------
155
  @api.post("/v1/images/generations")
156
  async def v1_images_generations(request: Request, authorization: str = Header(None)):
157
+ """
158
+ OpenAI-compatible image generation endpoint → Bytez DALL-E 3
159
+ """
160
  check_key(authorization)
161
 
162
  if not BYTEZ_AUTH:
163
  raise HTTPException(status_code=500, detail="Server BYTEZ_API_KEY not configured")
164
 
165
+ # -------- Parse request --------
166
  try:
167
  payload = await request.json()
168
  except json.JSONDecodeError:
169
  raise HTTPException(status_code=400, detail="Invalid JSON")
170
 
171
+ prompt = payload.get("prompt")
172
+ if not prompt:
173
  raise HTTPException(status_code=400, detail="Field 'prompt' is required")
174
 
175
  n = int(payload.get("n", 1))
176
+ response_format = payload.get("response_format", "url") # url | b64_json
177
 
178
+ # -------- Bytez request format --------
179
+ bytez_payload = {
180
+ "text": prompt
181
+ }
182
 
183
  headers = {
184
+ "Authorization": f"Bearer {BYTEZ_AUTH}",
185
  "Content-Type": "application/json",
186
  }
187
 
188
+ # -------- Call Bytez --------
189
  async with httpx.AsyncClient(timeout=200) as client:
190
  try:
191
  resp = await client.post(BYTEZ_IMAGE_URL, json=bytez_payload, headers=headers)
 
197
  except:
198
  detail = e.response.text
199
  raise HTTPException(status_code=e.response.status_code, detail={"upstream_error": detail})
 
 
200
 
201
  try:
202
  bytez_data = resp.json()
203
+ except:
204
  raise HTTPException(status_code=502, detail="Bytez returned invalid JSON")
205
 
206
+ # -----------------------------------------------------------------
207
+ # -------- Extract URL (bytez_data.output) --------
208
+ # -----------------------------------------------------------------
209
+ url_output = None
210
+ if isinstance(bytez_data, dict):
211
+ url_output = bytez_data.get("output")
212
+
213
+ # -----------------------------------------------------------------
214
+ # -------- Extract Base64 (provider.generatedImages[].imageBytes) --
215
+ # -----------------------------------------------------------------
216
+ b64_list = []
217
+ try:
218
+ generated = bytez_data["provider"]["generatedImages"]
219
+ for g in generated:
220
+ img = g.get("image", {})
221
+ if "imageBytes" in img:
222
+ b64_list.append(img["imageBytes"])
223
+ except Exception:
224
+ pass # ignore if provider/genImages is missing
225
+
226
+ # -----------------------------------------------------------------
227
+ # -------- Build OpenAI-compatible response ------------------------
228
+ # -----------------------------------------------------------------
229
  openai_data = []
230
+ count = max(len(b64_list), 1)
231
+ count = min(count, n)
232
+
233
+ for i in range(count):
234
+ # --- Base64 Output ---
235
+ if response_format == "b64_json":
236
+ if i < len(b64_list):
237
+ openai_data.append({"b64_json": b64_list[i]})
238
+ else:
239
+ # fallback: turn URL into base64-json payload (OpenAI accepts raw string)
240
+ openai_data.append({"b64_json": url_output})
241
+ else:
242
+ # --- URL Output ---
243
+ if url_output:
244
+ openai_data.append({"url": url_output})
245
+ elif i < len(b64_list):
246
+ # fallback: convert base64 into a data URL
247
+ openai_data.append({"url": f"data:image/png;base64,{b64_list[i]}"})
248
+ else:
249
+ openai_data.append({"url": ""})
250
+
251
+ result = {
252
+ "created": int(time.time()),
253
+ "data": openai_data,
254
+ }
255
 
256
+ return JSONResponse(result, headers={"Access-Control-Allow-Origin": "*"})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
 
259
 
260