Spaces:
Running
Running
File size: 4,524 Bytes
a7eb20d d411917 a7eb20d 57cd8cf a7eb20d 57cd8cf e97e0b7 345d10b 57cd8cf d411917 a814516 57cd8cf d411917 57cd8cf a7eb20d 1fe6e3b 57cd8cf a7eb20d 20d5756 57cd8cf a7eb20d 57cd8cf a7eb20d e97e0b7 a7eb20d 57cd8cf a7eb20d 20d5756 57cd8cf 981d40d 20d5756 a702cfd 981d40d a702cfd 981d40d aad84fe 20d5756 e827c31 57cd8cf |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
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) |