Skip to main content

Match recall segments with story segments.

Project description

rMatch

Automated matching of recall segments to story segments.

Ruff packaging framework: uv pre-commit

rMatch links each segment of a participant's spoken recall to the corresponding segment(s) in the original story, using a large language model. Use Claude via API for best accuracy, or google/gemma-4-31B-it to run fully locally:

Model short text (N=21) long text (N=19) movie transcripts (N=138)
Claude Opus 4.6 0.87 0.8 0.7
google/gemma-4-31B-it 0.84 ? 0.67

Pearson r with human ratings.

Table of contents

Quickstart

from rmatch import MatcherAnthropic

matcher = MatcherAnthropic(api_key="your_api_key")
matches = matcher.match(
    story_segments=["The cat sat on the mat.", "It purred softly."],
    recall_segments=["A cat was on a mat."],
)
# [(0, [0])]  — recall segment 0 matched story segment 0

You can also put your API key in a .env file instead of passing it directly (see API keys).

Installation

pip install rmatch              # API matchers + huggingface fallback
pip install rmatch[cuda]        # NVIDIA GPU (vLLM)
pip install rmatch[mac]         # Apple Silicon (MLX)

Requires Python 3.12 or 3.13.

Choosing a matcher

Matcher When to use
anthropic Best accuracy; needs an Anthropic API key (default model: claude-opus-4-6)
openai Cloud alternative; needs an OpenAI API key (default: gpt-4.1)
cuda Run locally on NVIDIA GPUs with vLLM (pip install rmatch[cuda])
mac Run locally on Apple Silicon (pip install rmatch[mac])
huggingface Portable local fallback; works on CPU, CUDA, or MPS
matcher = get_matcher("anthropic")   # or "openai", "mac", "cuda", "huggingface"

Matcher options

All keyword arguments are passed to get_matcher(name, **kwargs).

Shared across matchers

Argument Default Notes
model_name matcher-specific Override the default model
prompt "primary" See Prompts
max_retries 10 Retries when the model output cannot be parsed
api_key from .env / env See API keys
window_size 5 Recall context window

anthropic, openai

Argument Default Notes
dry_run False Estimate API cost without calling the API

cuda

Argument Default Notes
max_new_tokens 300 Max tokens generated per segment
max_model_len 90000 Max sequence length (prompt + generation); lower to save GPU memory
tensor_parallel_size auto Number of GPUs to use
gpu_memory_utilization 0.90 Fraction of GPU memory to use
verbose_errors False Log raw output on parse failures

mac

Argument Default Notes
window_size 5 Recall context window
max_new_tokens 300 Max tokens generated per segment
verbose_errors False Log raw output on parse failures

huggingface

Argument Default Notes
window_size 5 Recall context window
quantization none "4bit" or "8bit" to reduce memory
batch_size 64 Inference batch size
max_new_tokens 300 Max tokens generated per segment
verbose_errors False Log raw output on parse failures

matcher.match(story_segments, recall_segments)

  • story_segments — ordered list of story segment strings (ground truth).
  • recall_segments — ordered list of one participant's recall segment strings.

Returns one entry per recall segment in the format of (recall_index, [story_indices]) tuples (0-based):

[
    (0, [2, 5]),   # recall segment 0 -> story segments 2 and 5
    (1, []),       # recall segment 1 -> no match
    (2, [0]),      # recall segment 2 -> story segment 0
]

Output format

From matcher.match, you get a list of (recall_index, [story_indices]) tuples (0-based).

API keys

Resolved in this order (first match wins):

  1. api_key argument in Python
  2. .env file in the working directory
  3. Environment variables in your shell
ANTHROPIC_API_KEY="your_api_key"   # anthropic
OPENAI_API_KEY="your_api_key"      # openai
HF_TOKEN="your_hf_token"           # huggingface, mac, cuda (model download)

Prompts

All matchers share the same prompt templates. Pass prompt="primary_no_story" (etc.) to get_matcher. Default is primary.

Prompt Full story Segmented story Chain of thought Notes
primary yes yes yes Default; most complete prompt
primary_no_story no yes yes For long stories that exceed the context window
primary_no_cot yes yes no Ablation: no chain-of-thought
primary_no_story_no_cot no yes no Minimal prompt
secondary yes yes yes Alternative wording with XML output

Batch matching from files directly

If your story and recalls are already saved as .txt or .json files:

from pathlib import Path
from rmatch import match, MatcherCuda


matcher_gemma = MatcherCuda()

results = match(
    matcher=matcher_gemma,
    story_file=Path("story.txt"),
    recall_file=Path("recalls/"),   # file or directory of subject files
)

This loads all subjects, runs matching, and writes a JSON results file next to your recall data with the following format:

{
  "matcher_name": "anthropic",
  "story_name": "story",
  "story_segmentation": "lines",
  "recall_segmentation": "lines",
  "matches": {
    "sub-001": [[0, [3, 7]], [1, [12]]],
    "sub-002": [[0, [1]], [1, [5, 6]]]
  }
}

Each subject maps to a list of [recall_segment_id, [matched_story_segment_ids...]] pairs.

Benchmarks

Requires rBench:

git clone git@github.com:GabrielKP/rBench.git

Add to .env or environment:

BENCHMARK_ROOT="path/to/rBench"

Run:

uv run src/rmatch/evaluate.py {alice,monthiversary,memsearch}

CLI

If you prefer the command line over a Python script:

rmatch story.txt recalls/ --matcher anthropic

See rmatch --help for all options (model, prompt, window size, etc.).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rmatch-0.4.0.tar.gz (278.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rmatch-0.4.0-py3-none-any.whl (37.6 kB view details)

Uploaded Python 3

File details

Details for the file rmatch-0.4.0.tar.gz.

File metadata

  • Download URL: rmatch-0.4.0.tar.gz
  • Upload date:
  • Size: 278.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rmatch-0.4.0.tar.gz
Algorithm Hash digest
SHA256 181cfa3d83c79480d8aa1478093658fef27f2b34a125ef860e87c37f41031127
MD5 55f0f73d33eba1fad3c29152d6962d8c
BLAKE2b-256 e76de22a0f5cf485b03b27b0620197c00fbbf99673adfc4327af3e2949367cc7

See more details on using hashes here.

Provenance

The following attestation bundles were made for rmatch-0.4.0.tar.gz:

Publisher: publish.yml on GabrielKP/rMatch

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rmatch-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: rmatch-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 37.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rmatch-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9b891214dfc0f2b0878e31ccda71bcf7819440f2fbc6adcf5f84561137984893
MD5 78d1ce265a78c7c555b986d3ac6a057c
BLAKE2b-256 1462bdba7c17ae7d3cc0577722042a844ecba01539f5024d3c1d09b441527733

See more details on using hashes here.

Provenance

The following attestation bundles were made for rmatch-0.4.0-py3-none-any.whl:

Publisher: publish.yml on GabrielKP/rMatch

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page