Spaces:
Runtime error
Runtime error
pixel3user
commited on
Commit
·
b340e7a
1
Parent(s):
d924ea0
products
Browse files
app.py
CHANGED
|
@@ -13,37 +13,6 @@ from peft import PeftModel
|
|
| 13 |
from qwen_vl_utils import process_vision_info # pip install qwen-vl-utils
|
| 14 |
from tools.retriever import search as product_search
|
| 15 |
|
| 16 |
-
# ---- Product JSON block markers ----
|
| 17 |
-
PRODUCTS_START = "<DERMACARE_PRODUCTS_JSON>"
|
| 18 |
-
PRODUCTS_END = "</DERMACARE_PRODUCTS_JSON>"
|
| 19 |
-
|
| 20 |
-
def append_products_json_to_text(text_answer: str, products: list[dict]) -> str:
|
| 21 |
-
"""
|
| 22 |
-
Append a machine-readable JSON block to the end of the text.
|
| 23 |
-
The Flutter client will read between the PRODUCTS_START/END tags.
|
| 24 |
-
"""
|
| 25 |
-
payload = {
|
| 26 |
-
"version": 1,
|
| 27 |
-
"products": products or [],
|
| 28 |
-
}
|
| 29 |
-
block = PRODUCTS_START + json.dumps(payload, ensure_ascii=False) + PRODUCTS_END
|
| 30 |
-
return text_answer.rstrip() + "\n\n" + block
|
| 31 |
-
|
| 32 |
-
def to_product_card(meta):
|
| 33 |
-
return {
|
| 34 |
-
"id": meta.get("id"),
|
| 35 |
-
"brand": meta.get("brand_en") or meta.get("brand_zh"),
|
| 36 |
-
"name": meta.get("product_name_en") or meta.get("product_name_zh"),
|
| 37 |
-
"category": meta.get("category_en") or meta.get("category_zh"),
|
| 38 |
-
"price_value": meta.get("price_value"),
|
| 39 |
-
"price_currency": meta.get("price_currency"),
|
| 40 |
-
"why": "Matches your query by skin concern/ingredient.",
|
| 41 |
-
"how": "Use as directed on label; patch-test first.",
|
| 42 |
-
"url": meta.get("source_url"),
|
| 43 |
-
"image_url": meta.get("image_url"),
|
| 44 |
-
"score": round(float(meta.get("_score", 0.0)), 3),
|
| 45 |
-
}
|
| 46 |
-
|
| 47 |
print("VERSIONS:", transformers.__version__, accelerate.__version__, torch.__version__, np.__version__)
|
| 48 |
os.environ["ACCELERATE_USE_SLOW_RETRIEVAL"] = "true"
|
| 49 |
|
|
@@ -123,6 +92,40 @@ def recommend_products(query_text: str, budget_twd: int | None = None, k: int =
|
|
| 123 |
|
| 124 |
return answer
|
| 125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
# ---- Inference on GPU (ZeroGPU pattern) ----
|
| 127 |
@spaces.GPU(duration=120)
|
| 128 |
def generate_answer(image, question, temperature=0.7, top_p=0.95, max_tokens=256):
|
|
@@ -231,26 +234,15 @@ def pet_answer_with_recs(image, question, temperature=0.7, top_p=0.95, max_token
|
|
| 231 |
"Safety notes: For broken/infected skin, pregnancy/lactation, infants, "
|
| 232 |
"or if symptoms worsen—seek a qualified dermatologist. Patch-test first."
|
| 233 |
)
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
# Build deterministic product cards (top-3) for client rendering.
|
| 243 |
-
# If retrieval/index fails, fall back to empty list so the client gracefully
|
| 244 |
-
# renders only the text.
|
| 245 |
-
products_json = []
|
| 246 |
-
try:
|
| 247 |
-
top3 = [to_product_card(c) for c in cands[:3]]
|
| 248 |
-
# Filter out items missing essential fields
|
| 249 |
-
products_json = [p for p in top3 if p.get("id") and p.get("brand") and p.get("name")]
|
| 250 |
-
except Exception:
|
| 251 |
-
products_json = []
|
| 252 |
|
| 253 |
-
return
|
| 254 |
|
| 255 |
# ---- UI ----
|
| 256 |
with gr.Blocks(title="DermalCare - Pet & Skincare Assistant") as demo:
|
|
@@ -276,4 +268,4 @@ with gr.Blocks(title="DermalCare - Pet & Skincare Assistant") as demo:
|
|
| 276 |
outputs=answer
|
| 277 |
)
|
| 278 |
|
| 279 |
-
demo.queue().launch(show_api=False, share=True)
|
|
|
|
| 13 |
from qwen_vl_utils import process_vision_info # pip install qwen-vl-utils
|
| 14 |
from tools.retriever import search as product_search
|
| 15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
print("VERSIONS:", transformers.__version__, accelerate.__version__, torch.__version__, np.__version__)
|
| 17 |
os.environ["ACCELERATE_USE_SLOW_RETRIEVAL"] = "true"
|
| 18 |
|
|
|
|
| 92 |
|
| 93 |
return answer
|
| 94 |
|
| 95 |
+
|
| 96 |
+
def _count_products_from_tagged_json(text: str) -> int | None:
|
| 97 |
+
start_tag = "<DERMACARE_PRODUCTS_JSON>"
|
| 98 |
+
end_tag = "</DERMACARE_PRODUCTS_JSON>"
|
| 99 |
+
start = text.find(start_tag)
|
| 100 |
+
end = text.find(end_tag)
|
| 101 |
+
if start == -1 or end == -1 or end <= start:
|
| 102 |
+
return None
|
| 103 |
+
json_str = text[start + len(start_tag):end]
|
| 104 |
+
try:
|
| 105 |
+
payload = json.loads(json_str)
|
| 106 |
+
products = payload.get("products", [])
|
| 107 |
+
if isinstance(products, list):
|
| 108 |
+
return len(products)
|
| 109 |
+
except Exception:
|
| 110 |
+
return None
|
| 111 |
+
return None
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def _has_valid_suggestions(raw_suggestions: str) -> bool:
|
| 115 |
+
cleaned = raw_suggestions.strip()
|
| 116 |
+
if not cleaned:
|
| 117 |
+
return False
|
| 118 |
+
|
| 119 |
+
lower = cleaned.lower()
|
| 120 |
+
if "no relevant products" in lower:
|
| 121 |
+
return False
|
| 122 |
+
|
| 123 |
+
count = _count_products_from_tagged_json(cleaned)
|
| 124 |
+
if count is not None:
|
| 125 |
+
return count > 0
|
| 126 |
+
|
| 127 |
+
return True
|
| 128 |
+
|
| 129 |
# ---- Inference on GPU (ZeroGPU pattern) ----
|
| 130 |
@spaces.GPU(duration=120)
|
| 131 |
def generate_answer(image, question, temperature=0.7, top_p=0.95, max_tokens=256):
|
|
|
|
| 234 |
"Safety notes: For broken/infected skin, pregnancy/lactation, infants, "
|
| 235 |
"or if symptoms worsen—seek a qualified dermatologist. Patch-test first."
|
| 236 |
)
|
| 237 |
+
suggestions = suggestions.strip()
|
| 238 |
+
include_products = _has_valid_suggestions(suggestions)
|
| 239 |
+
|
| 240 |
+
sections = [base.strip()]
|
| 241 |
+
if include_products:
|
| 242 |
+
sections.append(f"Suggested products:\n{suggestions}")
|
| 243 |
+
sections.append(safety)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
|
| 245 |
+
return "\n\n".join([s for s in sections if s])
|
| 246 |
|
| 247 |
# ---- UI ----
|
| 248 |
with gr.Blocks(title="DermalCare - Pet & Skincare Assistant") as demo:
|
|
|
|
| 268 |
outputs=answer
|
| 269 |
)
|
| 270 |
|
| 271 |
+
demo.queue().launch(show_api=False, share=True)
|