naman1102 commited on
Commit
b8a605f
·
1 Parent(s): 66102de

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +44 -33
app.py CHANGED
@@ -28,12 +28,6 @@ llm = ChatOpenAI(model_name="gpt-4.1-mini", temperature=0.0)
28
 
29
  # ─── 2) Revised plan_node ───
30
  def plan_node(state: AgentState) -> AgentState:
31
- """
32
- Look at the last HumanMessage in state['messages'] to get user_input.
33
- Then call llm with exactly [SystemMessage, HumanMessage(user_input)] so
34
- we never feed in a list lacking an AIMessage internally.
35
- """
36
- # 1) Find the last HumanMessage from prior history
37
  prior_msgs = state.get("messages", [])
38
  user_input = ""
39
  for msg in reversed(prior_msgs):
@@ -41,30 +35,39 @@ def plan_node(state: AgentState) -> AgentState:
41
  user_input = msg.content
42
  break
43
 
44
- # 2) Build a fresh SystemMessage explaining exactly one dict key
45
  system_msg = SystemMessage(
46
  content=(
47
- "You are an agent that decides whether to call a tool or answer the user directly. "
48
- "The user's question is below. If the answer can be given directly, return {'final_answer': <your answer>}."
49
- "If you need to call a tool, set exactly one key from the following in a Python dict: "
50
- " web_search_query: <search terms>\n"
51
- " • ocr_path: <path to an image file>\n"
52
- " • excel_path: <path to a .xlsx file>, excel_sheet_name: <sheet name>.\n"
53
- " • audio_path: <path to an audio file>\n"
54
- "Do not include any extra text or markdown—only return a valid Python dict literal."
 
55
  )
56
  )
57
  human_msg = HumanMessage(content=user_input)
58
 
59
- # 3) Call the LLM with a brand‐new list [system_msg, human_msg]
60
  llm_response = llm([system_msg, human_msg])
61
  llm_out = llm_response.content.strip()
62
 
63
- # 4) Always append the LLM output as an AIMessage
 
 
 
 
 
64
  ai_msg = AIMessage(content=llm_out)
65
  new_msgs = prior_msgs.copy() + [ai_msg]
 
 
66
  try:
67
- parsed = eval(llm_out, {}, {})
 
68
  if isinstance(parsed, dict):
69
  partial: AgentState = {"messages": new_msgs}
