sushilideaclan01 commited on
Commit
8fb6f8f
·
1 Parent(s): c4a64b4

nomenclature fix

Browse files
backend/app/main.py CHANGED
@@ -535,7 +535,12 @@ def list_image_models(_user: dict = Depends(get_current_user)):
535
  GENERATE_ADS_CONCURRENCY = 3
536
 
537
 
538
- async def _save_creative_to_r2(replicate_url: str, creative_id: int, concept_name: str = "") -> tuple[str | None, str | None]:
 
 
 
 
 
539
  """Download image from Replicate URL and upload to R2. Returns (R2 presigned URL or None, R2 key or None)."""
540
  try:
541
  async with httpx.AsyncClient(timeout=60.0) as client:
@@ -547,7 +552,7 @@ async def _save_creative_to_r2(replicate_url: str, creative_id: int, concept_nam
547
  return None, None
548
  if not image_bytes:
549
  return None, None
550
- key = key_for_creative(creative_id, concept_name)
551
  r2_url = await asyncio.to_thread(
552
  upload_creative_image,
553
  image_bytes,
@@ -761,7 +766,12 @@ async def generate_ads(
761
  )
762
  if err or not url:
763
  return {"creative_id": cid, "image_url": None, "error": err}
764
- r2_url, r2_key = await _save_creative_to_r2(url, cid, (item.get("concept_name") or "").strip())
 
 
 
 
 
765
  final_url = r2_url if r2_url else url
766
  if r2_key and username:
767
  await asyncio.to_thread(
@@ -856,7 +866,12 @@ async def _stream_generate_ads(
856
  )
857
  if err or not url:
858
  return {"creative_id": cid, "image_url": None, "error": err}
859
- r2_url, r2_key = await _save_creative_to_r2(url, cid, (item.get("concept_name") or "").strip())
 
 
 
 
 
860
  final_url = r2_url if r2_url else url
861
  if r2_key and username:
862
  await asyncio.to_thread(
@@ -1062,7 +1077,11 @@ async def correct_image_endpoint(
1062
  image_bytes = r.content
1063
  concept = (entry.get("concept_name") or "image").strip()[:64]
1064
  cid = entry.get("creative_id", 0)
1065
- key = key_for_creative(cid, f"{concept}-corrected")
 
 
 
 
1066
  r2_url = await asyncio.to_thread(upload_creative_image, image_bytes, key=key, content_type="image/png")
1067
  if r2_url:
1068
  gallery_update_entry(
 
535
  GENERATE_ADS_CONCURRENCY = 3
536
 
537
 
538
+ async def _save_creative_to_r2(
539
+ replicate_url: str,
540
+ creative_id: int,
541
+ concept_name: str = "",
542
+ product_name: str = "",
543
+ ) -> tuple[str | None, str | None]:
544
  """Download image from Replicate URL and upload to R2. Returns (R2 presigned URL or None, R2 key or None)."""
545
  try:
546
  async with httpx.AsyncClient(timeout=60.0) as client:
 
552
  return None, None
553
  if not image_bytes:
554
  return None, None
555
+ key = key_for_creative(creative_id, concept_name, product_name)
556
  r2_url = await asyncio.to_thread(
557
  upload_creative_image,
558
  image_bytes,
 
766
  )
767
  if err or not url:
768
  return {"creative_id": cid, "image_url": None, "error": err}
769
+ r2_url, r2_key = await _save_creative_to_r2(
770
+ url,
771
+ cid,
772
+ (item.get("concept_name") or "").strip(),
773
+ (body.product_name or "").strip(),
774
+ )
775
  final_url = r2_url if r2_url else url
776
  if r2_key and username:
777
  await asyncio.to_thread(
 
866
  )
867
  if err or not url:
868
  return {"creative_id": cid, "image_url": None, "error": err}
869
+ r2_url, r2_key = await _save_creative_to_r2(
870
+ url,
871
+ cid,
872
+ (item.get("concept_name") or "").strip(),
873
+ (body.product_name or "").strip(),
874
+ )
875
  final_url = r2_url if r2_url else url
876
  if r2_key and username:
877
  await asyncio.to_thread(
 
1077
  image_bytes = r.content
1078
  concept = (entry.get("concept_name") or "image").strip()[:64]
1079
  cid = entry.get("creative_id", 0)
1080
+ key = key_for_creative(
1081
+ cid,
1082
+ f"{concept}-corrected",
1083
+ (entry.get("product_name") or "").strip(),
1084
+ )
1085
  r2_url = await asyncio.to_thread(upload_creative_image, image_bytes, key=key, content_type="image/png")
1086
  if r2_url:
1087
  gallery_update_entry(
backend/app/r2.py CHANGED
@@ -132,10 +132,29 @@ def put_object(
132
  return False
133
 
134
 
135
- def key_for_creative(creative_id: int, concept_slug: str = "") -> str:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  """Generate a stable R2 key for a creative image."""
137
- safe = (concept_slug or "").replace(" ", "-").replace("/", "-")[:64].strip() or "image"
138
- # Keep only alphanumeric and hyphen for object key
139
- safe = "".join(c for c in safe if c.isalnum() or c == "-") or "image"
140
  unique = uuid.uuid4().hex[:8]
141
- return f"creatives/{creative_id}-{safe}-{unique}.png"
 
132
  return False
133
 
134
 
135
+ def _sanitize_segment(value: str, *, sep: str = "-") -> str:
136
+ cleaned = (value or "").strip()
137
+ if not cleaned:
138
+ return ""
139
+ cleaned = cleaned.replace("/", " ").replace("\\", " ")
140
+ out_chars: list[str] = []
141
+ prev_sep = False
142
+ for ch in cleaned:
143
+ if ch.isalnum():
144
+ out_chars.append(ch)
145
+ prev_sep = False
146
+ else:
147
+ if not prev_sep:
148
+ out_chars.append(sep)
149
+ prev_sep = True
150
+ out = "".join(out_chars).strip(sep)
151
+ return out
152
+
153
+
154
+ def key_for_creative(creative_id: int, concept_slug: str = "", product_name: str = "") -> str:
155
  """Generate a stable R2 key for a creative image."""
156
+ safe_concept = _sanitize_segment(concept_slug, sep="-")[:64] or "image"
157
+ # Requested naming style: <product>_AI_creative_...
158
+ safe_product = _sanitize_segment(product_name, sep="_")[:64] or "product"
159
  unique = uuid.uuid4().hex[:8]
160
+ return f"creatives/{safe_product}_AI_creative_{creative_id}-{safe_concept}-{unique}.png"
backend/app/variation.py CHANGED
@@ -159,7 +159,12 @@ Return JSON only:
159
  return normalized
160
 
161
 
162
- async def _save_variation_to_r2(image_url: str, variation_id: int, concept_name: str) -> tuple[str | None, str | None]:
 
 
 
 
 
163
  try:
164
  async with httpx.AsyncClient(timeout=60.0) as client:
165
  resp = await client.get(image_url)
@@ -170,7 +175,7 @@ async def _save_variation_to_r2(image_url: str, variation_id: int, concept_name:
170
  return None, None
171
  if not image_bytes:
172
  return None, None
173
- key = key_for_creative(variation_id, concept_name)
174
  r2_url = await asyncio.to_thread(upload_creative_image, image_bytes, key=key, content_type=content_type)
175
  return (r2_url, key if r2_url else None)
176
 
@@ -223,7 +228,7 @@ async def generate_variations_stream(
223
  await asyncio.sleep(2 * attempt)
224
  if err or not image_out_url:
225
  return {"variation_id": vid, "concept_name": concept_name, "image_url": None, "error": err or "Generation failed"}
226
- r2_url, r2_key = await _save_variation_to_r2(image_out_url, vid, concept_name)
227
  final_url = r2_url or image_out_url
228
  if r2_key and username:
229
  await asyncio.to_thread(
 
159
  return normalized
160
 
161
 
162
+ async def _save_variation_to_r2(
163
+ image_url: str,
164
+ variation_id: int,
165
+ concept_name: str,
166
+ product_name: str | None = None,
167
+ ) -> tuple[str | None, str | None]:
168
  try:
169
  async with httpx.AsyncClient(timeout=60.0) as client:
170
  resp = await client.get(image_url)
 
175
  return None, None
176
  if not image_bytes:
177
  return None, None
178
+ key = key_for_creative(variation_id, concept_name, product_name or "")
179
  r2_url = await asyncio.to_thread(upload_creative_image, image_bytes, key=key, content_type=content_type)
180
  return (r2_url, key if r2_url else None)
181
 
 
228
  await asyncio.sleep(2 * attempt)
229
  if err or not image_out_url:
230
  return {"variation_id": vid, "concept_name": concept_name, "image_url": None, "error": err or "Generation failed"}
231
+ r2_url, r2_key = await _save_variation_to_r2(image_out_url, vid, concept_name, product_name)
232
  final_url = r2_url or image_out_url
233
  if r2_key and username:
234
  await asyncio.to_thread(