|
|
""" |
|
|
Advanced features for chatbot: follow-up suggestions, ambiguity detection, explanations. |
|
|
""" |
|
|
from typing import List, Dict, Any, Optional |
|
|
from hue_portal.core.models import Fine, Procedure, Office, Advisory |
|
|
|
|
|
|
|
|
def suggest_follow_up_questions(query: str, results: List[Any], intent: str) -> List[str]: |
|
|
""" |
|
|
Suggest follow-up questions based on query and results. |
|
|
|
|
|
Args: |
|
|
query: Original query. |
|
|
results: Retrieved results. |
|
|
intent: Detected intent. |
|
|
|
|
|
Returns: |
|
|
List of suggested follow-up questions. |
|
|
""" |
|
|
suggestions = [] |
|
|
|
|
|
if intent == "search_fine": |
|
|
if results: |
|
|
|
|
|
suggestions.append("Còn mức phạt nào khác không?") |
|
|
suggestions.append("Điều luật liên quan là gì?") |
|
|
suggestions.append("Biện pháp khắc phục như thế nào?") |
|
|
else: |
|
|
suggestions.append("Bạn có thể cho biết cụ thể loại vi phạm không?") |
|
|
|
|
|
elif intent == "search_procedure": |
|
|
if results: |
|
|
suggestions.append("Hồ sơ cần chuẩn bị gì?") |
|
|
suggestions.append("Lệ phí là bao nhiêu?") |
|
|
suggestions.append("Thời hạn xử lý là bao lâu?") |
|
|
suggestions.append("Nộp hồ sơ ở đâu?") |
|
|
else: |
|
|
suggestions.append("Bạn muốn tìm thủ tục nào cụ thể?") |
|
|
|
|
|
elif intent == "search_office": |
|
|
if results: |
|
|
suggestions.append("Số điện thoại liên hệ?") |
|
|
suggestions.append("Giờ làm việc như thế nào?") |
|
|
suggestions.append("Địa chỉ cụ thể ở đâu?") |
|
|
else: |
|
|
suggestions.append("Bạn muốn tìm đơn vị nào?") |
|
|
|
|
|
elif intent == "search_advisory": |
|
|
if results: |
|
|
suggestions.append("Còn cảnh báo nào khác không?") |
|
|
suggestions.append("Cách phòng tránh như thế nào?") |
|
|
else: |
|
|
suggestions.append("Bạn muốn tìm cảnh báo về chủ đề gì?") |
|
|
|
|
|
return suggestions[:3] |
|
|
|
|
|
|
|
|
def detect_ambiguity(query: str, results_count: int, confidence: float) -> Tuple[bool, Optional[str]]: |
|
|
""" |
|
|
Detect if query is ambiguous. |
|
|
|
|
|
Args: |
|
|
query: User query. |
|
|
results_count: Number of results found. |
|
|
confidence: Confidence score. |
|
|
|
|
|
Returns: |
|
|
Tuple of (is_ambiguous, ambiguity_reason). |
|
|
""" |
|
|
query_lower = query.lower() |
|
|
query_words = query.split() |
|
|
|
|
|
|
|
|
if len(query_words) <= 2: |
|
|
return (True, "Câu hỏi quá ngắn, cần thêm thông tin") |
|
|
|
|
|
|
|
|
if results_count > 10 and confidence < 0.5: |
|
|
return (True, "Kết quả quá nhiều, cần cụ thể hơn") |
|
|
|
|
|
|
|
|
generic_queries = ["thông tin", "tìm kiếm", "hỏi", "giúp"] |
|
|
if any(gq in query_lower for gq in generic_queries) and len(query_words) <= 3: |
|
|
return (True, "Câu hỏi chung chung, cần cụ thể hơn") |
|
|
|
|
|
return (False, None) |
|
|
|
|
|
|
|
|
def generate_explanation(result: Any, query: str, score: Optional[float] = None) -> str: |
|
|
""" |
|
|
Generate explanation for why a result is relevant. |
|
|
|
|
|
Args: |
|
|
result: Result object. |
|
|
result_type: Type of result. |
|
|
query: Original query. |
|
|
score: Relevance score. |
|
|
|
|
|
Returns: |
|
|
Explanation string. |
|
|
""" |
|
|
result_type = type(result).__name__.lower() |
|
|
explanation_parts = [] |
|
|
|
|
|
if "fine" in result_type: |
|
|
name = getattr(result, "name", "") |
|
|
code = getattr(result, "code", "") |
|
|
explanation_parts.append(f"Kết quả này phù hợp vì:") |
|
|
if code: |
|
|
explanation_parts.append(f"- Mã vi phạm: {code}") |
|
|
if name: |
|
|
explanation_parts.append(f"- Tên vi phạm: {name}") |
|
|
if score: |
|
|
explanation_parts.append(f"- Độ phù hợp: {score:.0%}") |
|
|
|
|
|
elif "procedure" in result_type: |
|
|
title = getattr(result, "title", "") |
|
|
explanation_parts.append(f"Kết quả này phù hợp vì:") |
|
|
if title: |
|
|
explanation_parts.append(f"- Tên thủ tục: {title}") |
|
|
if score: |
|
|
explanation_parts.append(f"- Độ phù hợp: {score:.0%}") |
|
|
|
|
|
elif "office" in result_type: |
|
|
unit_name = getattr(result, "unit_name", "") |
|
|
explanation_parts.append(f"Kết quả này phù hợp vì:") |
|
|
if unit_name: |
|
|
explanation_parts.append(f"- Tên đơn vị: {unit_name}") |
|
|
if score: |
|
|
explanation_parts.append(f"- Độ phù hợp: {score:.0%}") |
|
|
|
|
|
elif "advisory" in result_type: |
|
|
title = getattr(result, "title", "") |
|
|
explanation_parts.append(f"Kết quả này phù hợp vì:") |
|
|
if title: |
|
|
explanation_parts.append(f"- Tiêu đề: {title}") |
|
|
if score: |
|
|
explanation_parts.append(f"- Độ phù hợp: {score:.0%}") |
|
|
|
|
|
return "\n".join(explanation_parts) if explanation_parts else "Kết quả này phù hợp với câu hỏi của bạn." |
|
|
|
|
|
|
|
|
def compare_results(results: List[Any], result_type: str) -> str: |
|
|
""" |
|
|
Compare multiple results and highlight differences. |
|
|
|
|
|
Args: |
|
|
results: List of result objects. |
|
|
result_type: Type of results. |
|
|
|
|
|
Returns: |
|
|
Comparison summary string. |
|
|
""" |
|
|
if len(results) < 2: |
|
|
return "" |
|
|
|
|
|
comparison_parts = ["So sánh các kết quả:"] |
|
|
|
|
|
if result_type == "fine": |
|
|
|
|
|
fine_amounts = [] |
|
|
for result in results[:3]: |
|
|
if hasattr(result, "min_fine") and hasattr(result, "max_fine"): |
|
|
if result.min_fine and result.max_fine: |
|
|
fine_amounts.append(f"{result.name}: {result.min_fine:,.0f} - {result.max_fine:,.0f} VNĐ") |
|
|
|
|
|
if fine_amounts: |
|
|
comparison_parts.extend(fine_amounts) |
|
|
|
|
|
elif result_type == "procedure": |
|
|
|
|
|
for result in results[:3]: |
|
|
title = getattr(result, "title", "") |
|
|
domain = getattr(result, "domain", "") |
|
|
level = getattr(result, "level", "") |
|
|
if title: |
|
|
comp = f"- {title}" |
|
|
if domain: |
|
|
comp += f" ({domain})" |
|
|
if level: |
|
|
comp += f" - Cấp {level}" |
|
|
comparison_parts.append(comp) |
|
|
|
|
|
return "\n".join(comparison_parts) |
|
|
|
|
|
|