fp
This commit is contained in:
ufukasill-creator
2026-02-20 15:59:09 +03:00
parent 18db97cd2c
commit e49452529a
5 changed files with 455 additions and 0 deletions
+368
View File
@@ -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: <ad>\n"
"2) Topluluk Beğeni Skorları:\n"
"- Metacritic User Score: <değer veya 'bilgi yok'>\n"
"- OpenCritic / benzer eleştirmen ortalaması: <değer veya 'bilgi yok'>\n"
"- Oyuncu yorumu ortalaması (PS Store vb.): <değer veya 'bilgi yok'>\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...")