fp
fp
This commit is contained in:
+17
@@ -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
|
||||
Binary file not shown.
+63
@@ -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
|
||||
@@ -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...")
|
||||
@@ -0,0 +1,7 @@
|
||||
requests
|
||||
pyperclip
|
||||
pynput
|
||||
pyautogui
|
||||
sympy
|
||||
Pillow
|
||||
PyMuPDF
|
||||
Reference in New Issue
Block a user