- 添加本地 FAQ 库快速路径(问候语等社交响应) - 修复 Chatwoot 重启循环问题(PID 文件清理) - 添加 LLM 响应缓存(Redis 缓存,提升性能) - 添加智能推理模式(根据查询复杂度自动启用) - 添加订单卡片消息功能(Chatwoot 富媒体) - 增加 LLM 超时时间至 60 秒 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
122 lines
5.0 KiB
Python
122 lines
5.0 KiB
Python
"""
|
||
Local FAQ Library for instant responses
|
||
Common questions can be answered immediately without API calls
|
||
"""
|
||
import re
|
||
from typing import Optional, Dict
|
||
from .logger import get_logger
|
||
|
||
logger = get_logger(__name__)
|
||
|
||
|
||
class FAQLibrary:
|
||
"""Local FAQ library for instant common question responses"""
|
||
|
||
def __init__(self):
|
||
"""Initialize FAQ library with ONLY common greetings and social responses
|
||
|
||
Note: Business-related FAQs (register, order, payment, shipment, return, etc.)
|
||
should be handled by Strapi MCP to ensure accuracy and consistency.
|
||
This library only contains instant social responses for better UX.
|
||
"""
|
||
self.faqs = {
|
||
# ========== 问候类 Greetings ==========
|
||
"你好": "你好!我是您的B2B客户服务助手,很高兴为您服务。我可以帮您处理订单查询、产品咨询、售后问题等。请问有什么可以帮到您的吗?",
|
||
"您好": "您好!我是您的B2B客户服务助手,很高兴为您服务。我可以帮您处理订单查询、产品咨询、售后问题等。请问有什么可以帮到您的吗?",
|
||
"hi": "Hello! I'm your B2B customer service assistant. How can I help you today?",
|
||
"hello": "Hello! I'm here to assist you. How can I help you today?",
|
||
"hey": "Hey there! How can I help you today?",
|
||
|
||
# ========== 感谢类 Gratitude ==========
|
||
"谢谢": "不客气!如果还有其他问题,随时可以问我。祝您购物愉快!",
|
||
"感谢": "感谢您的支持!如有任何问题,随时联系我们。",
|
||
"thank you": "You're welcome! If you have any other questions, feel free to ask. Have a great day!",
|
||
"thanks": "You're welcome! Let me know if you need anything else.",
|
||
|
||
# ========== 再见类 Farewell ==========
|
||
"再见": "再见!如有需要,随时联系。祝您生活愉快!",
|
||
"bye": "Goodbye! Feel free to reach out anytime. Have a great day!",
|
||
"goodbye": "Goodbye! Have a wonderful day!",
|
||
|
||
# ========== 社交礼貌类 Social Politeness ==========
|
||
"早上好": "早上好!很高兴为您服务。请问有什么可以帮到您的吗?",
|
||
"下午好": "下午好!很高兴为您服务。请问有什么可以帮到您的吗?",
|
||
"晚上好": "晚上好!很高兴为您服务。请问有什么可以帮到您的吗?",
|
||
"good morning": "Good morning! How can I assist you today?",
|
||
"good afternoon": "Good afternoon! How can I assist you today?",
|
||
"good evening": "Good evening! How can I assist you today?",
|
||
}
|
||
|
||
# Compile regex patterns for fuzzy matching
|
||
self._compile_patterns()
|
||
|
||
def _compile_patterns(self):
|
||
"""Compile regex patterns for fuzzy FAQ matching"""
|
||
self.patterns = []
|
||
for keyword, response in self.faqs.items():
|
||
# Case-insensitive pattern with word boundaries
|
||
pattern = re.compile(re.escape(keyword), re.IGNORECASE)
|
||
self.patterns.append((pattern, response))
|
||
|
||
def find_match(self, query: str) -> Optional[str]:
|
||
"""Find matching FAQ response
|
||
|
||
Args:
|
||
query: User query text
|
||
|
||
Returns:
|
||
Matching FAQ response or None if no match found
|
||
"""
|
||
# Remove HTML tags and extra whitespace
|
||
clean_query = re.sub(r'<[^>]+>', '', query)
|
||
clean_query = ' '.join(clean_query.split())
|
||
|
||
# Try exact match first
|
||
if clean_query.lower() in (k.lower() for k in self.faqs.keys()):
|
||
for key, response in self.faqs.items():
|
||
if key.lower() == clean_query.lower():
|
||
logger.info("FAQ exact match", key=key, query=clean_query[:50])
|
||
return response
|
||
|
||
# Try fuzzy match (contains keyword)
|
||
for pattern, response in self.patterns:
|
||
if pattern.search(clean_query):
|
||
logger.info("FAQ fuzzy match", pattern=pattern.pattern, query=clean_query[:50])
|
||
return response
|
||
|
||
# No match found
|
||
logger.debug("No FAQ match found", query=clean_query[:50])
|
||
return None
|
||
|
||
def add_faq(self, keyword: str, response: str) -> None:
|
||
"""Add or update FAQ entry
|
||
|
||
Args:
|
||
keyword: Question keyword
|
||
response: Answer text
|
||
"""
|
||
self.faqs[keyword] = response
|
||
pattern = re.compile(re.escape(keyword), re.IGNORECASE)
|
||
self.patterns.append((pattern, response))
|
||
logger.info("FAQ added", keyword=keyword)
|
||
|
||
def get_all_keywords(self) -> list[str]:
|
||
"""Get all FAQ keywords
|
||
|
||
Returns:
|
||
List of FAQ keywords
|
||
"""
|
||
return list(self.faqs.keys())
|
||
|
||
|
||
# Global FAQ library instance
|
||
faq_library: Optional[FAQLibrary] = None
|
||
|
||
|
||
def get_faq_library() -> FAQLibrary:
|
||
"""Get or create global FAQ library instance"""
|
||
global faq_library
|
||
if faq_library is None:
|
||
faq_library = FAQLibrary()
|
||
return faq_library
|