|
|
import gradio as gr |
|
|
import requests |
|
|
import json |
|
|
from datetime import datetime |
|
|
import io |
|
|
from reportlab.lib.pagesizes import letter, A4 |
|
|
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle |
|
|
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle |
|
|
from reportlab.lib.units import inch |
|
|
from reportlab.lib import colors |
|
|
from reportlab.pdfbase import pdfmetrics |
|
|
from reportlab.pdfbase.ttfonts import TTFont |
|
|
import base64 |
|
|
import os |
|
|
import tempfile |
|
|
|
|
|
class FitnessAI: |
|
|
def __init__(self): |
|
|
self.api_key = None |
|
|
self.base_url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent" |
|
|
|
|
|
def set_api_key(self, api_key): |
|
|
self.api_key = api_key.strip() |
|
|
return "✅ API anahtarı başarıyla kaydedildi!" |
|
|
|
|
|
def generate_response(self, prompt): |
|
|
if not self.api_key: |
|
|
return "❌ Lütfen önce Gemini API anahtarınızı girin!" |
|
|
|
|
|
headers = { |
|
|
'Content-Type': 'application/json', |
|
|
} |
|
|
|
|
|
data = { |
|
|
"contents": [ |
|
|
{ |
|
|
"parts": [ |
|
|
{ |
|
|
"text": prompt |
|
|
} |
|
|
] |
|
|
} |
|
|
] |
|
|
} |
|
|
|
|
|
try: |
|
|
response = requests.post( |
|
|
f"{self.base_url}?key={self.api_key}", |
|
|
headers=headers, |
|
|
json=data, |
|
|
timeout=150 |
|
|
) |
|
|
|
|
|
if response.status_code == 200: |
|
|
result = response.json() |
|
|
return result['candidates'][0]['content']['parts'][0]['text'] |
|
|
else: |
|
|
return f"❌ API Hatası: {response.status_code} - {response.text}" |
|
|
|
|
|
except Exception as e: |
|
|
return f"❌ Bağlantı hatası: {str(e)}" |
|
|
|
|
|
def create_fitness_plan(self, api_key, name, age, gender, height, weight, |
|
|
fitness_level, goal, workout_days, workout_frequency, |
|
|
current_workouts, injuries, diet_info, body_focus_areas, |
|
|
preferred_workout_style, available_equipment): |
|
|
|
|
|
if api_key: |
|
|
self.set_api_key(api_key) |
|
|
|
|
|
|
|
|
prompt = f""" |
|
|
Sen dünya çapında tanınmış, 20+ yıl deneyimli, sertifikalı bir fitness antrenörü ve beslenme uzmanısın. |
|
|
Aşağıdaki kişi için ULTRA DETAYLI, profesyonel bir fitness ve beslenme planı hazırla: |
|
|
|
|
|
👤 KİŞİSEL BİLGİLER: |
|
|
- İsim: {name} |
|
|
- Yaş: {age} |
|
|
- Cinsiyet: {gender} |
|
|
- Boy: {height} cm |
|
|
- Kilo: {weight} kg |
|
|
- Fitness Seviyesi: {fitness_level} |
|
|
- Hedef: {goal} |
|
|
|
|
|
🏋️ ANTRENMAN BİLGİLERİ: |
|
|
- Haftalık Antrenman Günü: {workout_days} |
|
|
- Antrenman Sıklığı: {workout_frequency} |
|
|
- Mevcut Antrenman Rutini: {current_workouts} |
|
|
- Sakatlık/Kısıtlama: {injuries} |
|
|
- Odaklanmak İstediği Vücut Bölgeleri: {body_focus_areas} |
|
|
- Tercih Edilen Antrenman Stili: {preferred_workout_style} |
|
|
- Mevcut Ekipmanlar: {available_equipment} |
|
|
|
|
|
🍎 BESLENME BİLGİLERİ: |
|
|
- Mevcut Beslenme Durumu: {diet_info} |
|
|
|
|
|
LÜTFEN AŞAĞIDAKİ BAŞLIKLARDA ULTRA DETAYLI ANALİZ VE PLAN HAZIRLA: |
|
|
|
|
|
## 📊 KİŞİSEL ANALİZ |
|
|
- BMI hesaplama ve yorumu |
|
|
- Vücut kompozisyonu analizi |
|
|
- Fitness seviyesi değerlendirmesi |
|
|
- Güçlü ve zayıf yönler |
|
|
- Risk faktörleri |
|
|
|
|
|
## 🎯 HEDEFLENDİRİLMİŞ PLAN |
|
|
- Kısa vadeli hedefler (1-3 ay) |
|
|
- Orta vadeli hedefler (3-6 ay) |
|
|
- Uzun vadeli hedefler (6-12 ay) |
|
|
- Başarı ölçüm kriterleri |
|
|
|
|
|
## 🏋️♂️ DETAYLI ANTRENMAN PROGRAMI |
|
|
- Haftalık antrenman takvimi |
|
|
- Her gün için specific egzersizler |
|
|
- Set, tekrar, dinlenme süreleri |
|
|
- Progresyon planı |
|
|
- Isınma ve soğuma egzersizleri |
|
|
- Vücudun farklı bölgeleri için özel hareketler |
|
|
|
|
|
## 🍽️ BESLENME PLANI |
|
|
- Günlük kalori ihtiyacı hesaplaması |
|
|
- Makronutrient dağılımı (protein, karbonhidrat, yağ) |
|
|
- Günlük öğün planı (kahvaltı, öğle, akşam, ara öğünler) |
|
|
- Su tüketimi önerileri |
|
|
- Supplement önerileri |
|
|
- Kaçınılması gereken besinler |
|
|
|
|
|
## 📈 TAKİP VE ÖLÇÜM |
|
|
- Hangi metrikleri takip etmeli |
|
|
- Ölçüm sıklığı |
|
|
- Fotoğraf çekimi önerileri |
|
|
- Performans testleri |
|
|
|
|
|
## ⚠️ DİKKAT EDİLMESİ GEREKENLER |
|
|
- Yaygın hatalar |
|
|
- Güvenlik önlemleri |
|
|
- Motivasyon önerileri |
|
|
- Plana uyum stratejileri |
|
|
|
|
|
## 🔄 PLAN REVİZYONU |
|
|
- Ne zaman plan değişikliği yapılmalı |
|
|
- İlerleme değerlendirme kriterleri |
|
|
- Platoya girme durumunda yapılacaklar |
|
|
|
|
|
Türkçe, profesyonel ama samimi bir dille, detaylı bir şekilde yanıtla. Her bölümü açıklayıcı örneklerle destekle. |
|
|
""" |
|
|
|
|
|
response = self.generate_response(prompt) |
|
|
return response |
|
|
|
|
|
def create_pdf_report(self, content, name): |
|
|
"""PDF rapor oluşturma - geçici dosya olarak""" |
|
|
try: |
|
|
|
|
|
temp_file = tempfile.NamedTemporaryFile( |
|
|
delete=False, |
|
|
suffix='.pdf', |
|
|
prefix=f'fitness_plan_{name.replace(" ", "_")}_' |
|
|
) |
|
|
|
|
|
|
|
|
doc = SimpleDocTemplate(temp_file.name, pagesize=A4, |
|
|
rightMargin=72, leftMargin=72, |
|
|
topMargin=72, bottomMargin=18) |
|
|
|
|
|
|
|
|
styles = getSampleStyleSheet() |
|
|
title_style = ParagraphStyle( |
|
|
'CustomTitle', |
|
|
parent=styles['Heading1'], |
|
|
fontSize=20, |
|
|
textColor=colors.darkblue, |
|
|
alignment=1, |
|
|
spaceAfter=30, |
|
|
) |
|
|
|
|
|
heading_style = ParagraphStyle( |
|
|
'CustomHeading', |
|
|
parent=styles['Heading2'], |
|
|
fontSize=14, |
|
|
textColor=colors.darkgreen, |
|
|
spaceBefore=20, |
|
|
spaceAfter=10, |
|
|
) |
|
|
|
|
|
|
|
|
story = [] |
|
|
|
|
|
|
|
|
story.append(Paragraph(f"🏋️ {name} - Kişisel Fitness Raporu", title_style)) |
|
|
story.append(Paragraph(f"📅 Rapor Tarihi: {datetime.now().strftime('%d/%m/%Y')}", styles['Normal'])) |
|
|
story.append(Spacer(1, 30)) |
|
|
|
|
|
|
|
|
lines = content.split('\n') |
|
|
for line in lines: |
|
|
if line.strip(): |
|
|
try: |
|
|
if line.startswith('##'): |
|
|
story.append(Paragraph(line.replace('##', '').strip(), heading_style)) |
|
|
elif line.startswith('#'): |
|
|
story.append(Paragraph(line.replace('#', '').strip(), title_style)) |
|
|
else: |
|
|
|
|
|
clean_line = line.replace('•', '-').replace('★', '*').replace('►', '->') |
|
|
story.append(Paragraph(clean_line, styles['Normal'])) |
|
|
story.append(Spacer(1, 10)) |
|
|
except Exception as e: |
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
doc.build(story) |
|
|
temp_file.close() |
|
|
|
|
|
return temp_file.name |
|
|
|
|
|
except Exception as e: |
|
|
print(f"PDF oluşturma hatası: {str(e)}") |
|
|
return None |
|
|
|
|
|
|
|
|
fitness_ai = FitnessAI() |
|
|
|
|
|
def create_plan_interface(api_key, name, age, gender, height, weight, |
|
|
fitness_level, goal, workout_days, workout_frequency, |
|
|
current_workouts, injuries, diet_info, body_focus_areas, |
|
|
preferred_workout_style, available_equipment): |
|
|
|
|
|
if not api_key.strip(): |
|
|
return "❌ Lütfen Gemini API anahtarınızı girin!", None |
|
|
|
|
|
if not all([name, age, height, weight]): |
|
|
return "❌ Lütfen zorunlu alanları doldurun!", None |
|
|
|
|
|
try: |
|
|
|
|
|
plan = fitness_ai.create_fitness_plan( |
|
|
api_key, name, age, gender, height, weight, |
|
|
fitness_level, goal, workout_days, workout_frequency, |
|
|
current_workouts, injuries, diet_info, body_focus_areas, |
|
|
preferred_workout_style, available_equipment |
|
|
) |
|
|
|
|
|
if plan.startswith("❌"): |
|
|
return plan, None |
|
|
|
|
|
|
|
|
pdf_path = fitness_ai.create_pdf_report(plan, name) |
|
|
|
|
|
if pdf_path: |
|
|
return plan, pdf_path |
|
|
else: |
|
|
return plan + "\n\n⚠️ PDF oluşturulamadı, ancak metin planınızı yukarıda görebilirsiniz.", None |
|
|
|
|
|
except Exception as e: |
|
|
error_msg = f"❌ Bir hata oluştu: {str(e)}" |
|
|
return error_msg, None |
|
|
|
|
|
|
|
|
def create_interface(): |
|
|
with gr.Blocks( |
|
|
theme=gr.themes.Soft(), |
|
|
css=""" |
|
|
.gradio-container { |
|
|
max-width: 1200px !important; |
|
|
} |
|
|
.header { |
|
|
text-align: center; |
|
|
background: linear-gradient(45deg, #FF6B6B, #4ECDC4); |
|
|
-webkit-background-clip: text; |
|
|
-webkit-text-fill-color: transparent; |
|
|
font-size: 2.5em; |
|
|
font-weight: bold; |
|
|
margin-bottom: 20px; |
|
|
} |
|
|
.section { |
|
|
border: 2px solid #e0e0e0; |
|
|
border-radius: 10px; |
|
|
padding: 20px; |
|
|
margin: 10px 0; |
|
|
background: #f9f9f9; |
|
|
} |
|
|
""" |
|
|
) as interface: |
|
|
|
|
|
gr.HTML(""" |
|
|
<div class="header"> |
|
|
🏋️♂️ PROFESYONELFİTNESS AI ANTRENÖRÜ 🏋️♀️ |
|
|
</div> |
|
|
<div style="text-align: center; margin-bottom: 30px;"> |
|
|
<p style="font-size: 1.2em; color: #666;"> |
|
|
🎯 Kişiselleştirilmiş fitness ve beslenme planınızı hazırlayın! |
|
|
<br>💪 Profesyonel antrenör deneyimi ile desteklenen AI teknolojisi |
|
|
</p> |
|
|
</div> |
|
|
""") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
|
|
|
with gr.Group(): |
|
|
gr.HTML("<h3>🔑 API Ayarları</h3>") |
|
|
api_key = gr.Textbox( |
|
|
label="Gemini API Anahtarı", |
|
|
placeholder="AIzaSy...", |
|
|
type="password", |
|
|
info="Gemini API anahtarınızı buraya girin" |
|
|
) |
|
|
|
|
|
|
|
|
with gr.Group(): |
|
|
gr.HTML("<h3>👤 Kişisel Bilgiler</h3>") |
|
|
name = gr.Textbox(label="Ad Soyad", placeholder="Örn: Ali Yılmaz") |
|
|
age = gr.Number(label="Yaş", minimum=15, maximum=80, value=25) |
|
|
gender = gr.Radio(["Erkek", "Kadın"], label="Cinsiyet", value="Erkek") |
|
|
height = gr.Number(label="Boy (cm)", minimum=140, maximum=220, value=175) |
|
|
weight = gr.Number(label="Kilo (kg)", minimum=40, maximum=200, value=70) |
|
|
|
|
|
|
|
|
with gr.Group(): |
|
|
gr.HTML("<h3>🏋️ Fitness Bilgileri</h3>") |
|
|
fitness_level = gr.Radio( |
|
|
["Başlangıç", "Orta", "İleri", "Profesyonel"], |
|
|
label="Fitness Seviyesi", |
|
|
value="Orta" |
|
|
) |
|
|
goal = gr.Dropdown( |
|
|
["Kilo Verme", "Kas Kazanma", "Kondisyon Artırma", "Güç Geliştirme", |
|
|
"Vücut Şekillendirme", "Genel Sağlık", "Spor Performansı"], |
|
|
label="Ana Hedef", |
|
|
value="Kilo Verme" |
|
|
) |
|
|
workout_days = gr.Slider( |
|
|
minimum=2, maximum=7, value=4, step=1, |
|
|
label="Haftalık Antrenman Günü" |
|
|
) |
|
|
workout_frequency = gr.Dropdown( |
|
|
["30-45 dakika", "45-60 dakika", "60-90 dakika", "90+ dakika"], |
|
|
label="Antrenman Süresi", |
|
|
value="45-60 dakika" |
|
|
) |
|
|
|
|
|
with gr.Column(scale=1): |
|
|
|
|
|
with gr.Group(): |
|
|
gr.HTML("<h3>📝 Detaylı Bilgiler</h3>") |
|
|
current_workouts = gr.Textbox( |
|
|
label="Mevcut Antrenman Rutini", |
|
|
placeholder="Şu anda yaptığınız egzersizleri açıklayın...", |
|
|
lines=3 |
|
|
) |
|
|
injuries = gr.Textbox( |
|
|
label="Sakatlık/Kısıtlamalar", |
|
|
placeholder="Herhangi bir sakatlığınız veya sağlık kısıtlamanız var mı?", |
|
|
lines=2 |
|
|
) |
|
|
body_focus_areas = gr.CheckboxGroup( |
|
|
["Karın", "Bacak", "Göğüs", "Sırt", "Omuz", "Kol", "Kalça", "Kondisyon"], |
|
|
label="Odaklanmak İstediğiniz Vücut Bölgeleri", |
|
|
value=["Karın", "Bacak"] |
|
|
) |
|
|
preferred_workout_style = gr.Dropdown( |
|
|
["Ağırlık Antrenmanı", "Kardiyovasküler", "HIIT", "Yoga/Pilates", |
|
|
"Crossfit", "Calisthenics", "Karma"], |
|
|
label="Tercih Edilen Antrenman Stili", |
|
|
value="Karma" |
|
|
) |
|
|
available_equipment = gr.CheckboxGroup( |
|
|
["Spor Salonu", "Dumbbell", "Barbell", "Koşu Bandı", "Bisiklet", |
|
|
"Yoga Matı", "Resistance Band", "Kettlebell", "Sadece Vücut Ağırlığı"], |
|
|
label="Mevcut Ekipmanlar", |
|
|
value=["Spor Salonu"] |
|
|
) |
|
|
|
|
|
|
|
|
with gr.Group(): |
|
|
gr.HTML("<h3>🍎 Beslenme Bilgileri</h3>") |
|
|
diet_info = gr.Textbox( |
|
|
label="Mevcut Beslenme Durumu", |
|
|
placeholder="Günlük yemek düzeninizi, alerjilerinizi, beslenme kısıtlamalarınızı açıklayın...", |
|
|
lines=4 |
|
|
) |
|
|
|
|
|
|
|
|
create_btn = gr.Button( |
|
|
"🚀 KİŞİSEL FITNESS PLANIMI OLUŞTUR", |
|
|
variant="primary", |
|
|
size="lg" |
|
|
) |
|
|
|
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
output_text = gr.Textbox( |
|
|
label="📋 Kişisel Fitness Planınız", |
|
|
lines=20, |
|
|
max_lines=30, |
|
|
show_copy_button=True |
|
|
) |
|
|
|
|
|
pdf_file = gr.File( |
|
|
label="📄 PDF Raporu İndir", |
|
|
file_types=[".pdf"] |
|
|
) |
|
|
|
|
|
|
|
|
create_btn.click( |
|
|
fn=create_plan_interface, |
|
|
inputs=[ |
|
|
api_key, name, age, gender, height, weight, |
|
|
fitness_level, goal, workout_days, workout_frequency, |
|
|
current_workouts, injuries, diet_info, body_focus_areas, |
|
|
preferred_workout_style, available_equipment |
|
|
], |
|
|
outputs=[output_text, pdf_file] |
|
|
) |
|
|
|
|
|
|
|
|
gr.HTML(""" |
|
|
<div style="text-align: center; margin-top: 40px; padding: 20px; background: #f0f0f0; border-radius: 10px;"> |
|
|
<p><strong>💡 Kullanım İpuçları:</strong></p> |
|
|
<p>• Gemini API anahtarınızı <a href="https://aistudio.google.com/app/apikey" target="_blank">buradan</a> alabilirsiniz</p> |
|
|
<p>• Tüm bilgileri mümkün olduğunca detaylı doldurun</p> |
|
|
<p>• Plan oluşturulduktan sonra PDF olarak indirebilirsiniz</p> |
|
|
<p><em>⚠️ Bu plan genel bilgi amaçlıdır. Ciddi sağlık sorunları için doktor konsültasyonu önerilir.</em></p> |
|
|
</div> |
|
|
""") |
|
|
|
|
|
return interface |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo = create_interface() |
|
|
demo.launch( |
|
|
server_name="0.0.0.0", |
|
|
server_port=7860, |
|
|
share=True, |
|
|
show_error=True |
|
|
) |