| import gradio as gr |
| import json |
| import os |
| import re |
| from collections import Counter |
|
|
| |
|
|
| KB_PATH = "knowledge_base_v4.json" |
|
|
| |
| 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", {}) |
|
|
| |
|
|
| def find_best_pattern(query): |
| """Tìm pattern phù hợp nhất với query của user""" |
| query = query.upper() |
| |
| |
| for pattern in PATTERNS: |
| if pattern.upper() == query: |
| return pattern, 1.0 |
| |
| |
| for pattern in PATTERNS: |
| if pattern.upper() in query or query in pattern.upper(): |
| return pattern, 0.9 |
| |
| |
| 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 |
| |
| |
| for fk in FAILURE_KEYS: |
| if fk.upper() in query: |
| return fk, 0.5 |
| |
| return None, 0 |
|
|
| |
|
|
| 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')." |
| |
| |
| 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." |
| |
| |
| 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_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_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 = 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 = 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"") |
| |
| |
| 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"") |
| |
| |
| 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) |
|
|
| |
|
|
| def chat(message, history): |
| """Chat function for Gradio""" |
| response = build_response(message) |
| return response |
|
|
| |
| 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() |
|
|