Theflame47 commited on
Commit
4db81f7
·
verified ·
1 Parent(s): 63230f6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +91 -37
app.py CHANGED
@@ -9,6 +9,7 @@ import gradio as gr
9
  import base64
10
 
11
  PRINTIFY_BASE = "https://api.printify.com"
 
12
  GRID_FILENAME = "grid.png"
13
 
14
 
@@ -89,9 +90,7 @@ def _build_product(blob: Dict[str, Any], currency: str, logs: List[str]) -> Dict
89
 
90
  snapshot = []
91
  for v in variants:
92
- cents = v.get("cost")
93
- if cents is None:
94
- cents = v.get("price")
95
  cents = int(cents) if isinstance(cents, (int, str)) and str(cents).isdigit() else None
96
 
97
  ph = v.get("placeholders")
@@ -113,8 +112,8 @@ def _build_product(blob: Dict[str, Any], currency: str, logs: List[str]) -> Dict
113
  "sku": v.get("sku"),
114
  "size": (v.get("options") or {}).get("size"),
115
  "color": (v.get("options") or {}).get("color"),
116
- "costCents": cents,
117
- "cost": round(cents / 100, 2) if cents is not None else None,
118
  "placeholders": placeholders,
119
  })
120
 
@@ -150,10 +149,8 @@ def _build_product(blob: Dict[str, Any], currency: str, logs: List[str]) -> Dict
150
  if ph.get("position")
151
  })
152
 
153
- all_cost_cents = [v["costCents"] for v in snapshot if v["costCents"] is not None]
154
- if not all_cost_cents:
155
- raise RuntimeError("No variant cost returned by API (expected 'cost' or 'price' in cents).")
156
- min_price = round(min(all_cost_cents) / 100, 2)
157
 
158
  colors = sorted({v["color"] for v in snapshot if v["color"]})
159
  sizes = sorted({v["size"] for v in snapshot if v["size"]})
@@ -240,29 +237,6 @@ def _upload_grid_from_file(logs: List[str]) -> Dict[str, Any]:
240
  )
241
  return resp
242
 
243
- with open(path, "rb") as f:
244
- r = requests.post(
245
- f"{PRINTIFY_BASE}/v1/uploads/images.json",
246
- headers=_auth_headers(),
247
- files={"file": (GRID_FILENAME, f, "image/png")},
248
- timeout=60,
249
- )
250
-
251
- if r.status_code >= 400:
252
- raise RuntimeError(f"UPLOAD_HTTP {r.status_code}: {r.text[:2000]}")
253
-
254
- resp = r.json()
255
- if not isinstance(resp, dict) or not resp.get("id"):
256
- raise RuntimeError(f"Unexpected upload response: {str(resp)[:500]}")
257
-
258
- _log(
259
- logs,
260
- f"GRID_UPLOAD id={resp.get('id')} "
261
- f"file={resp.get('file_name') or resp.get('name')} "
262
- f"w={resp.get('width')} h={resp.get('height')}",
263
- )
264
- return resp
265
-
266
 
267
  def _scale_fill(ph_w: float, ph_h: float, img_w: float, img_h: float) -> float:
268
  if ph_w <= 0 or ph_h <= 0 or img_w <= 0 or img_h <= 0:
@@ -344,7 +318,7 @@ def _create_one_product_with_grid(
344
  "print_provider_id": int(provider_id),
345
  "variants": [{
346
  "id": int(variant_id),
347
- "price": int(product_info.get("price") * 100),
348
  "is_enabled": True,
349
  }],
350
  "print_areas": [{
@@ -356,8 +330,7 @@ def _create_one_product_with_grid(
356
  _log(
357
  logs,
358
  f"PHASE_B_CREATE shop_id={shop_id} "
359
- f"blueprint_id={bp_id} provider_id={provider_id} variant_id={variant_id} "
360
- f"price_cents={int(product_info.get('price') * 100)}",
361
  )
362
 
363
  created = _req(
@@ -455,16 +428,97 @@ def phase_b(currency: str) -> Generator[Tuple[str, str], None, None]:
455
  yield flush()
456
 
457
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
  with gr.Blocks(title="Printify Catalog Probe") as demo:
459
  gr.Markdown("Extract and normalize ONE Printify blueprint/provider into a structured JSON object.")
460
 
461
  currency = gr.Textbox(label="Currency", value="USD")
462
- btn = gr.Button("Run")
463
- btn_b = gr.Button("Phase B (Test)")
 
 
 
464
  logs = gr.Textbox(label="Logs", lines=18)
465
  out = gr.Textbox(label="Output JSON", lines=18)
466
 
467
  btn.click(run, inputs=[currency], outputs=[logs, out])
468
  btn_b.click(phase_b, inputs=[currency], outputs=[logs, out])
 
469
 
470
  demo.queue().launch()
 
9
  import base64
10
 
11
  PRINTIFY_BASE = "https://api.printify.com"
12
+ DEFAULT_BASE_PRICE = 24.99
13
  GRID_FILENAME = "grid.png"
14
 
15
 
 
90
 
91
  snapshot = []
92
  for v in variants:
93
+ cents = v.get("price")
 
 
94
  cents = int(cents) if isinstance(cents, (int, str)) and str(cents).isdigit() else None
95
 
96
  ph = v.get("placeholders")
 
112
  "sku": v.get("sku"),
113
  "size": (v.get("options") or {}).get("size"),
114
  "color": (v.get("options") or {}).get("color"),
115
+ "priceCents": cents,
116
+ "price": round(cents / 100, 2) if cents is not None else None,
117
  "placeholders": placeholders,
118
  })
119
 
 
149
  if ph.get("position")
150
  })
151
 
152
+ all_cents = [v["priceCents"] for v in snapshot if v["priceCents"] is not None]
153
+ min_price = round(min(all_cents) / 100, 2) if all_cents else DEFAULT_BASE_PRICE
 
 
154
 
155
  colors = sorted({v["color"] for v in snapshot if v["color"]})
156
  sizes = sorted({v["size"] for v in snapshot if v["size"]})
 
237
  )
