Seth0330 commited on
Commit
c7cc5ed
·
verified ·
1 Parent(s): 48ac593

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -49
app.py CHANGED
@@ -1,14 +1,11 @@
1
  import streamlit as st
2
- import os
3
  import json
4
- import traceback
5
- from datetime import datetime
6
 
7
- # ---- CONFIG ----
8
  COMMON_NAME_KEYS = ["user", "username", "name", "fullName", "firstName", "lastName"]
9
  LOGIN_KEYS = ["lastLogin", "login", "loggedIn", "lastLoggedIn", "last_login", "last_logged_in"]
10
 
11
- # --- ALWAYS INIT SESSION STATE FIRST (before any widgets)
12
  if "json_data" not in st.session_state:
13
  st.session_state.json_data = {}
14
  if "messages" not in st.session_state:
@@ -21,13 +18,12 @@ if "files_loaded" not in st.session_state:
21
  st.set_page_config(page_title="Instant JSON Q&A", layout="wide")
22
  st.title("Instant JSON-Backed AI Q&A (No More Clarifying Loops)")
23
 
24
- # --- Upload area
25
  st.sidebar.header("Upload Multiple JSON Files")
26
  uploaded_files = st.sidebar.file_uploader(
27
  "Choose one or more JSON files", type="json", accept_multiple_files=True
28
  )
29
 
30
- # --- Load/clear files as needed
31
  if uploaded_files and not st.session_state.files_loaded:
32
  st.session_state.json_data.clear()
33
  for f in uploaded_files:
@@ -43,48 +39,63 @@ elif not uploaded_files:
43
  st.session_state.json_data.clear()
44
  st.session_state.files_loaded = False
45
 
46
- # --- UNIVERSAL SEARCH FUNCTION ----
47
- def recursive_find_user(obj, target_name):
48
- """
49
- Recursively search for dicts containing a value matching target_name under any COMMON_NAME_KEYS.
50
- Returns list of matches: dicts with the matching name, file name, and all possible login info found.
51
- """
 
52
  matches = []
53
- def _search(obj, path, file_name):
54
- if isinstance(obj, dict):
55
- for k, v in obj.items():
56
- # Check if any "name" key matches (case-insensitive substring match)
57
- if k in COMMON_NAME_KEYS and target_name.lower() in str(v).lower():
58
- login_info = {}
59
- # Find login info at this level
60
- for lk in LOGIN_KEYS:
61
- if lk in obj:
62
- login_info[lk] = obj[lk]
63
- matches.append({
64
- "match_path": path + [k],
65
- "matched_name": v,
66
- "record": obj,
67
- "file": file_name,
68
- "login_info": login_info
69
- })
70
- _search(v, path + [k], file_name)
71
- elif isinstance(obj, list):
72
- for idx, item in enumerate(obj):
73
- _search(item, path + [f"[{idx}]"], file_name)
74
  for file_name, data in st.session_state.json_data.items():
75
- _search(data, [], file_name)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  return matches
77
 
78
- # --- MAIN QUERY LOGIC ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  def handle_user_query(query):
80
- # 1. If question looks like "last login for <name>", extract name and search
81
- import re
82
- # Covers "last login for", "when did X last login", "when was X last seen", etc.
83
  patterns = [
84
- r"(?:last\s*login.*?for|when\s+did)\s+(.*?)\?*$", # e.g. last login for Bob, when did Bob last login
85
- r"when\s+was\s+(.*?)\s+last\s+(?:login|logged\s*in)", # when was Bob last logged in
86
- r"last\s*login\s*of\s+(.*?)\?*$",
87
- r"(?:info|details|record) for\s+(.*?)\?*$"
88
  ]
89
  found_name = None
90
  for pat in patterns:
@@ -93,15 +104,14 @@ def handle_user_query(query):
93
  found_name = m.group(1).strip()
94
  break
95
  if not found_name:
96
- # Fallback: just look for the first capitalized word (e.g. Bob, Bob the Builder)
97
  m = re.search(r"([A-Z][a-z]+(?: [A-Z][a-z]+)*)", query)
98
  if m:
99
  found_name = m.group(1).strip()
100
  if found_name:
101
- results = recursive_find_user(st.session_state.json_data, found_name)
102
  if not results:
103
  return f"No records found for '{found_name}' in any file."
104
- # Report each match and all login fields found
105
  answers = []
106
  for res in results:
107
  login = ", ".join([f"{k}: {v}" for k, v in res["login_info"].items()]) if res["login_info"] else "No login info found"
@@ -110,10 +120,9 @@ def handle_user_query(query):
110
  )
111
  return "\n\n".join(answers)
112
  else:
113
- # For all other queries, just report "Sorry, direct name lookups only. (Add more query logic if you want!)"
114
- return "Sorry, I can only answer direct user info queries (e.g., 'When did Bob the Builder last login?'). If you want more logic, let me know!"
115
 
116
- # --- CHAT UI (NO LLM ROUNDTRIP!)
117
  st.markdown("### Ask about any user directly (e.g. 'When did Bob the Builder last login?')")
118
  for msg in st.session_state.messages:
119
  if msg["role"] == "user":
@@ -131,5 +140,7 @@ def send_message():
131
 
132
  if st.session_state.json_data:
133
  st.text_input("Your message:", key="temp_input", on_change=send_message)
 
 
134
  else:
