Add nickname detection and AI-based ambiguous message handling

Enhanced bot to respond to partial names and ambiguous greetings:

MentionDetector improvements (utils.py):
- Auto-generate nicknames from bot name (kenearosmd → Kene, Kenearos)
- Add patterns for all nicknames (full name + partial names)
- New is_ambiguous_greeting() method for greetings without clear mention
- Updated extract_content() to remove all name variants

Bot logic improvements (chatbot.py):
- New check_if_addressed() method uses AI to determine if ambiguous
  messages are directed at the bot
- AI analyzes greetings like "Hi wie gehts" and decides if bot should respond
- If AI confirms, message is processed like a normal mention

Recognition examples:
- kenearosmd: wie gehts → responds 
- Kene was meinst du → responds 
- Kenearos! → responds 
- Hi wie gehts → AI checks context → responds if appropriate 

This prevents the bot from spamming on every greeting while still
being responsive when addressed indirectly.
This commit is contained in:
Claude 2026-01-02 21:30:20 +00:00
parent 0b2d166a58
commit 5e0ebbb1c4
No known key found for this signature in database
2 changed files with 130 additions and 16 deletions

View file

@ -110,6 +110,62 @@ class EugenBot(irc.bot.SingleServerIRCBot):
self.handle_mention(username, message),
self.loop
)
# Check for ambiguous greetings (AI will decide if bot is addressed)
elif self.detector.is_ambiguous_greeting(message):
self.logger.debug(f"Ambiguous greeting detected from {username}: {message}")
if self.dashboard:
self.dashboard.log_event("info", {"message": f"Ambiguous greeting: {message}"})
# Ask AI if bot is addressed
asyncio.run_coroutine_threadsafe(
self.check_if_addressed(username, message),
self.loop
)
async def check_if_addressed(self, username, message):
"""
Check with AI if an ambiguous message is addressed to the bot
Args:
username (str): User who sent the message
message (str): Ambiguous message (e.g., "Hi wie gehts")
"""
try:
# Ask AI if the message is directed at the bot
check_prompt = f"""You are {self.bot_name}, a Twitch chat bot.
A user named {username} just wrote: "{message}"
This message doesn't explicitly mention you, but it might be directed at you.
Consider:
- Is this a greeting or question that could be for the bot?
- Is there recent conversation context suggesting it's for you?
- Or is it likely a general chat message not for the bot?
Respond with ONLY "YES" if the message is likely addressed to you, or "NO" if not.
Do not explain, just answer YES or NO."""
messages = [{"role": "user", "content": check_prompt}]
self.logger.debug(f"Asking AI if addressed: {message}")
response = await self.ai.get_response(messages)
if response and "YES" in response.upper():
self.logger.debug(f"AI says message is for bot: {message}")
if self.dashboard:
self.dashboard.log_event("info", {"message": f"AI confirmed: message is for bot"})
# Treat as mention and respond
await self.handle_mention(username, message)
else:
self.logger.debug(f"AI says message is not for bot: {message}")
if self.dashboard:
self.dashboard.log_event("info", {"message": f"AI confirmed: message is not for bot"})
except Exception as e:
self.logger.error(f"Error checking if addressed: {str(e)}")
if self.dashboard:
self.dashboard.log_event("error", {"error": str(e)})
async def handle_mention(self, username, message):
"""

View file

@ -13,19 +13,53 @@ class MentionDetector:
def __init__(self, bot_name="Eugen"):
self.bot_name = bot_name
# Generate nicknames/partial names from bot_name
self.nicknames = self._generate_nicknames(bot_name)
# Create patterns for various mention formats
# More flexible patterns that catch most cases
self.patterns = [
rf"@{bot_name}\b", # @Eugen (with word boundary)
rf"\b{bot_name}[:!?.,]", # Eugen: Eugen! Eugen? Eugen, Eugen.
rf"^{bot_name}\b", # Eugen at start of message
rf"\b{bot_name}\b", # Eugen anywhere as whole word
]
# Include bot name and all nicknames
all_names = [bot_name] + self.nicknames
self.patterns = []
for name in all_names:
self.patterns.extend([
rf"@{name}\b", # @name (with word boundary)
rf"\b{name}[:!?.,]", # name: name! name? name, name.
rf"^{name}\b", # name at start of message
rf"\b{name}\b", # name anywhere as whole word
])
# Case-insensitive compilation
self.compiled_patterns = [
re.compile(pattern, re.IGNORECASE) for pattern in self.patterns
]
# Patterns for ambiguous greetings (might be directed at bot)
self.greeting_patterns = [
r"^(hi|hey|hallo|hello|servus|moin)(\s|$|\W)",
r"^(wie\s+geht'?s|wie\s+gehts|how\s+are\s+you)",
r"^(alles\s+klar|everything\s+ok)",
]
self.compiled_greetings = [
re.compile(pattern, re.IGNORECASE) for pattern in self.greeting_patterns
]
def _generate_nicknames(self, bot_name):
"""Generate common nicknames from bot name"""
nicknames = []
# For kenearosmd, generate: Kene, Kenearos
if len(bot_name) >= 4:
nicknames.append(bot_name[:4]) # First 4 chars (Kene)
if len(bot_name) >= 8:
nicknames.append(bot_name[:8]) # First 8 chars (Kenearos)
# Remove duplicates and the full name
nicknames = [n for n in set(nicknames) if n != bot_name]
return nicknames
def is_mentioned(self, message):
"""
Check if bot was mentioned in message
@ -44,6 +78,28 @@ class MentionDetector:
return True
return False
def is_ambiguous_greeting(self, message):
"""
Check if message is an ambiguous greeting that might be for the bot
Args:
message (str): Chat message to check
Returns:
bool: True if message is an ambiguous greeting
"""
if not message:
return False
# Don't check if there's already a clear mention
if self.is_mentioned(message):
return False
for pattern in self.compiled_greetings:
if pattern.search(message):
return True
return False
def extract_content(self, message):
"""
Extract message content without the mention
@ -57,20 +113,22 @@ class MentionDetector:
if not message:
return ""
# Remove bot name mentions from the message
# Remove bot name and nickname mentions from the message
content = message
all_names = [self.bot_name] + self.nicknames
# Remove @mention at start
content = re.sub(rf"^@{self.bot_name}\b[,:]?\s*", "", content, flags=re.IGNORECASE)
for name in all_names:
# Remove @mention at start
content = re.sub(rf"^@{name}\b[,:]?\s*", "", content, flags=re.IGNORECASE)
# Remove bot name at start with optional punctuation
content = re.sub(rf"^{self.bot_name}\b[,:]?\s*", "", content, flags=re.IGNORECASE)
# Remove name at start with optional punctuation
content = re.sub(rf"^{name}\b[,:]?\s*", "", content, flags=re.IGNORECASE)
# Remove bot name at end with optional punctuation
content = re.sub(rf"\s*\b{self.bot_name}[,!?.]?\s*$", "", content, flags=re.IGNORECASE)
# Remove name at end with optional punctuation
content = re.sub(rf"\s*\b{name}[,!?.]?\s*$", "", content, flags=re.IGNORECASE)
# Remove bot name in middle with punctuation
content = re.sub(rf"\s*\b{self.bot_name}[,:!?]\s*", " ", content, flags=re.IGNORECASE)
# Remove name in middle with punctuation
content = re.sub(rf"\s*\b{name}[,:!?]\s*", " ", content, flags=re.IGNORECASE)
return content.strip()