updated app.py
Browse files
app.py
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
import gradio as gr
|
| 3 |
import google.generativeai as genai
|
|
@@ -8,12 +15,20 @@ import numpy as np
|
|
| 8 |
import faiss
|
| 9 |
from dotenv import load_dotenv
|
| 10 |
|
|
|
|
|
|
|
|
|
|
| 11 |
load_dotenv()
|
| 12 |
|
| 13 |
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
| 14 |
genai.configure(api_key=GEMINI_API_KEY)
|
| 15 |
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
MODEL_CONFIG = {
|
| 18 |
"temperature": 0.7,
|
| 19 |
"top_p": 0.95,
|
|
@@ -21,7 +36,10 @@ MODEL_CONFIG = {
|
|
| 21 |
"max_output_tokens": 4096
|
| 22 |
}
|
| 23 |
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
| 25 |
SYSTEM_PROMPT = (
|
| 26 |
"Sen deneyimli bir Türk aşçısısın. "
|
| 27 |
"Kullanıcılara yemek tarifleri, pişirme önerileri ve püf noktaları hakkında yardımcı oluyorsun. "
|
|
@@ -31,12 +49,23 @@ SYSTEM_PROMPT = (
|
|
| 31 |
"Rastgele uydurma bilgi verme; sadece veri setinde bulunan bilgilerden yararlan."
|
| 32 |
)
|
| 33 |
|
| 34 |
-
|
|
|
|
|
|
|
|
|
|
| 35 |
dataset = load_dataset("mertbozkurt/turkish-recipe", data_files="datav2.csv")
|
| 36 |
|
|
|
|
| 37 |
df = pd.DataFrame(dataset["train"])
|
|
|
|
|
|
|
| 38 |
df = df.sample(1000, random_state=42)
|
|
|
|
|
|
|
| 39 |
df.dropna(subset=["Title", "How-to-do"], inplace=True)
|
|
|
|
|
|
|
|
|
|
| 40 |
df["text"] = (
|
| 41 |
"Yemek Adı: " + df["Title"].astype(str) + "\n"
|
| 42 |
+ "Kategori: " + df["Category"].astype(str) + "\n"
|
|
@@ -44,51 +73,71 @@ df["text"] = (
|
|
| 44 |
+ "Yapılışı: " + df["How-to-do"].astype(str)
|
| 45 |
)
|
| 46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
model_embed = SentenceTransformer("intfloat/multilingual-e5-base")
|
| 48 |
|
| 49 |
-
# Tüm tariflerin embedding
|
| 50 |
embeddings = model_embed.encode(df["text"].tolist(), normalize_embeddings=True)
|
| 51 |
|
| 52 |
-
|
|
|
|
|
|
|
|
|
|
| 53 |
index = faiss.IndexFlatIP(embeddings.shape[1])
|
| 54 |
index.add(embeddings)
|
| 55 |
|
|
|
|
|
|
|
|
|
|
| 56 |
def retrieve_recipes(query, k=3):
|
| 57 |
q_emb = model_embed.encode([query], normalize_embeddings=True)
|
| 58 |
D, I = index.search(q_emb, k)
|
| 59 |
return df.iloc[I[0]]["text"].tolist()
|
| 60 |
|
| 61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
def chat_function(message, history):
|
| 63 |
try:
|
|
|
|
| 64 |
context = "\n\n".join(retrieve_recipes(message))
|
|
|
|
|
|
|
| 65 |
chat_context = "\n".join([f"Kullanıcı: {h[0]}\nAsistan: {h[1]}" for h in history])
|
| 66 |
|
|
|
|
| 67 |
prompt = f"""{SYSTEM_PROMPT}
|
| 68 |
-
|
| 69 |
Geçmiş konuşma:
|
| 70 |
{chat_context}
|
| 71 |
-
|
| 72 |
Yeni kullanıcı mesajı: {message}
|
| 73 |
-
|
| 74 |
Aşağıda veri tabanında benzer bulunan tarifler:
|
| 75 |
{context}
|
| 76 |
-
|
| 77 |
Bu bilgiler ışığında, kullanıcıya uygun Türkçe bir yanıt oluştur.
|
| 78 |
"""
|
| 79 |
|
|
|
|
| 80 |
model = genai.GenerativeModel(
|
| 81 |
model_name="gemini-2.0-flash",
|
| 82 |
generation_config=MODEL_CONFIG,
|
| 83 |
system_instruction=SYSTEM_PROMPT
|
| 84 |
)
|
| 85 |
|
|
|
|
| 86 |
response = model.generate_content(prompt)
|
| 87 |
return response.text if response.text else "Yanıt alınamadı."
|
| 88 |
except Exception as e:
|
| 89 |
return f"Hata: {str(e)}"
|
| 90 |
|
| 91 |
|
|
|
|
|
|
|
|
|
|
| 92 |
theme = gr.themes.Soft(
|
| 93 |
primary_hue="amber",
|
| 94 |
secondary_hue="red",
|
|
@@ -107,6 +156,10 @@ theme = gr.themes.Soft(
|
|
| 107 |
background_fill_secondary="rgba(255,255,255,0.6)",
|
| 108 |
)
|
| 109 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
demo = gr.ChatInterface(
|
| 111 |
fn=chat_function,
|
| 112 |
title="👨🍳 ChefMind - Türkçe Yapay Zekalı Yemek Asistanı Emir ÖZALP 🍽️",
|
|
@@ -126,7 +179,9 @@ demo = gr.ChatInterface(
|
|
| 126 |
theme=theme,
|
| 127 |
)
|
| 128 |
|
| 129 |
-
if __name__ == "__main__":
|
| 130 |
-
demo.launch(share=True)
|
| 131 |
-
|
| 132 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ChefMind - Türkçe Yapay Zekalı Yemek Asistanı
|
| 2 |
+
# Proje Sahibi: Emir ÖZALP
|
| 3 |
+
# Açıklama: Bu proje, Google Gemini destekli bir Türkçe yemek asistanıdır.
|
| 4 |
+
# Kullanıcıdan alınan girdiye göre veri setinden benzer tarifleri FAISS kullanarak bulur
|
| 5 |
+
# ve Gemini modeliyle doğal, açıklayıcı şekilde yanıtlar üretir.
|
| 6 |
+
|
| 7 |
+
# GEREKLİ KÜTÜPHANELERİN İÇE AKTARILMASI
|
| 8 |
import os
|
| 9 |
import gradio as gr
|
| 10 |
import google.generativeai as genai
|
|
|
|
| 15 |
import faiss
|
| 16 |
from dotenv import load_dotenv
|
| 17 |
|
| 18 |
+
|
| 19 |
+
# ORTAM DEĞİŞKENLERİNİN YÜKLENMESİ (.env dosyasından)
|
| 20 |
+
# Burada .env dosyasındaki API anahtarımı okutarak Google Gemini modelini yetkilendiriyorum.
|
| 21 |
load_dotenv()
|
| 22 |
|
| 23 |
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
| 24 |
genai.configure(api_key=GEMINI_API_KEY)
|
| 25 |
|
| 26 |
+
|
| 27 |
+
# MODEL YAPILANDIRMASI
|
| 28 |
+
# Burada modelin üretim (generation) parametrelerini belirliyorum.
|
| 29 |
+
# temperature: cevabın yaratıcılığını kontrol eder
|
| 30 |
+
# top_p, top_k: örnekleme çeşitliliğini sınırlar
|
| 31 |
+
# max_output_tokens: maksimum cevap uzunluğunu token bazında belirler
|
| 32 |
MODEL_CONFIG = {
|
| 33 |
"temperature": 0.7,
|
| 34 |
"top_p": 0.95,
|
|
|
|
| 36 |
"max_output_tokens": 4096
|
| 37 |
}
|
| 38 |
|
| 39 |
+
|
| 40 |
+
# SİSTEM PROMPT’U (MODELİN ROL TANIMI)
|
| 41 |
+
# Burada modelin nasıl davranacağını tanımlıyorum.
|
| 42 |
+
# Kısaca: Model bir Türk aşçısı gibi konuşacak, doğru, doğal ve açıklayıcı olacak.
|
| 43 |
SYSTEM_PROMPT = (
|
| 44 |
"Sen deneyimli bir Türk aşçısısın. "
|
| 45 |
"Kullanıcılara yemek tarifleri, pişirme önerileri ve püf noktaları hakkında yardımcı oluyorsun. "
|
|
|
|
| 49 |
"Rastgele uydurma bilgi verme; sadece veri setinde bulunan bilgilerden yararlan."
|
| 50 |
)
|
| 51 |
|
| 52 |
+
|
| 53 |
+
# VERİ SETİNİN YÜKLENMESİ
|
| 54 |
+
# Burada Hugging Face’te yer alan “mertbozkurt/turkish-recipe” veri setini yüklüyorum.
|
| 55 |
+
# Bu veri seti 11.000+ Türkçe yemek tarifinden oluşuyor.
|
| 56 |
dataset = load_dataset("mertbozkurt/turkish-recipe", data_files="datav2.csv")
|
| 57 |
|
| 58 |
+
# Dataset'i DataFrame formatına çeviriyorum.
|
| 59 |
df = pd.DataFrame(dataset["train"])
|
| 60 |
+
|
| 61 |
+
# Hugging Face Spaces üzerinde (free tier kullanıcı özelliklerinden ötürü) daha hızlı başlatmak için veri setinin belirli bir kısmını alıyorum.
|
| 62 |
df = df.sample(1000, random_state=42)
|
| 63 |
+
|
| 64 |
+
# Eksik tarifleri temizliyorum (Title ve How-to-do sütunları boş olanları siliyorum).
|
| 65 |
df.dropna(subset=["Title", "How-to-do"], inplace=True)
|
| 66 |
+
|
| 67 |
+
# Her tarif için tek bir metin alanı oluşturuyorum.
|
| 68 |
+
# Bu alanda yemek adı, kategori, malzemeler ve yapılış bilgisi birleştiriliyor.
|
| 69 |
df["text"] = (
|
| 70 |
"Yemek Adı: " + df["Title"].astype(str) + "\n"
|
| 71 |
+ "Kategori: " + df["Category"].astype(str) + "\n"
|
|
|
|
| 73 |
+ "Yapılışı: " + df["How-to-do"].astype(str)
|
| 74 |
)
|
| 75 |
|
| 76 |
+
|
| 77 |
+
# EMBEDDING MODELİNİN YÜKLENMESİ
|
| 78 |
+
# Burada SentenceTransformer kullanarak tarif metinlerini sayısal vektörlere dönüştürüyorum.
|
| 79 |
+
# multilingual-e5-base modeli, çok dilli metinleri anlamlı vektörlere çeviriyor.
|
| 80 |
model_embed = SentenceTransformer("intfloat/multilingual-e5-base")
|
| 81 |
|
| 82 |
+
# Tüm tariflerin embedding’lerini oluşturuyorum ve normalize ediyorum.
|
| 83 |
embeddings = model_embed.encode(df["text"].tolist(), normalize_embeddings=True)
|
| 84 |
|
| 85 |
+
|
| 86 |
+
# FAISS İLE BENZERLİK ARAMA
|
| 87 |
+
# FAISS (Facebook AI Similarity Search) hızlı vektör araması sağlar.
|
| 88 |
+
# Burada cosine similarity’e denk gelen inner product (dot product) kullanıyorum.
|
| 89 |
index = faiss.IndexFlatIP(embeddings.shape[1])
|
| 90 |
index.add(embeddings)
|
| 91 |
|
| 92 |
+
|
| 93 |
+
# TARİF GETİRME FONKSİYONU
|
| 94 |
+
# Kullanıcıdan gelen soruya en benzer tarifleri embedding uzayında arıyorum.
|
| 95 |
def retrieve_recipes(query, k=3):
|
| 96 |
q_emb = model_embed.encode([query], normalize_embeddings=True)
|
| 97 |
D, I = index.search(q_emb, k)
|
| 98 |
return df.iloc[I[0]]["text"].tolist()
|
| 99 |
|
| 100 |
|
| 101 |
+
# ANA CHAT FONKSİYONU
|
| 102 |
+
# Bu fonksiyon, Gradio arayüzünden gelen her mesaj için çalışır.
|
| 103 |
+
# 1. Kullanıcının sorusuna göre benzer tarifleri bulur.
|
| 104 |
+
# 2. Bu tarifleri Gemini modeline bağlam olarak verir.
|
| 105 |
+
# 3. Modelden Türkçe, doğal bir yanıt döndürür.
|
| 106 |
def chat_function(message, history):
|
| 107 |
try:
|
| 108 |
+
# Kullanıcı mesajına göre benzer tarifleri getiriyorum.
|
| 109 |
context = "\n\n".join(retrieve_recipes(message))
|
| 110 |
+
|
| 111 |
+
# Sohbet geçmişini düzenliyorum (modelin bağlamı koruyabilmesi için).
|
| 112 |
chat_context = "\n".join([f"Kullanıcı: {h[0]}\nAsistan: {h[1]}" for h in history])
|
| 113 |
|
| 114 |
+
# Model prompt’unu oluşturuyorum.
|
| 115 |
prompt = f"""{SYSTEM_PROMPT}
|
|
|
|
| 116 |
Geçmiş konuşma:
|
| 117 |
{chat_context}
|
|
|
|
| 118 |
Yeni kullanıcı mesajı: {message}
|
|
|
|
| 119 |
Aşağıda veri tabanında benzer bulunan tarifler:
|
| 120 |
{context}
|
|
|
|
| 121 |
Bu bilgiler ışığında, kullanıcıya uygun Türkçe bir yanıt oluştur.
|
| 122 |
"""
|
| 123 |
|
| 124 |
+
# Gemini modelini başlatıyorum.
|
| 125 |
model = genai.GenerativeModel(
|
| 126 |
model_name="gemini-2.0-flash",
|
| 127 |
generation_config=MODEL_CONFIG,
|
| 128 |
system_instruction=SYSTEM_PROMPT
|
| 129 |
)
|
| 130 |
|
| 131 |
+
# Cevabı üretiyorum.
|
| 132 |
response = model.generate_content(prompt)
|
| 133 |
return response.text if response.text else "Yanıt alınamadı."
|
| 134 |
except Exception as e:
|
| 135 |
return f"Hata: {str(e)}"
|
| 136 |
|
| 137 |
|
| 138 |
+
# GRADIO ARAYÜZ TASARIMI
|
| 139 |
+
# Burada Gradio’nun Soft temasını özelleştiriyorum.
|
| 140 |
+
# Arkaplanda yumuşak turuncu tonlar, cam efekti bloklar ve gradient butonlar kullanıldı.
|
| 141 |
theme = gr.themes.Soft(
|
| 142 |
primary_hue="amber",
|
| 143 |
secondary_hue="red",
|
|
|
|
| 156 |
background_fill_secondary="rgba(255,255,255,0.6)",
|
| 157 |
)
|
| 158 |
|
| 159 |
+
|
| 160 |
+
# GRADIO CHAT INTERFACE
|
| 161 |
+
# ChatInterface, kullanıcıyla etkileşimi sağlayan bileşen.
|
| 162 |
+
# Burada örnek sorular, başlık, açıklama ve tema ayarlarını tanımlıyorum.
|
| 163 |
demo = gr.ChatInterface(
|
| 164 |
fn=chat_function,
|
| 165 |
title="👨🍳 ChefMind - Türkçe Yapay Zekalı Yemek Asistanı Emir ÖZALP 🍽️",
|
|
|
|
| 179 |
theme=theme,
|
| 180 |
)
|
| 181 |
|
|
|
|
|
|
|
|
|
|
| 182 |
|
| 183 |
+
# UYGULAMA BAŞLATMA
|
| 184 |
+
# Eğer bu dosya doğrudan çalıştırılıyorsa (import edilmediyse),
|
| 185 |
+
# Gradio arayüzünü başlatıyorum. share=True, bağlantıyı dış dünyayla paylaşmamı sağlıyor.
|
| 186 |
+
if __name__ == "__main__":
|
| 187 |
+
demo.launch(share=True)
|