135
  st.info("Please upload at least one JSON file to start chatting.")
 
1
  import streamlit as st
 
2
  import json
 
 
3
 
4
+ # --- Constants for searching ---
5
  COMMON_NAME_KEYS = ["user", "username", "name", "fullName", "firstName", "lastName"]
6
  LOGIN_KEYS = ["lastLogin", "login", "loggedIn", "lastLoggedIn", "last_login", "last_logged_in"]
7
 
8
+ # --- Session state setup ---
9
  if "json_data" not in st.session_state:
10
  st.session_state.json_data = {}
11
  if "messages" not in st.session_state:
 
18
  st.set_page_config(page_title="Instant JSON Q&A", layout="wide")
19
  st.title("Instant JSON-Backed AI Q&A (No More Clarifying Loops)")
20
 
21
+ # --- Upload area ---
22
  st.sidebar.header("Upload Multiple JSON Files")
23
  uploaded_files = st.sidebar.file_uploader(
24
  "Choose one or more JSON files", type="json", accept_multiple_files=True
25
  )
26
 
 
27
  if uploaded_files and not st.session_state.files_loaded:
28
  st.session_state.json_data.clear()
29
  for f in uploaded_files:
 
39
  st.session_state.json_data.clear()
40
  st.session_state.files_loaded = False
41
 
42
+ # --- Robust normalization function for matching ---
43
+ def normalize(s):
44
+ # Lowercase, remove underscores/dashes, strip, collapse double spaces
45
+ return str(s).lower().replace("_", " ").replace("-", " ").replace(".", " ").strip()
46
+
47
+ # --- Recursive user search with robust matching ---
48
+ def recursive_find_user(target_name):
49
  matches = []
50
+ norm_target = normalize(target_name)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  for file_name, data in st.session_state.json_data.items():
52
+ def _search(obj, path):
53
+ if isinstance(obj, dict):
54
+ for k, v in obj.items():
55
+ if k in COMMON_NAME_KEYS and norm_target in normalize(v):
56
+ login_info = {}
57
+ for lk in LOGIN_KEYS:
58
+ if lk in obj:
59
+ login_info[lk] = obj[lk]
60
+ matches.append({
61
+ "match_path": path + [k],
62
+ "matched_name": v,
63
+ "record": obj,
64
+ "file": file_name,
65
+ "login_info": login_info
66
+ })
67
+ _search(v, path + [k])
68
+ elif isinstance(obj, list):
69
+ for idx, item in enumerate(obj):
70
+ _search(item, path + [f"[{idx}]"])
71
+ _search(data, [])
72
  return matches
73
 
74
+ # --- Show all user keys/values (for debug) ---
75
+ def show_all_users():
76
+ found = []
77
+ for file_name, data in st.session_state.json_data.items():
78
+ def recursive(obj, path):
79
+ if isinstance(obj, dict):
80
+ for k, v in obj.items():
81
+ if k in COMMON_NAME_KEYS:
82
+ found.append(f"{file_name} | {'.'.join(path + [k])} = {v}")
83
+ recursive(v, path + [k])
84
+ elif isinstance(obj, list):
85
+ for idx, item in enumerate(obj):
86
+ recursive(item, path + [f"[{idx}]"])
87
+ recursive(data, [])
88
+ return found
89
+
90
+ # --- Main Q&A logic ---
91
+ import re
92
  def handle_user_query(query):
93
+ # Try to extract a likely user name from the query
 
 
94
  patterns = [
95
+ r"(?:last\s*login.*?for|when\s+did)\s+([a-zA-Z0-9 _\-\.]+)",
96
+ r"when\s+was\s+([a-zA-Z0-9 _\-\.]+)\s+last\s+(?:login|logged\s*in)",
97
+ r"last\s*login\s*of\s+([a-zA-Z0-9 _\-\.]+)",
98
+ r"(?:info|details|record) for\s+([a-zA-Z0-9 _\-\.]+)"
99
  ]
100
  found_name = None
101
  for pat in patterns:
 
104
  found_name = m.group(1).strip()
105
  break
106
  if not found_name:
107
+ # Fallback: look for first capitalized word or phrase
108
  m = re.search(r"([A-Z][a-z]+(?: [A-Z][a-z]+)*)", query)
109
  if m:
110
  found_name = m.group(1).strip()
111
  if found_name:
112
+ results = recursive_find_user(found_name)
113
  if not results:
114
  return f"No records found for '{found_name}' in any file."
 
115
  answers = []
116
  for res in results:
117
  login = ", ".join([f"{k}: {v}" for k, v in res["login_info"].items()]) if res["login_info"] else "No login info found"
 
120
  )
121
  return "\n\n".join(answers)
122
  else:
123
+ return "Sorry, I can only answer direct user info queries (e.g., 'When did Bob the Builder last login?')."
 
124
 
125
+ # --- Chat UI ---
126
  st.markdown("### Ask about any user directly (e.g. 'When did Bob the Builder last login?')")
127
  for msg in st.session_state.messages:
128
  if msg["role"] == "user":
 
140
 
141
  if st.session_state.json_data:
142
  st.text_input("Your message:", key="temp_input", on_change=send_message)
143
+ if st.button("Show all users in uploaded JSONs"):
144
+ st.write(show_all_users())
145
  else:
146
  st.info("Please upload at least one JSON file to start chatting.")