Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
1 line
14 KiB
JSON
1 line
14 KiB
JSON
{"repo": "alperenevci/gamescout", "files": {"src/llm/api_client.py": {"a0d4b5757d58df4e20b1f8a0e47e1de3d5d1b0fb": {"t": 1786067735.546249, "n": 12862, "h": "2abd49f235b29d57", "c": "#!/usr/bin/env python3\n# llm/api_client.py - LLM API istemcisi\n\nimport os\nimport json\nimport requests\nimport logging\nfrom pathlib import Path\nfrom src.utils.helpers import get_logger\n\n# Proje kök dizinini import için ekleyin\nimport sys\nsys.path.append(str(Path(__file__).parent.parent))\n\nfrom config import settings\n\nlogger = get_logger(__name__)\n\nclass LLMAPIClient:\n \"\"\"\n Çeşitli LLM API'lerini (OpenAI, DeepSeek, Gemini vb.) kullanmak için istemci.\n LLM bazlı önerilerin üretilmesi için kullanılır.\n \"\"\"\n \n def __init__(self):\n \"\"\"API seçeneklerini yapılandırma dosyasından yükle.\"\"\"\n self.api_type = settings.LLM_API_TYPE\n self.api_key = settings.LLM_API_KEY\n self.api_model = settings.LLM_API_MODEL\n self.api_endpoint = settings.LLM_API_ENDPOINT\n self.max_tokens = settings.LLM_MAX_TOKENS\n self.temperature = settings.LLM_TEMPERATURE\n self.language = \"tr\" # Varsayılan dil olarak Türkçe\n\n def is_available(self):\n \"\"\"API'nin kullanıma hazır olup olmadığını kontrol et.\"\"\"\n # En azından API türü ve anahtarı olmalı\n return bool(self.api_type and self.api_key)\n \n def get_base_prompt(self, game_state, category=\"general\"):\n \"\"\"Oyun durumuna göre temel prompt oluşturur.\"\"\"\n # Basit durum formatı\n state_desc = f\"Bölge: {game_state.current_region if game_state.current_region else 'Bilinmiyor'}, \"\n state_desc += f\"Karakter Sınıfı: {game_state.character_class}, \"\n \n if game_state.nearby_points_of_interest:\n poi_names = [poi['name'] for poi in game_state.nearby_points_of_interest[:3]]\n state_desc += f\"Yakındaki Önemli Yerler: {', '.join(poi_names)}, \"\n \n if game_state.detected_keywords:\n state_desc += f\"Tespit Edilen Anahtar Kelimeler: {', '.join(game_state.detected_keywords)}, \"\n \n # Oyuncu için ipuçları ve öneriler oluşturacak prompt\n prompt = f\"\"\"\n Sen bir Baldur's Gate 3 oyun asistanısın. Oyuncunun oyun deneyimini artırmak için \n yararlı ipuçları ve öneriler sunuyorsun. Aşağıdaki oyun durum bilgilerine dayanarak\n oyuncuya yardımcı olacak {self.language} dilinde 3 yararlı öneri veya ipucu oluştur.\n Yanıtların kısa, öz ve doğrudan yararlı olmalı.\n \n Mevcut oyun durumu:\n {state_desc}\n \n İstenilen öneri kategorisi: {category}\n \n Öneriler veya ipuçları (her biri en fazla 150 karakter):\n \"\"\"\n \n return prompt\n \n def get_rag_prompt(self, user_query, contexts):\n \"\"\"RAG için prompt oluştur.\"\"\"\n prompt = f\"\"\"\n Kullanıcının Sorusu: {user_query}\n \n Aşağıdaki bağlamları kullanarak kullanıcının sorusuna {self.language} dilinde yanıt ver. \n Eğer verilen bilgiler İngilizce ise, bunları doğru bir şekilde {self.language} diline çevirerek cevap ver.\n Cevabın net, kısa ve doğru olsun. Sadece verilen bağlamlara dayanarak cevap ver.\n Eğer bağlamlarda cevap yoksa, \"Bu konu hakkında yeterli bilgim yok\" şeklinde yanıt ver.\n Sen bir Baldur's Gate 3 oyunu asistanısın ve görevin oyuncuya yardımcı olmaktır.\n \n Bağlamlar:\n \"\"\"\n \n for i, context in enumerate(contexts, 1):\n prompt += f\"\\n--- Bağlam {i} ---\\n\"\n prompt += f\"Başlık: {context.get('title', 'Başlık yok')}\\n\"\n content = context.get('content', 'İçerik yok')\n # İçeriği LLM token limitlerini aşmamak için kısalt\n if len(content) > 1000:\n content = content[:1000] + \"...\"\n prompt += f\"İçerik: {content}\\n\"\n \n return prompt\n \n def set_language(self, language_code):\n \"\"\"Yanıt dilini ayarla (tr: Türkçe, en: İngilizce).\"\"\"\n self.language = language_code\n logger.info(f\"LLM yanıt dili şu şekilde ayarlandı: {language_code}\")\n \n def call_openai(self, prompt):\n \"\"\"OpenAI API'sini çağır.\"\"\"\n import openai\n \n openai.api_key = self.api_key\n \n try:\n completion = openai.ChatCompletion.create(\n model=self.api_model or \"gpt-3.5-turbo\",\n messages=[\n {\"role\": \"system\", \"content\": \"Sen bir Baldur's Gate 3 oyun asistanısın. Türkçe cevaplar ver.\"},\n {\"role\": \"user\", \"content\": prompt}\n ],\n max_tokens=self.max_tokens or 300,\n temperature=self.temperature or 0.7\n )\n \n return completion.choices[0].message.content.strip()\n \n except Exception as e:\n logger.error(f\"OpenAI API çağrısı başarısız: {str(e)}\")\n return None\n \n def call_deepseek(self, prompt):\n \"\"\"DeepSeek API'sini çağır.\"\"\"\n headers = {\n \"Authorization\": f\"Bearer {self.api_key}\",\n \"Content-Type\": \"application/json\"\n }\n \n data = {\n \"model\": self.api_model or \"deepseek-chat\",\n \"messages\": [\n {\"role\": \"system\", \"content\": \"Sen bir Baldur's Gate 3 oyun asistanısın. Türkçe cevaplar ver.\"},\n {\"role\": \"user\", \"content\": prompt}\n ],\n \"max_tokens\": self.max_tokens or 300,\n \"temperature\": self.temperature or 0.7\n }\n \n try:\n response = requests.post(\n self.api_endpoint or \"https://api.deepseek.com/v1/chat/completions\",\n headers=headers,\n json=data,\n timeout=30\n )\n response.raise_for_status()\n \n response_data = response.json()\n return response_data[\"choices\"][0][\"message\"].content.strip()\n \n except Exception as e:\n logger.error(f\"DeepSeek API çağrısı başarısız: {str(e)}\")\n return None\n \n def call_gemini(self, prompt):\n \"\"\"Google Gemini API'sini çağır.\"\"\"\n try:\n import google.generativeai as genai\n \n genai.configure(api_key=self.api_key)\n model = genai.GenerativeModel(\n self.api_model or \"gemini-pro\", \n generation_config={\"temperature\": self.temperature or 0.7, \"max_output_tokens\": self.max_tokens or 300}\n )\n \n system_instruction = \"Sen bir Baldur's Gate 3 oyun asistanısın. Türkçe cevaplar ver.\"\n \n response = model.generate_content(\n [system_instruction, prompt]\n )\n \n return response.text.strip()\n \n except Exception as e:\n logger.error(f\"Gemini API çağrısı başarısız: {str(e)}\")\n return None\n \n def process_response_for_turkish(self, response):\n \"\"\"LLM yanıtındaki olası bozuk Türkçe karakterleri düzelt.\"\"\"\n if not response or self.language != \"tr\":\n return response\n \n # Türkçe karakterlerin düzgün görüntülenmesi için kontroller\n tr_replacements = {\n 'ı': 'ı',\n 'ü': 'ü',\n 'ö': 'ö',\n 'ÅŸ': 'ş', \n 'ç': 'ç',\n 'Äž': 'ğ',\n 'İ': 'İ',\n 'Ü': 'Ü',\n 'Ö': 'Ö',\n 'Åž': 'Ş',\n 'Ç': 'Ç',\n 'Äž': 'Ğ'\n }\n \n for wrong, correct in tr_replacements.items():\n response = response.replace(wrong, correct)\n \n return response\n \n def get_recommendation(self, game_state, category=\"general\"):\n \"\"\"\n Oyun durumuna dayalı olarak LLM'den önerileri alır.\n \n Args:\n game_state: Oyun durum nesnesi\n category: Öneri kategorisi (general, combat, exploration, vb.)\n \n Returns:\n list: Yanıt listesi veya boş liste (hata durumunda)\n \"\"\"\n if not self.is_available():\n logger.warning(\"LLM API yapılandırılmamış, öneriler devre dışı\")\n return []\n \n try:\n # Prompt oluştur\n prompt = self.get_base_prompt(game_state, category)\n \n # API türüne göre çağrı yap\n response = None\n \n if self.api_type.lower() == \"openai\":\n response = self.call_openai(prompt)\n elif self.api_type.lower() == \"deepseek\":\n response = self.call_deepseek(prompt)\n elif self.api_type.lower() == \"gemini\":\n response = self.call_gemini(prompt)\n else:\n logger.error(f\"Desteklenmeyen API türü: {self.api_type}\")\n return []\n \n if not response:\n logger.warning(\"LLM API'den yanıt alınamadı\")\n return []\n \n # Türkçe karakter düzeltmesi\n response = self.process_response_for_turkish(response)\n \n # Yanıtı satırlara ayır ve filtrele\n lines = [line.strip() for line in response.split(\"\\n\") if line.strip()]\n \n # İpucu/Öneri formatı kontrolü\n recommendations = []\n for line in lines:\n # Numaralandırma, tire veya yıldızla başlayan satırları al\n if (line.startswith((\"1.\", \"2.\", \"3.\", \"-\", \"*\", \"•\")) or \n any(line.lower().startswith(kw) for kw in [\"ipucu:\", \"öneri:\", \"tavsiye:\"])):\n # Öneri başlangıcı olabilecek öğeleri temizle\n cleaned = line\n for prefix in [\"1.\", \"2.\", \"3.\", \"-\", \"*\", \"•\", \"ipucu:\", \"öneri:\", \"tavsiye:\"]:\n if cleaned.lower().startswith(prefix):\n cleaned = cleaned[len(prefix):].strip()\n break\n recommendations.append(cleaned)\n \n # Eğer düzgün ipuçları bulunamadıysa, tüm yanıtı kullan\n if not recommendations and lines:\n recommendations = [r for r in lines if len(r) > 10 and len(r) < 200]\n \n # En fazla 3 öneri döndür\n return recommendations[:3]\n \n except Exception as e:\n logger.error(f\"Öneri alınırken hata: {str(e)}\")\n return []\n \n def get_rag_response(self, user_query, contexts):\n \"\"\"\n Kullanıcı sorgusuna ve bağlamlara dayanarak LLM'den RAG yanıtı alır.\n \n Args:\n user_query: Kullanıcı sorgusur\n contexts: Bilgi tabanından alınan ilgili bağlamlar\n \n Returns:\n str: LLM yanıtı veya hata mesajı\n \"\"\"\n if not self.is_available():\n return \"LLM API yapılandırılmamış. Ayarlarınızı kontrol edin.\"\n \n try:\n # RAG promptu oluştur\n prompt = self.get_rag_prompt(user_query, contexts)\n \n # API türüne göre çağrı yap\n response = None\n \n if self.api_type.lower() == \"openai\":\n response = self.call_openai(prompt)\n elif self.api_type.lower() == \"deepseek\":\n response = self.call_deepseek(prompt)\n elif self.api_type.lower() == \"gemini\":\n response = self.call_gemini(prompt)\n else:\n return f\"Desteklenmeyen API türü: {self.api_type}\"\n \n if not response:\n return \"LLM'den yanıt alınamadı.\"\n \n # Türkçe karakter düzeltmesi\n response = self.process_response_for_turkish(response)\n \n return response\n \n except Exception as e:\n logger.error(f\"RAG yanıtı alınırken hata: {str(e)}\")\n return f\"Hata oluştu: {str(e)}\"\n\n\n# Test - Örnek kullanım\nif __name__ == \"__main__\":\n from rag.decision_engine import GameState\n \n # Test için basit bir GameState nesnesi oluştur\n gs = GameState()\n gs.current_region = \"Emerald Grove\"\n gs.character_class = \"Wizard\"\n gs.detected_keywords = [\"görev\", \"savaş\", \"büyü\"]\n \n # LLM API istemcisini başlat\n client = LLMAPIClient()\n \n # Dil tercihi\n client.set_language(\"tr\") # Türkçe yanıtlar için\n \n # API yapılandırılmışsa öneriler al\n if client.is_available():\n print(\"\\nGenel öneriler:\")\n recommendations = client.get_recommendation(gs, \"general\")\n for i, rec in enumerate(recommendations, 1):\n print(f\"{i}. {rec}\")\n \n print(\"\\nSavaş önerileri:\")\n combat_recommendations = client.get_recommendation(gs, \"combat\")\n for i, rec in enumerate(combat_recommendations, 1):\n print(f\"{i}. {rec}\")\n else:\n print(\"LLM API yapılandırılmamış. API türünü ve anahtarınızı ayarlayın.\")"}}}} |