Spaces:
Running
Running
from flask import Flask, render_template, request, jsonify | |
from chat_indobert import get_response | |
import json | |
import torch | |
import numpy as np | |
from transformers import AutoTokenizer, AutoModelForSequenceClassification | |
from torch.utils.data import Dataset, DataLoader | |
from sklearn.metrics import precision_recall_fscore_support, classification_report | |
# Membuat instance dari Flask | |
app = Flask(__name__) | |
# Load dataset untuk mendapatkan daftar tags (intents) | |
with open('datasets_new.json', 'r') as f: | |
datasets = json.load(f) | |
tags = sorted(set(dataset['tag'] for dataset in datasets['intents'])) | |
# Load dataset uji mandiri dari datasets_uji_mandiri.json | |
with open('datasets_uji_mandiri.json', 'r') as f: | |
test_data = json.load(f) | |
# Ekstrak teks dan intent yang benar dari datasets_uji_mandiri.json | |
texts_test = [item['text'] for item in test_data] | |
true_intents = [item['true_intent'] for item in test_data] | |
# Konversi intent ke indeks label berdasarkan tags | |
labels_test = [tags.index(intent) for intent in true_intents if intent in tags] | |
# Periksa apakah ada intent yang tidak ada dalam tags | |
missing_intents = set(true_intents) - set(tags) | |
if missing_intents: | |
print(f"Peringatan: Intent {missing_intents} tidak ditemukan dalam tags. Pastikan datasets_new.json mencakup semua intent.") | |
# Load IndoBERT model dan tokenizer | |
tokenizer = AutoTokenizer.from_pretrained("indobert_model") | |
model = AutoModelForSequenceClassification.from_pretrained("indobert_model") | |
# Gunakan GPU kalau ada | |
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') | |
model.to(device) | |
model.eval() | |
# Dataset class untuk evaluasi | |
class IndoBERTDataset(Dataset): | |
def __init__(self, texts, labels): | |
self.texts = texts | |
self.labels = labels | |
def __getitem__(self, idx): | |
encoding = tokenizer(self.texts[idx], padding='max_length', truncation=True, max_length=20, return_tensors='pt') | |
return { | |
'input_ids': encoding['input_ids'].squeeze(), | |
'attention_mask': encoding['attention_mask'].squeeze(), | |
'labels': torch.tensor(self.labels[idx], dtype=torch.long) | |
} | |
def __len__(self): | |
return len(self.texts) | |
# Buat dataset dan dataloader untuk data uji mandiri | |
test_dataset = IndoBERTDataset(texts_test, labels_test) | |
test_loader = DataLoader(test_dataset, batch_size=8) | |
# Evaluasi model pada data uji mandiri | |
test_correct = 0 | |
test_total = 0 | |
test_preds = [] | |
test_labels = [] | |
with torch.no_grad(): | |
for batch in test_loader: | |
inputs = {k: v.to(device) for k, v in batch.items() if k != 'labels'} | |
labels = batch['labels'].to(device) | |
outputs = model(**inputs, labels=labels) | |
_, predicted = torch.max(outputs.logits, 1) | |
test_total += labels.size(0) | |
test_correct += (predicted == labels).sum().item() | |
test_preds.extend(predicted.cpu().numpy()) | |
test_labels.extend(labels.cpu().numpy()) | |
# Hitung metrik evaluasi | |
test_accuracy = 100 * test_correct / test_total | |
test_precision, test_recall, test_f1, _ = precision_recall_fscore_support(test_labels, test_preds, average='weighted', zero_division=0) | |
# Laporan klasifikasi untuk data uji | |
unique_test_labels = sorted(set(test_labels)) | |
filtered_test_tags = [tags[i] for i in unique_test_labels] | |
classification_report_str = classification_report(test_labels, test_preds, labels=unique_test_labels, target_names=filtered_test_tags, zero_division=0) | |
# Simpan hasil evaluasi dalam dictionary | |
evaluation_results = { | |
'accuracy': test_accuracy, | |
'precision': test_precision, | |
'recall': test_recall, | |
'f1_score': test_f1, | |
'classification_report': classification_report_str | |
} | |
# Mendefinisikan rute untuk halaman utama dengan metode GET | |
def index_get(): | |
return render_template("base.html") | |
# Mendefinisikan rute untuk memproses permintaan prediksi dengan metode POST | |
def predict(): | |
text = request.get_json().get("message") | |
if not text: | |
return jsonify({"answer": "Mohon masukkan pesan."}) | |
# Tokenisasi input pengguna | |
encoding = tokenizer(text, padding='max_length', truncation=True, max_length=20, return_tensors='pt') | |
input_ids = encoding['input_ids'].to(device) | |
attention_mask = encoding['attention_mask'].to(device) | |
# Dapatkan output dari model | |
with torch.no_grad(): | |
outputs = model(input_ids, attention_mask=attention_mask) | |
logits = outputs.logits | |
probabilities = torch.softmax(logits, dim=1).cpu().numpy()[0] | |
# Temukan tag yang diprediksi | |
predicted_index = np.argmax(probabilities) | |
predicted_tag = tags[predicted_index] | |
# Ambil respons dari dataset berdasarkan tag yang diprediksi | |
for intent in datasets['intents']: | |
if intent['tag'] == predicted_tag: | |
response = intent['responses'][0] # Ambil respons pertama | |
break | |
else: | |
response = "Maaf, saya tidak mengerti pertanyaan Anda." | |
# Siapkan data respons dengan probabilitas untuk semua tag | |
message = { | |
"answer": response, | |
"predicted_tag": predicted_tag, | |
"probabilities": {tag: float(prob) for tag, prob in zip(tags, probabilities)} | |
} | |
return jsonify(message) | |
# Mendefinisikan rute untuk menampilkan hasil akurasi | |
def show_accuracy(): | |
return render_template("accuracy.html", evaluation=evaluation_results) | |
# Menjalankan aplikasi Flask dalam mode debug | |
if __name__ == "__main__": | |
app.run(debug=True) |