import os import threading import uvicorn from fastapi import FastAPI from fastapi.responses import HTMLResponse, JSONResponse from pydantic import BaseModel from transformers import AutoTokenizer, AutoModelForCausalLM from datasets import load_dataset from peft import PeftModel import torch from huggingface_hub import hf_hub_download import zipfile from datetime import datetime import random # ✅ Zamanlı log fonksiyonu (flush destekli) def log(message): timestamp = datetime.now().strftime("%H:%M:%S") print(f"[{timestamp}] {message}") os.sys.stdout.flush() # ✅ Sabitler HF_TOKEN = os.environ.get("HF_TOKEN") MODEL_BASE = "UcsTurkey/kanarya-750m-fixed" FINE_TUNE_ZIP = "trained_model_002_005.zip" FINE_TUNE_REPO = "UcsTurkey/trained-zips" RAG_DATA_FILE = "merged_dataset_000_100.parquet" RAG_DATA_REPO = "UcsTurkey/turkish-general-culture-tokenized" USE_RAG = False # ✅ RAG kullanımını opsiyonel hale getiren sabit CONFIDENCE_THRESHOLD = -1.5 # ✅ Logit skorlarına göre eşik değeri FALLBACK_ANSWERS = [ "Bu konuda maalesef bilgim yok.", "Ne demek istediğinizi tam anlayamadım.", "Bu soruya şu an yanıt veremiyorum." ] app = FastAPI() chat_history = [] model = None tokenizer = None class Message(BaseModel): user_input: str @app.get("/") def health(): return {"status": "ok"} @app.get("/start", response_class=HTMLResponse) def root(): return """ Fine-Tune Chat

📘 Fine-tune Chat Test




        
    
    
    """

@app.post("/chat")
def chat(msg: Message):
    try:
        log(f"📦 Kullanıcı mesajı alındı: {msg}")
        global model, tokenizer
        if model is None or tokenizer is None:
            log("🚫 Hata: Model henüz yüklenmedi.")
            return {"error": "Model yüklenmedi. Lütfen birkaç saniye sonra tekrar deneyin."}

        user_input = msg.user_input.strip()
        if not user_input:
            return {"error": "Boş giriş"}

        full_prompt = f"SORU: {user_input}\nCEVAP:"
        log(f"📨 Prompt: {full_prompt}")

        inputs = tokenizer(full_prompt, return_tensors="pt")
        inputs = {k: v.to(model.device) for k, v in inputs.items()}

        with torch.no_grad():
            output = model.generate(
                **inputs,
                max_new_tokens=200,
                do_sample=True,
                temperature=0.7,
                return_dict_in_generate=True,
                output_scores=True
            )

        generated_ids = output.sequences[0]
        generated_text = tokenizer.decode(generated_ids, skip_special_tokens=True)
        answer = generated_text[len(full_prompt):].strip()

        if output.scores and len(output.scores) > 0:
            first_token_logit = output.scores[0][0]
            if torch.isnan(first_token_logit).any() or torch.isinf(first_token_logit).any():
                log("⚠️ Geçersiz logit (NaN/Inf) tespit edildi, fallback cevabı gönderiliyor.")
                fallback = random.choice(FALLBACK_ANSWERS)
                answer = fallback
                return {"answer": answer, "chat_history": chat_history}  # ilk tokenin logits
            top_logit_score = torch.max(first_token_logit).item()
            log(f"🔎 İlk token logit skoru: {top_logit_score:.4f}")

            if top_logit_score < CONFIDENCE_THRESHOLD:
                fallback = random.choice(FALLBACK_ANSWERS)
                log(f"⚠️ Düşük güven: fallback cevabı gönderiliyor: {fallback}")
                answer = fallback

        chat_history.append({"user": user_input, "bot": answer})
        log(f"🗨️ Soru: {user_input} → Yanıt: {answer[:60]}...")
        return {"answer": answer, "chat_history": chat_history}
    except Exception as e:
        log(f"❌ /chat sırasında hata oluştu: {e}")
        return {"error": str(e)}

def setup_model():
    try:
        global model, tokenizer

        log("📦 Fine-tune zip indiriliyor...")
        zip_path = hf_hub_download(
            repo_id=FINE_TUNE_REPO,
            filename=FINE_TUNE_ZIP,
            repo_type="model",
            token=HF_TOKEN
        )

        extract_dir = "/app/extracted"
        os.makedirs(extract_dir, exist_ok=True)

        with zipfile.ZipFile(zip_path, "r") as zip_ref:
            zip_ref.extractall(extract_dir)
        log("📂 Zip başarıyla açıldı.")

        log("🔁 Tokenizer yükleniyor...")
        tokenizer = AutoTokenizer.from_pretrained(os.path.join(extract_dir, "output"))

        log("🧠 Base model indiriliyor...")
        base_model = AutoModelForCausalLM.from_pretrained(
            MODEL_BASE,
            torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
        )

        log("➕ LoRA adapter uygulanıyor...")
        peft_model = PeftModel.from_pretrained(base_model, os.path.join(extract_dir, "output"))

        model = peft_model.model
        model.eval()

        log("✅ Model başarıyla yüklendi.")
    except Exception as e:
        log(f"❌ setup_model() sırasında hata oluştu: {e}")

def run_server():
    log("🚀 Uvicorn sunucusu başlatılıyor...")
    uvicorn.run(app, host="0.0.0.0", port=7860)

# ✅ Uygulama başlangıcı
threading.Thread(target=setup_model, daemon=True).start()
threading.Thread(target=run_server, daemon=True).start()

log("⌛ Model yükleniyor, istekler ve API sunucusu hazırlanıyor...")
while True:
    try:
        import time
        time.sleep(60)
    except Exception as e:
        log(f"❌ Ana bekleme döngüsünde hata: {e}")