Add files via upload
This commit is contained in:
@@ -0,0 +1,99 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import base64
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
|
# --- DEFAULT FALLBACK MODELS ---
|
||||||
|
DEFAULT_MODELS = [
|
||||||
|
"qwen/qwen-2.5-vl-7b-instruct:free",
|
||||||
|
"meta-llama/llama-3.2-11b-vision-instruct",
|
||||||
|
"google/gemini-2.5-flash-image",
|
||||||
|
]
|
||||||
|
|
||||||
|
# --- ARGUMENTS ---
|
||||||
|
if len(sys.argv) < 3:
|
||||||
|
print("Kullanım: ai.py <image_path> <prompt> [model1,model2,...]")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
image_path = sys.argv[1]
|
||||||
|
prompt = sys.argv[2]
|
||||||
|
|
||||||
|
# --- MODELS FROM UI (OPTIONAL) ---
|
||||||
|
if len(sys.argv) >= 4 and sys.argv[3].strip():
|
||||||
|
MODELS = [m.strip() for m in sys.argv[3].split(",")]
|
||||||
|
else:
|
||||||
|
MODELS = DEFAULT_MODELS
|
||||||
|
|
||||||
|
# --- API KEY ---
|
||||||
|
API_KEY = os.environ.get("OPENROUTER_API_KEY")
|
||||||
|
if not API_KEY:
|
||||||
|
print("HATA: OPENROUTER_API_KEY not set")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# --- IMAGE LOAD ---
|
||||||
|
if not os.path.exists(image_path):
|
||||||
|
print(f"HATA: Resim bulunamadı → {image_path}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open(image_path, "rb") as f:
|
||||||
|
image_b64 = base64.b64encode(f.read()).decode("utf-8")
|
||||||
|
|
||||||
|
# --- REQUEST CONFIG ---
|
||||||
|
URL = "https://openrouter.ai/api/v1/chat/completions"
|
||||||
|
|
||||||
|
HEADERS = {
|
||||||
|
"Authorization": f"Bearer {API_KEY}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"HTTP-Referer": "http://localhost",
|
||||||
|
"X-Title": "ai-capture",
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- MODEL TRY FUNCTION ---
|
||||||
|
def try_model(model_name):
|
||||||
|
payload = {
|
||||||
|
"model": model_name,
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": [
|
||||||
|
{"type": "text", "text": prompt},
|
||||||
|
{
|
||||||
|
"type": "image_url",
|
||||||
|
"image_url": {
|
||||||
|
"url": f"data:image/png;base64,{image_b64}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"max_tokens": 512,
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(
|
||||||
|
URL,
|
||||||
|
headers=HEADERS,
|
||||||
|
json=payload,
|
||||||
|
timeout=60,
|
||||||
|
)
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
data = response.json()
|
||||||
|
return data["choices"][0]["message"]["content"]
|
||||||
|
|
||||||
|
raise Exception(f"{model_name} → {response.status_code}: {response.text}")
|
||||||
|
|
||||||
|
|
||||||
|
# --- MAIN LOOP ---
|
||||||
|
for model in MODELS:
|
||||||
|
try:
|
||||||
|
answer = try_model(model)
|
||||||
|
print(answer)
|
||||||
|
sys.exit(0)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[FAIL] {e}", file=sys.stderr)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
print("HATA: Tüm modeller başarısız")
|
||||||
|
sys.exit(1)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
source ~/.config/ai_capture/env.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
TMP="$HOME/.cache/ai-capture"
|
||||||
|
mkdir -p "$TMP"
|
||||||
|
|
||||||
|
GEOM=$(slurp) || exit 1
|
||||||
|
IMG="$TMP/capture_$(date +%s).png"
|
||||||
|
|
||||||
|
grim -g "$GEOM" "$IMG"
|
||||||
|
|
||||||
|
python ~/ai_capture/ui.py "$IMG"
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
import gi
|
||||||
|
import subprocess
|
||||||
|
import threading
|
||||||
|
|
||||||
|
gi.require_version("Gtk", "4.0")
|
||||||
|
from gi.repository import Gtk, GLib
|
||||||
|
|
||||||
|
AI_SCRIPT = "/home/bob/ai_capture/ai.py"
|
||||||
|
|
||||||
|
MODELS = [
|
||||||
|
"qwen/qwen-2.5-vl-7b-instruct:free",
|
||||||
|
"meta-llama/llama-3.2-11b-vision-instruct",
|
||||||
|
"google/gemini-2.5-flash-image",
|
||||||
|
]
|
||||||
|
|
||||||
|
class App(Gtk.Application):
|
||||||
|
def __init__(self, image_path):
|
||||||
|
super().__init__(application_id="ai.capture.ui")
|
||||||
|
self.image_path = image_path
|
||||||
|
|
||||||
|
def do_activate(self):
|
||||||
|
win = Gtk.ApplicationWindow(application=self)
|
||||||
|
win.set_title("AI Capture")
|
||||||
|
win.set_default_size(900, 800)
|
||||||
|
|
||||||
|
root = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
|
||||||
|
root.set_margin_top(10)
|
||||||
|
root.set_margin_bottom(10)
|
||||||
|
root.set_margin_start(10)
|
||||||
|
root.set_margin_end(10)
|
||||||
|
|
||||||
|
# === IMAGE ===
|
||||||
|
picture = Gtk.Picture.new_for_filename(self.image_path)
|
||||||
|
picture.set_hexpand(True)
|
||||||
|
picture.set_vexpand(True)
|
||||||
|
picture.set_content_fit(Gtk.ContentFit.CONTAIN)
|
||||||
|
|
||||||
|
frame = Gtk.Frame()
|
||||||
|
frame.set_hexpand(True)
|
||||||
|
frame.set_vexpand(True)
|
||||||
|
frame.set_child(picture)
|
||||||
|
root.append(frame)
|
||||||
|
|
||||||
|
# === INPUT ROW ===
|
||||||
|
row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
|
||||||
|
|
||||||
|
self.entry = Gtk.Entry()
|
||||||
|
self.entry.set_placeholder_text("Bu görüntü hakkında sorunuzu yazın…")
|
||||||
|
self.entry.set_hexpand(True)
|
||||||
|
row.append(self.entry)
|
||||||
|
|
||||||
|
self.ask_btn = Gtk.Button(label="Sor")
|
||||||
|
self.ask_btn.connect("clicked", self.on_ask)
|
||||||
|
row.append(self.ask_btn)
|
||||||
|
|
||||||
|
menu_btn = Gtk.Button(label="⋮")
|
||||||
|
row.append(menu_btn)
|
||||||
|
|
||||||
|
root.append(row)
|
||||||
|
|
||||||
|
# === OUTPUT ===
|
||||||
|
self.output = Gtk.TextView()
|
||||||
|
self.output.set_editable(False)
|
||||||
|
self.output.set_wrap_mode(Gtk.WrapMode.WORD_CHAR)
|
||||||
|
|
||||||
|
out_scroll = Gtk.ScrolledWindow()
|
||||||
|
out_scroll.set_vexpand(True)
|
||||||
|
out_scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
||||||
|
out_scroll.set_child(self.output)
|
||||||
|
|
||||||
|
root.append(out_scroll)
|
||||||
|
|
||||||
|
# === MODEL POPOVER ===
|
||||||
|
popover = Gtk.Popover()
|
||||||
|
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4)
|
||||||
|
box.set_margin_top(8)
|
||||||
|
box.set_margin_bottom(8)
|
||||||
|
box.set_margin_start(8)
|
||||||
|
box.set_margin_end(8)
|
||||||
|
|
||||||
|
self.checks = {}
|
||||||
|
for m in MODELS:
|
||||||
|
cb = Gtk.CheckButton(label=m)
|
||||||
|
cb.set_active(m == MODELS[0])
|
||||||
|
self.checks[m] = cb
|
||||||
|
box.append(cb)
|
||||||
|
|
||||||
|
popover.set_child(box)
|
||||||
|
popover.set_parent(menu_btn)
|
||||||
|
menu_btn.connect("clicked", lambda *_: popover.popup())
|
||||||
|
|
||||||
|
win.set_child(root)
|
||||||
|
win.present()
|
||||||
|
|
||||||
|
def on_ask(self, _):
|
||||||
|
prompt = self.entry.get_text().strip()
|
||||||
|
if not prompt:
|
||||||
|
return
|
||||||
|
|
||||||
|
models = [m for m, cb in self.checks.items() if cb.get_active()]
|
||||||
|
if not models:
|
||||||
|
self.set_output("❌ En az bir model seçmelisiniz.")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.ask_btn.set_sensitive(False)
|
||||||
|
self.set_output("⏳ Yanıt alınıyor…")
|
||||||
|
|
||||||
|
threading.Thread(
|
||||||
|
target=self.run_ai,
|
||||||
|
args=(prompt, models),
|
||||||
|
daemon=True
|
||||||
|
).start()
|
||||||
|
|
||||||
|
def run_ai(self, prompt, models):
|
||||||
|
for model in models:
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
[
|
||||||
|
"python",
|
||||||
|
AI_SCRIPT,
|
||||||
|
self.image_path,
|
||||||
|
prompt,
|
||||||
|
model
|
||||||
|
],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=120
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode == 0 and result.stdout.strip():
|
||||||
|
GLib.idle_add(self.on_done, result.stdout.strip())
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
last_error = str(e)
|
||||||
|
|
||||||
|
GLib.idle_add(self.on_done, f"❌ Tüm modeller başarısız.\n{last_error}")
|
||||||
|
|
||||||
|
def on_done(self, text):
|
||||||
|
self.set_output(text)
|
||||||
|
self.ask_btn.set_sensitive(True)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def set_output(self, text):
|
||||||
|
buf = self.output.get_buffer()
|
||||||
|
buf.set_text(text)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
print("Kullanım: ui.py <image_path>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
app = App(sys.argv[1])
|
||||||
|
app.run()
|
||||||
Reference in New Issue
Block a user