From 795124dbf32b31b09e86d7709af8382d9b3a574a Mon Sep 17 00:00:00 2001 From: Tyler Date: Sat, 25 Oct 2025 01:50:12 -0700 Subject: [PATCH] improved gramatical handling and spelling result orders --- app.py | 36 +++++++++++++++++++++++++++------- data/grammatical_variants.json | 20 +++++++++++++++++++ styles/header.css | 21 +++++++++++++++++++- 3 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 data/grammatical_variants.json diff --git a/app.py b/app.py index f812c69..dd28fcc 100644 --- a/app.py +++ b/app.py @@ -105,6 +105,7 @@ cached: dict = { "chapter_list": [], "books_chapter_lengths": {}, "json_dictionary": json.load(open("data/1828_Webster_KJV.json", "r")), + "grammatical_variants": json.load(open("data/grammatical_variants.json", "r")), "html_response": open("html/response.html", "r").read(), "html_navbar": open("html/navbar.html", "r").read(), "css_navbar": open("styles/header.css", "r").read(), @@ -773,10 +774,31 @@ def search(): return send_file("html/search.html") results = lookup_fts(cleaned_keywords) if not results: - h = hunspell.HunSpell("data/kjv.dic", "data/kjv.aff") - - # Split query into words and correct each one + # PRIORITY 1: Try grammatical variant expansion first words = cleaned_keywords.split() + + for word in words: + variants = cached["grammatical_variants"].get(word.lower(), []) + if variants: + # Try each variant individually + for variant in variants: + variant_query = cleaned_keywords.replace(word, variant, 1) + results = lookup_fts(variant_query) + if results: + response_list = scripture_response(results) + arg_view = request.args.get("view", None) + if arg_view == "plain": + response = f"Showing results for '{variant_query}' (grammatical variant of '{cleaned_keywords}')\n
" + "
".join(response_list) + elif arg_view == "rich": + variant_notice = f"
Showing results for '{variant_query}' (grammatical variant of '{cleaned_keywords}')
" + response_str = "".join(response_list) + response = response_str.replace("
", f"
{variant_notice}", 1) + else: + response = jsonify({"original": cleaned_keywords, "variant": variant_query, "results": response_list}) + return response + + # PRIORITY 2: If grammatical variants didn't help, try spell-check + h = hunspell.HunSpell("data/kjv.dic", "data/kjv.aff") corrected_words = [] had_corrections = False @@ -798,19 +820,19 @@ def search(): corrected_keyword = " ".join(corrected_words) results = lookup_fts(corrected_keyword) if results: - # Prepend correction notice to results response_list = scripture_response(results) - correction_notice = f"
Showing results for '{corrected_keyword}' (corrected from '{cleaned_keywords}')
" arg_view = request.args.get("view", None) if arg_view == "plain": response = f"Showing results for '{corrected_keyword}' (corrected from '{cleaned_keywords}')\n
" + "
".join(response_list) elif arg_view == "rich": - response = correction_notice + "".join(response_list) + correction_notice = f"
Showing results for '{corrected_keyword}' (corrected from '{cleaned_keywords}')
" + response_str = "".join(response_list) + response = response_str.replace("
", f"
{correction_notice}", 1) else: response = jsonify({"corrected_from": cleaned_keywords, "corrected_to": corrected_keyword, "results": response_list}) return response - # If we still have no results, show suggestions + # PRIORITY 3: If we still have no results, show spelling suggestions suggestions = h.suggest(cleaned_keywords) return "{} not found, try one of the following: {}".format( cleaned_keywords, ", ".join(suggestions) if suggestions else "No suggestions available" diff --git a/data/grammatical_variants.json b/data/grammatical_variants.json new file mode 100644 index 0000000..b307b9c --- /dev/null +++ b/data/grammatical_variants.json @@ -0,0 +1,20 @@ +{ + "you": ["ye", "thee", "thou"], + "ye": ["you", "thee", "thou"], + "thee": ["you", "ye", "thou"], + "thou": ["you", "ye", "thee"], + "your": ["thy", "thine"], + "thy": ["your", "thine"], + "thine": ["your", "thy"], + "has": ["hath"], + "hath": ["has", "have"], + "have": ["hath"], + "does": ["doth"], + "doth": ["does", "do"], + "do": ["doth"], + "says": ["saith"], + "saith": ["says", "said"], + "said": ["saith"], + "are": ["art"], + "art": ["are"] +} diff --git a/styles/header.css b/styles/header.css index 3282fa5..798fa02 100644 --- a/styles/header.css +++ b/styles/header.css @@ -89,11 +89,30 @@ body { max-width: var(--content-max-width); margin: 0 auto; padding: var(--space-md); - margin-top: var(--header-height); + margin-top: calc(var(--header-height) + var(--space-md)); color: var(--color-text-primary); white-space: pre-wrap; } +/* Correction & Variant Notices */ +.correction-notice, +.variant-notice { + font-family: var(--font-ui); + font-size: 0.95rem; + padding: var(--space-md) var(--space-lg); + margin-bottom: var(--space-lg); + background-color: var(--color-bg-tertiary); + border-left: 4px solid var(--color-accent-primary); + border-radius: var(--border-radius-sm); + color: var(--color-text-secondary); +} + +.correction-notice strong, +.variant-notice strong { + color: var(--color-accent-primary); + font-weight: 600; +} + /* Results Count */ .results-count { font-family: var(--font-ui);