File size: 4,125 Bytes
31f500f 6a4046c 17d08c9 37ebc59 6a4046c e4eb613 6a4046c 37ebc59 f0f8994 96813b8 f0f8994 6a4046c f0f8994 6a4046c f0f8994 6a4046c 7840b1b 37ebc59 6a4046c f0f8994 3ba2a7e 6a4046c 37ebc59 f0f8994 37ebc59 f0f8994 6a4046c e1f3d9e 37ebc59 e1f3d9e 6a4046c 17d08c9 6a4046c f0f8994 6a4046c f0f8994 6a4046c f0f8994 6a4046c 17d08c9 f0f8994 37ebc59 f0f8994 3ba2a7e 37ebc59 6a4046c 37ebc59 f0f8994 998d9ed d0da9f8 f0f8994 17d08c9 3ba2a7e 37ebc59 f0f8994 cf7d8ac f0f8994 e4eb613 37ebc59 6a4046c 998d9ed 3ba2a7e 37ebc59 | 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 | from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from transformers import AutoTokenizer
import onnxruntime as ort
import numpy as np
from pathlib import Path
import traceback
# === Inisialisasi FastAPI ===
app = FastAPI(title="Portfolio Chatbot API", version="1.0")
# === CORS (boleh dibatasi ke domain Vercel kamu nanti) ===
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # contoh: ["https://your-frontend.vercel.app"]
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# === Path model dan tokenizer ===
BASE_DIR = Path(__file__).resolve().parent
MODEL_PATH = BASE_DIR / "models" / "bert_chatbot.onnx"
TOKENIZER_PATH = BASE_DIR / "models" / "bert-base-multilingual-cased"
# === Global variable untuk model dan tokenizer ===
tokenizer = None
session = None
# === Load model dan tokenizer ===
def load_model():
global tokenizer, session
try:
print("π Loading tokenizer dan ONNX model...")
tokenizer = AutoTokenizer.from_pretrained(str(TOKENIZER_PATH))
session = ort.InferenceSession(str(MODEL_PATH), providers=["CPUExecutionProvider"])
print("β
Model dan tokenizer berhasil dimuat!")
print("π₯ Model expects inputs:", [i.name for i in session.get_inputs()])
except Exception as e:
print("β ERROR saat memuat model/tokenizer:", e)
traceback.print_exc()
load_model()
# === Label mapping (HARUS sama seperti saat training) ===
id2label = {
0: "about_me",
1: "career_goal",
2: "experience",
3: "fallback",
4: "greeting",
5: "projects",
6: "skills",
}
# === Kamus respon sesuai training ===
responses = {
"about_me": "I am a passionate developer specializing in AI and web development.",
"skills": "My main skills are HTML5, CSS3, JavaScript, Laravel, Node.js, Database, TensorFlow, PyTorch, Firebase, and Jupyter Notebook.",
"projects": "Some of my projects are Mobile Apps Bald Detection and Jupyter Notebook Bald Detection.",
"experience": "I have worked as IT Support, AI Engineer, and Freelancer on multiple projects.",
"career_goal": "My career goal is to become a Full Stack Developer and Machine Learning Engineer.",
"greeting": "Hello! How can I help you regarding this portfolio?",
"fallback": "I'm sorry, I don't understand. Please ask another question."
}
# === Request schema ===
class ChatRequest(BaseModel):
text: str
# === Root endpoint ===
@app.get("/")
async def root():
return {"message": "π Portfolio Chatbot API is running successfully!"}
# === Chatbot endpoint ===
@app.post("/chatbot")
async def chatbot(req: ChatRequest):
"""
Endpoint utama untuk memproses input teks dan mengembalikan intent serta respon.
"""
intent = "fallback"
# Pastikan model sudah termuat
if session is None or tokenizer is None:
return {"reply": responses["fallback"], "intent": "error_loading"}
try:
# === Tokenisasi input ===
inputs = tokenizer(
req.text,
return_tensors="np", # output dalam format numpy
padding=True,
truncation=True,
max_length=128
)
# === Siapkan input sesuai nama yang diminta oleh model ===
expected_inputs = [i.name for i in session.get_inputs()]
ort_inputs = {k: v.astype(np.int64) for k, v in inputs.items() if k in expected_inputs}
# === Jalankan inferensi ONNX ===
ort_outputs = session.run(None, ort_inputs)
logits = ort_outputs[0]
# === Prediksi intent ===
pred_id = int(np.argmax(logits, axis=1)[0])
intent = id2label.get(pred_id, "fallback")
# === Ambil respon ===
reply = responses.get(intent, responses["fallback"])
print(f"π§ Input: {req.text} | Intent: {intent} | Reply: {reply}")
return {"reply": reply, "intent": intent}
except Exception as e:
print("β Runtime error:", e)
traceback.print_exc()
return {"reply": "β οΈ Internal server error.", "intent": intent}
|