puresenseai commited on
Commit
7f7d39e
·
verified ·
1 Parent(s): 28a3522

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +173 -0
app.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import random
3
+ import warnings
4
+ import logging
5
+ from fastapi import FastAPI, File, UploadFile
6
+ from fastapi.middleware.cors import CORSMiddleware
7
+ from PIL import Image
8
+ import io
9
+ import torch
10
+ import numpy as np
11
+ import cv2
12
+ import mediapipe as mp
13
+ from transformers import Owlv2Processor, Owlv2ForObjectDetection
14
+ from transformers import CLIPProcessor, CLIPModel
15
+ from duckduckgo_search import DDGS
16
+
17
+ # --- AYARLAR ---
18
+ warnings.filterwarnings("ignore")
19
+ logging.getLogger("transformers").setLevel(logging.ERROR)
20
+
21
+ app = FastAPI()
22
+
23
+ # Mobil uygulamadan gelen isteklere izin ver
24
+ app.add_middleware(
25
+ CORSMiddleware,
26
+ allow_origins=["*"],
27
+ allow_credentials=True,
28
+ allow_methods=["*"],
29
+ allow_headers=["*"],
30
+ )
31
+
32
+ # --- MODELLERİ BAŞLATTA YÜKLE ---
33
+ print("⏳ Modeller Yükleniyor...")
34
+ device = "cpu" # Hugging Face Free Tier CPU kullanır
35
+
36
+ # OWL-v2
37
+ owl_id = "google/owlv2-base-patch16-ensemble"
38
+ owl_processor = Owlv2Processor.from_pretrained(owl_id)
39
+ owl_model = Owlv2ForObjectDetection.from_pretrained(owl_id).to(device)
40
+
41
+ # CLIP
42
+ clip_id = "openai/clip-vit-base-patch32"
43
+ clip_processor = CLIPProcessor.from_pretrained(clip_id)
44
+ clip_model = CLIPModel.from_pretrained(clip_id).to(device)
45
+
46
+ # MediaPipe
47
+ mp_face_mesh = mp.solutions.face_mesh
48
+ face_mesh = mp_face_mesh.FaceMesh(static_image_mode=True, max_num_faces=1, refine_landmarks=True)
49
+
50
+ print("✅ Sunucu Hazır!")
51
+
52
+ # --- SÖZLÜKLER VE YEDEK ÜRÜNLER ---
53
+ TR_LABELS = {
54
+ "acne": "Akne", "pimple": "Sivilce", "dark spot": "Leke",
55
+ "wrinkles": "Kırışıklık", "oily skin": "Yağlanma",
56
+ "dry flaky skin": "Kuruluk", "skin redness": "Kızarıklık",
57
+ "peeling skin": "Soyulma", "rough skin": "Pürüzlü"
58
+ }
59
+
60
+ FALLBACK_DATABASE = {
61
+ "Salisilik Asit": [{"title": "La Roche-Posay Effaclar", "link": "https://www.trendyol.com/sr?q=effaclar"}, {"title": "CeraVe SA", "link": "https://www.hepsiburada.com/ara?q=cerave+sa"}],
62
+ "Çay Ağacı": [{"title": "The Body Shop Tea Tree", "link": "https://www.thebodyshop.com.tr"}, {"title": "Sebamed Clear Face", "link": "https://www.gratis.com"}],
63
+ "C Vitamini": [{"title": "Garnier C Vitamini", "link": "https://www.trendyol.com"}, {"title": "La Roche-Posay C10", "link": "https://www.hepsiburada.com"}],
64
+ "Hyaluronik Asit": [{"title": "L'Oreal Hyaluron Uzmanı", "link": "https://www.trendyol.com"}, {"title": "Vichy Mineral 89", "link": "https://www.hepsiburada.com"}],
65
+ "Centella": [{"title": "Dr. Jart+ Cicapair", "link": "https://www.sephora.com.tr"}, {"title": "Missha Cica", "link": "https://www.missha.com.tr"}]
66
+ }
67
+
68
+ # --- FONKSİYONLAR ---
69
+ def get_skin_type(image):
70
+ prompts = ["extremely oily shiny skin", "very dry flaky skin", "normal skin", "combination skin"]
71
+ labels = ["YAĞLI", "KURU", "NORMAL", "KARMA"]
72
+ inputs = clip_processor(text=prompts, images=image, return_tensors="pt", padding=True).to(device)
73
+ with torch.no_grad(): probs = clip_model(**inputs).logits_per_image.softmax(dim=1)
74
+ return labels[torch.max(probs, 1).indices.item()]
75
+
76
+ def get_products(ingredient, skin_type):
77
+ found = []
78
+ # Canlı Arama
79
+ try:
80
+ with DDGS() as ddgs:
81
+ query = f"site:trendyol.com {ingredient} {skin_type} cilt"
82
+ results = list(ddgs.text(query, max_results=2))
83
+ for r in results:
84
+ found.append({"title": r['title'].split("|")[0], "link": r['href'], "source": "Trendyol"})
85
+ except: pass
86
+
87
+ # Yedek Depo
88
+ if len(found) < 2:
89
+ key_found = None
90
+ for key in FALLBACK_DATABASE:
91
+ if key in ingredient: key_found = key
92
+ if key_found:
93
+ for item in FALLBACK_DATABASE[key_found]:
94
+ found.append({"title": item['title'], "link": item['link'], "source": "Öneri"})
95
+
96
+ return found[:4]
97
+
98
+ def generate_prescription(skin_type, issues):
99
+ prescriptions = []
100
+ # Temel
101
+ if skin_type == "YAĞLI": prescriptions.append({"sorun": "Yağlı Cilt Temizliği", "icerik": "Salisilik Asit"})
102
+ elif skin_type == "KURU": prescriptions.append({"sorun": "Kuru Cilt Onarımı", "icerik": "Hyaluronik Asit"})
103
+
104
+ # Soruna Özel
105
+ unique_issues = list(set(issues))
106
+ for issue in unique_issues:
107
+ if "acne" in issue or "pimple" in issue:
108
+ prescriptions.append({"sorun": "Akne Tedavisi", "icerik": "Çay Ağacı"})
109
+ break
110
+ elif "dark spot" in issue:
111
+ prescriptions.append({"sorun": "Leke Giderici", "icerik": "C Vitamini"})
112
+ elif "redness" in issue:
113
+ prescriptions.append({"sorun": "Kızarıklık Giderici", "icerik": "Centella"})
114
+
115
+ return prescriptions
116
+
117
+ # --- API ENDPOINT ---
118
+ @app.get("/")
119
+ def home():
120
+ return {"status": "Pure Sense API Çalışıyor", "version": "1.0"}
121
+
122
+ @app.post("/analyze")
123
+ async def analyze_skin(file: UploadFile = File(...)):
124
+ contents = await file.read()
125
+ image = Image.open(io.BytesIO(contents)).convert("RGB")
126
+
127
+ # 1. Cilt Tipi
128
+ skin_type = get_skin_type(image)
129
+
130
+ # 2. Sorun Tespiti
131
+ text_queries = [["acne", "pimple", "dark spot", "skin redness", "dry flaky skin"]]
132
+ inputs = owl_processor(text=text_queries, images=image, return_tensors="pt").to(device)
133
+ with torch.no_grad(): outputs = owl_model(**inputs)
134
+
135
+ target_sizes = torch.Tensor([image.size[::-1]])
136
+ results = owl_processor.post_process_object_detection(outputs=outputs, target_sizes=target_sizes, threshold=0.02)[0]
137
+
138
+ detections = []
139
+ issues_found = []
140
+
141
+ for score, label, box in zip(results["scores"], results["labels"], results["boxes"]):
142
+ lbl_en = text_queries[0][label]
143
+ conf = round(score.item() * 100, 1)
144
+
145
+ if lbl_en in ["acne", "pimple"] and conf < 10: continue
146
+ if lbl_en not in ["acne", "pimple"] and conf < 3: continue
147
+
148
+ lbl_tr = TR_LABELS.get(lbl_en, lbl_en)
149
+ if lbl_tr not in issues_found: issues_found.append(lbl_tr)
150
+
151
+ detections.append({
152
+ "label": lbl_tr,
153
+ "confidence": conf,
154
+ "box": [int(i) for i in box.tolist()]
155
+ })
156
+
157
+ # 3. Reçete
158
+ prescriptions = []
159
+ rx_list = generate_prescription(skin_type, [i.lower() for i in text_queries[0] if TR_LABELS.get(i,i) in issues_found]) # Basit eşleştirme
160
+
161
+ for rx in rx_list:
162
+ prods = get_products(rx['icerik'], skin_type)
163
+ prescriptions.append({
164
+ "title": rx['sorun'],
165
+ "ingredient": rx['icerik'],
166
+ "products": prods
167
+ })
168
+
169
+ return {
170
+ "skin_type": skin_type,
171
+ "detections": detections,
172
+ "prescriptions": prescriptions
173
+ }