Spaces:
Sleeping
Sleeping
Upload 2 files
Browse files
agents.py
CHANGED
|
@@ -94,6 +94,8 @@ def extract_json_array(text: str):
|
|
| 94 |
json_str = re.sub(r'"\s*}\s*"', '"}', json_str)
|
| 95 |
# Fix missing commas between objects
|
| 96 |
json_str = re.sub(r'"\s*}\s*{', '"},{', json_str)
|
|
|
|
|
|
|
| 97 |
return json.loads(json_str)
|
| 98 |
except Exception as e3:
|
| 99 |
print("[extract_json_array] JSON fixing failed:", e3)
|
|
@@ -138,6 +140,8 @@ def safe_json_parse(content: str, fallback_value=None):
|
|
| 138 |
fixed_content = re.sub(r'"\s*}\s*"', '"}', fixed_content)
|
| 139 |
# Fix missing commas between objects
|
| 140 |
fixed_content = re.sub(r'"\s*}\s*{', '"},{', fixed_content)
|
|
|
|
|
|
|
| 141 |
return json.loads(fixed_content)
|
| 142 |
except Exception as e3:
|
| 143 |
print(f"[safe_json_parse] JSON fixing failed: {e3}")
|
|
@@ -229,6 +233,36 @@ async def extract_books_node(state):
|
|
| 229 |
books = manual_books
|
| 230 |
print("[extract_books_node] Pattern-based extraction successful:", books)
|
| 231 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 232 |
print("[extract_books_node] Parsed books:", books)
|
| 233 |
|
| 234 |
# Ensure books is a list and each book has required fields
|
|
@@ -475,6 +509,7 @@ async def reasoning_node(state):
|
|
| 475 |
print("[reasoning_node] Validated final recommendations:", validated_recommendations)
|
| 476 |
print("[reasoning_node] Final reasoning:\n", final_reasoning)
|
| 477 |
|
|
|
|
| 478 |
result_state = {
|
| 479 |
"final_recommendations": validated_recommendations,
|
| 480 |
"final_reasoning": final_reasoning
|
|
@@ -483,7 +518,8 @@ async def reasoning_node(state):
|
|
| 483 |
print("[reasoning_node] Returning state with keys:", list(result_state.keys()))
|
| 484 |
print("[reasoning_node] π exit with", result_state)
|
| 485 |
|
| 486 |
-
|
|
|
|
| 487 |
|
| 488 |
except Exception as e:
|
| 489 |
print("[reasoning_node] β exception:", repr(e))
|
|
|
|
| 94 |
json_str = re.sub(r'"\s*}\s*"', '"}', json_str)
|
| 95 |
# Fix missing commas between objects
|
| 96 |
json_str = re.sub(r'"\s*}\s*{', '"},{', json_str)
|
| 97 |
+
# Fix extra quotes around individual objects in arrays
|
| 98 |
+
json_str = re.sub(r'"\s*({[^}]+})\s*"', r'\1', json_str)
|
| 99 |
return json.loads(json_str)
|
| 100 |
except Exception as e3:
|
| 101 |
print("[extract_json_array] JSON fixing failed:", e3)
|
|
|
|
| 140 |
fixed_content = re.sub(r'"\s*}\s*"', '"}', fixed_content)
|
| 141 |
# Fix missing commas between objects
|
| 142 |
fixed_content = re.sub(r'"\s*}\s*{', '"},{', fixed_content)
|
| 143 |
+
# Fix extra quotes around individual objects in arrays
|
| 144 |
+
fixed_content = re.sub(r'"\s*({[^}]+})\s*"', r'\1', fixed_content)
|
| 145 |
return json.loads(fixed_content)
|
| 146 |
except Exception as e3:
|
| 147 |
print(f"[safe_json_parse] JSON fixing failed: {e3}")
|
|
|
|
| 233 |
books = manual_books
|
| 234 |
print("[extract_books_node] Pattern-based extraction successful:", books)
|
| 235 |
|
| 236 |
+
# Additional fix: if books is a list but contains malformed strings, try to fix them
|
| 237 |
+
if isinstance(books, list) and books:
|
| 238 |
+
print("[extract_books_node] Checking for malformed book entries...")
|
| 239 |
+
fixed_books = []
|
| 240 |
+
for book in books:
|
| 241 |
+
if isinstance(book, str):
|
| 242 |
+
# Try to parse the string as JSON
|
| 243 |
+
try:
|
| 244 |
+
# Remove extra quotes around the object
|
| 245 |
+
cleaned_book = book.strip()
|
| 246 |
+
if cleaned_book.startswith('"') and cleaned_book.endswith('"'):
|
| 247 |
+
cleaned_book = cleaned_book[1:-1]
|
| 248 |
+
parsed_book = json.loads(cleaned_book)
|
| 249 |
+
if isinstance(parsed_book, dict) and parsed_book.get("title"):
|
| 250 |
+
fixed_books.append(parsed_book)
|
| 251 |
+
except:
|
| 252 |
+
# Try regex extraction as fallback
|
| 253 |
+
title_match = re.search(r'"title":\s*"([^"]+)"', book)
|
| 254 |
+
author_match = re.search(r'"author":\s*"([^"]+)"', book)
|
| 255 |
+
if title_match:
|
| 256 |
+
title = title_match.group(1)
|
| 257 |
+
author = author_match.group(1) if author_match else "Unknown"
|
| 258 |
+
fixed_books.append({"title": title, "author": author})
|
| 259 |
+
elif isinstance(book, dict) and book.get("title"):
|
| 260 |
+
fixed_books.append(book)
|
| 261 |
+
|
| 262 |
+
if fixed_books:
|
| 263 |
+
books = fixed_books
|
| 264 |
+
print("[extract_books_node] Fixed malformed book entries:", books)
|
| 265 |
+
|
| 266 |
print("[extract_books_node] Parsed books:", books)
|
| 267 |
|
| 268 |
# Ensure books is a list and each book has required fields
|
|
|
|
| 509 |
print("[reasoning_node] Validated final recommendations:", validated_recommendations)
|
| 510 |
print("[reasoning_node] Final reasoning:\n", final_reasoning)
|
| 511 |
|
| 512 |
+
# Return the new state with our data
|
| 513 |
result_state = {
|
| 514 |
"final_recommendations": validated_recommendations,
|
| 515 |
"final_reasoning": final_reasoning
|
|
|
|
| 518 |
print("[reasoning_node] Returning state with keys:", list(result_state.keys()))
|
| 519 |
print("[reasoning_node] π exit with", result_state)
|
| 520 |
|
| 521 |
+
# Try returning as a dict to ensure proper state handling
|
| 522 |
+
return dict(result_state)
|
| 523 |
|
| 524 |
except Exception as e:
|
| 525 |
print("[reasoning_node] β exception:", repr(e))
|
app.py
CHANGED
|
@@ -33,14 +33,29 @@ async def run_book_recommender(user_input):
|
|
| 33 |
}
|
| 34 |
|
| 35 |
# Ensure we have the expected keys in final_state
|
|
|
|
|
|
|
|
|
|
| 36 |
if "final_recommendations" not in final_state:
|
|
|
|
| 37 |
final_state["final_recommendations"] = []
|
| 38 |
if "final_reasoning" not in final_state:
|
|
|
|
| 39 |
final_state["final_reasoning"] = "β οΈ Missing reasoning data from graph execution."
|
| 40 |
|
| 41 |
-
# Access the final state
|
| 42 |
recs = final_state.get("final_recommendations", [])
|
| 43 |
reasoning = final_state.get("final_reasoning", "")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
# Defensive formatting of recommendations
|
| 46 |
try:
|
|
|
|
| 33 |
}
|
| 34 |
|
| 35 |
# Ensure we have the expected keys in final_state
|
| 36 |
+
print(f"π Final state keys: {list(final_state.keys())}")
|
| 37 |
+
print(f"π Final state content: {final_state}")
|
| 38 |
+
|
| 39 |
if "final_recommendations" not in final_state:
|
| 40 |
+
print("β οΈ final_recommendations not found in final state")
|
| 41 |
final_state["final_recommendations"] = []
|
| 42 |
if "final_reasoning" not in final_state:
|
| 43 |
+
print("β οΈ final_reasoning not found in final state")
|
| 44 |
final_state["final_reasoning"] = "β οΈ Missing reasoning data from graph execution."
|
| 45 |
|
| 46 |
+
# Access the final state - check both possible structures
|
| 47 |
recs = final_state.get("final_recommendations", [])
|
| 48 |
reasoning = final_state.get("final_reasoning", "")
|
| 49 |
+
|
| 50 |
+
# If not found in direct keys, check if they're nested under 'reasoning'
|
| 51 |
+
if not recs and "reasoning" in final_state:
|
| 52 |
+
reasoning_data = final_state.get("reasoning", {})
|
| 53 |
+
if isinstance(reasoning_data, dict):
|
| 54 |
+
recs = reasoning_data.get("final_recommendations", [])
|
| 55 |
+
reasoning = reasoning_data.get("final_reasoning", reasoning)
|
| 56 |
+
|
| 57 |
+
print(f"π Extracted recs: {recs}")
|
| 58 |
+
print(f"π Extracted reasoning (first 200 chars): {reasoning[:200] if reasoning else 'None'}...")
|
| 59 |
|
| 60 |
# Defensive formatting of recommendations
|
| 61 |
try:
|