File size: 2,409 Bytes
5d8fd4f | 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 | """
Conversation Engine — handles general chat using pattern-response pairs.
How it works:
1. Loads 'conversation.txt' at startup.
Each non-comment line format: PATTERN|||RESPONSE
2. Tries to match user input against compiled regex patterns.
3. Returns (response, matched):
matched = True → a pattern fired; use the response directly
matched = False → no match; caller should escalate to LLM fallback
EXTENSION POINT: The respond() method can be replaced wholesale with an LLM
call without touching any other module. Contract: (str) → (str, bool).
"""
import os
import re
from typing import List, Tuple
CONVERSATION_FILE = os.path.join(os.path.dirname(__file__), "conversation.txt")
def _load_patterns(filepath: str) -> List[Tuple[re.Pattern, str]]:
patterns: List[Tuple[re.Pattern, str]] = []
if not os.path.exists(filepath):
return patterns
with open(filepath, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
if "|||" not in line:
continue
pattern_part, response_part = line.split("|||", 1)
pattern_str = pattern_part.strip()
response_str = response_part.strip()
if not pattern_str or not response_str:
continue
try:
compiled = re.compile(pattern_str, re.IGNORECASE)
patterns.append((compiled, response_str))
except re.error:
continue
return patterns
class ConversationEngine:
"""Rule-based pattern-matching chat engine backed by conversation.txt."""
def __init__(self, conversation_file: str = CONVERSATION_FILE):
self.patterns = _load_patterns(conversation_file)
def respond(self, user_input: str) -> Tuple[str, bool]:
"""
Match user input against stored patterns.
Returns:
(response, matched)
matched = True → pattern found, response is ready to use
matched = False → no pattern matched; escalate to LLM
"""
text = user_input.strip()
for pattern, response in self.patterns:
if pattern.search(text):
return (response, True)
# Signal: no rule matched — let the LLM handle it
return ("", False)
|