Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -51,11 +51,15 @@ print("✅ Sunucu Hazır!")
|
|
| 51 |
|
| 52 |
# --- SÖZLÜKLER ---
|
| 53 |
TR_LABELS = {
|
| 54 |
-
"acne
|
| 55 |
-
"
|
| 56 |
-
"
|
| 57 |
-
"
|
| 58 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
}
|
| 60 |
|
| 61 |
CILT_TIPI_TR = {
|
|
@@ -63,7 +67,7 @@ CILT_TIPI_TR = {
|
|
| 63 |
"NORMAL": "Normal Cilt", "KARMA": "Karma Cilt"
|
| 64 |
}
|
| 65 |
|
| 66 |
-
# --- MAĞAZA URL ŞABLONLARI
|
| 67 |
MARKET_TEMPLATES = {
|
| 68 |
"Trendyol": "https://www.trendyol.com/sr?q={query}&os=1",
|
| 69 |
"Hepsiburada": "https://www.hepsiburada.com/ara?q={query}",
|
|
@@ -79,67 +83,46 @@ MARKET_TEMPLATES = {
|
|
| 79 |
"Beymen": "https://www.beymen.com/tr/search?q={query}"
|
| 80 |
}
|
| 81 |
|
| 82 |
-
# ---
|
| 83 |
def generate_smart_search_link(market_name, search_phrase):
|
| 84 |
-
"""
|
| 85 |
-
Arama cümlesini URL uyumlu hale getirir ve linki üretir.
|
| 86 |
-
"""
|
| 87 |
-
# 1. URL Encoding (Boşluk -> %20 veya +)
|
| 88 |
if market_name in ["Sephora", "Hepsiburada", "Amazon", "Yves Rocher"]:
|
| 89 |
-
encoded_query = urllib.parse.quote_plus(search_phrase)
|
| 90 |
else:
|
| 91 |
-
encoded_query = urllib.parse.quote(search_phrase)
|
| 92 |
|
| 93 |
-
# 2. Şablona Yerleştir
|
| 94 |
template = MARKET_TEMPLATES.get(market_name, MARKET_TEMPLATES["Trendyol"])
|
| 95 |
return template.format(query=encoded_query)
|
| 96 |
|
| 97 |
def get_dynamic_products(issue, skin_type_tr, ingredient_hint, is_premium=False):
|
| 98 |
-
"""
|
| 99 |
-
Her sorun için dinamik mağaza linkleri üretir.
|
| 100 |
-
"""
|
| 101 |
products = []
|
| 102 |
|
| 103 |
-
# 1. ARAMA CÜMLESİNİ KUR (Senin İstediğin Format)
|
| 104 |
-
# Formül: "{Sorun} Karşıtı {Cilt Tipi}"
|
| 105 |
-
# Örn: "Leke Karşıtı Kuru Cilt" veya "Salisilik Asit Yağlı Cilt"
|
| 106 |
-
|
| 107 |
if ingredient_hint:
|
| 108 |
-
# Eğer spesifik içerik varsa (Salisilik Asit gibi), onu öncelikli arat
|
| 109 |
search_text = f"{ingredient_hint} {skin_type_tr}"
|
| 110 |
else:
|
| 111 |
-
# Yoksa sorun bazlı arat
|
| 112 |
search_text = f"{issue} Karşıtı {skin_type_tr}"
|
| 113 |
|
| 114 |
-
# 2. MAĞAZA SEÇİMİ
|
| 115 |
all_markets = list(MARKET_TEMPLATES.keys())
|
| 116 |
|
| 117 |
if not is_premium:
|
| 118 |
-
# Standart: Sadece 3 popüler mağaza
|
| 119 |
active_markets = ["Trendyol", "Gratis", "Watsons"]
|
| 120 |
else:
|
| 121 |
-
# Premium: Rastgele 6 mağaza (Çeşitlilik için)
|
| 122 |
active_markets = all_markets.copy()
|
| 123 |
random.shuffle(active_markets)
|
| 124 |
active_markets = active_markets[:6]
|
| 125 |
|
| 126 |
-
# 3. LİNKLERİ OLUŞTUR
|
| 127 |
for market in active_markets:
|
| 128 |
final_link = generate_smart_search_link(market, search_text)
|
| 129 |
-
|
| 130 |
products.append({
|
| 131 |
"source": market,
|
| 132 |
"title": f"{market}: {search_text}",
|
| 133 |
"link": final_link
|
| 134 |
})
|
| 135 |
-
|
| 136 |
return products
|
| 137 |
|
| 138 |
def generate_prescription_logic(skin_type_code, issues):
|
| 139 |
blocks = []
|
| 140 |
skin_type_text = CILT_TIPI_TR.get(skin_type_code, "Hassas Cilt")
|
| 141 |
|
| 142 |
-
# 1. CİLT TİPİ İÇİN BAKIM
|
| 143 |
if "YAĞLI" in skin_type_code:
|
| 144 |
blocks.append({"title": "Günlük Temizleme", "issue": "Yağlanma", "ingredient": "Yüz Yıkama Jeli"})
|
| 145 |
elif "KURU" in skin_type_code:
|
|
@@ -147,7 +130,6 @@ def generate_prescription_logic(skin_type_code, issues):
|
|
| 147 |
elif "KARMA" in skin_type_code:
|
| 148 |
blocks.append({"title": "Dengeleyici Bakım", "issue": "Dengeleyici", "ingredient": "Yüz Yıkama Köpüğü"})
|
| 149 |
|
| 150 |
-
# 2. SORUNLAR İÇİN ÇÖZÜM
|
| 151 |
unique_issues = list(set(issues))
|
| 152 |
for issue in unique_issues:
|
| 153 |
tr_issue = TR_LABELS.get(issue, issue)
|
|
@@ -155,13 +137,14 @@ def generate_prescription_logic(skin_type_code, issues):
|
|
| 155 |
ingredient_hint = None
|
| 156 |
title = f"{tr_issue} Çözümü"
|
| 157 |
|
| 158 |
-
|
|
|
|
| 159 |
ingredient_hint = "Akne Karşıtı"
|
| 160 |
-
elif "
|
| 161 |
ingredient_hint = "Leke Karşıtı"
|
| 162 |
-
elif "
|
| 163 |
ingredient_hint = "Yatıştırıcı"
|
| 164 |
-
elif "
|
| 165 |
ingredient_hint = "Yaşlanma Karşıtı"
|
| 166 |
|
| 167 |
blocks.append({
|
|
@@ -183,7 +166,7 @@ def get_skin_type(image):
|
|
| 183 |
# --- API ENDPOINT ---
|
| 184 |
@app.get("/")
|
| 185 |
def home():
|
| 186 |
-
return {"status": "Pure Sense API (
|
| 187 |
|
| 188 |
@app.post("/analyze")
|
| 189 |
async def analyze_skin(
|
|
@@ -193,11 +176,20 @@ async def analyze_skin(
|
|
| 193 |
contents = await file.read()
|
| 194 |
image = Image.open(io.BytesIO(contents)).convert("RGB")
|
| 195 |
|
| 196 |
-
# 1. Cilt Tipi
|
| 197 |
skin_type_code = get_skin_type(image)
|
| 198 |
|
| 199 |
-
#
|
| 200 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 201 |
inputs = owl_processor(text=text_queries, images=image, return_tensors="pt").to(device)
|
| 202 |
with torch.no_grad(): outputs = owl_model(**inputs)
|
| 203 |
|
|
@@ -211,31 +203,48 @@ async def analyze_skin(
|
|
| 211 |
lbl_en = text_queries[0][label]
|
| 212 |
conf = round(score.item() * 100, 1)
|
| 213 |
|
| 214 |
-
#
|
|
|
|
|
|
|
| 215 |
if lbl_en == "deep wrinkles" and conf < 40: continue
|
| 216 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 217 |
if conf < 3: continue
|
| 218 |
|
| 219 |
lbl_tr = TR_LABELS.get(lbl_en, lbl_en)
|
| 220 |
-
|
|
|
|
|
|
|
|
|
|
| 221 |
|
| 222 |
detections.append({
|
| 223 |
-
"label": lbl_tr,
|
| 224 |
"confidence": conf,
|
| 225 |
"box": [int(i) for i in box.tolist()]
|
| 226 |
})
|
| 227 |
|
| 228 |
-
#
|
| 229 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
|
| 231 |
final_prescriptions = []
|
| 232 |
for block in prescription_blocks:
|
| 233 |
-
# Akıllı Link Jeneratörü
|
| 234 |
products = get_dynamic_products(block['issue'], skin_type_text, block['ingredient'], is_premium)
|
| 235 |
-
|
| 236 |
final_prescriptions.append({
|
| 237 |
"title": block['title'],
|
| 238 |
-
"ingredient": block['
|
| 239 |
"products": products
|
| 240 |
})
|
| 241 |
|
|
|
|
| 51 |
|
| 52 |
# --- SÖZLÜKLER ---
|
| 53 |
TR_LABELS = {
|
| 54 |
+
"inflamed acne pimple": "Akne", # İsimler güncellendi
|
| 55 |
+
"whitehead": "Sivilce",
|
| 56 |
+
"dark spot": "Leke",
|
| 57 |
+
"deep wrinkles": "Kırışıklık",
|
| 58 |
+
"oily skin": "Yağlanma",
|
| 59 |
+
"dry flaky skin": "Kuruluk",
|
| 60 |
+
"diffuse skin redness": "Kızarıklık",
|
| 61 |
+
"peeling skin": "Deri Soyulması",
|
| 62 |
+
"rough skin": "Pürüzlü"
|
| 63 |
}
|
| 64 |
|
| 65 |
CILT_TIPI_TR = {
|
|
|
|
| 67 |
"NORMAL": "Normal Cilt", "KARMA": "Karma Cilt"
|
| 68 |
}
|
| 69 |
|
| 70 |
+
# --- MAĞAZA URL ŞABLONLARI ---
|
| 71 |
MARKET_TEMPLATES = {
|
| 72 |
"Trendyol": "https://www.trendyol.com/sr?q={query}&os=1",
|
| 73 |
"Hepsiburada": "https://www.hepsiburada.com/ara?q={query}",
|
|
|
|
| 83 |
"Beymen": "https://www.beymen.com/tr/search?q={query}"
|
| 84 |
}
|
| 85 |
|
| 86 |
+
# --- LİNK OLUŞTURUCU ---
|
| 87 |
def generate_smart_search_link(market_name, search_phrase):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
if market_name in ["Sephora", "Hepsiburada", "Amazon", "Yves Rocher"]:
|
| 89 |
+
encoded_query = urllib.parse.quote_plus(search_phrase)
|
| 90 |
else:
|
| 91 |
+
encoded_query = urllib.parse.quote(search_phrase)
|
| 92 |
|
|
|
|
| 93 |
template = MARKET_TEMPLATES.get(market_name, MARKET_TEMPLATES["Trendyol"])
|
| 94 |
return template.format(query=encoded_query)
|
| 95 |
|
| 96 |
def get_dynamic_products(issue, skin_type_tr, ingredient_hint, is_premium=False):
|
|
|
|
|
|
|
|
|
|
| 97 |
products = []
|
| 98 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
if ingredient_hint:
|
|
|
|
| 100 |
search_text = f"{ingredient_hint} {skin_type_tr}"
|
| 101 |
else:
|
|
|
|
| 102 |
search_text = f"{issue} Karşıtı {skin_type_tr}"
|
| 103 |
|
|
|
|
| 104 |
all_markets = list(MARKET_TEMPLATES.keys())
|
| 105 |
|
| 106 |
if not is_premium:
|
|
|
|
| 107 |
active_markets = ["Trendyol", "Gratis", "Watsons"]
|
| 108 |
else:
|
|
|
|
| 109 |
active_markets = all_markets.copy()
|
| 110 |
random.shuffle(active_markets)
|
| 111 |
active_markets = active_markets[:6]
|
| 112 |
|
|
|
|
| 113 |
for market in active_markets:
|
| 114 |
final_link = generate_smart_search_link(market, search_text)
|
|
|
|
| 115 |
products.append({
|
| 116 |
"source": market,
|
| 117 |
"title": f"{market}: {search_text}",
|
| 118 |
"link": final_link
|
| 119 |
})
|
|
|
|
| 120 |
return products
|
| 121 |
|
| 122 |
def generate_prescription_logic(skin_type_code, issues):
|
| 123 |
blocks = []
|
| 124 |
skin_type_text = CILT_TIPI_TR.get(skin_type_code, "Hassas Cilt")
|
| 125 |
|
|
|
|
| 126 |
if "YAĞLI" in skin_type_code:
|
| 127 |
blocks.append({"title": "Günlük Temizleme", "issue": "Yağlanma", "ingredient": "Yüz Yıkama Jeli"})
|
| 128 |
elif "KURU" in skin_type_code:
|
|
|
|
| 130 |
elif "KARMA" in skin_type_code:
|
| 131 |
blocks.append({"title": "Dengeleyici Bakım", "issue": "Dengeleyici", "ingredient": "Yüz Yıkama Köpüğü"})
|
| 132 |
|
|
|
|
| 133 |
unique_issues = list(set(issues))
|
| 134 |
for issue in unique_issues:
|
| 135 |
tr_issue = TR_LABELS.get(issue, issue)
|
|
|
|
| 137 |
ingredient_hint = None
|
| 138 |
title = f"{tr_issue} Çözümü"
|
| 139 |
|
| 140 |
+
# Anahtar kelimelere göre içerik eşleştirme (Güncellendi)
|
| 141 |
+
if "Akne" in tr_issue or "Sivilce" in tr_issue:
|
| 142 |
ingredient_hint = "Akne Karşıtı"
|
| 143 |
+
elif "Leke" in tr_issue:
|
| 144 |
ingredient_hint = "Leke Karşıtı"
|
| 145 |
+
elif "Kızarıklık" in tr_issue:
|
| 146 |
ingredient_hint = "Yatıştırıcı"
|
| 147 |
+
elif "Kırışıklık" in tr_issue:
|
| 148 |
ingredient_hint = "Yaşlanma Karşıtı"
|
| 149 |
|
| 150 |
blocks.append({
|
|
|
|
| 166 |
# --- API ENDPOINT ---
|
| 167 |
@app.get("/")
|
| 168 |
def home():
|
| 169 |
+
return {"status": "Pure Sense API (Acne Focus Fix) Çalışıyor"}
|
| 170 |
|
| 171 |
@app.post("/analyze")
|
| 172 |
async def analyze_skin(
|
|
|
|
| 176 |
contents = await file.read()
|
| 177 |
image = Image.open(io.BytesIO(contents)).convert("RGB")
|
| 178 |
|
|
|
|
| 179 |
skin_type_code = get_skin_type(image)
|
| 180 |
|
| 181 |
+
# --- GÜNCELLENMİŞ HASSAS PROMPTLAR ---
|
| 182 |
+
# "acne" yerine "inflamed acne pimple" (İltihaplı Akne)
|
| 183 |
+
# "skin redness" yerine "diffuse skin redness" (Yaygın Kızarıklık)
|
| 184 |
+
text_queries = [[
|
| 185 |
+
"inflamed acne pimple",
|
| 186 |
+
"whitehead",
|
| 187 |
+
"dark spot",
|
| 188 |
+
"diffuse skin redness",
|
| 189 |
+
"dry flaky skin",
|
| 190 |
+
"deep wrinkles"
|
| 191 |
+
]]
|
| 192 |
+
|
| 193 |
inputs = owl_processor(text=text_queries, images=image, return_tensors="pt").to(device)
|
| 194 |
with torch.no_grad(): outputs = owl_model(**inputs)
|
| 195 |
|
|
|
|
| 203 |
lbl_en = text_queries[0][label]
|
| 204 |
conf = round(score.item() * 100, 1)
|
| 205 |
|
| 206 |
+
# --- ZEKİ FİLTRELEME MANTIĞI ---
|
| 207 |
+
|
| 208 |
+
# 1. Kırışıklık: Çok sıkı tut (%40), yoksa her çizgiye kırışıklık der.
|
| 209 |
if lbl_en == "deep wrinkles" and conf < 40: continue
|
| 210 |
+
|
| 211 |
+
# 2. Akne/Sivilce: Biraz gevşek bırak (%8), küçük noktaları kaçırmasın.
|
| 212 |
+
if lbl_en in ["inflamed acne pimple", "whitehead"] and conf < 8: continue
|
| 213 |
+
|
| 214 |
+
# 3. Kızarıklık: SIKI TUT (%15).
|
| 215 |
+
# Eğer %15'ten azsa "Bu sadece sivilcenin etrafıdır, ana sorun kızarıklık değildir" de ve gizle.
|
| 216 |
+
if lbl_en == "diffuse skin redness" and conf < 15: continue
|
| 217 |
+
|
| 218 |
+
# 4. Diğerleri: Standart %3
|
| 219 |
if conf < 3: continue
|
| 220 |
|
| 221 |
lbl_tr = TR_LABELS.get(lbl_en, lbl_en)
|
| 222 |
+
|
| 223 |
+
# İngilizce ham halini listeye ekle (Reçete için)
|
| 224 |
+
# (Türkçeye çevirmeden ekliyoruz ki aşağıda TR_LABELS ile eşleşsin)
|
| 225 |
+
if lbl_en not in issues_found: issues_found.append(lbl_en)
|
| 226 |
|
| 227 |
detections.append({
|
| 228 |
+
"label": lbl_tr, # Kullanıcıya Türkçe göster
|
| 229 |
"confidence": conf,
|
| 230 |
"box": [int(i) for i in box.tolist()]
|
| 231 |
})
|
| 232 |
|
| 233 |
+
# Reçete Hazırlığı (issues_found içindeki İngilizce keyleri kullan)
|
| 234 |
+
raw_issues_for_rx = []
|
| 235 |
+
for i in issues_found:
|
| 236 |
+
# TR_LABELS içindeki key'ler ile eşleşiyorsa listeye al
|
| 237 |
+
if i in TR_LABELS:
|
| 238 |
+
raw_issues_for_rx.append(i)
|
| 239 |
+
|
| 240 |
+
prescription_blocks, skin_type_text = generate_prescription_logic(skin_type_code, raw_issues_for_rx)
|
| 241 |
|
| 242 |
final_prescriptions = []
|
| 243 |
for block in prescription_blocks:
|
|
|
|
| 244 |
products = get_dynamic_products(block['issue'], skin_type_text, block['ingredient'], is_premium)
|
|
|
|
| 245 |
final_prescriptions.append({
|
| 246 |
"title": block['title'],
|
| 247 |
+
"ingredient": block['ingredient'],
|
| 248 |
"products": products
|
| 249 |
})
|
| 250 |
|