Fast fuzzy finding in Python

If you've never used fzf, it's a blazingly fast fuzzy matcher tool for CLI. I wanted to use something similar for searching through Gradio, and I found a fast fuzzy matcher written in Rust that has Python bindings: Blueshoe/pfuzzer.

I'm using this for a dashboard I made for creating and improving Anki decks using LLMs:

20251115-Fast fuzzy finding in Python.png

Here's some example code:

#!/usr/bin/env python3
# /// script
# dependencies = [
#   "gradio",
#   "pfuzzer @ git+https://github.com/Blueshoe/pfuzzer.git",
# ]
# ///

import gradio as gr
from pfuzzer import Pfuzzer

CARDS = [
    "What is a Python list comprehension?",
    "Explain JavaScript closures",
    "What is the Pythagorean theorem?",
    "How does gradient descent work?",
    "What is a SQL JOIN?",
    "Explain React hooks",
    "What is Big O notation?",
    "How does quicksort work?",
    "What is a hash table?",
    "Explain neural networks",
    "What is recursion?",
    "How does TCP/IP work?",
    "What is functional programming?",
    "Explain database normalization",
    "What is the DOM?",
]
N = 5

def search(query: str) -> str:
    """Fuzzy search using pfuzzer (fzf algorithm)"""
    if not query.strip():
        return ""
    
    fuzzer = Pfuzzer()
    scores = fuzzer.compare_strings(CARDS, query)
    

    matches = [(i, score) for i, score in enumerate(scores) if score]
    matches.sort(key=lambda x: x[1], reverse=True)
    
    if not matches:
        return f"No matches for '{query}'"
    
    results = [f"πŸ” Found {len(matches)} matches:\n"]
    for i, score in matches[:N]:
        results.append(f"{score}% - {CARDS[i]}")
    
    return "\n".join(results)


with gr.Blocks(title="Fuzzy Search Demo") as demo:
    gr.Markdown("# Fast Fuzzy Search with pfuzzer")
    
    search_input = gr.Textbox(label="Search", placeholder="Try: 'python', 'net', 'sql'...")
    search_output = gr.Textbox(label="Results", lines=8)
    
    # trigger_mode="always_last" cancels the current search and starts a new one if you type something new
    search_input.change(
        search,
        inputs=search_input,
        outputs=search_output,
        trigger_mode="always_last"
    )

if __name__ == "__main__":
    demo.launch()

At first I was confused by the source code since there are no Python files. #TIL that Rust lets you create Python modules without ever writing any actual Python using pyo3. Neat! I love all the Python tooling like uv and ruff coming out these days.

Copyright Ricardo Decal. ricardodecal.com