238
  return resp
239
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
 
241
  def _scale_fill(ph_w: float, ph_h: float, img_w: float, img_h: float) -> float:
242
  if ph_w <= 0 or ph_h <= 0 or img_w <= 0 or img_h <= 0:
 
318
  "print_provider_id": int(provider_id),
319
  "variants": [{
320
  "id": int(variant_id),
321
+ "price": 1,
322
  "is_enabled": True,
323
  }],
324
  "print_areas": [{
 
330
  _log(
331
  logs,
332
  f"PHASE_B_CREATE shop_id={shop_id} "
333
+ f"blueprint_id={bp_id} provider_id={provider_id} variant_id={variant_id}",
 
334
  )
335
 
336
  created = _req(
 
428
  yield flush()
429
 
430
 
431
+ def phase_c(currency: str, product_id: str) -> Generator[Tuple[str, str], None, None]:
432
+ logs: List[str] = []
433
+ result: Dict[str, Any] = {}
434
+
435
+ def flush():
436
+ return "\n".join(logs), json.dumps(result, indent=2)
437
+
438
+ try:
439
+ _log(logs, "PHASE_C_START")
440
+ yield flush()
441
+
442
+ if not product_id or not str(product_id).strip():
443
+ raise RuntimeError("Missing product_id.")
444
+
445
+ shops = _req("GET", "/v1/shops.json")
446
+ _log(logs, f"SHOP_LIST {json.dumps(shops)}")
447
+ yield flush()
448
+
449
+ shop_id = _pick_shop_id(shops)
450
+ _log(logs, f"SHOP_ID {shop_id}")
451
+ yield flush()
452
+
453
+ pid = str(product_id).strip()
454
+ _log(logs, f"PHASE_C_GET_PRODUCT product_id={pid}")
455
+ prod = _req("GET", f"/v1/shops/{shop_id}/products/{pid}.json")
456
+ result["productDetails"] = prod
457
+ yield flush()
458
+
459
+ variants = prod.get("variants") or []
460
+ if not isinstance(variants, list) or not variants:
461
+ raise RuntimeError("Product details missing variants.")
462
+
463
+ update_variants = []
464
+ for v in variants:
465
+ vid = v.get("id")
466
+ cost = v.get("cost")
467
+ if vid is None or cost is None:
468
+ _log(logs, f"COST_MISSING variant_id={vid} cost={cost}")
469
+ continue
470
+ try:
471
+ vid_i = int(vid)
472
+ cost_i = int(cost)
473
+ except Exception:
474
+ _log(logs, f"COST_BAD variant_id={vid} cost={cost}")
475
+ continue
476
+
477
+ update_variants.append({
478
+ "id": vid_i,
479
+ "price": cost_i,
480
+ "is_enabled": bool(v.get("is_enabled")),
481
+ })
482
+
483
+ _log(
484
+ logs,
485
+ f"PRICE_RECONCILE variant_id={vid_i} cost={cost_i} "
486
+ f"old_price={v.get('price')} enabled={bool(v.get('is_enabled'))}",
487
+ )
488
+
489
+ if not update_variants:
490
+ raise RuntimeError("No variants with cost found to reconcile pricing.")
491
+
492
+ payload = {"variants": update_variants}
493
+
494
+ _log(logs, f"PHASE_C_UPDATE_PRICES count={len(update_variants)}")
495
+ updated = _req("PUT", f"/v1/shops/{shop_id}/products/{pid}.json", json_body=payload)
496
+ result["priceUpdateResponse"] = updated
497
+ yield flush()
498
+
499
+ _log(logs, "PHASE_C_DONE")
500
+ yield flush()
501
+
502
+ except Exception as e:
503
+ _log(logs, f"ERROR: {e}")
504
+ result = {"error": str(e)}
505
+ yield flush()
506
+
507
+
508
  with gr.Blocks(title="Printify Catalog Probe") as demo:
509
  gr.Markdown("Extract and normalize ONE Printify blueprint/provider into a structured JSON object.")
510
 
511
  currency = gr.Textbox(label="Currency", value="USD")
512
+ product_id = gr.Textbox(label="Product ID (for Phase C)", value="")
513
+
514
+ btn = gr.Button("Run (A)")
515
+ btn_b = gr.Button("Phase B (Create Test)")
516
+ btn_c = gr.Button("Phase C (Pricing Reconciliation)")
517
  logs = gr.Textbox(label="Logs", lines=18)
518
  out = gr.Textbox(label="Output JSON", lines=18)
519
 
520
  btn.click(run, inputs=[currency], outputs=[logs, out])
521
  btn_b.click(phase_b, inputs=[currency], outputs=[logs, out])
522
+ btn_c.click(phase_c, inputs=[currency, product_id], outputs=[logs, out])
523
 
524
  demo.queue().launch()