|
import os |
|
import sys |
|
import traceback |
|
from fastapi import FastAPI |
|
from pydantic import BaseModel |
|
from llama_cpp import Llama |
|
from huggingface_hub import hf_hub_download |
|
from datetime import datetime |
|
import concurrent.futures |
|
|
|
|
|
def log(message): |
|
timestamp = datetime.now().strftime("%H:%M:%S") |
|
line = f"[{timestamp}] {message}" |
|
print(line, flush=True) |
|
|
|
|
|
REPO_ID = "oncu/Turkish-Llama-3-8B-function-calling-GGUF" |
|
FILENAME = "turkish-llama-3-8b-function-calling.q8_0.gguf" |
|
LOCAL_MODEL_PATH = f"/tmp/{FILENAME}" |
|
HF_TOKEN = os.getenv("HF_TOKEN") |
|
|
|
|
|
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: <cevap metni veya NONE> |
|
#INTENT: <intent_adı> (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: |
|
- doviz-kuru-intent → parametre: currency (dolar, euro, TL) |
|
- yol-durumu-intent → parametreler: from_location, to_location (Ankara, İstanbul, İzmir) |
|
- hava-durumu-intent → parametre: city (Ankara, İstanbul, İzmir) |
|
❗ Kullanıcıya hitap ederken formal bir dil kullanınız, sadece bu formatlı blokları döndürünüz. |
|
""" |
|
|
|
app = FastAPI() |
|
llm = None |
|
|
|
class ChatRequest(BaseModel): |
|
prompt: str |
|
|
|
@app.on_event("startup") |
|
def load_model(): |
|
global llm |
|
try: |
|
log("🚀 Uygulama başlatılıyor...") |
|
log("📥 Model indirme başlatılıyor...") |
|
|
|
model_path = hf_hub_download( |
|
repo_id=REPO_ID, |
|
filename=FILENAME, |
|
local_dir="/tmp", |
|
token=HF_TOKEN |
|
) |
|
log(f"✅ Model indirildi: {model_path}") |
|
|
|
log("📦 GGUF model yükleniyor...") |
|
llm = Llama(model_path=model_path, n_gpu_layers=-1, n_ctx=1024) |
|
log("✅ Model başarıyla yüklendi ve kullanılmaya hazır.") |
|
log("💡 Artık /chat endpoint'ine POST isteği gönderebilirsiniz.") |
|
except Exception as e: |
|
log(f"❌ Model yükleme hatası: {e}") |
|
traceback.print_exc() |
|
sys.exit(1) |
|
|
|
@app.post("/chat") |
|
def chat(req: ChatRequest): |
|
try: |
|
log(f"💬 Yeni istek alındı: '{req.prompt}'") |
|
prompt = f"{SYSTEM_PROMPT}\n\nKullanıcı: {req.prompt}\nAsistan:" |
|
log("🧠 LLM çağrısı başlatılıyor...") |
|
|
|
with concurrent.futures.ThreadPoolExecutor() as executor: |
|
future = executor.submit( |
|
llm, |
|
prompt, |
|
max_tokens=512, |
|
stop=["Kullanıcı:", "Asistan:"], |
|
echo=False |
|
) |
|
response = future.result(timeout=30) |
|
answer = response["choices"][0]["text"].strip() |
|
log("✅ LLM cevabı başarıyla alındı.") |
|
return {"response": answer} |
|
|
|
except concurrent.futures.TimeoutError: |
|
log("❌ LLM çağrısı timeout oldu (30 saniye).") |
|
return {"error": "LLM çağrısı zaman aşımına uğradı."} |
|
except Exception as e: |
|
log(f"❌ /chat sırasında hata oluştu: {e}") |
|
traceback.print_exc() |
|
return {"error": f"Hata: {str(e)}"} |
|
|
|
@app.get("/") |
|
def health(): |
|
return {"status": "ok"} |
|
|