#!/usr/bin/env python3 """Search cards by ABILITY TEXT rather than by an existing card. python3 tools/similar_text.py --deck decks/reaper-king-no-more "whenever a creature an opponent controls dies, put it onto the battlefield under your control" """ import sys, os, json, numpy as np from sentence_transformers import SentenceTransformer sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from deckctx import DeckContext, ROOT from cards import DB ctx = DeckContext.from_args() db = DB(blacklist_path=ctx.blacklist_path) identity = ctx.identity(db) k = 15 args = sys.argv[1:] if "-n" in args: i = args.index("-n"); k = int(args[i+1]); del args[i:i+2] q = " ".join(args) or sys.exit(__doc__) z = np.load(os.path.join(ROOT, "data", "embeddings.npz"), allow_pickle=True) names, emb = list(z["names"]), z["embedding"] m = SentenceTransformer("Alibaba-NLP/gte-modernbert-base", device="cuda", trust_remote_code=True) qv = m.encode([json.dumps({"text": q}, indent=2)], normalize_embeddings=True)[0] ci, legal = {}, {} for l in open(os.path.join(ROOT, "data", "oracle-cards.jsonl")): c = json.loads(l) ci[c["name"]] = set(c.get("color_identity", [])) legal[c["name"]] = c.get("legalities", {}).get("commander") == "legal" print(f'~~ cards whose text reads like: "{q}" ({"".join(sorted(identity))}-legal only) ~~') for i in np.argsort(-(emb @ qv)): n = names[i] if not legal.get(n) or not ci.get(n, {"W"}) <= identity: continue print(f" {(emb @ qv)[i]:.3f} {n}") k -= 1 if k == 0: break