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()
|