From e49452529a3c65abeb331d417d0caa171c6f2706 Mon Sep 17 00:00:00 2001 From: ufukasill-creator Date: Fri, 20 Feb 2026 15:59:09 +0300 Subject: [PATCH] fp fp --- BASLAT.bat | 17 ++ __pycache__/main.cpython-314.pyc | Bin 0 -> 15476 bytes kurulum.bat | 63 ++++++ main.pyw | 368 +++++++++++++++++++++++++++++++ requirements.txt | 7 + 5 files changed, 455 insertions(+) create mode 100644 BASLAT.bat create mode 100644 __pycache__/main.cpython-314.pyc create mode 100644 kurulum.bat create mode 100644 main.pyw create mode 100644 requirements.txt diff --git a/BASLAT.bat b/BASLAT.bat new file mode 100644 index 0000000..e876afd --- /dev/null +++ b/BASLAT.bat @@ -0,0 +1,17 @@ +@echo off +setlocal +cd /d "%~dp0" + +if not exist ".venv\Scripts\pythonw.exe" ( + echo [INFO] Sanal ortam bulunamadi. Ilk kurulum baslatiliyor... + call "%~dp0kurulum.bat" + if not %errorlevel%==0 ( + echo [HATA] Kurulum basarisiz. Program baslatilamadi. + pause + exit /b 1 + ) +) + +call ".venv\Scripts\activate.bat" +start "AI Asistan" /B ".venv\Scripts\pythonw.exe" "%~dp0main.pyw" +exit /b 0 diff --git a/__pycache__/main.cpython-314.pyc b/__pycache__/main.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..04e5fca819ecc220a6de5eff0ea9ab68bcc0ae8a GIT binary patch literal 15476 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 literal 0 HcmV?d00001 diff --git a/kurulum.bat b/kurulum.bat new file mode 100644 index 0000000..2323602 --- /dev/null +++ b/kurulum.bat @@ -0,0 +1,63 @@ +@echo off +setlocal +cd /d "%~dp0" + +echo [1/4] Python kontrol ediliyor... +set "PY_CMD=" + +where python >nul 2>nul +if %errorlevel%==0 ( + python -c "import sys; raise SystemExit(0 if sys.version_info.major==3 else 1)" >nul 2>nul + if %errorlevel%==0 set "PY_CMD=python" +) + +if not defined PY_CMD ( + where py >nul 2>nul + if %errorlevel%==0 ( + py -3.13 -c "import sys" >nul 2>nul + if %errorlevel%==0 ( + set "PY_CMD=py -3.13" + ) else ( + py -3 -c "import sys" >nul 2>nul + if %errorlevel%==0 ( + set "PY_CMD=py -3" + ) else ( + py -c "import sys" >nul 2>nul + if %errorlevel%==0 set "PY_CMD=py" + ) + ) + ) +) + +if not defined PY_CMD ( + echo [HATA] Uygun Python 3 bulunamadi. + echo [HATA] Python 3.13 kurup tekrar deneyin: https://www.python.org/downloads/ + exit /b 1 +) + +echo [2/4] Sanal ortam olusturuluyor... +if not exist ".venv\Scripts\python.exe" ( + %PY_CMD% -m venv .venv + if not %errorlevel%==0 ( + echo [HATA] .venv olusturulamadi. + exit /b 1 + ) +) + +echo [3/4] pip guncelleniyor... +call ".venv\Scripts\activate.bat" +python -m pip install --upgrade pip +if not %errorlevel%==0 ( + echo [HATA] pip guncellenemedi. + exit /b 1 +) + +echo [4/4] Paketler kuruluyor... +pip install -r requirements.txt +if not %errorlevel%==0 ( + echo [HATA] Paket kurulumu basarisiz. + exit /b 1 +) + +echo [OK] Kurulum tamamlandi. +exit /b 0 diff --git a/main.pyw b/main.pyw new file mode 100644 index 0000000..66d12e4 --- /dev/null +++ b/main.pyw @@ -0,0 +1,368 @@ +import pyperclip +from pynput import keyboard +import pyautogui +import tkinter as tk +from tkinter import messagebox +import time +import threading +import requests +import queue + + +# --- AYARLAR --- +OLLAMA_URL = "http://localhost:11434/api/generate" +MODEL_ADI = "gemini-3-flash-preview:latest" # Ana model (F8) +TEXT_MODEL_CANDIDATES = [ + MODEL_ADI, + "gemini-3-flash-preview:cloud", +] + +KISAYOL_METIN = keyboard.Key.f8 # Metin secimi icin kisayol + + +# Global değişkenler +root = None +gui_queue = queue.Queue() +kisayol_basildi = False + + +# --- MENÜ SEÇENEKLERİ VE PROMPT'LAR --- +ISLEMLER = { + "📝 Gramer Düzelt": "Bu metni Türkçe yazım ve dil bilgisi kurallarına göre düzelt, resmi ve akıcı olsun. Sadece sonucu ver.", + "🇬🇧 İngilizceye Çevir": "Bu metni İngilizceye çevir. Sadece çeviriyi ver.", + "🇹🇷 Türkçeye Çevir": "Bu metni Türkçeye çevir. Sadece çeviriyi ver.", + "📑 Özetle (Madde Madde)": "Bu metni analiz et ve en önemli noktaları madde madde özetle.", + "💼 Daha Resmi Yap": "Bu metni kurumsal bir e-posta diline çevir, çok resmi olsun.", + "🐍 Python Koduna Çevir": "Bu metindeki isteği yerine getiren bir Python kodu yaz. Sadece kodu ver.", + "📧 Cevap Yaz (Mail)": "Bu gelen bir e-posta, buna kibar ve profesyonel bir cevap metni taslağı yaz.", + "🎮 PS5 Oyun Skor + Acımasız Yorum": ( + "Seçili metni bir PS5 oyunu adı olarak ele al. Aşağıdaki formatta Türkçe cevap ver:\n" + "1) Oyun: \n" + "2) Topluluk Beğeni Skorları:\n" + "- Metacritic User Score: \n" + "- OpenCritic / benzer eleştirmen ortalaması: \n" + "- Oyuncu yorumu ortalaması (PS Store vb.): \n" + "3) Hüküm: sadece 'IYI' veya 'KOTU'\n" + "4) Acımasız Yorum: 2-4 cümle, net ve sert.\n" + "Kurallar: Kesin bilmediğin puanı uydurma, onun yerine 'bilgi yok' yaz. " + "Yorumu skorlarla tutarlı kur." + ), +} + + +def get_available_text_model(): + """Metin işlemede kullanılabilir modeli seçer.""" + preferred_models = [] + for model in TEXT_MODEL_CANDIDATES: + if model and model not in preferred_models: + preferred_models.append(model) + + try: + response = requests.get("http://localhost:11434/api/tags", timeout=5) + if response.status_code != 200: + return MODEL_ADI + + models = response.json().get("models", []) + installed_lower = {m.get("name", "").lower(): m.get("name", "") for m in models} + + for candidate in preferred_models: + candidate_lower = candidate.lower() + if candidate_lower in installed_lower: + return installed_lower[candidate_lower] + + candidate_base = candidate_lower.split(":")[0] + for installed_name_lower, installed_name in installed_lower.items(): + if installed_name_lower.startswith(candidate_base + ":"): + return installed_name + except Exception: + pass + + return MODEL_ADI + + +def ollama_cevap_al(prompt): + """Ollama API'den cevap al.""" + try: + aktif_model = get_available_text_model() + payload = { + "model": aktif_model, + "prompt": prompt, + "stream": False, + "options": { + "temperature": 0.7, + "top_p": 0.9, + }, + } + + response = requests.post(OLLAMA_URL, json=payload, timeout=60) + + if response.status_code == 200: + result = response.json() + return result.get("response", "").strip() + + err_msg = ( + f"Ollama API Hatası: {response.status_code}\n" + f"Model: {aktif_model}\n" + f"Cevap: {response.text}" + ) + print(f"❌ {err_msg}") + gui_queue.put((messagebox.showerror, ("API Hatası", err_msg))) + return None + + except requests.exceptions.ConnectionError: + err_msg = ( + "Ollama'ya bağlanılamadı.\n" + "Programın çalıştığından emin olun!\n" + "(http://localhost:11434)" + ) + print(f"❌ {err_msg}") + gui_queue.put((messagebox.showerror, ("Bağlantı Hatası", err_msg))) + return None + except Exception as e: + err_msg = f"Beklenmeyen Hata: {e}" + print(f"❌ {err_msg}") + gui_queue.put((messagebox.showerror, ("Hata", err_msg))) + return None + + +def strip_code_fence(text): + if not text: + return text + cleaned = text.strip() + if cleaned.startswith("```"): + lines = cleaned.splitlines() + lines = lines[1:] if lines else [] + while lines and lines[-1].strip() == "```": + lines = lines[:-1] + cleaned = "\n".join(lines).strip() + return cleaned + + +def secili_metni_kopyala(max_deneme=4): + sentinel = f"__AI_ASISTAN__{time.time_ns()}__" + try: + pyperclip.copy(sentinel) + except Exception: + pass + + for _ in range(max_deneme): + pyautogui.hotkey("ctrl", "c") + time.sleep(0.2) + metin = pyperclip.paste() + if metin and metin.strip() and metin != sentinel: + return metin + return "" + + +def pencere_modunda_gosterilsin_mi(komut_adi): + return "PS5 Oyun Skor" in komut_adi + + +def sonuc_penceresi_goster(baslik, icerik): + pencere = tk.Toplevel(root) + pencere.title(baslik) + pencere.geometry("780x520") + pencere.minsize(520, 320) + pencere.attributes("-topmost", True) + + frame = tk.Frame(pencere, bg="#1f1f1f") + frame.pack(fill="both", expand=True, padx=10, pady=10) + + text_alani = tk.Text( + frame, + wrap="word", + bg="#2b2b2b", + fg="white", + insertbackground="white", + font=("Segoe UI", 10), + padx=10, + pady=10, + ) + kaydirma = tk.Scrollbar(frame, command=text_alani.yview) + text_alani.configure(yscrollcommand=kaydirma.set) + + text_alani.pack(side="left", fill="both", expand=True) + kaydirma.pack(side="right", fill="y") + + text_alani.insert("1.0", icerik) + text_alani.config(state="disabled") + + alt_frame = tk.Frame(pencere, bg="#1f1f1f") + alt_frame.pack(fill="x", padx=10, pady=(0, 10)) + + def panoya_kopyala(): + pyperclip.copy(icerik) + + tk.Button( + alt_frame, + text="Panoya Kopyala", + command=panoya_kopyala, + bg="#3d3d3d", + fg="white", + activebackground="#4d4d4d", + activeforeground="white", + relief="flat", + padx=12, + pady=6, + ).pack(side="left") + + tk.Button( + alt_frame, + text="Kapat", + command=pencere.destroy, + bg="#3d3d3d", + fg="white", + activebackground="#4d4d4d", + activeforeground="white", + relief="flat", + padx=12, + pady=6, + ).pack(side="right") + + pencere.focus_force() + pencere.lift() + + +def islemi_yap(komut_adi, secili_metin): + prompt_emri = ISLEMLER[komut_adi] + full_prompt = f"{prompt_emri}:\n\n'{secili_metin}'" + + print(f"🤖 İşlem: {komut_adi}") + print("⏳ Ollama ile işleniyor...") + + sonuc = ollama_cevap_al(full_prompt) + if not sonuc: + print("❌ Sonuç alınamadı.") + return + + sonuc = strip_code_fence(sonuc) + if sonuc.startswith("'") and sonuc.endswith("'"): + sonuc = sonuc[1:-1] + + if pencere_modunda_gosterilsin_mi(komut_adi): + gui_queue.put((sonuc_penceresi_goster, (komut_adi, sonuc))) + print("✅ Sonuç ayrı pencerede gösterildi.") + return + + time.sleep(0.2) + pyperclip.copy(sonuc) + time.sleep(0.1) + pyautogui.hotkey("ctrl", "v") + print("✅ İşlem tamamlandı!") + + +def process_queue(): + """Kuyruktaki GUI işlemlerini ana thread'de çalıştırır.""" + try: + while True: + try: + task = gui_queue.get_nowait() + except queue.Empty: + break + func, args = task + func(*args) + finally: + if root: + root.after(100, process_queue) + + +def menu_goster(): + """Metni kopyalar ve menüyü gösterir (ana thread).""" + secili_metin = secili_metni_kopyala() + if not secili_metin.strip(): + gui_queue.put( + ( + messagebox.showwarning, + ( + "Secim Bulunamadi", + "Lutfen once metin secin, sonra F8 ile menuyu acin.", + ), + ) + ) + return + + menu = tk.Menu( + root, + tearoff=0, + bg="#2b2b2b", + fg="white", + activebackground="#4a4a4a", + activeforeground="white", + font=("Segoe UI", 10), + ) + + def komut_olustur(k_adi, s_metin): + def komut_calistir(): + threading.Thread( + target=islemi_yap, args=(k_adi, s_metin), daemon=True + ).start() + + return komut_calistir + + for baslik in ISLEMLER.keys(): + menu.add_command(label=baslik, command=komut_olustur(baslik, secili_metin)) + + menu.add_separator() + menu.add_command(label="❌ İptal", command=lambda: None) + + try: + x, y = pyautogui.position() + menu.tk_popup(x, y) + finally: + menu.grab_release() + + +def on_press(key): + global kisayol_basildi + try: + if key == KISAYOL_METIN and not kisayol_basildi: + kisayol_basildi = True + gui_queue.put((menu_goster, ())) + except AttributeError: + pass + + +def on_release(key): + global kisayol_basildi + try: + if key == KISAYOL_METIN: + kisayol_basildi = False + except AttributeError: + pass + + +if __name__ == "__main__": + print("=" * 60) + print("🤖 AI Asistan - Metin İşleme") + print("=" * 60) + aktif_text_model = get_available_text_model() + print(f"📦 Metin İşleme (F8): {aktif_text_model}") + print() + print("🔧 Kullanım:") + print(" F8 - Metin sec ve AI islemleri yap") + print() + print("⚠️ Programı kapatmak için bu pencereyi kapatın veya Ctrl+C yapın.") + print("=" * 60) + + try: + test_response = requests.get("http://localhost:11434/api/tags", timeout=5) + if test_response.status_code == 200: + print("✅ Ollama bağlantısı başarılı!") + else: + print("⚠️ Ollama'ya bağlanılamadı, servisi kontrol edin!") + except Exception: + print("⚠️ Ollama çalışmıyor olabilir! 'ollama serve' ile başlatın.") + + print() + + listener = keyboard.Listener(on_press=on_press, on_release=on_release) + listener.start() + + root = tk.Tk() + root.withdraw() + root.after(100, process_queue) + + try: + root.mainloop() + except KeyboardInterrupt: + print("Kapatılıyor...") diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..cae8a95 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +requests +pyperclip +pynput +pyautogui +sympy +Pillow +PyMuPDF