""" Topical index for finding Bible verses by theme. Organized by major theological and practical topics. """ import json from functools import lru_cache from pathlib import Path from typing import Dict, Any @lru_cache(maxsize=1) def _load_topics(): """Load topics from per-topic JSON files, fallback to legacy single file.""" base_dir = Path(__file__).parent / "data" topics_dir = base_dir / "topics" legacy_path = base_dir / "topics.json" aggregated = {} if topics_dir.exists(): for path in sorted(topics_dir.glob("*.json")): with open(path, "r", encoding="utf-8") as f: content = json.load(f) if isinstance(content, dict): aggregated.update(content) elif legacy_path.exists(): with open(legacy_path, "r", encoding="utf-8") as f: aggregated = json.load(f) return aggregated def _get_verse_text_for_reference(reference: str) -> str: """Look up a single verse text from a reference like 'John 3:16'.""" if not reference or not isinstance(reference, str): return "" parts = reference.rsplit(" ", 1) if len(parts) != 2 or ":" not in parts[1]: return "" book = parts[0] chapter_part, verse_part = parts[1].split(":", 1) # Use the first verse in a range (e.g., 3:16-17 -> 3:16) verse_segment = verse_part.split("-")[0] try: from .kjv import bible return bible.get_verse_text(book, int(chapter_part), int(verse_segment)) or "" except Exception: return "" def _enrich_topic_with_text(topic: Dict[str, Any]) -> Dict[str, Any]: """Attach verse text (and normalized reference fields) to a topic's verses.""" subtopics = topic.get("subtopics", {}) enriched_subtopics = {} for subtopic_name, subtopic_data in subtopics.items(): verses_with_text = [] for entry in subtopic_data.get("verses", []): if isinstance(entry, dict): reference = entry.get("reference") or entry.get("ref") or "" note = entry.get("note", "") else: reference = str(entry) note = "" verse_text = _get_verse_text_for_reference(reference) verses_with_text.append({ "reference": reference, "ref": reference, "text": verse_text, "note": note }) enriched_subtopics[subtopic_name] = { **subtopic_data, "verses": verses_with_text } return { **topic, "subtopics": enriched_subtopics } def get_all_topics(): """Get all topics""" return _load_topics() def get_topic(topic_name: str): """Get a specific topic""" return _load_topics().get(topic_name) @lru_cache(maxsize=None) def get_topic_with_text(topic_name: str): """Get a topic with verse text attached to each reference.""" topic = _load_topics().get(topic_name) if not topic: return None return _enrich_topic_with_text(topic) def search_topics(query: str): """Search for topics by name or description""" query_lower = query.lower() results = [] for topic_name, topic_data in _load_topics().items(): if query_lower in topic_name.lower() or query_lower in topic_data.get("description", "").lower(): results.append({ "name": topic_name, "description": topic_data["description"], "subtopic_count": len(topic_data.get("subtopics", {})) }) return results