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