Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -14,8 +14,31 @@ from langgraph.graph import StateGraph, START, END
|
|
14 |
from langgraph.graph.message import add_messages
|
15 |
from langchain.schema import HumanMessage, AIMessage, SystemMessage
|
16 |
# Create a ToolNode that knows about your web_search function
|
|
|
17 |
|
18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
# --- Constants ---
|
20 |
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
21 |
|
@@ -39,19 +62,20 @@ def respond_to_input(user_input: str) -> str:
|
|
39 |
"""
|
40 |
# (A) First message: describe your tools
|
41 |
system_msg = SystemMessage(
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
)
|
|
|
55 |
)
|
56 |
|
57 |
# (B) initial state has only the system prompt
|
@@ -61,12 +85,33 @@ def respond_to_input(user_input: str) -> str:
|
|
61 |
final_state = compiled_graph.invoke(initial_state, user_input)
|
62 |
|
63 |
# (D) Pull out the last AIMessage from final_state["messages"]:
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
|
71 |
|
72 |
class BasicAgent:
|
|
|
14 |
from langgraph.graph.message import add_messages
|
15 |
from langchain.schema import HumanMessage, AIMessage, SystemMessage
|
16 |
# Create a ToolNode that knows about your web_search function
|
17 |
+
import json
|
18 |
|
19 |
+
def parse_tool_json(text: str) -> dict | None:
|
20 |
+
"""
|
21 |
+
Given a string like '{"tool":"web_search","query":"..."}'
|
22 |
+
or '"{\"tool\":\"web_search\",\"query\":\"...\"}"', return
|
23 |
+
the parsed dict. Otherwise, return None.
|
24 |
+
"""
|
25 |
+
t = text.strip()
|
26 |
+
# If it’s wrapped in single or double quotes, remove them:
|
27 |
+
if (t.startswith('"') and t.endswith('"')) or (t.startswith("'") and t.endswith("'")):
|
28 |
+
t = t[1:-1]
|
29 |
+
try:
|
30 |
+
obj = json.loads(t)
|
31 |
+
if isinstance(obj, dict) and "tool" in obj:
|
32 |
+
return obj
|
33 |
+
except Exception:
|
34 |
+
return None
|
35 |
+
return None
|
36 |
+
|
37 |
+
|
38 |
+
# (Keep Constan
|
39 |
+
#
|
40 |
+
#
|
41 |
+
# ts as is)
|
42 |
# --- Constants ---
|
43 |
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
44 |
|
|
|
62 |
"""
|
63 |
# (A) First message: describe your tools
|
64 |
system_msg = SystemMessage(
|
65 |
+
content=(
|
66 |
+
"You are an assistant with access to exactly these tools:\n"
|
67 |
+
" 1) web_search(query:str)\n"
|
68 |
+
" 2) parse_excel(path:str,sheet_name:str)\n"
|
69 |
+
" 3) ocr_image(path:str)\n\n"
|
70 |
+
"⚠️ **IMPORTANT** ⚠️: If (and only if) you need to call one of these tools, "
|
71 |
+
"output exactly one JSON object and nothing else. For example:\n"
|
72 |
+
"```json\n"
|
73 |
+
'{"tool":"web_search","query":"Mercedes Sosa albums 2000-2009"}\n'
|
74 |
+
"```\n"
|
75 |
+
"That JSON must start at the very first character of your response and end at the very last character—"
|
76 |
+
"no quotes, no code fences, no extra explanation. \n\n"
|
77 |
+
"If you do NOT need any tool, simply reply with your final answer as plain text (no JSON)."
|
78 |
+
)
|
79 |
)
|
80 |
|
81 |
# (B) initial state has only the system prompt
|
|
|
85 |
final_state = compiled_graph.invoke(initial_state, user_input)
|
86 |
|
87 |
# (D) Pull out the last AIMessage from final_state["messages"]:
|
88 |
+
last_msg = None
|
89 |
+
for msg in final_state["messages"][::-1]:
|
90 |
+
if isinstance(msg, AIMessage):
|
91 |
+
last_msg = msg.content
|
92 |
+
break
|
93 |
+
|
94 |
+
# Try to parse it as a tool‐call dict:
|
95 |
+
tool_dict = parse_tool_json(last_msg or "")
|
96 |
+
if tool_dict is not None:
|
97 |
+
# run the tool and then feed it back into the LLM:
|
98 |
+
result = tool_node.run(tool_dict)
|
99 |
+
# Append the tool’s result as an AIMessage, then invoke again:
|
100 |
+
new_state = {
|
101 |
+
"messages": [
|
102 |
+
*final_state["messages"],
|
103 |
+
AIMessage(content=result)
|
104 |
+
]
|
105 |
+
}
|
106 |
+
second_pass = compiled_graph.invoke(new_state, "")
|
107 |
+
# Get that second pass’s last AIMessage:
|
108 |
+
for msg in second_pass["messages"][::-1]:
|
109 |
+
if isinstance(msg, AIMessage):
|
110 |
+
return msg.content
|
111 |
+
return ""
|
112 |
+
else:
|
113 |
+
# No valid tool JSON → treat last_msg as final answer
|
114 |
+
return last_msg or ""
|
115 |
|
116 |
|
117 |
class BasicAgent:
|