Skip to content

Commit

Permalink
Add autocomplete functionality
Browse files Browse the repository at this point in the history
Uses fuzzy string matching from `rapidfuzz`. Still needs work to refactor
the ad-hoc similarity being computed in the FrameDb class.
  • Loading branch information
AbhijeetKrishnan committed Feb 17, 2024
1 parent 86ad7db commit 7cbe1fe
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 1 deletion.
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ dependencies = [
"discord.py",
"beautifulsoup4",
"Requests",
"lxml"
"lxml",
"rapidfuzz"
]

[project.urls]
Expand Down
2 changes: 2 additions & 0 deletions src/framedb/framedb.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ def _is_command_in_alias(command: str, move: Move) -> bool:
def _correct_character_name(char_name_query: str) -> str | None:
"Check if input in dictionary or in dictionary values"

char_name_query = char_name_query.lower().strip()
char_name_query = char_name_query.replace(" ", "_")
try:
return CharacterName(char_name_query).value
except ValueError:
Expand Down
21 changes: 21 additions & 0 deletions src/heihachi/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import discord
import discord.ext.commands
from rapidfuzz import process
from rapidfuzz.distance import JaroWinkler

from framedb import CharacterName, FrameDb, FrameService
from heihachi import button, embed
Expand Down Expand Up @@ -75,10 +77,29 @@ async def _character_command(interaction: discord.Interaction["FrameDataBot"], m

return _character_command

async def _character_name_autocomplete(
self, interaction: discord.Interaction["FrameDataBot"], current: str
) -> List[discord.app_commands.Choice[str]]:
"""
Autocomplete function for character names
Ref.: https://stackoverflow.com/a/75912806/6753162
"""
# TODO: honestly, just build a trie of all char names and aliases and use it here

char_choices = [char.pretty() for char in CharacterName]
trimmed_choices = process.extract(
current.lower(), char_choices, scorer=JaroWinkler.distance, limit=3, score_cutoff=0.9
)
return [discord.app_commands.Choice(name=char, value=char) for char, score, idx in trimmed_choices][
:25
] # Discord has a max choice number of 25 (https://github.com/Rapptz/discord.py/discussions/9241)

def _add_bot_commands(self) -> None:
"Add all frame commands to the bot"

@self.tree.command(name="fd", description="Frame data from a character move")
@discord.app_commands.autocomplete(character=self._character_name_autocomplete)
async def _frame_data_cmd(
interaction: discord.Interaction["FrameDataBot"], character: str, move: str
) -> None: # TODO: use command argument completion for char names
Expand Down

0 comments on commit 7cbe1fe

Please sign in to comment.