Seth0330 commited on
Commit
65ce454
·
verified ·
1 Parent(s): 0fa3514

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +27 -15
app.py CHANGED
@@ -1,12 +1,22 @@
1
  import streamlit as st
2
  import json
 
 
3
 
 
4
  COMMON_NAME_KEYS = ["user", "username", "name", "fullName", "firstName", "lastName", "customer"]
5
  LOGIN_KEYS = ["lastLogin", "login", "loggedIn", "lastLoggedIn", "last_login", "last_logged_in"]
6
 
7
  def normalize(s):
8
- return str(s).lower().replace("_", " ").replace("-", " ").replace(".", " ").strip()
 
 
 
 
 
 
9
 
 
10
  def recursive_find_user(target_name):
11
  matches = []
12
  norm_target = normalize(target_name)
@@ -14,8 +24,8 @@ def recursive_find_user(target_name):
14
  def _search(obj, path):
15
  if isinstance(obj, dict):
16
  for k, v in obj.items():
17
- # Direct match for string value
18
- if k in COMMON_NAME_KEYS and isinstance(v, str) and norm_target in normalize(v):
19
  login_info = {}
20
  for lk in LOGIN_KEYS:
21
  if lk in obj:
@@ -27,10 +37,10 @@ def recursive_find_user(target_name):
27
  "file": file_name,
28
  "login_info": login_info
29
  })
30
- # Nested dict, e.g., user: { username: ... }
31
  if k in COMMON_NAME_KEYS and isinstance(v, dict):
32
  for nk, nv in v.items():
33
- if nk in COMMON_NAME_KEYS and norm_target in normalize(nv):
34
  login_info = {}
35
  for lk in LOGIN_KEYS:
36
  if lk in obj:
@@ -49,6 +59,7 @@ def recursive_find_user(target_name):
49
  _search(data, [])
50
  return matches
51
 
 
52
  def show_all_users():
53
  found = []
54
  for file_name, data in st.session_state.json_data.items():
@@ -69,13 +80,13 @@ def show_all_users():
69
  recursive(data, [])
70
  return found
71
 
72
- import re
73
  def handle_user_query(query):
74
  patterns = [
75
- r"(?:last\s*login.*?for|when\s+did)\s+([a-zA-Z0-9 _\-\.]+)",
76
- r"when\s+was\s+([a-zA-Z0-9 _\-\.]+)\s+last\s+(?:login|logged\s*in)",
77
- r"last\s*login\s*of\s+([a-zA-Z0-9 _\-\.]+)",
78
- r"(?:info|details|record) for\s+([a-zA-Z0-9 _\-\.]+)"
79
  ]
80
  found_name = None
81
  for pat in patterns:
@@ -84,7 +95,8 @@ def handle_user_query(query):
84
  found_name = m.group(1).strip()
85
  break
86
  if not found_name:
87
- m = re.search(r"([A-Z][a-z]+(?: [A-Z][a-z]+)*)", query)
 
88
  if m:
89
  found_name = m.group(1).strip()
90
  if found_name:
@@ -101,7 +113,7 @@ def handle_user_query(query):
101
  else:
102
  return "Sorry, I can only answer direct user info queries (e.g., 'When did Bob the Builder last login?')."
103
 
104
- # --- Streamlit UI ---
105
  if "json_data" not in st.session_state:
106
  st.session_state.json_data = {}
107
  if "messages" not in st.session_state:
@@ -111,8 +123,8 @@ if "temp_input" not in st.session_state:
111
  if "files_loaded" not in st.session_state:
112
  st.session_state.files_loaded = False
113
 
114
- st.set_page_config(page_title="Instant JSON Q&A", layout="wide")
115
- st.title("Instant JSON-Backed AI Q&A (Now Handles Nested Users!)")
116
 
