Stefan888 commited on
Commit
abd4794
·
1 Parent(s): 81917a3

first version with search tool

Browse files
Files changed (2) hide show
  1. app.py +143 -7
  2. requirements.txt +11 -1
app.py CHANGED
@@ -1,8 +1,16 @@
1
  import os
2
- import gradio as gr
3
- import requests
4
- import inspect
5
- import pandas as pd
 
 
 
 
 
 
 
 
6
 
7
  # (Keep Constants as is)
8
  # --- Constants ---
@@ -10,14 +18,142 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
10
 
11
  # --- Basic Agent Definition ---
12
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  class BasicAgent:
14
  def __init__(self):
15
  print("BasicAgent initialized.")
16
  def __call__(self, question: str) -> str:
17
  print(f"Agent received question (first 50 chars): {question[:50]}...")
18
- fixed_answer = "This is a default answer."
19
- print(f"Agent returning fixed answer: {fixed_answer}")
20
- return fixed_answer
 
 
 
 
 
 
 
 
21
 
22
  def run_and_submit_all( profile: gr.OAuthProfile | None):
23
  """
 
1
  import os
2
+ from IPython.display import Image, display
3
+ from typing import TypedDict, List, Dict, Any, Optional
4
+ from langgraph.graph import StateGraph, START, END
5
+ from langchain_openai import ChatOpenAI
6
+ from langchain_core.messages import HumanMessage, AIMessage
7
+ from langchain_huggingface import ChatHuggingFace, HuggingFaceEndpoint
8
+ #from langchain_community.tools import DuckDuckGoSearchRun
9
+ from langgraph.prebuilt import ToolNode, tools_condition
10
+ from langchain_core.messages import HumanMessage, SystemMessage
11
+ from langchain_core.utils.function_calling import convert_to_openai_tool
12
+ from langchain.tools import Tool
13
+ from serpapi import GoogleSearch
14
 
15
  # (Keep Constants as is)
16
  # --- Constants ---
 
18
 
19
  # --- Basic Agent Definition ---
20
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
21
+
22
+ SERPAPI_API_KEY = SERPAPI_TOKEN
23
+
24
+ def serpapi_search(query: str) -> str:
25
+ print(f"Running SerpAPI search for: {query}")
26
+ params = {
27
+ "engine": "google",
28
+ "q": query,
29
+ "api_key": SERPAPI_API_KEY,
30
+ "num": 3,
31
+ }
32
+ search = GoogleSearch(params)
33
+ results = search.get_dict()
34
+ if "organic_results" in results:
35
+ snippets = [item.get("snippet", "") for item in results["organic_results"]]
36
+ return "\n".join(snippets)
37
+ return "No results found."
38
+
39
+ serpapi_tool = Tool(
40
+ name="serpapi_search",
41
+ func=serpapi_search,
42
+ description="A tool that allows you to search the web using Google via SerpAPI. Input should be a search query."
43
+ )
44
+
45
+ # Initialize LLM
46
+ model = ChatOpenAI( model="gpt-4o",temperature=0)
47
+ vision_llm = ChatOpenAI(model="gpt-4o")
48
+
49
+ #search_tool = DuckDuckGoSearchRun()
50
+ tools = [serpapi_tool]
51
+
52
+ llm_with_tools = model.bind_tools(tools, parallel_tool_calls=False)
53
+
54
+ class AgentState(TypedDict):
55
+ question: Dict[str, Any]
56
+ messages: List[Any]
57
+ answer: Optional[str]
58
+ tool_calls: Optional[list]
59
+ tool_outputs: Optional[list]
60
+
61
+ def assistant(state: AgentState):
62
+ print("\n--- ASSISTANT NODE ---")
63
+ print(f"State received: {state}")
64
+ question = state["question"]
65
+ print(f"Question dict: {question}")
66
+ #textual_description_of_tool = """
67
+ #search_tool: A tool that allows you to search the web using DuckDuckGo. It returns a list of search results based on the query provided.
68
+ #"""
69
+ textual_description_of_tool = """
70
+ serpapi_search: A tool that allows you to search the web using Google via SerpAPI. It returns a list of search results based on the query provided.
71
+ """
72
+ system_prompt = SystemMessage(
73
+ content=f"""
74
+ You are an expert assistant. Try to answer the question as accurately as possible.
75
+ You can use the following tools to help you:
76
+ {textual_description_of_tool}
77
+ """
78
+ )
79
+ user_prompt = HumanMessage(content=f"Question: {question.get('question', question)}")
80
+ messages = [system_prompt, user_prompt] + state.get("messages", [])
81
+ # If tool_outputs exist, add them as context
82
+ if state.get("tool_outputs"):
83
+ messages.append(HumanMessage(content=f"Tool results: {state['tool_outputs']}"))
84
+ print(f"Messages sent to LLM: {messages}")
85
+ response = llm_with_tools.invoke(messages)
86
+ print(f"Raw LLM response: {response}")
87
+ # If the LLM wants to call a tool, store tool_calls in state
88
+ tool_calls = getattr(response, "tool_calls", None)
89
+ if tool_calls:
90
+ print(f"Tool calls requested: {tool_calls}")
91
+ state["tool_calls"] = tool_calls
92
+ state["answer"] = "" # Not final yet
93
+ else:
94
+ state["answer"] = response.content.strip()
95
+ print(f"Model response: {state['answer']}")
96
+ state.setdefault("messages", []).append(AIMessage(content=state["answer"]))
97
+ return state
98
+
99
+ def tool_node(state: AgentState):
100
+ print("\n--- TOOL NODE ---")
101
+ print(f"State received: {state}")
102
+ outputs = []
103
+ for call in state.get("tool_calls", []):
104
+ print(f"Tool call: {call}")
105
+ args = call.get("args", {})
106
+ # Try to get 'query' or fallback to the first value
107
+ query = args.get("query")
108
+ if query is None and len(args) > 0:
109
+ query = list(args.values())[0]
110
+ print(f"Query to use: {query}")
111
+ if call["name"] == "serpapi_search":
112
+ try:
113
+ result = serpapi_search(query)
114
+ except Exception as e:
115
+ print(f"Error running SerpAPI search: {e}")
116
+ result = f"Error: {e}"
117
+ outputs.append(result)
118
+ state["tool_outputs"] = outputs
119
+ state["tool_calls"] = None # Clear tool calls
120
+ return state
121
+
122
+ #building the graph
123
+ answering_graph = StateGraph(AgentState)
124
+
125
+ # Add nodes
126
+ answering_graph.add_node("assistant", assistant)
127
+ #answering_graph.add_node("tools", ToolNode(tools))
128
+ answering_graph.add_node("tools", tool_node)
129
+
130
+ # Add edges
131
+ answering_graph.add_edge(START, "assistant")
132
+ answering_graph.add_conditional_edges(
133
+ "assistant",
134
+ lambda state: "tools" if state.get("tool_calls") else END
135
+ )
136
+ answering_graph.add_edge("tools", "assistant")
137
+
138
+ # Compile the graph
139
+ compiled_graph = answering_graph.compile()
140
+
141
  class BasicAgent:
142
  def __init__(self):
143
  print("BasicAgent initialized.")
144
  def __call__(self, question: str) -> str:
145
  print(f"Agent received question (first 50 chars): {question[:50]}...")
146
+
147
+ initial_state = {
148
+ "question": question,
149
+ "messages": [],
150
+ "answer": None
151
+ }
152
+
153
+ print(f"Initial state: {initial_state}")
154
+ answer = compiled_graph.invoke(initial_state)
155
+ print(f"Agent returning answer: {answer}")
156
+ return answer
157
 
158
  def run_and_submit_all( profile: gr.OAuthProfile | None):
159
  """
requirements.txt CHANGED
@@ -1,2 +1,12 @@
 
 
 
 
 
 
 
 
1
  gradio
2
- requests
 
 
 
1
+ langchain
2
+ langchain-openai
3
+ langchain-huggingface
4
+ langchain-community
5
+ langgraph
6
+ openai
7
+ google-search-results
8
+ serpapi
9
  gradio
10
+ requests
11
+ pandas
12
+ ipython