Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,15 +1,18 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
import json
|
|
|
|
|
|
|
| 3 |
from rapidfuzz import process, fuzz
|
|
|
|
|
|
|
| 4 |
|
| 5 |
# --- CONFIGURATION ---
|
| 6 |
DATA_FILE = "navy_acronyms_clean.json"
|
|
|
|
| 7 |
|
| 8 |
# --- PAGE SETUP ---
|
| 9 |
st.set_page_config(page_title="Navy Acronym Finder", page_icon="⚓")
|
| 10 |
-
|
| 11 |
st.title("EDQP Acronym Lookup")
|
| 12 |
-
st.markdown("Type an acronym below to find its definition. Uses fuzzy matching to handle typos.")
|
| 13 |
|
| 14 |
# --- LOAD DATA ---
|
| 15 |
@st.cache_data
|
|
@@ -18,52 +21,69 @@ def load_acronyms():
|
|
| 18 |
with open(DATA_FILE, 'r', encoding='utf-8') as f:
|
| 19 |
return json.load(f)
|
| 20 |
except FileNotFoundError:
|
| 21 |
-
return {
|
| 22 |
|
| 23 |
acronym_dict = load_acronyms()
|
| 24 |
acronym_keys = list(acronym_dict.keys())
|
| 25 |
|
| 26 |
# --- SEARCH BAR ---
|
| 27 |
-
query = st.text_input("Enter Acronym:", placeholder="e.g., ACAT,
|
| 28 |
|
| 29 |
-
# --- RESULTS ---
|
| 30 |
if query:
|
| 31 |
query = query.upper().strip()
|
| 32 |
-
|
| 33 |
-
# 1. Exact Match (The "Right" Answer)
|
| 34 |
if query in acronym_dict:
|
| 35 |
st.success(f"**{query}**")
|
| 36 |
st.markdown(f"### {acronym_dict[query]}")
|
| 37 |
st.divider()
|
| 38 |
|
| 39 |
-
# 2. Fuzzy / Top 5 Suggestions
|
| 40 |
st.markdown("#### Did you mean?")
|
| 41 |
-
|
| 42 |
-
# Extracts top 5 similar keys based on the user query
|
| 43 |
-
# scorer=fuzz.ratio gives a simple similarity score
|
| 44 |
matches = process.extract(query, acronym_keys, limit=5, scorer=fuzz.ratio)
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
score = match_tuple[1]
|
| 50 |
-
|
| 51 |
-
# Don't show the exact match again if we already showed the big green box
|
| 52 |
-
if candidate == query:
|
| 53 |
-
continue
|
| 54 |
-
|
| 55 |
-
# Only show relevant matches (score > 40)
|
| 56 |
-
if score > 40:
|
| 57 |
-
with st.expander(f"**{candidate}** (Match: {int(score)}%)"):
|
| 58 |
st.write(acronym_dict[candidate])
|
| 59 |
|
| 60 |
-
# ---
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
st.
|
| 64 |
-
|
| 65 |
-
st.divider()
|
| 66 |
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
st.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
import json
|
| 3 |
+
import uuid
|
| 4 |
+
from datetime import datetime
|
| 5 |
from rapidfuzz import process, fuzz
|
| 6 |
+
from huggingface_hub import HfApi
|
| 7 |
+
import os
|
| 8 |
|
| 9 |
# --- CONFIGURATION ---
|
| 10 |
DATA_FILE = "navy_acronyms_clean.json"
|
| 11 |
+
SUGGESTIONS_REPO = "NavyDevilDoc/navy-acronym-suggestions"
|
| 12 |
|
| 13 |
# --- PAGE SETUP ---
|
| 14 |
st.set_page_config(page_title="Navy Acronym Finder", page_icon="⚓")
|
|
|
|
| 15 |
st.title("EDQP Acronym Lookup")
|
|
|
|
| 16 |
|
| 17 |
# --- LOAD DATA ---
|
| 18 |
@st.cache_data
|
|
|
|
| 21 |
with open(DATA_FILE, 'r', encoding='utf-8') as f:
|
| 22 |
return json.load(f)
|
| 23 |
except FileNotFoundError:
|
| 24 |
+
return {}
|
| 25 |
|
| 26 |
acronym_dict = load_acronyms()
|
| 27 |
acronym_keys = list(acronym_dict.keys())
|
| 28 |
|
| 29 |
# --- SEARCH BAR ---
|
| 30 |
+
query = st.text_input("Enter Acronym:", placeholder="e.g., ACAT, C4ISR...", max_chars=10)
|
| 31 |
|
|
|
|
| 32 |
if query:
|
| 33 |
query = query.upper().strip()
|
|
|
|
|
|
|
| 34 |
if query in acronym_dict:
|
| 35 |
st.success(f"**{query}**")
|
| 36 |
st.markdown(f"### {acronym_dict[query]}")
|
| 37 |
st.divider()
|
| 38 |
|
|
|
|
| 39 |
st.markdown("#### Did you mean?")
|
|
|
|
|
|
|
|
|
|
| 40 |
matches = process.extract(query, acronym_keys, limit=5, scorer=fuzz.ratio)
|
| 41 |
+
for match in matches:
|
| 42 |
+
candidate, score = match[0], match[1]
|
| 43 |
+
if candidate != query and score > 40:
|
| 44 |
+
with st.expander(f"**{candidate}** ({int(score)}%)"):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
st.write(acronym_dict[candidate])
|
| 46 |
|
| 47 |
+
# --- SUGGESTION BOX (The New Feature) ---
|
| 48 |
+
st.divider()
|
| 49 |
+
with st.expander("📝 Suggest an Acronym / Report an Error"):
|
| 50 |
+
st.write("Don't see an acronym? Let me know and I'll add it to the database.")
|
|
|
|
|
|
|
| 51 |
|
| 52 |
+
with st.form("suggestion_form"):
|
| 53 |
+
s_acr = st.text_input("Acronym")
|
| 54 |
+
s_def = st.text_area("Definition / Context")
|
| 55 |
+
submitted = st.form_submit_button("Submit Suggestion")
|
| 56 |
+
|
| 57 |
+
if submitted and s_acr and s_def:
|
| 58 |
+
try:
|
| 59 |
+
# 1. Prepare the Payload
|
| 60 |
+
payload = {
|
| 61 |
+
"acronym": s_acr.upper(),
|
| 62 |
+
"definition": s_def,
|
| 63 |
+
"timestamp": datetime.utcnow().isoformat()
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
# 2. Create a unique filename (so suggestions never overwrite each other)
|
| 67 |
+
# Example: suggestion_2026-01-11_uuid.json
|
| 68 |
+
file_name = f"suggestion_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{uuid.uuid4().hex[:6]}.json"
|
| 69 |
+
|
| 70 |
+
# 3. Create a temporary local file
|
| 71 |
+
with open(file_name, "w") as f:
|
| 72 |
+
json.dump(payload, f)
|
| 73 |
+
|
| 74 |
+
# 4. Upload to the "Mailbox" Dataset
|
| 75 |
+
api = HfApi(token=os.getenv("HF_TOKEN"))
|
| 76 |
+
api.upload_file(
|
| 77 |
+
path_or_fileobj=file_name,
|
| 78 |
+
path_in_repo=file_name,
|
| 79 |
+
repo_id=SUGGESTIONS_REPO,
|
| 80 |
+
repo_type="dataset"
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
st.success("✅ Suggestion sent! I'll review it shortly.")
|
| 84 |
+
|
| 85 |
+
# Cleanup local temp file
|
| 86 |
+
os.remove(file_name)
|
| 87 |
+
|
| 88 |
+
except Exception as e:
|
| 89 |
+
st.error(f"Error sending suggestion: {e}")
|