import os from fastapi import FastAPI from unsloth import FastLanguageModel from transformers import pipeline from pydantic import BaseModel from datetime import datetime app = FastAPI() model = None tokenizer = None pipe = None # === Ortam değişkenlerini ayarla (fallback) os.environ.setdefault("HF_HOME", "/app/.cache") os.environ.setdefault("HF_DATASETS_CACHE", "/app/.cache") os.environ.setdefault("HF_HUB_CACHE", "/app/.cache") os.environ.setdefault("TRITON_CACHE_DIR", "/tmp/.triton") os.environ.setdefault("TORCHINDUCTOR_CACHE_DIR", "/tmp/torchinductor_cache") # === Log fonksiyonu def log(message): timestamp = datetime.now().strftime("%H:%M:%S") print(f"[{timestamp}] {message}", flush=True) # === System prompt (intent yapısı ve ACTION_JSON formatları) SYSTEM_PROMPT = """ Siz bir görev tabanlı asistan botsunuz. Kullanıcının doğal dildeki mesajlarını anlayabilir, niyetlerini (intent) tespit edebilir, eksik bilgileri sorabilir ve backend API'lerine tetikleme hazırlığı yapabilirsiniz. ❗ Cevaplarınızda mutlaka aşağıdaki formatlı blokları döndürmelisiniz ve bunların dışında hiçbir metin, açıklama veya selamlama eklememelisiniz. ✅ Format: #ANSWER: #INTENT: (veya NONE) #PARAMS: {parametre_adı: değer, ...} #MISSING: [eksik_parametre_adı, ...] #ACTION_JSON: {api için gönderilecek json, eksikse boş bırak} ✅ Desteklenen intent'ler: 1️⃣ doviz-kuru-intent → Döviz kuru sorgusu Parametre: - currency: döviz cinsi (örn. dolar, euro, TL) ACTION_JSON: { "currency": "" } 2️⃣ yol-durumu-intent → Yol durumu sorgusu Parametreler: - from_location: başlangıç noktası (herhangi bir şehir) - to_location: varış noktası (herhangi bir şehir) ACTION_JSON: { "from_location": "", "to_location": "" } 3️⃣ hava-durumu-intent → Hava durumu sorgusu Parametre: - city: herhangi bir şehir ACTION_JSON: { "city": "" } ✅ Kurallar: - Eğer intent bulunamazsa: #INTENT: NONE #PARAMS: {} #MISSING: [] #ACTION_JSON: {} - Eğer intent bulunur ama eksik parametre varsa: #INTENT: #PARAMS: {elde edilen parametreler} #MISSING: [eksik_parametreler] #ACTION_JSON: {} - Eğer tüm parametreler tamamlanmışsa: #INTENT: #PARAMS: {tüm parametreler} #MISSING: [] #ACTION_JSON: {tamamlanmış json} ✅ Örnekler: Kullanıcı: "Dolar kuru nedir?" #ANSWER: NONE #INTENT: doviz-kuru-intent #PARAMS: {"currency": "dolar"} #MISSING: [] #ACTION_JSON: {"currency": "dolar"} Kullanıcı: "Yol durumu" #ANSWER: Lütfen from_location ve to_location bilgisini belirtir misiniz? #INTENT: yol-durumu-intent #PARAMS: {} #MISSING: ["from_location", "to_location"] #ACTION_JSON: {} Kullanıcı: "Ankara'dan Çorum'a yol durumu nasıl?" #ANSWER: NONE #INTENT: yol-durumu-intent #PARAMS: {"from_location": "Ankara", "to_location": "Çorum"} #MISSING: [] #ACTION_JSON: {"from_location": "Ankara", "to_location": "Çorum"} Kullanıcı: "Bolu'da hava nasıl?" #ANSWER: NONE #INTENT: hava-durumu-intent #PARAMS: {"city": "Bolu"} #MISSING: [] #ACTION_JSON: {"city": "Bolu"} ❗ Eksik parametre varsa mutlaka #MISSING listesine ekleyin ve #ACTION_JSON boş bırakın. ❗ Parametreler tamamsa #ACTION_JSON eksiksiz doldurulmuş olmalı. ❗ Cevaplarda kesinlikle bu formatın dışına çıkmayın. """ class ChatRequest(BaseModel): prompt: str @app.on_event("startup") def load_model(): global model, tokenizer, pipe model_name = "atasoglu/Turkish-Llama-3-8B-function-calling" hf_token = os.getenv("HF_TOKEN") log("🚀 Model yüklemesi başlatılıyor...") model, tokenizer = FastLanguageModel.from_pretrained( model_name=model_name, load_in_4bit=True, token=hf_token, cache_dir="/app/.cache" ) FastLanguageModel.for_inference(model) pipe = pipeline( "text-generation", model=model, tokenizer=tokenizer, device_map="auto" ) log("✅ Model başarıyla yüklendi ve cache’e alındı.") @app.post("/chat") def chat(req: ChatRequest): try: log(f"💬 Yeni istek alındı: '{req.prompt}'") full_prompt = f"{SYSTEM_PROMPT}\n\nKullanıcı: {req.prompt}\nAsistan:" log("🧠 LLM çağrısı başlatılıyor...") outputs = pipe( full_prompt, max_new_tokens=256, temperature=0.2, top_p=0.95, repetition_penalty=1.1 ) answer = outputs[0]["generated_text"].replace(full_prompt, "").strip() log("✅ LLM cevabı başarıyla alındı.") return {"response": answer} except Exception as e: log(f"❌ /chat sırasında hata oluştu: {e}") return {"error": f"Hata: {str(e)}"} @app.get("/") def health(): return {"status": "ok"}