0
0
Lập trình
Flame Kris
Flame Krisbacodekiller

Xây Dựng API Kiểm Tra Tính Tương Tự Văn Bản Với SBERT và Flask

Đăng vào 4 tháng trước

• 5 phút đọc

Giới Thiệu

Trong thế giới công nghệ hiện đại, việc phát hiện các câu hỏi trùng lặp là một thách thức lớn, đặc biệt trong các hệ thống quản lý thi cử. Hãy tưởng tượng rằng hai giáo viên khác nhau đã nhập các câu hỏi tương tự nhau vào cơ sở dữ liệu nhưng với cách diễn đạt khác nhau. Điều này có thể gây ra sự nhầm lẫn và khó khăn cho cả giáo viên và sinh viên. Bài viết này sẽ hướng dẫn bạn xây dựng một API kiểm tra tính tương tự văn bản sử dụng Sentence Transformers (SBERT)Flask.

Sentence-Transformers (SBERT) Là Gì?

Sentence Transformers (SBERT) là một công cụ mạnh mẽ cho phép chuyển đổi câu thành các nhúng ngữ nghĩa. Điều này giúp chúng ta đo lường mức độ tương tự của hai câu không chỉ dựa trên từ ngữ mà còn dựa trên ý nghĩa. Chẳng hạn, hai câu sau đây:

“Thủ đô của Pháp là thành phố nào?”
“Thành phố nào là thủ đô của Pháp?”

Mặc dù chúng có cấu trúc ngữ pháp khác nhau, nhưng ý nghĩa của chúng là giống nhau. SBERT giúp nhận diện các câu hỏi trùng lặp một cách tự động, dễ dàng hơn so với việc sử dụng các phương pháp tìm kiếm từ khóa thông thường.

Thiết Lập Dự Án

Trước khi bắt đầu lập trình, hãy thiết lập một môi trường sạch sẽ cho dự án của bạn. Tôi khuyên bạn nên sử dụng môi trường ảo (venv) để giữ cho các phụ thuộc tách biệt và tránh xung đột với các dự án Python khác.

Cài Đặt Thư Viện Cần Thiết

Trong môi trường ảo của bạn, cài đặt các thư viện cần thiết:

Copy
pip install flask sentence-transformers

Các thư viện này sẽ giúp bạn:

  • Flask → tạo API REST của chúng ta.
  • Sentence Transformers → tải SBERT và tính toán các nhúng câu.

Xây Dựng Ứng Dụng Flask Cơ Bản

Trước khi đưa vào SBERT, hãy bắt đầu với một ứng dụng Flask tối giản nhất có thể để đảm bảo mọi thứ hoạt động.

Tạo một tệp có tên app.py trong thư mục dự án của bạn và thêm mã sau:

python Copy
from flask import Flask

# Tạo một instance của ứng dụng Flask
app = Flask(__name__)

# Định nghĩa một route cơ bản
@app.route('/')
def home():
    return "Xin chào, Flask đang chạy!"

if __name__ == '__main__':
    app.run(debug=True)

Khởi động server với:

Copy
python app.py

Hoặc

Copy
flask --app app run

Nếu mọi thứ được thiết lập đúng cách, bạn sẽ thấy thông báo:

Copy
* Đang chạy trên http://127.0.0.1:5000/ (Nhấn CTRL+C để thoát)

Mở trình duyệt và truy cập vào http://127.0.0.1:5000, bạn sẽ thấy:

Copy
Xin chào, Flask đang chạy!

Thêm Trợ Giúp Cho SBERT

Ứng dụng Flask của chúng ta đã chạy, giờ hãy tích hợp SBERT. Để giữ cho mã của chúng ta sạch sẽ, hãy tạo một tệp mới có tên embedding_service.py để xử lý ba điều:

  1. Tải mô hình một lần (lazy loading).
  2. Chuyển đổi văn bản thành các nhúng (vector).
  3. So sánh hai nhúng để lấy độ tương tự.

Bước 1: Tải Mô Hình

python Copy
from transformers import AutoTokenizer, AutoModel

# Biến toàn cục được tải chậm
_tokenizer = None
_model = None

