mirror of
https://github.com/kennethreitz/kjvstudy.org.git
synced 2026-06-05 14:50:17 +00:00
Enrich topic pages with verse text
This commit is contained in:
@@ -14,7 +14,7 @@ from ..utils.pdf import render_html_to_pdf, render_html_to_pdf_async, WEASYPRINT
|
||||
from ..kjv import bible
|
||||
from ..cross_references import get_cross_references
|
||||
from ..reading_plans import get_plan, get_plan_summary
|
||||
from ..topics import get_all_topics, get_topic
|
||||
from ..topics import get_all_topics, get_topic_with_text
|
||||
from ..interlinear_loader import get_interlinear_data, has_interlinear_data
|
||||
from ..utils.books import normalize_book_name, OT_BOOKS
|
||||
from ..utils.search import perform_full_text_search
|
||||
@@ -1230,7 +1230,7 @@ async def api_get_topics():
|
||||
@router.get("/topics/{topic_name}")
|
||||
async def api_get_topic(topic_name: str = Path(..., description="Topic name", example="faith")):
|
||||
"""Get details about a specific topic."""
|
||||
topic = get_topic(topic_name)
|
||||
topic = get_topic_with_text(topic_name)
|
||||
if not topic:
|
||||
raise HTTPException(status_code=404, detail="Topic not found")
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from .kjv import bible, VerseReference
|
||||
from .cross_references import get_cross_references
|
||||
from .reading_plans import get_plan, get_all_plans, get_plan_summary
|
||||
from .topics import get_all_topics, get_topic, search_topics
|
||||
from .topics import get_all_topics, get_topic_with_text, search_topics
|
||||
from .interlinear_loader import get_interlinear_data, has_interlinear_data, get_all_interlinear_verses, preload_data, find_verses_by_strongs, count_strongs_occurrences
|
||||
from .strongs import format_strongs_entry, search_strongs, get_all_strongs
|
||||
from .books import get_book_data, has_book_data
|
||||
@@ -1880,7 +1880,7 @@ async def resources_page(request: Request):
|
||||
async def topic_detail(request: Request, topic_name: str):
|
||||
"""View verses for a specific topic"""
|
||||
books = bible.get_books()
|
||||
topic = get_topic(topic_name)
|
||||
topic = get_topic_with_text(topic_name)
|
||||
|
||||
if not topic:
|
||||
raise HTTPException(status_code=404, detail="Topic not found")
|
||||
@@ -1914,7 +1914,7 @@ async def topic_detail_pdf(topic_name: str):
|
||||
detail="PDF generation is not available. WeasyPrint system libraries are not installed."
|
||||
)
|
||||
|
||||
topic = get_topic(topic_name)
|
||||
topic = get_topic_with_text(topic_name)
|
||||
if not topic:
|
||||
raise HTTPException(status_code=404, detail="Topic not found")
|
||||
|
||||
|
||||
@@ -153,33 +153,45 @@
|
||||
{% for verse in subtopic_data.verses %}
|
||||
<li class="verse-item">
|
||||
<span class="verse-ref">
|
||||
{% set ref_parts = verse.ref.rsplit(' ', 1) %}
|
||||
{% if ref_parts|length == 2 %}
|
||||
{% set book_name = ref_parts[0] %}
|
||||
{% set chapter_verse = ref_parts[1] %}
|
||||
{% if ':' in chapter_verse %}
|
||||
{% set ch = chapter_verse.split(':')[0] %}
|
||||
{% set v = chapter_verse.split(':')[1] %}
|
||||
{% if '-' not in v %}
|
||||
{# Single verse - make it a link #}
|
||||
<a href="/book/{{ book_name }}/chapter/{{ ch }}/verse/{{ v }}">{{ verse.ref }}</a>
|
||||
{% set reference = verse.reference if verse.reference is defined else (verse.ref if verse.ref is defined else verse) %}
|
||||
{% if reference is not string %}
|
||||
{% set reference = reference|string %}
|
||||
{% endif %}
|
||||
{% set reference = reference.strip() %}
|
||||
{% if reference %}
|
||||
{% set ref_parts = reference.rsplit(' ', 1) %}
|
||||
{% if ref_parts|length == 2 %}
|
||||
{% set book_name = ref_parts[0] %}
|
||||
{% set chapter_verse = ref_parts[1] %}
|
||||
{% if ':' in chapter_verse %}
|
||||
{% set ch = chapter_verse.split(':')[0] %}
|
||||
{% set v = chapter_verse.split(':')[1] %}
|
||||
{% if '-' not in v %}
|
||||
{# Single verse - make it a link #}
|
||||
<a href="/book/{{ book_name }}/chapter/{{ ch }}/verse/{{ v }}">{{ reference }}</a>
|
||||
{% else %}
|
||||
{# Verse range - link to chapter with anchor #}
|
||||
{% set v_start = v.split('-')[0] %}
|
||||
{% set v_end = v.split('-')[1] %}
|
||||
<a href="/book/{{ book_name }}/chapter/{{ ch }}#verse-{{ v_start }}-{{ v_end }}">{{ reference }}</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{# Verse range - link to chapter with anchor #}
|
||||
{% set v_start = v.split('-')[0] %}
|
||||
{% set v_end = v.split('-')[1] %}
|
||||
<a href="/book/{{ book_name }}/chapter/{{ ch }}#verse-{{ v_start }}-{{ v_end }}">{{ verse.ref }}</a>
|
||||
{# No colon, just display text #}
|
||||
{{ reference }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{# No colon, just display text #}
|
||||
{{ verse.ref }}
|
||||
{{ reference }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ verse.ref }}
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if verse.note %}
|
||||
{% if verse.note is defined and verse.note %}
|
||||
<span class="verse-note">— {{ verse.note }}</span>
|
||||
{% endif %}
|
||||
{% if verse.text is defined and verse.text %}
|
||||
<div style="margin-top: 0.4rem; color: var(--text-secondary); line-height: 1.6;">
|
||||
{{ verse.text }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
@@ -97,8 +97,17 @@
|
||||
<ul class="verse-list">
|
||||
{% for verse in subtopic.verses %}
|
||||
<li class="verse-item">
|
||||
<span class="verse-ref">{{ verse.ref }}</span>
|
||||
{% if verse.note %}<span class="verse-note">— {{ verse.note }}</span>{% endif %}
|
||||
{% set reference = verse.reference if verse.reference is defined else (verse.ref if verse.ref is defined else verse) %}
|
||||
{% if reference is not string %}
|
||||
{% set reference = reference|string %}
|
||||
{% endif %}
|
||||
<span class="verse-ref">{{ reference }}</span>
|
||||
{% if verse.note is defined and verse.note %}<span class="verse-note">— {{ verse.note }}</span>{% endif %}
|
||||
{% if verse.text is defined and verse.text %}
|
||||
<div style="margin-top: 6px; color: #555;">
|
||||
{{ verse.text }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
+68
-4
@@ -4,9 +4,12 @@ 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"
|
||||
@@ -27,17 +30,78 @@ def _load_topics():
|
||||
return aggregated
|
||||
|
||||
|
||||
TOPICS = _load_topics()
|
||||
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 TOPICS
|
||||
return _load_topics()
|
||||
|
||||
|
||||
def get_topic(topic_name: str):
|
||||
"""Get a specific topic"""
|
||||
return TOPICS.get(topic_name)
|
||||
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):
|
||||
@@ -45,7 +109,7 @@ def search_topics(query: str):
|
||||
query_lower = query.lower()
|
||||
results = []
|
||||
|
||||
for topic_name, topic_data in TOPICS.items():
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user