* feat(rag): Phase 1 — rewrite build_card_text to natural-language format * feat(rag): Phase 2 — Forge-enriched ChromaDB RAG store (2a–2e) Phase 2a: Forge lazy import guard (_try_import_forge_lookup) Phase 2b: _build_document appends Forge trigger/replacement/static/keyword tags Phase 2c: _build_metadata adds has_trigger, has_replacement, has_static, trigger_modes fields Phase 2d: query_cards extended with require_trigger, require_replacement, require_static params + ChromaDB where clause support Phase 2e: get_rag_stats reports forge_enriched and forge_coverage; _write_build_meta tracks coverage; build loop counts enriched cards * feat(rag): Phase 3 — add mtgrules second ChromaDB collection Adds build_rules_index() and query_rules() operating on a separate 'mtgrules' ChromaDB collection. Chunks MagicCompRules.txt by rule-number boundaries, embeds each chunk, and exposes semantic search. Completely independent from the mtg_oracle card collection. * feat(coach): Phase 4 — behavior-aware RAG + rules context in coach_service Phase 4a: run_coaching_session uses dual RAG query - Primary: commander synergy (n=10) - Secondary: require_replacement=True for graveyard/protection cards (n=5) - Deduplicates by name before merging Phase 4b: query_rules() fetches 3 Commander rules chunks to ground the prompt - Passed as rules_context kwarg to build_user_prompt() * feat(rag): Phase 5 — add /api/rag/build-rules and /api/rag/query-rules endpoints
46 lines
1.4 KiB
Python
46 lines
1.4 KiB
Python
"""
|
|
services/card_text.py
|
|
=====================
|
|
Shared utility for building card text representations.
|
|
|
|
Both services/rag_store.py and coach/embeddings.py need to produce
|
|
identical text strings for embedding so that vector similarity is
|
|
consistent across both systems. This module provides a single
|
|
canonical implementation.
|
|
|
|
Format: Natural-language sentences.
|
|
(fields that are empty/missing are omitted)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
def build_card_text(card: dict) -> str:
|
|
"""Build canonical natural-language card text for embedding.
|
|
|
|
Produces '{Name} is a {Type}. It costs {ManaCost}. {OracleText}'
|
|
Fields that are empty/None are omitted.
|
|
|
|
Args:
|
|
card: Dict with keys 'name', 'mana_cost', 'type_line', 'oracle_text'.
|
|
Missing keys are treated as empty strings.
|
|
|
|
Returns:
|
|
Natural language string suitable for nomic-embed-text or GTE models.
|
|
"""
|
|
name = (card.get("name", "") or "").strip()
|
|
mana = (card.get("mana_cost", "") or "").strip()
|
|
types = (card.get("type_line", "") or "").strip()
|
|
oracle = (card.get("oracle_text", "") or "").strip()
|
|
|
|
parts: list[str] = []
|
|
if name:
|
|
base = f"{name} is a {types}." if types else f"{name}."
|
|
parts.append(base)
|
|
if mana:
|
|
parts.append(f"It costs {mana}.")
|
|
if oracle:
|
|
parts.append(oracle)
|
|
|
|
return " ".join(parts) if parts else name
|