def _load_model():
    """Tải tokenizer và mô hình SBERT một lần (lazy loading)."""
    global _tokenizer, _model
    if _tokenizer is None or _model is None:
        _tokenizer = AutoTokenizer.from_pretrained("sentence-transformers/all-MiniLM-L6-v2")
        _model = AutoModel.from_pretrained("sentence-transformers/all-MiniLM-L6-v2")
    return _tokenizer, _model

Bước 2: Chuyển Câu Thành Vector

python Copy
import torch
import torch.nn.functional as F

def mean_pooling(model_output, attention_mask):
    """Tính trung bình các nhúng token với attention mask (SBERT pooling tiêu chuẩn)."""
    token_embeddings = model_output[0]
    mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
    return torch.sum(token_embeddings * mask_expanded, 1) / torch.clamp(mask_expanded.sum(1), min=1e-9)


def to_vector(text):
    """Chuyển đổi một chuỗi (hoặc danh sách các chuỗi) thành nhúng SBERT."""
    if isinstance(text, str):
        text = [text]

    tokenizer, model = _load_model()
    encoded_input = tokenizer(text, padding=True, truncation=True, return_tensors="pt")

    with torch.no_grad():
        model_output = model(**encoded_input)

    sentence_embeddings = mean_pooling(model_output, encoded_input["attention_mask"])
    return F.normalize(sentence_embeddings, p=2, dim=1)

Bước 3: So Sánh Hai Câu

python Copy
def compare(text1, text2):
    """So sánh hai văn bản và trả về độ tương tự cosine."""
    v1 = to_vector(text1)
    v2 = to_vector(text2)
    similarity = torch.nn.functional.cosine_similarity(v1, v2)
    return similarity.item()

Xây Dựng REST API

Bây giờ chúng ta sẽ mở rộng tệp app.py để:

  • Chấp nhận hai văn bản đầu vào qua yêu cầu POST.
  • Sử dụng embedding_service để tính toán độ tương tự.
  • Trả về điểm tương tự dưới dạng JSON.

Bước 1: Nhập Trợ Giúp

Trong app.py, nhập trợ giúp mà chúng ta đã tạo:

python Copy
from flask import Flask, request, jsonify
from embedding_service import compare

Bước 2: Thêm Một Route Mới

Chúng ta sẽ định nghĩa một endpoint mới /similarity chấp nhận yêu cầu POST với hai văn bản.

python Copy
@app.route('/similarity', methods=['POST'])
def similarity():
    try:
        data = request.get_json()
        text1 = data.get("text1")
        text2 = data.get("text2")

        if not text1 or not text2:
            return jsonify({"error": "Cả text1 và text2 đều cần thiết"}), 400

        score = compare(text1, text2)
        return jsonify({
            "text1": text1,
            "text2": text2,
            "similarity": score
        })
    except Exception as e:
        return jsonify({"error": str(e)}), 500

Bước 3: Kiểm Tra API

Chạy lại ứng dụng Flask:

Copy
python app.py

Giờ đây, bạn có thể gửi yêu cầu POST với hai câu (sử dụng curl, Postman, hoặc httpie):

Copy
curl -X POST http://127.0.0.1:5000/similarity \
    -H "Content-Type: application/json" \
    -d '{"text1": "Thủ đô của Pháp là thành phố nào?", "text2": "Thành phố nào là thủ đô của Pháp?"}'

Nếu mọi thứ hoạt động tốt, bạn sẽ nhận được phản hồi JSON như sau:

Copy
{
  "similarity": 0.9416358470916748,
  "text1": "Thủ đô của Pháp là thành phố nào?",
  "text2": "Thành phố nào là thủ đô của Pháp?"
}

Kết Luận Và Các Bước Tiếp Theo

Trong bài viết này, chúng ta đã xây dựng một API kiểm tra tính tương tự văn bản từ đầu đến cuối. Để cải thiện dự án này, bạn có thể:

  • Đăng ký các nhúng vào một cơ sở dữ liệu vector (chẳng hạn như Pinecone, Weaviate, Qdrant hoặc FAISS).
  • Mở rộng API với FastAPI + Uvicorn cho môi trường sản xuất.
  • Thêm xác thực và ghi log nếu người khác sẽ sử dụng dịch vụ của bạn.

Với những cải tiến này, dịch vụ nhúng của bạn có thể phát triển thành một công cụ tìm kiếm ngữ nghĩa thực thụ.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào