Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI, Request, UploadFile, File | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from deepface import DeepFace | |
| import cv2 | |
| import numpy as np | |
| import tempfile | |
| import os | |
| import google.generativeai as genai | |
| app = FastAPI() | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Google GenAI yapılandırması (Kullanıcının verdiği şekilde bırakıldı) | |
| os.environ['GOOGLE_API_KEY'] = "AIzaSyCfAzWCivzmDJdeUZtCzhvpWvPTVlRhhwg" # Lütfen gerçek API anahtarınızı kullanın ve güvenli yönetin. | |
| try: | |
| genai.configure(api_key=os.getenv('GOOGLE_API_KEY')) | |
| # Kullanıcının belirttiği model adı. Eğer bu model mevcut değilse veya erişiminiz yoksa hata alırsınız. | |
| model = genai.GenerativeModel("models/gemini-2.0-flash-lite") # Önerilen daha yaygın model: "gemini-1.5-flash-latest" veya "gemini-pro" | |
| # Orijinal: "models/gemini-2.0-flash-lite" | |
| except Exception as e: | |
| print(f"Google GenAI yapılandırma hatası: {e}. Model None olarak ayarlandı.") | |
| model = None | |
| system_prompt = ( | |
| "Sen deneyimli ama sade bir dille konuşan, içten ve empatik bir psikologsun. " | |
| "Danışanla konuşurken kısa, samimi ve destekleyici cevaplar ver. " | |
| "Yargılamadan dinle, anlayış göster ve gerekirse profesyonel destek almanın doğal bir şey olduğunu hatırlat. " | |
| "Sade konuş, insan gibi, uzun uzun açıklama yapma. Danışanı yormadan cesaret ver." | |
| "Önceki konuşmaları da dikkate alarak hastanın ismini ve vereceğin cevabı da önceki konuşmalara göre ver." | |
| "Sürekli olarak aynı türde cevaplar verme. Gerçek bir insan piskolog gibi davran. Yapay zeka olduğun anlşılmasın." | |
| ) | |
| async def chat(request: Request): | |
| content_type = request.headers.get("content-type", "") | |
| # Görsel geldiyse | |
| if "multipart/form-data" in content_type: | |
| form = await request.form() | |
| image_file: UploadFile = form.get("image") | |
| if image_file: | |
| temp_file_path = None | |
| try: | |
| # Geçici dosyayı güvenli bir şekilde oluştur | |
| with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_file_obj: # Dosya uzantısı eklemek iyi bir pratiktir | |
| temp_file_obj.write(await image_file.read()) | |
| temp_file_path = temp_file_obj.name | |
| img = cv2.imread(temp_file_path) | |
| if img is None: | |
| # Geçici dosyayı silmeyi unutma | |
| if temp_file_path and os.path.exists(temp_file_path): | |
| os.remove(temp_file_path) | |
| return {"response": "Görüntü dosyası okunamadı veya bozuk."} | |
| # DeepFace analizi | |
| # Bazen ilk analizde tüm özellikler gelmeyebilir, hepsini isteyelim | |
| # enforce_detection=False yüz bulunamazsa hata vermez, None döner veya boş liste. | |
| # True yaparsak yüz bulamazsa exception atar. | |
| analysis_results = DeepFace.analyze(img_path=temp_file_path, actions=["age", "gender", "emotion"], enforce_detection=True) | |
| # DeepFace birden fazla yüz bulursa ilkini alır | |
| if not analysis_results: # Eğer enforce_detection=False ise bu kontrol gerekebilir | |
| if temp_file_path and os.path.exists(temp_file_path): | |
| os.remove(temp_file_path) | |
| return {"response": "Görüntüde yüz tespit edilemedi."} | |
| analysis = analysis_results[0] | |
| age = analysis["age"] | |
| gender_probabilities = analysis["gender"] | |
| emotion = analysis["dominant_emotion"] | |
| # Cinsiyetin en yüksek olasılığını seç | |
| gender = "Man" if gender_probabilities["Man"] > gender_probabilities["Woman"] else "Woman" | |
| # İstemciye "Erkek" veya "Kadın" olarak göndermek daha iyi olabilir, ancak mevcut yapıyı koruyoruz. | |
| # GenAI yapısına uyumlu döndür (Kullanıcının istediği gibi) | |
| # Bu endpointten age, gender, emotion'ı ayrı JSON field'ları olarak döndürmek, | |
| # /stress_evaluation'a gönderimi kolaylaştırır. Ancak mevcut yapı korunuyor. | |
| response_text = f"Bu kişi {gender} ve yaklaşık {age} yaşında. Yüz ifadesine göre şu anki duygusu: {emotion}." | |
| return {"response": response_text, "age": age, "gender": gender, "emotion": emotion} # age, gender, emotion eklendi | |
| except Exception as e: | |
| return {"response": f"Yüz analizi yapılamadı: {str(e)}"} | |
| finally: | |
| # Geçici dosyayı her zaman sil | |
| if temp_file_path and os.path.exists(temp_file_path): | |
| os.remove(temp_file_path) | |
| else: | |
| return {"response": "Görsel dosya bulunamadı."} | |
| # Metin gelmişse: GenAI tarafı | |
| if not model: | |
| return {"response": "GenAI modeli yüklenemedi. Lütfen API anahtarınızı ve model adını kontrol edin."} | |
| try: | |
| body = await request.json() | |
| except Exception: | |
| return {"response": "Geçersiz JSON formatı."} | |
| user_input = body.get("message", "") | |
| previous_messages = body.get("previousMessages", []) | |
| full_prompt = system_prompt + "\n\n" | |
| for message in previous_messages: | |
| full_prompt += f"Danışan: {message['user']}\nPsikolog: {message['bot']}\n" | |
| full_prompt += f"Danışan: {user_input}\nPsikolog:" | |
| try: | |
| response = model.generate_content([full_prompt]) | |
| return {"response": response.text.strip()} | |
| except Exception as e: | |
| return {"response": f"GenAI hatası: {str(e)}"} | |
| # Sadece puanları içeren listeler (sıralama önemli!) | |
| stress_factors_6_12 = [ | |
| 20, 40, 25, 30, 35, 50, 60, 40, 45, 100, | |
| 70, 63, 68, 50, 45, 50, 46, 47, 40, 56, | |
| 53, 35, 30, 41 | |
| ] | |
| stress_factors_12_18 = [ | |
| 40, 50, 35, 30, 45, 35, 25, 40, 40, 100, | |
| 100, 70, 90, 63, 68, 50, 53, 56, 50, 51, | |
| 47, 45, 53, 41, 34, 37, 31, 50 | |
| ] | |
| stress_factors_19_plus = [ | |
| 100, 73, 65, 63, 63, 53, 50, 47, 45, 45, | |
| 44, 40, 39, 39, 39, 38, 37, 36, 35, 32, | |
| 30, 29, 29, 29, 28, 26, 26, 25, 24, 23, | |
| 20, 20, 20, 19, 19, 18, 17, 16 | |
| ] | |
| async def stress_evaluation(request: Request): | |
| if not model: # Modelin yüklenip yüklenmediğini kontrol et | |
| return {"response": "GenAI modeli yüklenemedi. Lütfen API anahtarınızı ve model adını kontrol edin."} | |
| data = await request.json() | |
| age_str = data.get("age") # /chat endpointinden gelen age | |
| gender_from_chat = data.get("gender") # /chat endpointinden gelen gender ("Man" veya "Woman") | |
| emotion_from_chat = data.get("emotion") # /chat endpointinden gelen emotion | |
| stress_answers = data.get("stressAnswers", []) # [0, 1, 1, 0, ...] formatında | |
| if age_str is None or gender_from_chat is None or emotion_from_chat is None or not stress_answers: | |
| return {"response": "Eksik bilgi gönderildi: yaş, cinsiyet, duygu ve stres cevapları gereklidir."} | |
| try: | |
| age = int(age_str) | |
| except ValueError: | |
| return {"response": "Yaş değeri sayı olmalıdır."} | |
| # Yaşa göre puan listesi | |
| age_group_name = "" | |
| if 6 <= age <= 12: | |
| factors = stress_factors_6_12 | |
| age_group_name = "6-12 yaş" | |
| elif 13 <= age <= 18: | |
| factors = stress_factors_12_18 | |
| age_group_name = "13-18 yaş" | |
| elif age >= 19: # 19 ve üzeri için aynı liste | |
| factors = stress_factors_19_plus | |
| age_group_name = "19 yaş ve üzeri" | |
| else: | |
| return {"response": f"Desteklenmeyen yaş grubu: {age}. Lütfen 6 yaş ve üzeri bir değer girin."} | |
| if len(stress_answers) != len(factors): | |
| return {"response": f"{age_group_name} için {len(factors)} adet stres cevabı bekleniyor. Gönderilen: {len(stress_answers)}"} | |
| # Stres puanını hesapla | |
| total_score = sum(score for selected, score in zip(stress_answers, factors) if selected == 1) | |
| # Stres yüzdesi (0-100 aralığında) | |
| max_possible_score = sum(factors) | |
| stress_percentage = (total_score / max_possible_score) * 100 if max_possible_score > 0 else 0 | |
| # Seviye, risk ve oda önerisi belirle (Yüzdeye göre) | |
| stress_level_description = "" | |
| risk_info = "" | |
| specific_room_recommendation_text = "" | |
| gender_tr = "Erkek" if gender_from_chat == "Man" else "Kadın" # Prompt için Türkçeleştirme | |
| if stress_percentage < 34: # Düşük stres (%0-33) | |
| stress_level_description = "Düşük stres" | |
| risk_info = "Bu seviyede stres genellikle yönetilebilirdir." | |
| specific_room_recommendation_text = ( | |
| "Görünüşe göre stres seviyen şu an için oldukça iyi bir düzeyde. Bu harika! " | |
| "Yine de gün içinde biraz mola vermek ve zihnini dinlendirmek istersen, uygulamamızdaki **Sera Odası** tam sana göre olabilir. " | |
| "Orada doğanın sakinleştirici sesleri ve görüntüleriyle huzur bulabilirsin." | |
| ) | |
| elif stress_percentage < 67: # Orta stres (%34-66) | |
| stress_level_description = "Orta düzey stres (%50 hastalık riski)" | |
| risk_info = "Bu seviyedeki stres, uzun vadede bazı sağlık sorunları için yaklaşık %50 civarında bir risk oluşturabilir. Bu yüzden dikkatli olmakta ve önlem almakta fayda var." | |
| specific_room_recommendation_text = ( | |
| "Stres seviyen orta düzeyde görünüyor. Bazen hayatın koşturmacası içinde böyle hissetmek doğal. " | |
| "Bu konuda bir adım atmak istersen, uygulamamızdaki **Meditasyon Odası**'na bir göz atabilirsin. " | |
| "Farklı rehberli meditasyon seansları ile gevşeyebilir ve zihnine bir mola verebilirsin. Denemeye ne dersin?" | |
| ) | |
| else: # Yüksek stres (%67-100) | |
| stress_level_description = "Yüksek stres (%80 hastalık riski)" | |
| risk_info = "Yüksek stres, %80'e varan oranlarda sağlık sorunları riskini beraberinde getirebilir. Bu durumu ciddiye almak ve kendine iyi bakmak gerçekten önemli." | |
| specific_room_recommendation_text = ( | |
| "Stres seviyenin yüksek olduğunu görüyorum. Lütfen unutma, bu konuda yalnız değilsin ve destek aramak çok doğal bir adım. " | |
| "Uygulamamız üzerinden bir **uzman psikologla canlı görüşme** yaparak profesyonel yardım almayı düşünebilirsin. " | |
| "Bir uzmanla konuşmak, yaşadıklarınla başa çıkmana yardımcı olabilir." | |
| ) | |
| # GenAI için prompt oluşturma | |
| # system_prompt'u burada kullanmıyoruz, çünkü o daha çok genel chatbot davranışı için. | |
| # Bu endpoint spesifik bir görev için (stres değerlendirme sonrası tavsiye). | |
| # Ancak, eğer istenirse system_prompt'un bir kısmı buraya da eklenebilir. | |
| # Şimdilik sadece görev odaklı bir prompt. | |
| prompt_for_bot = ( | |
| f"Danışan {age} yaşında bir {gender_tr}. Stres testi sonuçlarına göre stres yüzdesi %{stress_percentage:.0f}. " | |
| f"Bu durum '{stress_level_description}' olarak değerlendiriliyor. Testi yaparkenki yüz ifadesi '{emotion_from_chat}' şeklindeydi. {risk_info}\n\n" | |
| f"Lütfen bu danışana durumuyla ilgili kısa, samimi ve destekleyici bir geri bildirim ver. " | |
| f"Konuşmanın sonunda, ona şu öneriyi yap: '{specific_room_recommendation_text}'\n\n" | |
| "Psikolog rolünde, sade bir dille konuş, danışanı yormadan cesaretlendir ve anlayış göster." | |
| ) | |
| # print(f"DEBUG: GenAI Prompt: {prompt_for_bot}") # Debug için | |
| try: | |
| # Sadece prompt'u gönderiyoruz, çünkü bu tek seferlik bir tavsiye, devam eden bir sohbet değil. | |
| response = model.generate_content([prompt_for_bot]) | |
| advice_from_genai = response.text.strip() | |
| except Exception as e: | |
| advice_from_genai = ( | |
| f"Şu anda sana özel bir tavsiye oluştururken bir sorunla karşılaştım. " | |
| f"Ancak genel olarak, stres seviyenin '{stress_level_description}' olduğunu ve bununla ilgili {risk_info.lower()} bilmelisin. " | |
| f"Durumuna göre {specific_room_recommendation_text.split('.')[0].lower()} gibi aktiviteler iyi gelebilir. " | |
| f"(Hata: {str(e)})" | |
| ) | |
| return { | |
| "stress_score_raw": total_score, # Ham puan | |
| "stress_percentage": round(stress_percentage, 2), # Yüzdeyi 0-100 arası gönder | |
| "stress_level_description": stress_level_description, | |
| "advice": advice_from_genai # GenAI'den gelen tam tavsiye | |
| } |