Ogghey's picture
Update app.py
57cd8cf verified
import os
import shutil
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from sentence_transformers import SentenceTransformer, util
import torch
import requests
# Rate limit
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
# Inisialisasi FastAPI dan Limiter
limiter = Limiter(key_func=get_remote_address)
app = FastAPI()
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
# ๐Ÿ” Paksa cache aman untuk Hugging Face Spaces
HF_CACHE = "/tmp/hf"
os.environ["TRANSFORMERS_CACHE"] = HF_CACHE
os.environ["HF_HOME"] = HF_CACHE
os.makedirs(HF_CACHE, exist_ok=True)
# Bersihkan cache model jika terkunci
if os.path.exists(f"{HF_CACHE}/models--sentence-transformers--paraphrase-MiniLM-L3-v2.lock"):
os.remove(f"{HF_CACHE}/models--sentence-transformers--paraphrase-MiniLM-L3-v2.lock")
if os.path.exists(f"{HF_CACHE}/models--sentence-transformers--paraphrase-MiniLM-L3-v2"):
shutil.rmtree(f"{HF_CACHE}/models--sentence-transformers--paraphrase-MiniLM-L3-v2", ignore_errors=True)
# Supabase
SUPABASE_URL = "https://olbjfxlclotxtnpjvpfj.supabase.co"
SUPABASE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im9sYmpmeGxjbG90eHRucGp2cGZqIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTIyMzYwMDEsImV4cCI6MjA2NzgxMjAwMX0.7q_o5DCFEAAysnWXMChH4MI5qNhIVc4OgpT5JvgYxc0"
# Model
model = SentenceTransformer("sentence-transformers/paraphrase-MiniLM-L3-v2")
# ๐Ÿ” Ambil FAQ berdasarkan UID
def get_faq_from_supabase(uid):
url = f"{SUPABASE_URL}/rest/v1/faq_texts?uid=eq.{uid}"
headers = {
"apikey": SUPABASE_KEY,
"Authorization": f"Bearer {SUPABASE_KEY}",
"Content-Type": "application/json"
}
try:
r = requests.get(url, headers=headers)
r.raise_for_status()
data = r.json()
return [{"q": d["question"], "a": d["answer"]} for d in data]
except Exception as e:
print("โŒ Supabase error:", e)
return []
# ๐Ÿ”ฎ Endpoint prediksi jawaban dari pertanyaan user
@app.post("/predict")
@limiter.limit("5/minute")
async def predict(request: Request):
body = await request.json()
uid, question = body.get("data", [None, None])
if not uid or not question:
return {"data": ["UID atau pertanyaan tidak valid."]}
faqs = get_faq_from_supabase(uid)
if not faqs:
return {"data": ["FAQ tidak ditemukan untuk UID ini."]}
questions = [f["q"] for f in faqs]
answers = [f["a"] for f in faqs]
embeddings = model.encode(questions, convert_to_tensor=True)
query_embedding = model.encode(question, convert_to_tensor=True)
similarity = util.pytorch_cos_sim(query_embedding, embeddings)
best_idx = torch.argmax(similarity).item()
return {"data": [answers[best_idx]]}
# ๐Ÿงน Hapus satu pesan berdasarkan ID
@app.post("/delete_chat")
async def delete_chat(request: Request):
body = await request.json()
message_id = body.get("id")
if not message_id:
return JSONResponse({"error": "ID pesan wajib diisi."}, status_code=400)
url = f"{SUPABASE_URL}/rest/v1/chat_logs?id=eq.{message_id}"
headers = {
"apikey": SUPABASE_KEY,
"Authorization": f"Bearer {SUPABASE_KEY}",
"Content-Type": "application/json",
"Prefer": "return=representation"
}
try:
r = requests.delete(url, headers=headers)
r.raise_for_status()
return {"message": f"Pesan dengan ID {message_id} berhasil dihapus."}
except Exception as e:
print("โŒ Gagal hapus pesan:", e)
return JSONResponse({"error": "Gagal menghapus pesan."}, status_code=500)
# ๐Ÿงผ Hapus semua pesan milik user tertentu
@app.post("/delete_all_by_uid")
async def delete_all_by_uid(request: Request):
body = await request.json()
uid = body.get("uid")
if not uid:
return JSONResponse({"error": "UID wajib diisi."}, status_code=400)
url = f"{SUPABASE_URL}/rest/v1/chat_logs?uid=eq.{uid}"
headers = {
"apikey": SUPABASE_KEY,
"Authorization": f"Bearer {SUPABASE_KEY}",
"Content-Type": "application/json",
"Prefer": "return=representation"
}
try:
r = requests.delete(url, headers=headers)
r.raise_for_status()
return {"message": f"Semua pesan dengan UID {uid} berhasil dihapus."}
except Exception as e:
return JSONResponse({"error": str(e)}, status_code=500)