File size: 6,296 Bytes
fa928ca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import gradio as gr
import json
import os
import re
from collections import Counter

# ── CONFIG ───────────────────────────────────────────────────────────────────

KB_PATH = "knowledge_base_v4.json"

# Load knowledge base
with open(KB_PATH, "r", encoding="utf-8") as f:
    KB = json.load(f)

PATTERNS = KB.get("by_pattern", {})
FAILURE_KEYS = KB.get("by_failure_key", {})
LOOKUP = KB.get("lookup", {})

# ── FUZZY SEARCH ───────────────────────────────────────────────────────────────

def find_best_pattern(query):
    """Tìm pattern phù hợp nhất với query của user"""
    query = query.upper()
    
    # 1. Exact match
    for pattern in PATTERNS:
        if pattern.upper() == query:
            return pattern, 1.0
    
    # 2. Substring match
    for pattern in PATTERNS:
        if pattern.upper() in query or query in pattern.upper():
            return pattern, 0.9
    
    # 3. Keyword matching
    query_words = set(re.findall(r'\b[A-Z]{2,}\b', query))
    best_match = None
    best_score = 0
    
    for pattern in PATTERNS:
        pattern_words = set(re.findall(r'\b[A-Z]{2,}\b', pattern.upper()))
        if not pattern_words:
            continue
        common = query_words & pattern_words
        score = len(common) / max(len(query_words), len(pattern_words))
        if score > best_score:
            best_score = score
            best_match = pattern
    
    if best_score >= 0.3:
        return best_match, best_score
    
    # 4. Failure key matching
    for fk in FAILURE_KEYS:
        if fk.upper() in query:
            return fk, 0.5  # Return failure key for broad matching
    
    return None, 0

# ── RESPONSE BUILDER ─────────────────────────────────────────────────────────

def build_response(query):
    """Xây dựng phản hồi từ knowledge base"""
    
    pattern, score = find_best_pattern(query)
    
    if not pattern:
        return "Không tìm thấy thông tin phù hợp. Vui lòng mô tả lỗi chi tiết hơn (ví dụ: 'lỗi channel 53', 'TRIP PE TEM', 'DDR failed')."
    
    # Get entry
    if pattern in PATTERNS:
        entry = PATTERNS[pattern]
    elif pattern in FAILURE_KEYS:
        entry = FAILURE_KEYS[pattern]
    else:
        return "Lỗi: Không tìm thấy dữ liệu."
    
    # Build response
    lines = []
    lines.append(f"## Phân tích lỗi: {pattern}")
    lines.append(f"")
    lines.append(f"- **Tổng cases:** {entry['total_cases']}")
    lines.append(f"- **Pass rate:** {entry['pass_rate']}%")
    lines.append(f"- **Pass:** {entry['pass_count']} | **Fail:** {entry['fail_count']}")
    lines.append(f"- **Board types:** {', '.join(entry.get('board_types', []))}")
    lines.append(f"")
    
    # BKM Procedure
    bkm_procs = entry.get('bkm_procedures', [])
    if bkm_procs:
        lines.append(f"## Quy trình BKM")
        for proc in bkm_procs[:3]:
            lines.append(f"- {proc}")
        lines.append(f"")
    
    # BKM Components
    bkm_comps = entry.get('bkm_components', [])
    if bkm_comps:
        lines.append(f"## Linh kiện theo BKM")
        lines.append(f"- {', '.join(bkm_comps[:10])}")
        lines.append(f"")
    
    # Priority Replace
    priority = entry.get('priority_replace', [])
    if priority:
        lines.append(f"## Thống kê - Linh kiện thay nhiều nhất")
        lines.append(f"| Rank | Linh kiện | Pass Rate | Số lần thay | Pass | Fail |")
        lines.append(f"|------|-----------|-----------|-------------|------|------|")
        for i, p in enumerate(priority[:10], 1):
            lines.append(f"| {i} | {p['component']} | {p['pass_rate']}% | {p['count']} | {p['pass']} | {p['fail']} |")
        lines.append(f"")
    
    # Best Actions
    best_actions = entry.get('best_actions', [])
    if best_actions:
        lines.append(f"## Hành động hiệu quả nhất")
        lines.append(f"| Rank | Hành động | Linh kiện | Pass Rate | Số lần | Pass | Fail |")
        lines.append(f"|------|-----------|-----------|-----------|--------|------|------|")
        for i, a in enumerate(best_actions[:10], 1):
            lines.append(f"| {i} | {a['action']} | {a['component']} | {a['pass_rate']}% | {a['count']} | {a['pass']} | {a['fail']} |")
        lines.append(f"")
    
    # Top Technicians
    techs = entry.get('top_technicians', [])
    if techs:
        lines.append(f"## Kỹ thuật viên tốt nhất")
        lines.append(f"| Rank | Tên | Pass Rate | Tổng cases | Pass |")
        lines.append(f"|------|-----|-----------|------------|------|")
        for i, t in enumerate(techs[:5], 1):
            lines.append(f"| {i} | {t['name']} | {t['pass_rate']}% | {t['total']} | {t['pass']} |")
        lines.append(f"")
    
    # Sample descriptions
    samples = entry.get('sample_original_descriptions', [])
    if samples:
        lines.append(f"## Ví dụ mô tả lỗi tương tự")
        for s in samples:
            lines.append(f"- {s}")
        lines.append(f"")
    
    lines.append(f"---")
    lines.append(f"*Độ chính xác tìm kiếm: {int(score*100)}%*")
    
    return "\n".join(lines)

# ── GRADIO UI ────────────────────────────────────────────────────────────────

def chat(message, history):
    """Chat function for Gradio"""
    response = build_response(message)
    return response

# Create interface
demo = gr.ChatInterface(
    fn=chat,
    title="HDMT Debug Assistant v4",
    description="Chatbot hỗ trợ debug HDMT boards. Mô tả lỗi để nhận phân tích và hướng dẫn.",
    examples=[
        "lỗi channel 53",
        "TRIP PE TEM",
        "DDR failed",
        "blue screen",
        "ADATE error",
        "FPGA calibration",
        "MISSING J18",
    ],
)

if __name__ == "__main__":
    demo.launch()