117
  uploaded_files = st.sidebar.file_uploader(
118
  "Choose one or more JSON files", type="json", accept_multiple_files=True
@@ -132,7 +144,7 @@ elif not uploaded_files:
132
  st.session_state.json_data.clear()
133
  st.session_state.files_loaded = False
134
 
135
- st.markdown("### Ask about any user directly (e.g. 'When did Bob the Builder last login?')")
136
  for msg in st.session_state.messages:
137
  if msg["role"] == "user":
138
  st.markdown(f"<div style='color: #4F8BF9;'><b>User:</b> {msg['content']}</div>", unsafe_allow_html=True)
 
1
  import streamlit as st
2
  import json
3
+ import difflib
4
+ import re
5
 
6
+ # --- Flexible/fuzzy search utilities ---
7
  COMMON_NAME_KEYS = ["user", "username", "name", "fullName", "firstName", "lastName", "customer"]
8
  LOGIN_KEYS = ["lastLogin", "login", "loggedIn", "lastLoggedIn", "last_login", "last_logged_in"]
9
 
10
  def normalize(s):
11
+ # Lowercase, replace separators with spaces, strip, collapse whitespace
12
+ return ' '.join(str(s).lower().replace("_", " ").replace("-", " ").replace(".", " ").split())
13
+
14
+ def is_fuzzy_match(a, b, threshold=0.7):
15
+ # Both a and b should be normalized strings
16
+ ratio = difflib.SequenceMatcher(None, a, b).ratio()
17
+ return ratio >= threshold or a in b or b in a
18
 
19
+ # --- Fuzzy, nested user search ---
20
  def recursive_find_user(target_name):
21
  matches = []
22
  norm_target = normalize(target_name)
 
24
  def _search(obj, path):
25
  if isinstance(obj, dict):
26
  for k, v in obj.items():
27
+ # Direct match for string value (fuzzy/partial)
28
+ if k in COMMON_NAME_KEYS and isinstance(v, str) and is_fuzzy_match(norm_target, normalize(v)):
29
  login_info = {}
30
  for lk in LOGIN_KEYS:
31
  if lk in obj:
 
37
  "file": file_name,
38
  "login_info": login_info
39
  })
40
+ # Nested dict (fuzzy/partial)
41
  if k in COMMON_NAME_KEYS and isinstance(v, dict):
42
  for nk, nv in v.items():
43
+ if nk in COMMON_NAME_KEYS and is_fuzzy_match(norm_target, normalize(nv)):
44
  login_info = {}
45
  for lk in LOGIN_KEYS:
46
  if lk in obj:
 
59
  _search(data, [])
60
  return matches
61
 
62
+ # --- Show all user keys/values (for debug) ---
63
  def show_all_users():
64
  found = []
65
  for file_name, data in st.session_state.json_data.items():
 
80
  recursive(data, [])
81
  return found
82
 
83
+ # --- User query handler ---
84
  def handle_user_query(query):
85
  patterns = [
86
+ r"(?:last\s*login.*?for|when\s+did)\s+([a-zA-Z0-9 _\-\.@]+)",
87
+ r"when\s+was\s+([a-zA-Z0-9 _\-\.@]+)\s+last\s+(?:login|logged\s*in)",
88
+ r"last\s*login\s*of\s+([a-zA-Z0-9 _\-\.@]+)",
89
+ r"(?:info|details|record) for\s+([a-zA-Z0-9 _\-\.@]+)"
90
  ]
91
  found_name = None
92
  for pat in patterns:
 
95
  found_name = m.group(1).strip()
96
  break
97
  if not found_name:
98
+ # Fallback: look for any word with at least 3 letters (handles very short names too)
99
+ m = re.search(r"([A-Za-z0-9][A-Za-z0-9 _\-\.@]{2,})", query)
100
  if m:
101
  found_name = m.group(1).strip()
102
  if found_name:
 
113
  else:
114
  return "Sorry, I can only answer direct user info queries (e.g., 'When did Bob the Builder last login?')."
115
 
116
+ # --- Streamlit UI setup ---
117
  if "json_data" not in st.session_state:
118
  st.session_state.json_data = {}
119
  if "messages" not in st.session_state:
 
123
  if "files_loaded" not in st.session_state:
124
  st.session_state.files_loaded = False
125
 
126
+ st.set_page_config(page_title="Flexible JSON User Q&A", layout="wide")
127
+ st.title("Instant JSON-Backed AI Q&A (Fuzzy Flexible Search!)")
128
 
129
  uploaded_files = st.sidebar.file_uploader(
130
  "Choose one or more JSON files", type="json", accept_multiple_files=True
 
144
  st.session_state.json_data.clear()
145
  st.session_state.files_loaded = False
146
 
147
+ st.markdown("### Ask about any user (partial/typo/fuzzy OK) try: `bob`, `bob the builder`, `astrofan`, `alice`, `johnny.appleseed`")
148
  for msg in st.session_state.messages:
149
  if msg["role"] == "user":
150
  st.markdown(f"<div style='color: #4F8BF9;'><b>User:</b> {msg['content']}</div>", unsafe_allow_html=True)