mirror of
https://github.com/kennethreitz/kjvstudy.org.git
synced 2026-06-05 23:00:16 +00:00
Add comprehensive /stats page with site metrics
Hidden statistics page (not linked in navigation) displaying: Bible Text Statistics: - 31,102 verses across 66 books - 1,189 chapters - 783,137 words total - Averages per verse and chapter Verse Commentary: - 66 books with commentary files - 12,330 verses covered (39.6% of Bible) - 3.4M words of theological analysis - Avg 278 words per commented verse Cross-References: - 66 book files - 24,900 verses with cross-references (80% coverage) - 120,858 total references - Avg 4.9 references per verse Language Tools: - 8,674 Hebrew Strong's entries - 5,624 Greek Strong's entries - 14,298 total concordance entries - 12 MB interlinear data (compressed) Study Resources: - 36 study guides - 36 topics - 39 resource files - 24 Bible stories - 127 biographies - 6 reading plans Technical Data: - 361 total JSON files - 58.1 MB total data size - 150+ book abbreviations Access via /stats (hidden, not linked in nav) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1268,6 +1268,158 @@ def get_daily_verse(date_str=None):
|
||||
|
||||
|
||||
|
||||
@app.get("/stats", response_class=HTMLResponse)
|
||||
async def stats(request: Request):
|
||||
"""Hidden statistics page - comprehensive site metrics"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
data_dir = Path(__file__).parent / "data"
|
||||
|
||||
# Bible statistics
|
||||
total_verses = bible.get_verse_count()
|
||||
total_books = len(bible.get_books())
|
||||
total_chapters = len(bible.get_chapters())
|
||||
|
||||
# Calculate words in Bible
|
||||
total_words = sum(len(verse.text.split()) for verse in bible.iter_verses())
|
||||
|
||||
# Count unique book types
|
||||
ot_books = len(OT_BOOKS)
|
||||
nt_books = len(NT_BOOKS)
|
||||
|
||||
# Data file statistics
|
||||
total_json_files = len(list(data_dir.glob('**/*.json')))
|
||||
|
||||
# Verse commentary statistics
|
||||
verse_commentary_files = len(list((data_dir / 'verse_commentary').glob('*.json')))
|
||||
total_commentary_verses = 0
|
||||
total_commentary_words = 0
|
||||
for file in (data_dir / 'verse_commentary').glob('*.json'):
|
||||
data = json.load(open(file))
|
||||
commentary = data.get('commentary', {})
|
||||
for chapter in commentary.values():
|
||||
for verse_data in chapter.values():
|
||||
total_commentary_verses += 1
|
||||
# Count words in analysis + historical
|
||||
analysis = verse_data.get('analysis', '')
|
||||
historical = verse_data.get('historical', '')
|
||||
# Strip HTML tags for accurate word count
|
||||
import re
|
||||
clean_analysis = re.sub(r'<[^>]+>', '', analysis)
|
||||
clean_historical = re.sub(r'<[^>]+>', '', historical)
|
||||
total_commentary_words += len(clean_analysis.split()) + len(clean_historical.split())
|
||||
|
||||
# Cross-reference statistics
|
||||
cross_reference_files = len(list((data_dir / 'cross_references').glob('*.json')))
|
||||
total_cross_refs = 0
|
||||
verses_with_cross_refs = 0
|
||||
for file in (data_dir / 'cross_references').glob('*.json'):
|
||||
data = json.load(open(file))
|
||||
verses_with_cross_refs += len(data)
|
||||
for verse_refs in data.values():
|
||||
total_cross_refs += len(verse_refs)
|
||||
|
||||
# Red letter statistics
|
||||
red_letter_data = json.load(open(data_dir / 'red_letter_verses.json'))
|
||||
total_red_letter_verses = len(red_letter_data['verses'])
|
||||
|
||||
# Study resources
|
||||
study_guide_files = len(list((data_dir / 'study_guides').glob('*.json')))
|
||||
topic_files = len(list((data_dir / 'topics').glob('*.json')))
|
||||
resource_files = len(list((data_dir / 'resources').glob('*.json')))
|
||||
story_files = len(list((data_dir / 'stories').glob('*.json')))
|
||||
|
||||
# Interlinear data size
|
||||
interlinear_file = data_dir / 'interlinear.json.gz'
|
||||
interlinear_size_mb = interlinear_file.stat().st_size / 1024 / 1024 if interlinear_file.exists() else 0
|
||||
|
||||
# Calculate total data directory size
|
||||
total_data_size = sum(f.stat().st_size for f in data_dir.glob('**/*') if f.is_file())
|
||||
total_data_size_mb = total_data_size / 1024 / 1024
|
||||
|
||||
# Book abbreviations
|
||||
bible_metadata_file = data_dir / 'bible_metadata.json'
|
||||
bible_metadata = json.load(open(bible_metadata_file))
|
||||
total_abbreviations = len(bible_metadata.get('book_abbreviations', {}))
|
||||
|
||||
# Biographies
|
||||
bio_data = json.load(open(data_dir / 'biographies.json'))
|
||||
total_biographies = len(bio_data.get('biographies', {}))
|
||||
|
||||
# Reading plans
|
||||
reading_plan_files = len(list((data_dir / 'reading_plans').glob('*.json')))
|
||||
|
||||
# Strong's concordance
|
||||
strongs_dir = data_dir / 'strongs'
|
||||
if strongs_dir.exists():
|
||||
hebrew_data = json.load(open(strongs_dir / 'hebrew.json'))
|
||||
greek_data = json.load(open(strongs_dir / 'greek.json'))
|
||||
total_hebrew_entries = len(hebrew_data)
|
||||
total_greek_entries = len(greek_data)
|
||||
else:
|
||||
total_hebrew_entries = 0
|
||||
total_greek_entries = 0
|
||||
|
||||
stats_data = {
|
||||
'bible': {
|
||||
'total_verses': total_verses,
|
||||
'total_books': total_books,
|
||||
'ot_books': ot_books,
|
||||
'nt_books': nt_books,
|
||||
'total_chapters': total_chapters,
|
||||
'total_words': total_words,
|
||||
'avg_words_per_verse': round(total_words / total_verses, 1),
|
||||
'avg_verses_per_chapter': round(total_verses / total_chapters, 1),
|
||||
},
|
||||
'commentary': {
|
||||
'files': verse_commentary_files,
|
||||
'verses_covered': total_commentary_verses,
|
||||
'total_words': total_commentary_words,
|
||||
'avg_words_per_verse': round(total_commentary_words / total_commentary_verses, 1) if total_commentary_verses > 0 else 0,
|
||||
'coverage_percent': round((total_commentary_verses / total_verses) * 100, 1),
|
||||
},
|
||||
'cross_references': {
|
||||
'files': cross_reference_files,
|
||||
'verses_with_refs': verses_with_cross_refs,
|
||||
'total_references': total_cross_refs,
|
||||
'avg_refs_per_verse': round(total_cross_refs / verses_with_cross_refs, 1) if verses_with_cross_refs > 0 else 0,
|
||||
'coverage_percent': round((verses_with_cross_refs / total_verses) * 100, 1),
|
||||
},
|
||||
'red_letter': {
|
||||
'total_verses': total_red_letter_verses,
|
||||
'percent_of_bible': round((total_red_letter_verses / total_verses) * 100, 1),
|
||||
},
|
||||
'study_resources': {
|
||||
'study_guides': study_guide_files,
|
||||
'topics': topic_files,
|
||||
'resources': resource_files,
|
||||
'stories': story_files,
|
||||
'biographies': total_biographies,
|
||||
'reading_plans': reading_plan_files,
|
||||
},
|
||||
'language_tools': {
|
||||
'hebrew_entries': total_hebrew_entries,
|
||||
'greek_entries': total_greek_entries,
|
||||
'total_strongs': total_hebrew_entries + total_greek_entries,
|
||||
'interlinear_size_mb': round(interlinear_size_mb, 1),
|
||||
},
|
||||
'data': {
|
||||
'total_json_files': total_json_files,
|
||||
'total_size_mb': round(total_data_size_mb, 1),
|
||||
'book_abbreviations': total_abbreviations,
|
||||
}
|
||||
}
|
||||
|
||||
return templates.TemplateResponse(
|
||||
"stats.html",
|
||||
{
|
||||
"request": request,
|
||||
"stats": stats_data,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def read_root(request: Request):
|
||||
books = bible.get_books()
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Site Statistics - KJV Study{% endblock %}
|
||||
{% block description %}Comprehensive statistics about KJV Study - Bible data, commentary, cross-references, and study resources{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<article>
|
||||
<h1>KJV Study Statistics</h1>
|
||||
<p class="subtitle">Comprehensive metrics about this Bible study resource</p>
|
||||
|
||||
<section>
|
||||
<h2>Bible Text</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<td><strong>Total Verses</strong></td>
|
||||
<td>{{ "{:,}".format(stats.bible.total_verses) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Total Books</strong></td>
|
||||
<td>{{ stats.bible.total_books }} ({{ stats.bible.ot_books }} OT + {{ stats.bible.nt_books }} NT)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Total Chapters</strong></td>
|
||||
<td>{{ "{:,}".format(stats.bible.total_chapters) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Total Words</strong></td>
|
||||
<td>{{ "{:,}".format(stats.bible.total_words) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Average Words per Verse</strong></td>
|
||||
<td>{{ stats.bible.avg_words_per_verse }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Average Verses per Chapter</strong></td>
|
||||
<td>{{ stats.bible.avg_verses_per_chapter }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Verse Commentary</h2>
|
||||
<p>In-depth theological analysis with Greek/Hebrew word studies</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><strong>Commentary Files</strong></td>
|
||||
<td>{{ stats.commentary.files }} books</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Verses with Commentary</strong></td>
|
||||
<td>{{ "{:,}".format(stats.commentary.verses_covered) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Coverage</strong></td>
|
||||
<td>{{ stats.commentary.coverage_percent }}% of Bible</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Total Commentary Words</strong></td>
|
||||
<td>{{ "{:,}".format(stats.commentary.total_words) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Average Words per Verse</strong></td>
|
||||
<td>{{ "{:,}".format(stats.commentary.avg_words_per_verse|int) }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Cross-References</h2>
|
||||
<p>Based on Treasury of Scripture Knowledge (CC-BY)</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><strong>Files</strong></td>
|
||||
<td>{{ stats.cross_references.files }} books</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Verses with Cross-References</strong></td>
|
||||
<td>{{ "{:,}".format(stats.cross_references.verses_with_refs) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Coverage</strong></td>
|
||||
<td>{{ stats.cross_references.coverage_percent }}% of Bible</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Total Cross-References</strong></td>
|
||||
<td>{{ "{:,}".format(stats.cross_references.total_references) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Average per Verse</strong></td>
|
||||
<td>{{ stats.cross_references.avg_refs_per_verse }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Red Letter Edition</h2>
|
||||
<p>Words of Jesus Christ</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><strong>Verses</strong></td>
|
||||
<td>{{ "{:,}".format(stats.red_letter.total_verses) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Percentage of Bible</strong></td>
|
||||
<td>{{ stats.red_letter.percent_of_bible }}%</td>
|
||||
</tr>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Language Tools</h2>
|
||||
<p>Hebrew, Greek, and interlinear resources</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><strong>Hebrew Strong's Entries</strong></td>
|
||||
<td>{{ "{:,}".format(stats.language_tools.hebrew_entries) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Greek Strong's Entries</strong></td>
|
||||
<td>{{ "{:,}".format(stats.language_tools.greek_entries) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Total Strong's Concordance</strong></td>
|
||||
<td>{{ "{:,}".format(stats.language_tools.total_strongs) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Interlinear Data Size</strong></td>
|
||||
<td>{{ stats.language_tools.interlinear_size_mb }} MB (compressed)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Study Resources</h2>
|
||||
<p>Topical studies, reading plans, and biblical resources</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><strong>Study Guides</strong></td>
|
||||
<td>{{ stats.study_resources.study_guides }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Topics</strong></td>
|
||||
<td>{{ stats.study_resources.topics }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Resources</strong></td>
|
||||
<td>{{ stats.study_resources.resources }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Bible Stories</strong></td>
|
||||
<td>{{ stats.study_resources.stories }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Biographies</strong></td>
|
||||
<td>{{ stats.study_resources.biographies }} biblical figures</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Reading Plans</strong></td>
|
||||
<td>{{ stats.study_resources.reading_plans }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Technical Data</h2>
|
||||
<p>Data files and infrastructure</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><strong>Total JSON Files</strong></td>
|
||||
<td>{{ "{:,}".format(stats.data.total_json_files) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Total Data Size</strong></td>
|
||||
<td>{{ stats.data.total_size_mb }} MB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Book Abbreviations</strong></td>
|
||||
<td>{{ stats.data.book_abbreviations }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Summary</h2>
|
||||
<p>KJV Study contains:</p>
|
||||
<ul>
|
||||
<li>{{ "{:,}".format(stats.bible.total_verses) }} verses from the 1769 Cambridge KJV</li>
|
||||
<li>{{ "{:,}".format(stats.commentary.verses_covered) }} verses with in-depth commentary ({{ stats.commentary.coverage_percent }}% coverage)</li>
|
||||
<li>{{ "{:,}".format(stats.commentary.total_words) }} words of theological analysis</li>
|
||||
<li>{{ "{:,}".format(stats.cross_references.total_references) }} cross-references linking related passages</li>
|
||||
<li>{{ "{:,}".format(stats.language_tools.total_strongs) }} Strong's Concordance entries for word studies</li>
|
||||
<li>{{ stats.study_resources.biographies }} biblical biographies</li>
|
||||
<li>{{ stats.study_resources.study_guides }} topical study guides</li>
|
||||
<li>{{ stats.study_resources.reading_plans }} reading plans</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<p style="margin-top: 3rem; color: #999; font-size: 0.9rem;">
|
||||
<em>This is a hidden page not linked from navigation. Access via direct URL: <code>/stats</code></em>
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<style>
|
||||
.subtitle {
|
||||
font-size: 1.2rem;
|
||||
color: #666;
|
||||
margin-top: -1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
tr {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
td:last-child {
|
||||
text-align: right;
|
||||
font-family: 'Consolas', 'Monaco', monospace;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
section {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
section p {
|
||||
color: var(--text-secondary);
|
||||
font-style: italic;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
code {
|
||||
background: var(--code-bg);
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user