Add exact match redirect and family tree search integration

Family tree search:
- Exact name matches now redirect directly to person page
- Added search_family_tree() helper function

Homepage search:
- Now includes family tree people in search results
- Shows up to 5 matching people with their info
- Results separated into "Bible Verses" and "People in Family Tree"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-22 15:56:46 -05:00
parent 9232c66409
commit a1519d5689
2 changed files with 89 additions and 3 deletions
+66 -2
View File
@@ -575,25 +575,31 @@ async def custom_http_exception_handler(request: Request, exc: StarletteHTTPExce
@app.get("/search", response_class=HTMLResponse)
def search_page(request: Request, q: str = Query(None, description="Search query")):
"""Search page with results"""
"""Search page with results (includes Bible verses and family tree)"""
books = list(bible.iter_books())
search_results = []
family_tree_results = []
is_direct_verse = False
if q and len(q.strip()) >= 2:
# Search Bible verses
search_results = perform_full_text_search(q.strip())
# Check if this was a direct verse reference match
if search_results and len(search_results) == 1 and search_results[0].get("score") == 100.0:
is_direct_verse = True
# Also search family tree (limit to 5 results)
family_tree_results = search_family_tree(q.strip(), limit=5)
return templates.TemplateResponse(
"search.html",
{
"request": request,
"query": q or "",
"results": search_results,
"family_tree_results": family_tree_results,
"books": books,
"total_results": len(search_results),
"total_results": len(search_results) + len(family_tree_results),
"is_direct_verse": is_direct_verse
}
)
@@ -4203,6 +4209,7 @@ def family_tree_search_page(request: Request, q: str = ""):
# Search for people
results = []
exact_match_id = None
if q:
query_lower = q.lower()
for person_id, person in family_tree_data.items():
@@ -4214,6 +4221,13 @@ def family_tree_search_page(request: Request, q: str = ""):
"birth_year": person.get("birth_year", "Unknown"),
"death_year": person.get("death_year", "Unknown")
})
# Check for exact match
if person["name"].lower() == query_lower:
exact_match_id = person_id
# If there's exactly one result with an exact match, redirect to that person's page
if exact_match_id:
return RedirectResponse(url=f"/family-tree/person/{exact_match_id}", status_code=303)
return templates.TemplateResponse(
"family_tree_search.html",
@@ -4672,6 +4686,56 @@ def get_family_tree_data():
return _family_tree_cache, _name_to_person_id_cache
def search_family_tree(query: str, limit: Optional[int] = None) -> List[Dict]:
"""
Search family tree for people matching the query.
Returns list of matching people with their info.
"""
results = []
if not query or len(query.strip()) < 2:
return results
try:
# Load GEDCOM file from static folder
static_dir = Path(__file__).parent / "static"
gedcom_path = static_dir / "adameve.ged"
if not gedcom_path.exists() or not GedcomReader:
return results
# Parse GEDCOM data
family_tree_data, generations = parse_gedcom_to_tree_data(gedcom_path)
# Search for people
query_lower = query.lower().strip()
for person_id, person in family_tree_data.items():
if query_lower in person["name"].lower():
results.append({
"type": "person",
"id": person_id,
"name": person["name"],
"generation": person.get("generation"),
"birth_year": person.get("birth_year", "Unknown"),
"death_year": person.get("death_year", "Unknown"),
"url": f"/family-tree/person/{person_id}",
"description": f"Generation {person.get('generation', '?')} from Adam"
})
# Sort by relevance (exact matches first, then alphabetically)
results.sort(key=lambda x: (
0 if x["name"].lower() == query_lower else 1,
x["name"]
))
# Limit results if specified
if limit is not None:
return results[:limit]
return results
except Exception:
return results
def link_person_names_in_text(text: str) -> str:
"""
Find person names and verse references in text and link them.
+23 -1
View File
@@ -112,6 +112,8 @@
Found <strong>{{ total_results }}</strong> result{{ 's' if total_results != 1 else '' }} for "<strong>{{ query }}</strong>"
</div>
{% if results %}
<h2 style="margin-top: 2rem;">Bible Verses</h2>
{% for result in results %}
<article class="search-result">
<div class="result-reference">
@@ -120,7 +122,27 @@
<div class="result-text">{{ result.highlighted_text | link_names | safe }}</div>
</article>
{% endfor %}
{% else %}
{% endif %}
{% if family_tree_results %}
<h2 style="margin-top: 2rem;">People in Family Tree</h2>
{% for result in family_tree_results %}
<article class="search-result">
<div class="result-reference">
<a href="{{ result.url }}">{{ result.name }}</a>
</div>
<div class="result-text" style="color: #666;">
{{ result.description }}
{% if result.birth_year != "Unknown" or result.death_year != "Unknown" %}
{% if result.birth_year != "Unknown" %}Born {{ result.birth_year }}{% endif %}
{% if result.death_year != "Unknown" %}{% if result.birth_year != "Unknown" %}, {% endif %}Died {{ result.death_year }}{% endif %}
{% endif %}
</div>
</article>
{% endfor %}
{% endif %}
{% elif total_results == 0 %}
<div class="search-stats">
<p><strong>No results found</strong> for "{{ query }}". Try different words or check your spelling.</p>
</div>