Update app.py
Browse files
app.py
CHANGED
|
@@ -37,7 +37,7 @@ elif not uploaded_files:
|
|
| 37 |
st.session_state.json_data.clear()
|
| 38 |
st.session_state.files_loaded = False
|
| 39 |
|
| 40 |
-
# --- NORMALIZE ---
|
| 41 |
def normalize(s):
|
| 42 |
return ' '.join(str(s).lower().replace("_", " ").replace("-", " ").replace(".", " ").split())
|
| 43 |
|
|
@@ -120,6 +120,32 @@ def count_key_occurrences(file_name, key):
|
|
| 120 |
except Exception as e:
|
| 121 |
return {"error": str(e)}
|
| 122 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
# --- FUNCTION SCHEMA for OpenAI ---
|
| 124 |
function_schema = [
|
| 125 |
{
|
|
@@ -167,14 +193,28 @@ function_schema = [
|
|
| 167 |
},
|
| 168 |
"required": ["file_name", "key"]
|
| 169 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
}
|
| 171 |
]
|
| 172 |
|
| 173 |
-
# --- SYSTEM PROMPT
|
| 174 |
system_message = {
|
| 175 |
"role": "system",
|
| 176 |
"content": (
|
| 177 |
"You are a JSON data assistant. Use the functions provided to answer the user's question. "
|
|
|
|
| 178 |
"If the user's query does not mention a key, use 'fuzzy_value_search' to match on any value. "
|
| 179 |
"If a key is mentioned (like 'apps_installed'), use 'search_all_jsons' for that key and the value. "
|
| 180 |
"You may use 'list_keys' to help discover the file structure if needed. "
|
|
@@ -209,7 +249,7 @@ def send_message():
|
|
| 209 |
"https://api.openai.com/v1/chat/completions",
|
| 210 |
headers=HEADERS,
|
| 211 |
json={
|
| 212 |
-
"model": "gpt-
|
| 213 |
"messages": chat_messages,
|
| 214 |
"functions": function_schema,
|
| 215 |
"function_call": "auto",
|
|
@@ -236,6 +276,12 @@ def send_message():
|
|
| 236 |
result = list_keys(args.get("file_name"))
|
| 237 |
elif func_name == "count_key_occurrences":
|
| 238 |
result = count_key_occurrences(args.get("file_name"), args.get("key"))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 239 |
else:
|
| 240 |
result = {"error": f"Unknown function: {func_name}"}
|
| 241 |
|
|
@@ -253,7 +299,7 @@ def send_message():
|
|
| 253 |
"https://api.openai.com/v1/chat/completions",
|
| 254 |
headers=HEADERS,
|
| 255 |
json={
|
| 256 |
-
"model": "gpt-
|
| 257 |
"messages": followup_messages,
|
| 258 |
"temperature": 0,
|
| 259 |
"max_tokens": 1200,
|
|
|
|
| 37 |
st.session_state.json_data.clear()
|
| 38 |
st.session_state.files_loaded = False
|
| 39 |
|
| 40 |
+
# --- NORMALIZE & FUZZY ---
|
| 41 |
def normalize(s):
|
| 42 |
return ' '.join(str(s).lower().replace("_", " ").replace("-", " ").replace(".", " ").split())
|
| 43 |
|
|
|
|
| 120 |
except Exception as e:
|
| 121 |
return {"error": str(e)}
|
| 122 |
|
| 123 |
+
# --- NEW: FIND/COUNT IN ARRAYS ---
|
| 124 |
+
def find_in_arrays(key, value, return_count=True):
|
| 125 |
+
# Searches ALL arrays for dicts where key == value
|
| 126 |
+
matches = []
|
| 127 |
+
count = 0
|
| 128 |
+
for file_name, data in st.session_state.json_data.items():
|
| 129 |
+
def recursive(obj):
|
| 130 |
+
nonlocal count
|
| 131 |
+
if isinstance(obj, list):
|
| 132 |
+
for item in obj:
|
| 133 |
+
if isinstance(item, dict):
|
| 134 |
+
for k, v in item.items():
|
| 135 |
+
if normalize(k) == normalize(key) and normalize(str(v)) == normalize(str(value)):
|
| 136 |
+
matches.append({
|
| 137 |
+
"file": file_name,
|
| 138 |
+
"item": item,
|
| 139 |
+
"array_path": key
|
| 140 |
+
})
|
| 141 |
+
count += 1
|
| 142 |
+
recursive(item)
|
| 143 |
+
elif isinstance(obj, dict):
|
| 144 |
+
for v in obj.values():
|
| 145 |
+
recursive(v)
|
| 146 |
+
recursive(data)
|
| 147 |
+
return count if return_count else matches
|
| 148 |
+
|
| 149 |
# --- FUNCTION SCHEMA for OpenAI ---
|
| 150 |
function_schema = [
|
| 151 |
{
|
|
|
|
| 193 |
},
|
| 194 |
"required": ["file_name", "key"]
|
| 195 |
}
|
| 196 |
+
},
|
| 197 |
+
{
|
| 198 |
+
"name": "find_in_arrays",
|
| 199 |
+
"description": "Find/count all objects in any arrays/lists where key equals value (e.g. done:true for completed tasks).",
|
| 200 |
+
"parameters": {
|
| 201 |
+
"type": "object",
|
| 202 |
+
"properties": {
|
| 203 |
+
"key": {"type": "string", "description": "The key to search for, e.g., 'done'"},
|
| 204 |
+
"value": {"type": "string", "description": "The value to match, e.g., 'true' or 'false'"},
|
| 205 |
+
"return_count": {"type": "boolean", "description": "Return the count (true) or matching records (false)."}
|
| 206 |
+
},
|
| 207 |
+
"required": ["key", "value"]
|
| 208 |
+
}
|
| 209 |
}
|
| 210 |
]
|
| 211 |
|
| 212 |
+
# --- SYSTEM PROMPT ---
|
| 213 |
system_message = {
|
| 214 |
"role": "system",
|
| 215 |
"content": (
|
| 216 |
"You are a JSON data assistant. Use the functions provided to answer the user's question. "
|
| 217 |
+
"If the user asks for the number or details of items in a list/array (e.g., completed tasks), use 'find_in_arrays'. "
|
| 218 |
"If the user's query does not mention a key, use 'fuzzy_value_search' to match on any value. "
|
| 219 |
"If a key is mentioned (like 'apps_installed'), use 'search_all_jsons' for that key and the value. "
|
| 220 |
"You may use 'list_keys' to help discover the file structure if needed. "
|
|
|
|
| 249 |
"https://api.openai.com/v1/chat/completions",
|
| 250 |
headers=HEADERS,
|
| 251 |
json={
|
| 252 |
+
"model": "gpt-4o",
|
| 253 |
"messages": chat_messages,
|
| 254 |
"functions": function_schema,
|
| 255 |
"function_call": "auto",
|
|
|
|
| 276 |
result = list_keys(args.get("file_name"))
|
| 277 |
elif func_name == "count_key_occurrences":
|
| 278 |
result = count_key_occurrences(args.get("file_name"), args.get("key"))
|
| 279 |
+
elif func_name == "find_in_arrays":
|
| 280 |
+
result = find_in_arrays(
|
| 281 |
+
args.get("key"),
|
| 282 |
+
args.get("value"),
|
| 283 |
+
args.get("return_count", True)
|
| 284 |
+
)
|
| 285 |
else:
|
| 286 |
result = {"error": f"Unknown function: {func_name}"}
|
| 287 |
|
|
|
|
| 299 |
"https://api.openai.com/v1/chat/completions",
|
| 300 |
headers=HEADERS,
|
| 301 |
json={
|
| 302 |
+
"model": "gpt-4o",
|
| 303 |
"messages": followup_messages,
|
| 304 |
"temperature": 0,
|
| 305 |
"max_tokens": 1200,
|