Spaces:
Runtime error
Runtime error
pixel3user
commited on
Commit
·
2cc645f
1
Parent(s):
4b3e157
added json cards
Browse files
app.py
CHANGED
|
@@ -137,6 +137,73 @@ def _has_valid_suggestions(raw_suggestions: str) -> bool:
|
|
| 137 |
|
| 138 |
return True
|
| 139 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
# ---- Inference on GPU (ZeroGPU pattern) ----
|
| 141 |
@spaces.GPU(duration=120)
|
| 142 |
def generate_answer(image, question, temperature=0.7, top_p=0.95, max_tokens=256):
|
|
@@ -257,6 +324,10 @@ def pet_answer_with_recs(image, question, temperature=0.7, top_p=0.95, max_token
|
|
| 257 |
sections = [base.strip()]
|
| 258 |
if include_products:
|
| 259 |
sections.append(f"Suggested products:\n{suggestions}")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 260 |
sections.append(safety)
|
| 261 |
|
| 262 |
return "\n\n".join([s for s in sections if s])
|
|
|
|
| 137 |
|
| 138 |
return True
|
| 139 |
|
| 140 |
+
# ---- JSON block helpers ----
|
| 141 |
+
def _extract_products_json_block(text: str) -> str | None:
|
| 142 |
+
start_tag = "<DERMACARE_PRODUCTS_JSON>"
|
| 143 |
+
end_tag = "</DERMACARE_PRODUCTS_JSON>"
|
| 144 |
+
start = text.find(start_tag)
|
| 145 |
+
end = text.find(end_tag)
|
| 146 |
+
if start == -1 or end == -1 or end <= start:
|
| 147 |
+
return None
|
| 148 |
+
json_str = text[start + len(start_tag):end]
|
| 149 |
+
try:
|
| 150 |
+
payload = json.loads(json_str)
|
| 151 |
+
products = payload.get("products", [])
|
| 152 |
+
if isinstance(products, list) and len(products) > 0:
|
| 153 |
+
return f"{start_tag}{json.dumps(payload, ensure_ascii=False)}{end_tag}"
|
| 154 |
+
except Exception:
|
| 155 |
+
return None
|
| 156 |
+
return None
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
def _filter_candidates_by_budget(cands: list[dict], budget_twd: int | None) -> list[dict]:
|
| 160 |
+
if not budget_twd:
|
| 161 |
+
return cands
|
| 162 |
+
filtered: list[dict] = []
|
| 163 |
+
for c in cands:
|
| 164 |
+
currency = c.get("price_currency")
|
| 165 |
+
value = c.get("price_value")
|
| 166 |
+
if currency == "TWD" and isinstance(value, (int, float)) and value is not None:
|
| 167 |
+
if value <= budget_twd:
|
| 168 |
+
filtered.append(c)
|
| 169 |
+
else:
|
| 170 |
+
filtered.append(c)
|
| 171 |
+
return filtered
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
def _build_products_json_block_from_candidates(cands: list[dict], max_items: int = 3) -> str | None:
|
| 175 |
+
if not cands:
|
| 176 |
+
return None
|
| 177 |
+
ranked = sorted(cands, key=lambda x: x.get("_score", 0.0), reverse=True)
|
| 178 |
+
picked = ranked[:max_items]
|
| 179 |
+
products = []
|
| 180 |
+
for c in picked:
|
| 181 |
+
products.append({
|
| 182 |
+
"id": c.get("id"),
|
| 183 |
+
"brand": c.get("brand_en") or c.get("brand_zh"),
|
| 184 |
+
"name": c.get("product_name_en") or c.get("product_name_zh"),
|
| 185 |
+
"category": c.get("category_en") or c.get("category_zh"),
|
| 186 |
+
"price_value": c.get("price_value"),
|
| 187 |
+
"price_currency": c.get("price_currency"),
|
| 188 |
+
"why": None,
|
| 189 |
+
"how": None,
|
| 190 |
+
"url": c.get("source_url"),
|
| 191 |
+
"image_url": c.get("image_url"),
|
| 192 |
+
})
|
| 193 |
+
valid_count = sum(1 for p in products if p.get("name"))
|
| 194 |
+
if valid_count == 0:
|
| 195 |
+
return None
|
| 196 |
+
payload = {"version": 1, "products": products}
|
| 197 |
+
return f"<DERMACARE_PRODUCTS_JSON>{json.dumps(payload, ensure_ascii=False)}</DERMACARE_PRODUCTS_JSON>"
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
def _ensure_products_json_block(suggestions: str, cands: list[dict], budget_twd: int | None) -> str | None:
|
| 201 |
+
existing = _extract_products_json_block(suggestions)
|
| 202 |
+
if existing:
|
| 203 |
+
return existing
|
| 204 |
+
filtered = _filter_candidates_by_budget(cands, budget_twd)
|
| 205 |
+
return _build_products_json_block_from_candidates(filtered)
|
| 206 |
+
|
| 207 |
# ---- Inference on GPU (ZeroGPU pattern) ----
|
| 208 |
@spaces.GPU(duration=120)
|
| 209 |
def generate_answer(image, question, temperature=0.7, top_p=0.95, max_tokens=256):
|
|
|
|
| 324 |
sections = [base.strip()]
|
| 325 |
if include_products:
|
| 326 |
sections.append(f"Suggested products:\n{suggestions}")
|
| 327 |
+
if "<DERMACARE_PRODUCTS_JSON>" not in suggestions:
|
| 328 |
+
json_block = _ensure_products_json_block(suggestions, cands, budget_twd)
|
| 329 |
+
if json_block:
|
| 330 |
+
sections.append(json_block)
|
| 331 |
sections.append(safety)
|
| 332 |
|
| 333 |
return "\n\n".join([s for s in sections if s])
|