70
  allowed = {
@@ -78,31 +81,29 @@ def plan_node(state: AgentState) -> AgentState:
78
  for k, v in parsed.items():
79
  if k in allowed:
80
  partial[k] = v
 
81
  return partial
82
- except Exception:
83
- pass
 
 
 
 
84
 
85
- # 5) Fallback
86
- return {
87
- "messages": new_msgs,
88
- "final_answer": "Sorry, I could not parse your intent."
89
- }
90
 
91
 
92
  # ─── 3) Revised finalize_node ───
93
  def finalize_node(state: AgentState) -> AgentState:
94
- # If plan_node already provided a final answer, skip LLM
95
  if state.get("final_answer") is not None:
 
96
  return {"final_answer": state["final_answer"]}
97
 
98
- # Re-extract the last user question from messages
99
  question = ""
100
  for msg in reversed(state.get("messages", [])):
101
  if isinstance(msg, HumanMessage):
102
  question = msg.content
103
  break
104
 
105
- # Build a combined context
106
  combined = f"USER_QUESTION: {question}\n"
107
  if sr := state.get("web_search_result"):
108
  combined += f"WEB_SEARCH_RESULT: {sr}\n"
@@ -110,11 +111,17 @@ def finalize_node(state: AgentState) -> AgentState:
110
  combined += f"OCR_RESULT: {orc}\n"
111
  if exr := state.get("excel_result"):
112
  combined += f"EXCEL_RESULT: {exr}\n"
113
- # Check for both possible transcript keys
114
  audio_transcript = state.get("audio_transcript") or state.get("transcript")
115
  if audio_transcript:
116
  combined += f"AUDIO_TRANSCRIPT: {audio_transcript}\n"
117
- combined += "Based on the above, provide ONLY the final answer. Do not include any explanation or extra text. the final answer should be in the same language as the user's question. should be as few words as possible. if its multiple words, put them comma sepreated. if its a number, then return the number ONLY as a string."
 
 
 
 
 
 
 
118
 
119
  llm_response = llm([SystemMessage(content=combined)])
120
  return {"final_answer": llm_response.content.strip()}
@@ -153,17 +160,21 @@ graph.add_edge(START, "plan")
153
 
154
  # 5.c) plan → conditional: if any tool key was set, go to "tools"; otherwise "finalize"
155
  def route_plan(plan_out: AgentState) -> str:
 
 
 
156
  if (
157
  plan_out.get("web_search_query")
158
  or plan_out.get("ocr_path")
159
  or plan_out.get("excel_path")
160
- or plan_out.get("audio_path") # newly added
161
  ):
162
- print("Going to tools")
163
  return "tools"
164
- print("Going to finalize")
165
  return "finalize"
166
 
 
167
  graph.add_conditional_edges(
168
  "plan",
169
  route_plan,
 
28
 
29
  # ─── 2) Revised plan_node ───
30
  def plan_node(state: AgentState) -> AgentState:
 
 
 
 
 
 
31
  prior_msgs = state.get("messages", [])
32
  user_input = ""
33
  for msg in reversed(prior_msgs):
 
35
  user_input = msg.content
36
  break
37
 
38
+ # (1) Build your system/human messages exactly as before
39
  system_msg = SystemMessage(
40
  content=(
41
+ "You are an agent that decides whether to call a tool or answer directly.\n"
42
+ "User’s question: \"" + user_input + "\"\n\n"
43
+ "If you can answer directly, return exactly {\"final_answer\":\"<your answer>\"}.\n"
44
+ "• Otherwise, respond with exactly one of:\n"
45
+ " {\"web_search_query\":\"<search terms>\"}\n"
46
+ " {\"ocr_path\":\"<path to image>\"}\n"
47
+ " {\"excel_path\":\"<path to xlsx>\", \"excel_sheet_name\":\"<sheet>\"}\n"
48
+ " {\"audio_path\":\"<path to audio file>\"}\n"
49
+ "Do not include any extra characters or markdown—only the JSON literal."
50
  )
51
  )
52
  human_msg = HumanMessage(content=user_input)
53
 
54
+ # (2) Call the LLM
55
  llm_response = llm([system_msg, human_msg])
56
  llm_out = llm_response.content.strip()
57
 
58
+ # ── DEBUG: print raw LLM output ──
59
+ print("\n>>> plan_node got raw LLM output:")
60
+ print(llm_out)
61
+ print("<<< end raw output\n")
62
+
63
+ # (3) Append the LLM output to the message history
64
  ai_msg = AIMessage(content=llm_out)
65
  new_msgs = prior_msgs.copy() + [ai_msg]
66
+
67
+ # (4) Try parsing as JSON
68
  try:
69
+ parsed = json.loads(llm_out)
70
+ print(">>> plan_node parsed JSON:", parsed)
71
  if isinstance(parsed, dict):
72
  partial: AgentState = {"messages": new_msgs}
73
  allowed = {
 
81
  for k, v in parsed.items():
82
  if k in allowed:
83
  partial[k] = v
84
+ print(f">>> plan_node is setting {k!r} → {v!r}")
85
  return partial
86
+ except json.JSONDecodeError as e:
87
+ print(">>> plan_node JSON parse error:", e)
88
+
89
+ # (5) Fallback
90
+ print(">>> plan_node falling back to final_answer alone\n")
91
+ return {"messages": new_msgs, "final_answer": "Sorry, I could not parse your intent."}
92
 
 
 
 
 
 
93
 
94
 
95
  # ─── 3) Revised finalize_node ───
96
  def finalize_node(state: AgentState) -> AgentState:
 
97
  if state.get("final_answer") is not None:
98
+ print(">>> finalize_node: returning existing final_answer:", state["final_answer"])
99
  return {"final_answer": state["final_answer"]}
100
 
 
101
  question = ""
102
  for msg in reversed(state.get("messages", [])):
103
  if isinstance(msg, HumanMessage):
104
  question = msg.content
105
  break
106
 
 
107
  combined = f"USER_QUESTION: {question}\n"
108
  if sr := state.get("web_search_result"):
109
  combined += f"WEB_SEARCH_RESULT: {sr}\n"
 
111
  combined += f"OCR_RESULT: {orc}\n"
112
  if exr := state.get("excel_result"):
113
  combined += f"EXCEL_RESULT: {exr}\n"
 
114
  audio_transcript = state.get("audio_transcript") or state.get("transcript")
115
  if audio_transcript:
116
  combined += f"AUDIO_TRANSCRIPT: {audio_transcript}\n"
117
+
118
+ combined += (
119
+ "Based on the above, provide ONLY the final answer. "
120
+ "…(rest of your instructions)…"
121
+ )
122
+
123
+ # DEBUG: show exactly what we're sending to GPT-4 for final answer
124
+ print("\n>>> finalize_node prompt to LLM:\n" + combined + "\n<<< end prompt >>>\n")
125
 
126
  llm_response = llm([SystemMessage(content=combined)])
127
  return {"final_answer": llm_response.content.strip()}
 
160
 
161
  # 5.c) plan → conditional: if any tool key was set, go to "tools"; otherwise "finalize"
162
  def route_plan(plan_out: AgentState) -> str:
163
+ # print what keys are present in plan_out
164
+ print(f">> route_plan sees plan_out keys: {list(plan_out.keys())}")
165
+
166
  if (
167
  plan_out.get("web_search_query")
168
  or plan_out.get("ocr_path")
169
  or plan_out.get("excel_path")
170
+ or plan_out.get("audio_path")
171
  ):
172
+ print(">> route_plan ➡️ tools")
173
  return "tools"
174
+ print(">> route_plan ➡️ finalize")
175
  return "finalize"
176
 
177
+
178
  graph.add_conditional_edges(
179
  "plan",
180
  route_plan,