Enhance help command to provide a dynamic list of available commands based on usage statistics. Implemented database querying for command usage and improved fallback mechanisms for command listing. Updated CommandManager to utilize the new method for better help text suggestions.

This commit is contained in:
agessaman
2025-12-29 16:46:57 -08:00
parent 53b31c20a5
commit 427b27fee3
2 changed files with 112 additions and 37 deletions
+15 -6
View File
@@ -422,13 +422,22 @@ class CommandManager:
return f"Help {command_name}: {help_text}"
# If still not found, return unknown command message with helpful suggestion
available_commands = []
for cmd_name, cmd_instance in self.commands.items():
available_commands.append(cmd_name)
if hasattr(cmd_instance, 'keywords'):
available_commands.extend(cmd_instance.keywords)
# Use the help command's method to get popular commands (only primary names, no aliases)
available_str = ""
if 'help' in self.commands:
help_command = self.commands['help']
if hasattr(help_command, 'get_available_commands_list'):
available_str = help_command.get_available_commands_list()
# Fallback if help command doesn't have the method
if not available_str:
# Only show primary command names, not keywords
primary_names = sorted([
cmd.name if hasattr(cmd, 'name') else name
for name, cmd in self.commands.items()
])
available_str = ', '.join(primary_names)
available_str = ', '.join(sorted(set(available_commands)))
if hasattr(self.bot, 'translator'):
return self.bot.translator.translate('commands.help.unknown', command=command_name, available=available_str)
return f"Unknown: {command_name}. Available: {available_str}. Try 'help' for command list."
+97 -31
View File
@@ -4,6 +4,8 @@ Help command for the MeshCore Bot
Provides help information for commands and general usage
"""
import sqlite3
from collections import defaultdict
from .base_command import BaseCommand
from ..models import MeshMessage
@@ -68,36 +70,100 @@ class HelpCommand(BaseCommand):
return help_text
def get_available_commands_list(self) -> str:
"""Get a formatted list of available commands"""
commands_list = ""
# Group commands by category
basic_commands = ['test', 'ping', 'help']
custom_syntax = ['t_phrase'] # Use the actual command key
special_commands = ['advert']
commands_list += "**Basic Commands:**\n"
for cmd in basic_commands:
if cmd in self.bot.command_manager.commands:
help_text = self.bot.command_manager.commands[cmd].get_help_text()
commands_list += f"• `{cmd}` - {help_text}\n"
commands_list += "\n**Custom Syntax:**\n"
for cmd in custom_syntax:
if cmd in self.bot.command_manager.commands:
help_text = self.bot.command_manager.commands[cmd].get_help_text()
# Add user-friendly aliases
if cmd == 't_phrase':
commands_list += f"• `t phrase` - {help_text}\n"
else:
commands_list += f"• `{cmd}` - {help_text}\n"
commands_list += "\n**Special Commands:**\n"
for cmd in special_commands:
if cmd in self.bot.command_manager.commands:
help_text = self.bot.command_manager.commands[cmd].get_help_text()
commands_list += f"• `{cmd}` - {help_text}\n"
return commands_list
"""Get a list of most popular commands in descending order, showing only one variant per command"""
try:
# Use the plugin loader's keyword mappings to map keywords/aliases to primary command names
plugin_loader = self.bot.command_manager.plugin_loader
keyword_mappings = plugin_loader.keyword_mappings.copy() if hasattr(plugin_loader, 'keyword_mappings') else {}
# Build a set of all primary command names and ensure they map to themselves
primary_names = set()
for cmd_name, cmd_instance in self.bot.command_manager.commands.items():
primary_name = cmd_instance.name if hasattr(cmd_instance, 'name') else cmd_name
primary_names.add(primary_name)
# Ensure primary name maps to itself in keyword_mappings
keyword_mappings[primary_name.lower()] = primary_name
# Query the database for command usage statistics
command_counts = defaultdict(int)
try:
with sqlite3.connect(self.bot.db_manager.db_path) as conn:
cursor = conn.cursor()
# Check if command_stats table exists
cursor.execute("""
SELECT name FROM sqlite_master
WHERE type='table' AND name='command_stats'
""")
if cursor.fetchone():
# Query command usage
cursor.execute("""
SELECT command_name, COUNT(*) as count
FROM command_stats
GROUP BY command_name
""")
for row in cursor.fetchall():
command_name = row[0]
count = row[1]
# Map keyword/alias to primary command name
# First try the plugin_loader's keyword_mappings
primary_name = keyword_mappings.get(command_name.lower())
# If not found in mappings, check if it's already a primary name
if primary_name is None:
if command_name in primary_names:
primary_name = command_name
else:
# Try to find which command this belongs to by checking all commands
for cmd_name, cmd_instance in self.bot.command_manager.commands.items():
# Check if command_name matches the command's name
cmd_primary = cmd_instance.name if hasattr(cmd_instance, 'name') else cmd_name
if cmd_primary == command_name:
primary_name = cmd_primary
break
# Check if it's a keyword of this command
if hasattr(cmd_instance, 'keywords'):
if command_name.lower() in [k.lower() for k in cmd_instance.keywords]:
primary_name = cmd_primary
break
# If still not found, use the command_name as-is
if primary_name is None:
primary_name = command_name
command_counts[primary_name] += count
except Exception as e:
self.logger.debug(f"Error querying command stats: {e}")
# If stats table doesn't exist or query fails, fall back to all commands
for cmd_name in self.bot.command_manager.commands.keys():
primary_name = self.bot.command_manager.commands[cmd_name].name if hasattr(self.bot.command_manager.commands[cmd_name], 'name') else cmd_name
command_counts[primary_name] = 0
# If we have stats, sort by count descending, otherwise use all commands
if command_counts:
# Sort by count descending, then by name for consistency
sorted_commands = sorted(
command_counts.items(),
key=lambda x: (-x[1], x[0])
)
# Extract just the command names (only primary names, no aliases)
command_names = [name for name, _ in sorted_commands]
else:
# Fallback: use all primary command names
command_names = sorted([
cmd.name if hasattr(cmd, 'name') else name
for name, cmd in self.bot.command_manager.commands.items()
])
# Return comma-separated list
return ', '.join(command_names)
except Exception as e:
self.logger.error(f"Error getting available commands list: {e}")
# Fallback to simple list of all command names
command_names = sorted([
cmd.name if hasattr(cmd, 'name') else name
for name, cmd in self.bot.command_manager.commands.items()
])
return ', '.join(command_names)