File size: 4,723 Bytes
cb3d0a6
679ad8d
cb3d0a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
679ad8d
cb3d0a6
 
 
 
 
679ad8d
 
 
 
 
cb3d0a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
679ad8d
 
 
 
cb3d0a6
679ad8d
 
 
 
 
cb3d0a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import pandas as pd
import numpy as np
import plotly.express as px
from sklearn.decomposition import PCA
from sklearn.metrics.pairwise import cosine_similarity
from sentence_transformers import SentenceTransformer
import warnings
warnings.filterwarnings('ignore')

# ==========================================
# 1. KHỞI TẠO MODELS (Load sẵn khi import file)
# ==========================================
print("[Utils] Đang khởi tạo các mô hình...")
model_sbert = SentenceTransformer('keepitreal/vietnamese-sbert')
model_e5 = SentenceTransformer('intfloat/multilingual-e5-base')
model_bge = SentenceTransformer('BAAI/bge-m3')
print("[Utils] Đã load xong 3 models!")

# ==========================================
# 2. DỮ LIỆU NỀN (KNOWLEDGE BASE)
# ==========================================
base_sentences = [
    "Tôi rất thích nghiên cứu về Trí tuệ nhân tạo.",
    "I love studying Artificial Intelligence.",
    "Con mèo đang ngủ trên ghế sofa.",
    "The cat is taking a nap on the couch.",
    "Công thức làm bánh pizza ngon nhất thế giới."
]

# ==========================================
# 3. HÀM XỬ LÝ LOGIC LÕI
# ==========================================
def process_embedding_analysis(user_text, base_text_input):
    """
    Nhận text từ UI, tính toán vector, trả về Biểu đồ Plotly và Dataframe kết quả.
    """
    if not user_text.strip():
        return None, None, None, pd.DataFrame()
    
    base_sentences = [s.strip() for s in base_text_input.split('\n') if s.strip()]
    
    if len(base_sentences) == 0:
        return None, None, None, pd.DataFrame({"Lỗi": ["Vui lòng nhập ít nhất 1 câu vào Dữ liệu nền!"]})
        
    # Tui viết một cái hàm nhỏ (helper function) bên trong để tái sử dụng code cho gọn nè
    def get_plot_and_sim(model, model_name, is_e5=False):
        sentences_to_encode = base_sentences.copy()
        query_to_encode = user_text
        
        # Xử lý riêng cho E5 (cái vụ gắn prefix á)
        if is_e5:
            sentences_to_encode = [f"passage: {text}" for text in base_sentences]
            query_to_encode = f"query: {user_text}"
            
        base_embeddings = model.encode(sentences_to_encode)
        user_embedding = model.encode([query_to_encode])
        similarities = cosine_similarity(user_embedding, base_embeddings)[0]
        
        # Tính PCA
        all_texts = sentences_to_encode + [query_to_encode]
        all_emb = model.encode(all_texts)
        
        n_samples = len(all_texts)
        n_comp = min(2, n_samples)
        pca = PCA(n_components=n_comp)
        emb_2d = pca.fit_transform(all_emb)
        # pca = PCA(n_components=2)
        # emb_2d = pca.fit_transform(all_emb)
        
        if n_comp == 1:
            emb_2d = np.hstack((emb_2d, np.zeros((n_samples, 1))))
        
        df_plot = pd.DataFrame({
            'X': emb_2d[:, 0], 'Y': emb_2d[:, 1],
            'Text': base_sentences + [user_text],
            'Loại': ["Dữ liệu nền"] * len(base_sentences) + ["Câu bạn nhập"]
        })
        
        # Vẽ hình
        fig = px.scatter(
            df_plot, x='X', y='Y', color='Loại', hover_name='Text',
            title=f"{model_name}",
            color_discrete_map={"Dữ liệu nền": "#636EFA", "Câu bạn nhập": "#EF553B"}
        )
        
        # Vẽ đường nối
        best_match_idx = similarities.argmax()
        fig.add_shape(
            type="line",
            x0=emb_2d[-1, 0], y0=emb_2d[-1, 1],
            x1=emb_2d[best_match_idx, 0], y1=emb_2d[best_match_idx, 1],
            line=dict(color="gray", width=2, dash="dot"), layer="below"
        )
        
        # Thu nhỏ margin xíu cho 3 biểu đồ đứng cạnh nhau không bị chật
        fig.update_traces(marker=dict(size=10, line=dict(width=1, color='white')))
        fig.update_layout(template="plotly_white", margin=dict(l=10, r=10, t=35, b=10))
        
        return fig, similarities

    # Bắt đầu chạy cả 3 con AI nè
    fig_sbert, sim_sbert = get_plot_and_sim(model_sbert, "1. Vietnamese SBERT")
    fig_e5, sim_e5 = get_plot_and_sim(model_e5, "2. Microsoft E5", is_e5=True)
    fig_bge, sim_bge = get_plot_and_sim(model_bge, "3. BAAI BGE-M3")
    
    # Gộp điểm của 3 con vào chung 1 cái bảng cho dễ nhìn á
    results_df = pd.DataFrame({
        "Câu trong Database": base_sentences,
        "SBERT (%)": [round(s * 100, 1) for s in sim_sbert],
        "E5 (%)": [round(s * 100, 1) for s in sim_e5],
        "BGE-M3 (%)": [round(s * 100, 1) for s in sim_bge]
    })
    
    return fig_sbert, fig_e5, fig_bge, results_df