Spaces:
Sleeping
Sleeping
| import os | |
| import random | |
| import warnings | |
| import logging | |
| from fastapi import FastAPI, File, UploadFile | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from PIL import Image | |
| import io | |
| import torch | |
| import numpy as np | |
| import cv2 | |
| import mediapipe as mp | |
| from transformers import Owlv2Processor, Owlv2ForObjectDetection | |
| from transformers import CLIPProcessor, CLIPModel | |
| from duckduckgo_search import DDGS | |
| # --- AYARLAR --- | |
| warnings.filterwarnings("ignore") | |
| logging.getLogger("transformers").setLevel(logging.ERROR) | |
| app = FastAPI() | |
| # Mobil uygulamadan gelen isteklere izin ver | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # --- MODELLERİ BAŞLATTA YÜKLE --- | |
| print("⏳ Modeller Yükleniyor...") | |
| device = "cpu" # Hugging Face Free Tier CPU kullanır | |
| # OWL-v2 | |
| owl_id = "google/owlv2-base-patch16-ensemble" | |
| owl_processor = Owlv2Processor.from_pretrained(owl_id) | |
| owl_model = Owlv2ForObjectDetection.from_pretrained(owl_id).to(device) | |
| # CLIP | |
| clip_id = "openai/clip-vit-base-patch32" | |
| clip_processor = CLIPProcessor.from_pretrained(clip_id) | |
| clip_model = CLIPModel.from_pretrained(clip_id).to(device) | |
| # MediaPipe | |
| mp_face_mesh = mp.solutions.face_mesh | |
| face_mesh = mp_face_mesh.FaceMesh(static_image_mode=True, max_num_faces=1, refine_landmarks=True) | |
| print("✅ Sunucu Hazır!") | |
| # --- SÖZLÜKLER VE YEDEK ÜRÜNLER --- | |
| TR_LABELS = { | |
| "acne": "Akne", "pimple": "Sivilce", "dark spot": "Leke", | |
| "wrinkles": "Kırışıklık", "oily skin": "Yağlanma", | |
| "dry flaky skin": "Kuruluk", "skin redness": "Kızarıklık", | |
| "peeling skin": "Soyulma", "rough skin": "Pürüzlü" | |
| } | |
| FALLBACK_DATABASE = { | |
| "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"}], | |
| "Çay Ağacı": [{"title": "The Body Shop Tea Tree", "link": "https://www.thebodyshop.com.tr"}, {"title": "Sebamed Clear Face", "link": "https://www.gratis.com"}], | |
| "C Vitamini": [{"title": "Garnier C Vitamini", "link": "https://www.trendyol.com"}, {"title": "La Roche-Posay C10", "link": "https://www.hepsiburada.com"}], | |
| "Hyaluronik Asit": [{"title": "L'Oreal Hyaluron Uzmanı", "link": "https://www.trendyol.com"}, {"title": "Vichy Mineral 89", "link": "https://www.hepsiburada.com"}], | |
| "Centella": [{"title": "Dr. Jart+ Cicapair", "link": "https://www.sephora.com.tr"}, {"title": "Missha Cica", "link": "https://www.missha.com.tr"}] | |
| } | |
| # --- FONKSİYONLAR --- | |
| def get_skin_type(image): | |
| prompts = ["extremely oily shiny skin", "very dry flaky skin", "normal skin", "combination skin"] | |
| labels = ["YAĞLI", "KURU", "NORMAL", "KARMA"] | |
| inputs = clip_processor(text=prompts, images=image, return_tensors="pt", padding=True).to(device) | |
| with torch.no_grad(): probs = clip_model(**inputs).logits_per_image.softmax(dim=1) | |
| return labels[torch.max(probs, 1).indices.item()] | |
| def get_products(ingredient, skin_type): | |
| found = [] | |
| # Canlı Arama | |
| try: | |
| with DDGS() as ddgs: | |
| query = f"site:trendyol.com {ingredient} {skin_type} cilt" | |
| results = list(ddgs.text(query, max_results=2)) | |
| for r in results: | |
| found.append({"title": r['title'].split("|")[0], "link": r['href'], "source": "Trendyol"}) | |
| except: pass | |
| # Yedek Depo | |
| if len(found) < 2: | |
| key_found = None | |
| for key in FALLBACK_DATABASE: | |
| if key in ingredient: key_found = key | |
| if key_found: | |
| for item in FALLBACK_DATABASE[key_found]: | |
| found.append({"title": item['title'], "link": item['link'], "source": "Öneri"}) | |
| return found[:4] | |
| def generate_prescription(skin_type, issues): | |
| prescriptions = [] | |
| # Temel | |
| if skin_type == "YAĞLI": prescriptions.append({"sorun": "Yağlı Cilt Temizliği", "icerik": "Salisilik Asit"}) | |
| elif skin_type == "KURU": prescriptions.append({"sorun": "Kuru Cilt Onarımı", "icerik": "Hyaluronik Asit"}) | |
| # Soruna Özel | |
| unique_issues = list(set(issues)) | |
| for issue in unique_issues: | |
| if "acne" in issue or "pimple" in issue: | |
| prescriptions.append({"sorun": "Akne Tedavisi", "icerik": "Çay Ağacı"}) | |
| break | |
| elif "dark spot" in issue: | |
| prescriptions.append({"sorun": "Leke Giderici", "icerik": "C Vitamini"}) | |
| elif "redness" in issue: | |
| prescriptions.append({"sorun": "Kızarıklık Giderici", "icerik": "Centella"}) | |
| return prescriptions | |
| # --- API ENDPOINT --- | |
| def home(): | |
| return {"status": "Pure Sense API Çalışıyor", "version": "1.0"} | |
| async def analyze_skin(file: UploadFile = File(...)): | |
| contents = await file.read() | |
| image = Image.open(io.BytesIO(contents)).convert("RGB") | |
| # 1. Cilt Tipi | |
| skin_type = get_skin_type(image) | |
| # 2. Sorun Tespiti | |
| text_queries = [["acne", "pimple", "dark spot", "skin redness", "dry flaky skin"]] | |
| inputs = owl_processor(text=text_queries, images=image, return_tensors="pt").to(device) | |
| with torch.no_grad(): outputs = owl_model(**inputs) | |
| target_sizes = torch.Tensor([image.size[::-1]]) | |
| results = owl_processor.post_process_object_detection(outputs=outputs, target_sizes=target_sizes, threshold=0.02)[0] | |
| detections = [] | |
| issues_found = [] | |
| for score, label, box in zip(results["scores"], results["labels"], results["boxes"]): | |
| lbl_en = text_queries[0][label] | |
| conf = round(score.item() * 100, 1) | |
| if lbl_en in ["acne", "pimple"] and conf < 10: continue | |
| if lbl_en not in ["acne", "pimple"] and conf < 3: continue | |
| lbl_tr = TR_LABELS.get(lbl_en, lbl_en) | |
| if lbl_tr not in issues_found: issues_found.append(lbl_tr) | |
| detections.append({ | |
| "label": lbl_tr, | |
| "confidence": conf, | |
| "box": [int(i) for i in box.tolist()] | |
| }) | |
| # 3. Reçete | |
| prescriptions = [] | |
| 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 | |
| for rx in rx_list: | |
| prods = get_products(rx['icerik'], skin_type) | |
| prescriptions.append({ | |
| "title": rx['sorun'], | |
| "ingredient": rx['icerik'], | |
| "products": prods | |
| }) | |
| return { | |
| "skin_type": skin_type, | |
| "detections": detections, | |
| "prescriptions": prescriptions | |
| } |