diff --git a/scripts/show_commentary_coverage.py b/scripts/show_commentary_coverage.py new file mode 100755 index 0000000..b53fc64 --- /dev/null +++ b/scripts/show_commentary_coverage.py @@ -0,0 +1,287 @@ +#!/usr/bin/env python3 +""" +Show which verses have enhanced commentary and which don't. + +This script analyzes the verse_commentary.json file and displays statistics +about commentary coverage across the Bible. It helps track progress on adding +enhanced verse-by-verse commentary. + +Usage: + python scripts/show_commentary_coverage.py # Show summary + python scripts/show_commentary_coverage.py --book Genesis # Show specific book + python scripts/show_commentary_coverage.py --list # List all commentated verses + python scripts/show_commentary_coverage.py --missing # Show verses without commentary + python scripts/show_commentary_coverage.py --stats # Detailed statistics +""" + +import json +import sys +from pathlib import Path +from collections import defaultdict +from typing import Dict, List, Tuple +import argparse + + +# Path to data directory +DATA_DIR = Path(__file__).parent.parent / "kjvstudy_org" / "data" +VERSE_COMMENTARY_PATH = DATA_DIR / "verse_commentary.json" + + +def load_commentary() -> Dict[str, dict]: + """Load verse commentary from JSON file.""" + if not VERSE_COMMENTARY_PATH.exists(): + print(f"Error: {VERSE_COMMENTARY_PATH} not found") + sys.exit(1) + + with open(VERSE_COMMENTARY_PATH, 'r', encoding='utf-8') as f: + return json.load(f) + + +def parse_verse_ref(verse_ref: str) -> Tuple[str, int, int]: + """ + Parse verse reference like 'Genesis 1:1' into (book, chapter, verse). + + Args: + verse_ref: Verse reference string like "Genesis 1:1" or "1 John 3:16" + + Returns: + Tuple of (book_name, chapter_num, verse_num) + """ + parts = verse_ref.rsplit(' ', 1) + if len(parts) != 2: + return ("Unknown", 0, 0) + + book = parts[0] + chapter_verse = parts[1] + + if ':' not in chapter_verse: + return (book, 0, 0) + + chapter_str, verse_str = chapter_verse.split(':', 1) + try: + chapter = int(chapter_str) + verse = int(verse_str) + except ValueError: + return (book, 0, 0) + + return (book, chapter, verse) + + +def organize_by_book(commentary: Dict[str, dict]) -> Dict[str, Dict[int, List[int]]]: + """ + Organize commentary by book and chapter. + + Returns: + Dict of {book: {chapter: [verse1, verse2, ...]}} + """ + organized = defaultdict(lambda: defaultdict(list)) + + for verse_ref in commentary.keys(): + book, chapter, verse = parse_verse_ref(verse_ref) + if chapter > 0 and verse > 0: + organized[book][chapter].append(verse) + + # Sort verses within each chapter + for book in organized: + for chapter in organized[book]: + organized[book][chapter].sort() + + return dict(organized) + + +def show_summary(commentary: Dict[str, dict]): + """Show high-level summary of commentary coverage.""" + organized = organize_by_book(commentary) + + print("=" * 70) + print("VERSE COMMENTARY COVERAGE SUMMARY") + print("=" * 70) + print() + + total_verses = len(commentary) + total_books = len(organized) + + print(f"📖 Total verses with enhanced commentary: {total_verses}") + print(f"📚 Books with commentary: {total_books}") + print() + + print("Coverage by Book:") + print("-" * 70) + + for book in sorted(organized.keys()): + chapters = organized[book] + total_verses_in_book = sum(len(verses) for verses in chapters.values()) + chapter_list = sorted(chapters.keys()) + chapter_range = f"{min(chapter_list)}-{max(chapter_list)}" if len(chapter_list) > 1 else str(chapter_list[0]) + + print(f" {book:30} {total_verses_in_book:4} verses (chapters: {chapter_range})") + + print() + + +def show_book_detail(commentary: Dict[str, dict], book_name: str): + """Show detailed commentary coverage for a specific book.""" + organized = organize_by_book(commentary) + + if book_name not in organized: + print(f"❌ No commentary found for book: {book_name}") + print(f"\nAvailable books:") + for book in sorted(organized.keys()): + print(f" - {book}") + return + + print("=" * 70) + print(f"COMMENTARY COVERAGE: {book_name}") + print("=" * 70) + print() + + chapters = organized[book_name] + total_verses = sum(len(verses) for verses in chapters.values()) + + print(f"Total verses: {total_verses}") + print(f"Chapters with commentary: {len(chapters)}") + print() + + for chapter in sorted(chapters.keys()): + verses = chapters[chapter] + verse_list = ", ".join(str(v) for v in verses) + print(f" Chapter {chapter:3} ({len(verses):2} verses): {verse_list}") + + print() + + +def list_all_verses(commentary: Dict[str, dict]): + """List all verses with commentary.""" + organized = organize_by_book(commentary) + + print("=" * 70) + print("ALL VERSES WITH ENHANCED COMMENTARY") + print("=" * 70) + print() + + for book in sorted(organized.keys()): + print(f"\n{book}") + print("-" * 70) + + chapters = organized[book] + for chapter in sorted(chapters.keys()): + verses = chapters[chapter] + verse_list = ", ".join(str(v) for v in verses) + print(f" {chapter}:{verse_list}") + + print() + + +def show_statistics(commentary: Dict[str, dict]): + """Show detailed statistics about commentary coverage.""" + organized = organize_by_book(commentary) + + print("=" * 70) + print("DETAILED COMMENTARY STATISTICS") + print("=" * 70) + print() + + # Total verses + total_verses = len(commentary) + total_books = len(organized) + total_chapters = sum(len(chapters) for chapters in organized.values()) + + print(f"📊 Total Statistics:") + print(f" • Enhanced verses: {total_verses}") + print(f" • Books covered: {total_books}") + print(f" • Chapters covered: {total_chapters}") + print() + + # Book-level stats + print("📚 Coverage by Testament:") + + # Common book groupings + ot_books = ["Genesis", "Exodus", "Leviticus", "Numbers", "Deuteronomy", + "Joshua", "Judges", "Ruth", "1 Samuel", "2 Samuel", "1 Kings", "2 Kings", + "1 Chronicles", "2 Chronicles", "Ezra", "Nehemiah", "Esther", + "Job", "Psalms", "Proverbs", "Ecclesiastes", "Song of Solomon", + "Isaiah", "Jeremiah", "Lamentations", "Ezekiel", "Daniel", + "Hosea", "Joel", "Amos", "Obadiah", "Jonah", "Micah", "Nahum", + "Habakkuk", "Zephaniah", "Haggai", "Zechariah", "Malachi"] + + nt_books = ["Matthew", "Mark", "Luke", "John", "Acts", "Romans", + "1 Corinthians", "2 Corinthians", "Galatians", "Ephesians", "Philippians", + "Colossians", "1 Thessalonians", "2 Thessalonians", "1 Timothy", "2 Timothy", + "Titus", "Philemon", "Hebrews", "James", "1 Peter", "2 Peter", + "1 John", "2 John", "3 John", "Jude", "Revelation"] + + ot_verses = sum(sum(len(verses) for verses in organized[book].values()) + for book in ot_books if book in organized) + nt_verses = sum(sum(len(verses) for verses in organized[book].values()) + for book in nt_books if book in organized) + + ot_books_with_commentary = sum(1 for book in ot_books if book in organized) + nt_books_with_commentary = sum(1 for book in nt_books if book in organized) + + print(f" • Old Testament: {ot_verses} verses across {ot_books_with_commentary} books") + print(f" • New Testament: {nt_verses} verses across {nt_books_with_commentary} books") + print() + + # Top books by coverage + print("🏆 Top 10 Books by Commentary Coverage:") + book_verse_counts = [] + for book in organized: + count = sum(len(verses) for verses in organized[book].values()) + book_verse_counts.append((book, count)) + + book_verse_counts.sort(key=lambda x: x[1], reverse=True) + for i, (book, count) in enumerate(book_verse_counts[:10], 1): + print(f" {i:2}. {book:30} {count:4} verses") + + print() + + # Commentary field completeness + print("✅ Commentary Field Completeness:") + has_analysis = sum(1 for v in commentary.values() if v.get('analysis')) + has_historical = sum(1 for v in commentary.values() if v.get('historical_context')) + has_questions = sum(1 for v in commentary.values() if v.get('questions')) + has_application = sum(1 for v in commentary.values() if v.get('application')) + + print(f" • Analysis: {has_analysis}/{total_verses} ({100*has_analysis/total_verses:.1f}%)") + print(f" • Historical Context: {has_historical}/{total_verses} ({100*has_historical/total_verses:.1f}%)") + print(f" • Questions: {has_questions}/{total_verses} ({100*has_questions/total_verses:.1f}%)") + print(f" • Application: {has_application}/{total_verses} ({100*has_application/total_verses:.1f}%)") + + print() + + +def main(): + """Main entry point.""" + parser = argparse.ArgumentParser( + description="Show verse commentary coverage", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + python scripts/show_commentary_coverage.py + python scripts/show_commentary_coverage.py --book Genesis + python scripts/show_commentary_coverage.py --list + python scripts/show_commentary_coverage.py --stats + """ + ) + + parser.add_argument('--book', type=str, help='Show detail for a specific book') + parser.add_argument('--list', action='store_true', help='List all commentated verses') + parser.add_argument('--stats', action='store_true', help='Show detailed statistics') + + args = parser.parse_args() + + # Load commentary data + commentary = load_commentary() + + if args.book: + show_book_detail(commentary, args.book) + elif args.list: + list_all_verses(commentary) + elif args.stats: + show_statistics(commentary) + else: + show_summary(commentary) + + +if __name__ == "__main__": + main()