import gradio as gr import re import os import json import requests from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity import google.generativeai as genai # from google.generativeai import APIError # Kütüphane versiyonu uyumsuzluğu nedeniyle kaldırıldı # --- Sabitler --- PROMPT_FILE_PATH = "README_tr-TR.md" APP_TITLE = "Nano Banana Pro Prompt Generator" GEMINI_MODEL = "gemini-2.5-flash" OPENROUTER_URL = "https://openrouter.ai/api/v1/chat/completions" # --- 1. Veri İşleme (Data Parsing) --- def parse_markdown_prompts(file_path): """ Markdown dosyasını okur ve prompt verilerini ayrıştırır. """ if not os.path.exists(file_path): print(f"Hata: {file_path} dosyası bulunamadı.") return [], [] with open(file_path, "r", encoding="utf-8") as f: content = f.read() # Regex: ### No. [Sayı]: [Başlık] ... #### 📖 Açıklama ... #### 📝 İstem ```[Prompt]``` # re.DOTALL, '.' karakterinin yeni satırları da eşleştirmesini sağlar. PROMPT_BLOCK_REGEX = re.compile( r"### No\. \d+:(.*?)\n+" # Başlık (Grup 1) r".*?#### 📖 Açıklama\n+" r"(.*?)\n+" # Açıklama (Grup 2) r".*?#### 📝 İstem\n+" r"```\n+" r"(.*?)\n+" # İstem (Prompt) (Grup 3) r"```", re.DOTALL | re.IGNORECASE ) prompts_data = [] descriptions = [] for match in PROMPT_BLOCK_REGEX.finditer(content): title = match.group(1).strip() description = match.group(2).strip() prompt = match.group(3).strip() prompts_data.append({ "title": title, "description": description, "prompt": prompt }) # Arama için sadece açıklamaları kullanıyoruz descriptions.append(description) print(f"Toplam {len(prompts_data)} prompt örneği yüklendi.") return prompts_data, descriptions # Uygulama başladığında veriyi yükle PROMPTS_DATA, DESCRIPTIONS = parse_markdown_prompts(PROMPT_FILE_PATH) # --- 2. Arama Motoru (Retrieval Mechanism) --- if DESCRIPTIONS: VECTORIZER = TfidfVectorizer().fit(DESCRIPTIONS) TFIDF_MATRIX = VECTORIZER.transform(DESCRIPTIONS) else: VECTORIZER = None TFIDF_MATRIX = None def retrieve_top_k_prompts(query, k=3): """ Kullanıcı sorgusuna en benzer k adet prompt örneğini bulur. """ if not VECTORIZER: return [] query_vec = VECTORIZER.transform([query]) cosine_similarities = cosine_similarity(query_vec, TFIDF_MATRIX).flatten() # En yüksek benzerliğe sahip k indeksi bul top_k_indices = cosine_similarities.argsort()[-k:][::-1] # İndekslere karşılık gelen prompt verilerini döndür return [PROMPTS_DATA[i] for i in top_k_indices] # --- 3. LLM Entegrasyonu (Gemini/OpenRouter) --- def generate_prompt_with_llm(api_key, user_query, reference_prompts, model_name=GEMINI_MODEL): """ LLM kullanarak yeni bir prompt oluşturur. """ # Referans promptları sistem promptuna eklemek için formatla references_text = "\n\n---\n\n".join([ f"Örnek {i+1} Başlık: {ref['title']}\nÖrnek {i+1} Açıklama: {ref['description']}\nÖrnek {i+1} İstem:\n```\n{ref['prompt']}\n```" for i, ref in enumerate(reference_prompts) ]) system_prompt = f""" Sen uzman bir prompt mühendisisin. Görevin, kullanıcının isteği için, aşağıda verilen referans örneklerin kalitesinde ve yapısında, **sadece** JSON formatında yeni bir prompt oluşturmaktır. **Kısıtlamalar:** 1. **Sadece** JSON formatında çıktı ver. Başka hiçbir açıklama, giriş veya metin ekleme. 2. JSON yapısı şu şekilde olmalıdır: {{"prompt": "Oluşturduğun yeni istem metni buraya gelecek."}} 3. Yeni istem, kullanıcının isteğini karşılamalı ve referanslardaki detay seviyesini ve stilini yansıtmalıdır. 4. İstem metni Türkçe olmalıdır. **Referans Örnekler:** {references_text} """ user_message = f"Kullanıcının İsteği: {user_query}" # API Anahtarının Gemini mi yoksa OpenRouter mı olduğunu kontrol et if api_key.startswith("sk-"): # OpenRouter anahtarları genellikle sk- ile başlar print("OpenRouter API kullanılıyor...") headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } data = { "model": model_name, # OpenRouter'da model adı kullanıcı tarafından seçilebilir, burada varsayılanı kullanıyoruz "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_message} ], "response_format": {"type": "json_object"} } try: response = requests.post(OPENROUTER_URL, headers=headers, json=data) response.raise_for_status() result = response.json() return result["choices"][0]["message"]["content"] except requests.exceptions.RequestException as e: return f"OpenRouter API Hatası: {e}" except KeyError: return f"OpenRouter API'den beklenmeyen yanıt: {result}" else: # Varsayılan olarak Gemini API kullanılıyor print("Google Gemini API kullanılıyor...") try: # API Anahtarını yapılandır genai.configure(api_key=api_key) config = genai.types.GenerateContentConfig( system_instruction=system_prompt, response_mime_type="application/json", response_schema={"type": "object", "properties": {"prompt": {"type": "string"}}} ) response = genai.client.models.generate_content( model=model_name, contents=user_message, config=config ) return response.text except Exception as e: # APIError yerine genel Exception kullanıldı return f"Gemini API Hatası: {e}" # --- 4. Arayüz (Gradio) --- def generate_prompt_interface(api_key, user_query, model_choice): """ Gradio arayüzünden gelen girdileri işler ve sonucu döndürür. """ if not PROMPTS_DATA: return "Hata: Prompt verileri yüklenemedi. Lütfen README_tr-TR.md dosyasının varlığını ve formatını kontrol edin." if not api_key or not user_query: return "Lütfen API Anahtarınızı ve İsteğinizi girin." # 1. En benzer 3 promptu bul try: reference_prompts = retrieve_top_k_prompts(user_query, k=3) except Exception as e: return f"Arama (RAG) Mekanizması Hatası: {e}" if not reference_prompts: return "Hata: Benzer prompt örneği bulunamadı. Veri setinizde sorun olabilir." # 2. LLM ile yeni prompt oluştur try: # Kullanıcıdan gelen model adını doğrudan kullan generated_json_text = generate_prompt_with_llm(api_key, user_query, reference_prompts, model_name=model_choice) # LLM'den gelen metni JSON olarak ayrıştırmaya çalış try: # Bazen LLM sadece JSON döndürmez, bu yüzden sadece JSON bloğunu ayıklamamız gerekebilir json_match = re.search(r"\{.*?\}", generated_json_text, re.DOTALL) if json_match: json_text = json_match.group(0) # JSON'ı ayrıştır ve güzelce formatla parsed_json = json.loads(json_text) return json.dumps(parsed_json, indent=4, ensure_ascii=False) else: return f"LLM'den geçerli JSON formatı alınamadı. Ham Çıktı:\n{generated_json_text}" except json.JSONDecodeError: return f"LLM'den gelen çıktı JSON olarak ayrıştırılamadı. Ham Çıktı:\n{generated_json_text}" except Exception as e: return f"Prompt Üretme Hatası: {e}" # --- Gradio Arayüzü Tanımlama --- # OpenRouter'ın desteklediği popüler modellerden bazıları # OpenRouter modelleri için artık serbest metin girişi kullanılıyor. with gr.Blocks(title=APP_TITLE) as demo: gr.Markdown(f"# {APP_TITLE}") gr.Markdown( "Bu uygulama, Nano Banana Pro prompt örneklerini (RAG) kullanarak, Google Gemini veya OpenRouter API'leri aracılığıyla yeni ve kaliteli promptlar üretir." ) with gr.Row(): api_key_input = gr.Textbox( label="API Anahtarı (Gemini veya OpenRouter)", type="password", placeholder="Gemini API Key (AIza...) veya OpenRouter Key (sk-...) girin" ) model_choice = gr.Textbox( label="Kullanılacak LLM Modeli (Gemini için 'gemini-2.5-flash', OpenRouter için tam model adı)", placeholder="Örn: gemini-2.5-flash veya openai/gpt-4o", value="gemini-2.5-flash", interactive=True ) user_query_input = gr.Textbox( label="Kullanıcı İsteği", placeholder="Örn: Cyberpunk tarzı bir İstanbul manzarası, neon ışıklar ve yağmur yansıması", lines=3 ) generate_button = gr.Button("Prompt Oluştur", variant="primary") output_prompt = gr.Code( label="Oluşturulan JSON Prompt", language="json", lines=10 ) # Buton tıklama olayını bağla generate_button.click( fn=generate_prompt_interface, inputs=[api_key_input, user_query_input, model_choice], outputs=output_prompt ) gr.Markdown( f""" ### Nasıl Çalışır? 1. **Veri Yükleme:** `{PROMPT_FILE_PATH}` dosyasındaki {len(PROMPTS_DATA)} prompt örneği belleğe yüklenir. 2. **Arama (RAG):** Girdiğiniz isteğe en benzer 3 prompt, TF-IDF ve Kosinüs Benzerliği kullanılarak bulunur. 3. **Üretim:** Bulunan 3 referans prompt, bir Sistem Prompt'u içine yerleştirilir ve seçtiğiniz LLM'e (Gemini veya OpenRouter) gönderilerek yeni bir prompt oluşturulması istenir. """ ) if __name__ == "__main__": demo.launch()