Spaces:
Sleeping
Sleeping
| import json | |
| import os | |
| import gradio as gr | |
| import spaces | |
| from dotenv import load_dotenv | |
| from groq import Groq | |
| import db | |
| load_dotenv(os.path.join(os.path.dirname(__file__), "..", ".env")) | |
| load_dotenv() | |
| MODEL = "llama-3.3-70b-versatile" | |
| def _zerogpu_noop(): | |
| """Unused — satisfies the ZeroGPU hardware startup check. This app is CPU-only.""" | |
| return None | |
| _client = None | |
| def get_client() -> Groq: | |
| global _client | |
| if _client is None: | |
| _client = Groq(api_key=os.environ.get("GROQ_API_KEY")) | |
| return _client | |
| TOOLS_SCHEMA = [ | |
| { | |
| "type": "function", | |
| "function": { | |
| "name": "list_books", | |
| "description": "Kitapçıdaki kitapları listeler. 'query' verilirse başlık veya yazara göre filtreler, verilmezse tüm katalogu döner. Her kitap için stok ve fiyat bilgisi içerir.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "query": {"type": "string", "description": "Başlık veya yazar adında aranacak kelime (opsiyonel)"}, | |
| }, | |
| "required": [], | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": { | |
| "name": "create_order", | |
| "description": "Belirtilen kitaptan, belirtilen adette sipariş oluşturur ve stoktan düşer. Stok yetersizse hata döner.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "book_id": {"type": "integer", "description": "list_books çağrısından dönen kitap id'si"}, | |
| "quantity": {"type": "integer", "description": "Sipariş edilecek adet"}, | |
| "customer_name": {"type": "string", "description": "Müşterinin adı"}, | |
| }, | |
| "required": ["book_id", "quantity", "customer_name"], | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": { | |
| "name": "check_order_status", | |
| "description": "Verilen sipariş numarasının (order_id) durumunu, hangi kitap ve ne kadar olduğunu döner.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "order_id": {"type": "integer", "description": "create_order çağrısından dönen sipariş numarası"}, | |
| }, | |
| "required": ["order_id"], | |
| }, | |
| }, | |
| }, | |
| ] | |
| AVAILABLE_FUNCTIONS = { | |
| "list_books": db.list_books, | |
| "create_order": db.create_order, | |
| "check_order_status": db.check_order_status, | |
| } | |
| SYSTEM_PROMPT = ( | |
| "Sen bir kitapçının sipariş asistanısın. Elinde list_books, create_order ve " | |
| "check_order_status araçları var. KURALLAR: " | |
| "1) Kitap adı, yazar, fiyat, stok gibi bilgileri ASLA uydurma — her zaman önce list_books " | |
| "çağır ve sadece dönen gerçek veriyi kullan. " | |
| "2) Katalogda olmayan bir kitap sorulursa, 'bu kitap katalogda yok' de, var gibi davranma. " | |
| "3) Sipariş oluşturmadan önce book_id'yi list_books sonucundan al, tahmin etme. " | |
| "4) Stok yetersizse veya hata dönerse bunu kullanıcıya net şekilde söyle. " | |
| "5) Kısa, net ve Türkçe yanıt ver." | |
| ) | |
| def run_agent(user_message: str, history: list): | |
| messages = [{"role": "system", "content": SYSTEM_PROMPT}] | |
| for turn in history: | |
| messages.append({"role": turn["role"], "content": turn["content"]}) | |
| messages.append({"role": "user", "content": user_message}) | |
| trace_lines = [] | |
| turn_num = 1 | |
| max_turns = 6 | |
| while turn_num <= max_turns: | |
| for attempt in range(3): | |
| try: | |
| response = get_client().chat.completions.create( | |
| model=MODEL, | |
| messages=messages, | |
| tools=TOOLS_SCHEMA, | |
| tool_choice="auto", | |
| ) | |
| break | |
| except Exception as e: | |
| if "tool_use_failed" in str(e) and attempt < 2: | |
| continue | |
| raise | |
| msg = response.choices[0].message | |
| if not msg.tool_calls: | |
| final_text = msg.content or "" | |
| if trace_lines: | |
| trace = "\n".join(trace_lines) | |
| return f"```\n{trace}\n```\n\n**Yanıt:**\n{final_text}" | |
| return final_text | |
| messages.append( | |
| { | |
| "role": "assistant", | |
| "content": msg.content, | |
| "tool_calls": [ | |
| { | |
| "id": tc.id, | |
| "type": "function", | |
| "function": {"name": tc.function.name, "arguments": tc.function.arguments}, | |
| } | |
| for tc in msg.tool_calls | |
| ], | |
| } | |
| ) | |
| trace_lines.append(f"[Tur {turn_num}] Araç Çağrıları:") | |
| for tc in msg.tool_calls: | |
| name = tc.function.name | |
| args = json.loads(tc.function.arguments) | |
| func = AVAILABLE_FUNCTIONS.get(name) | |
| result = func(**args) if func else {"error": f"Unknown tool {name}"} | |
| args_str = ", ".join(f"{k}={v!r}" for k, v in args.items()) | |
| trace_lines.append(f" -> {name}({args_str})") | |
| trace_lines.append(f" <- {result}") | |
| messages.append( | |
| { | |
| "role": "tool", | |
| "tool_call_id": tc.id, | |
| "name": name, | |
| "content": json.dumps(result, ensure_ascii=False), | |
| } | |
| ) | |
| turn_num += 1 | |
| return "Üzgünüm, çok fazla araç çağrısı yapıldı, yanıt üretilemedi." | |
| def chat_fn(message, history): | |
| if not os.environ.get("GROQ_API_KEY"): | |
| return "GROQ_API_KEY ortam değişkeni ayarlanmamış. Lütfen Space secrets kısmına ekleyin." | |
| try: | |
| return run_agent(message, history) | |
| except Exception as e: | |
| return f"Hata: {e}" | |
| demo = gr.ChatInterface( | |
| fn=chat_fn, | |
| title="📚 Kitapçı Asistanı — Tool Calling Demo", | |
| description=( | |
| "Model, katalog/stok/fiyat sorularında `list_books`, sipariş için `create_order`, " | |
| "sipariş takibi için `check_order_status` araçlarını otomatik çağırır. Tüm veriler " | |
| "gerçek bir SQLite veritabanından gelir; model katalogda olmayan bir kitabı asla uydurmaz. " | |
| "Arka planda hangi aracın hangi parametrelerle çağrıldığı yanıtın üstünde gösterilir.\n\n" | |
| "Örnek: *'Elinizde Orwell'in kitabı var mı, varsa 2 tane sipariş vermek istiyorum, adım Ali.'*" | |
| ), | |
| examples=[ | |
| "Katalogda hangi kitaplar var?", | |
| "1984 kitabından 2 adet sipariş vermek istiyorum, adım Ayşe.", | |
| "Fahrenheit 451'den 1 tane alabilir miyim?", | |
| "3 numaralı siparişimin durumu ne?", | |
| ], | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |