wt002 commited on
Commit
d17ef16
·
verified ·
1 Parent(s): a52ceb6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +22 -175
app.py CHANGED
@@ -3,20 +3,8 @@ import gradio as gr
3
  import requests
4
  import inspect
5
  import pandas as pd
6
- from typing import TypedDict, Annotated, Sequence, Dict, Any, List, Optional
7
- from langchain_core.messages import BaseMessage, HumanMessage
8
- from langchain_core.tools import tool
9
- from langchain_openai import ChatOpenAI
10
- from langgraph.graph import END, StateGraph
11
- from langgraph.prebuilt import ToolNode
12
- from langchain_community.tools import DuckDuckGoSearchResults
13
- from langchain_community.utilities import WikipediaAPIWrapper
14
- from langchain.agents import create_tool_calling_agent, AgentExecutor
15
- from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
16
- import operator
17
- from langchain_experimental.utilities import PythonREPL
18
- from functools import wraps
19
- import logging
20
 
21
  # (Keep Constants as is)
22
  # --- Constants ---
@@ -26,168 +14,29 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
26
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
27
 
28
 
29
-
30
- # --- Configure logging ---
31
- logging.basicConfig(level=logging.INFO)
32
- logger = logging.getLogger(__name__)
33
-
34
- # --- Constants ---
35
- DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
36
- DEFAULT_MODEL = "gpt-3.5-turbo"
37
- MAX_RESPONSE_LENGTH = 2000 # Prevent overly long responses
38
-
39
- def handle_errors(func):
40
- """Decorator to handle common errors in agent operations."""
41
- @wraps(func)
42
- def wrapper(*args, **kwargs):
43
- try:
44
- return func(*args, **kwargs)
45
- except Exception as e:
46
- logger.error(f"Error in {func.__name__}: {str(e)}")
47
- return {"error": str(e)}
48
- return wrapper
49
-
50
- class AgentState(TypedDict):
51
- messages: Annotated[Sequence[BaseMessage], operator.add]
52
- sender: str
53
-
54
- @tool
55
- def wikipedia_search(query: str) -> str:
56
- """Search Wikipedia for information. Useful for historical facts, scientific concepts, and general knowledge."""
57
- try:
58
- return WikipediaAPIWrapper().run(query)[:MAX_RESPONSE_LENGTH]
59
- except Exception as e:
60
- return f"Wikipedia search failed: {str(e)}"
61
-
62
- @tool
63
- def web_search(query: str, num_results: int = 3) -> list:
64
- """Search the web for current information. Useful for news, recent events, and up-to-date data."""
65
- try:
66
- results = DuckDuckGoSearchResults(num_results=num_results).run(query)
67
- return [str(r)[:500] for r in results][:num_results] # Limit result size
68
- except Exception as e:
69
- return [f"Web search failed: {str(e)}"]
70
-
71
- @tool
72
- def calculate(expression: str) -> str:
73
- """Evaluate mathematical expressions. Supports basic arithmetic and complex formulas."""
74
- try:
75
- python_repl = PythonREPL()
76
- result = python_repl.run(expression)
77
- return str(result)[:100] # Limit numeric output length
78
- except Exception as e:
79
- return f"Calculation failed: {str(e)}"
80
-
81
  class BasicAgent:
82
- """An enhanced LangGraph agent with better error handling and response processing."""
83
-
84
- def __init__(self, model_name: str = DEFAULT_MODEL, temperature: float = 0.7):
85
- """Initialize the agent with tools and workflow."""
86
- self.model_name = model_name
87
- self.temperature = temperature
88
- self.tools = [wikipedia_search, web_search, calculate]
89
- self.llm = ChatOpenAI(model=model_name, temperature=temperature)
90
- self.agent_executor = self._build_agent_executor()
91
- self.workflow = self._build_workflow()
92
- logger.info(f"AdvancedAgent initialized with model: {model_name}")
93
-
94
- def _build_agent_executor(self) -> AgentExecutor:
95
- """Build the agent executor with proper prompt and tools."""
96
- prompt = ChatPromptTemplate.from_messages([
97
- ("system", self._get_system_prompt()),
98
- MessagesPlaceholder(variable_name="messages"),
99
- MessagesPlaceholder(variable_name="agent_scratchpad"),
100
- ])
101
- agent = create_tool_calling_agent(self.llm, self.tools, prompt)
102
- return AgentExecutor(
103
- agent=agent,
104
- tools=self.tools,
105
- verbose=True,
106
- handle_parsing_errors=True
107
- )
108
-
109
- def _get_system_prompt(self) -> str:
110
- """Return a comprehensive system prompt for the agent."""
111
- return """You are an advanced AI assistant with access to tools. Follow these rules:
112
- 1. Be precise and factual
113
- 2. Use tools when needed
114
- 3. Cite your sources
115
- 4. Break complex problems into steps
116
- 5. Admit when you don't know something"""
117
-
118
- def _build_workflow(self) -> StateGraph:
119
- """Build and compile the agent workflow."""
120
- workflow = StateGraph(AgentState)
121
-
122
- workflow.add_node("agent", self._run_agent)
123
- workflow.add_node("tools", ToolNode(self.tools))
124
-
125
- workflow.set_entry_point("agent")
126
- workflow.add_conditional_edges(
127
- "agent",
128
- self._should_continue,
129
- {"continue": "tools", "end": END}
130
- )
131
- workflow.add_edge("tools", "agent")
132
-
133
- return workflow.compile()
134
 
135
- @handle_errors
136
- def _run_agent(self, state: AgentState) -> Dict[str, Any]:
137
- """Execute the agent with error handling."""
138
- response = self.agent_executor.invoke({"messages": state["messages"]})
139
- return {"messages": [response["output"]]}
140
-
141
- def _should_continue(self, state: AgentState) -> str:
142
- """Determine if the workflow should continue based on tool calls."""
143
- last_message = state["messages"][-1]
144
- return "continue" if last_message.additional_kwargs.get("tool_calls") else "end"
145
-
146
- @handle_errors
147
- def __call__(self, query: str) -> Dict[str, Any]:
148
- """Process a user query and return a structured response."""
149
- if not query or len(query.strip()) == 0:
150
- return {"error": "Empty query provided"}
151
-
152
- logger.info(f"Processing query: {query[:50]}...")
153
- state = AgentState(messages=[HumanMessage(content=query)], sender="user")
154
-
155
- for output in self.workflow.stream(state):
156
- for key, value in output.items():
157
- if key == "messages":
158
- for message in value:
159
- if isinstance(message, BaseMessage):
160
- response = message.content[:MAX_RESPONSE_LENGTH]
161
- return {
162
- "response": response,
163
- "sources": self._extract_sources(state["messages"]),
164
- "steps": self._extract_steps(state["messages"]),
165
- "model": self.model_name
166
- }
167
- return {"response": "No response generated", "sources": [], "steps": []}
168
-
169
- def _extract_sources(self, messages: Sequence[BaseMessage]) -> List[str]:
170
- """Extract and format sources from tool messages."""
171
- sources = []
172
- for msg in messages:
173
- if hasattr(msg, 'additional_kwargs') and 'name' in msg.additional_kwargs:
174
- source_name = msg.additional_kwargs.get('name', 'unknown')
175
- content = str(msg.content)[:200] # Truncate long content
176
- sources.append(f"{source_name}: {content}")
177
- return sources
178
-
179
- def _extract_steps(self, messages: Sequence[BaseMessage]) -> List[str]:
180
- """Extract and format the reasoning steps."""
181
- steps = []
182
- for msg in messages:
183
- if hasattr(msg, 'additional_kwargs') and 'tool_calls' in msg.additional_kwargs:
184
- for call in msg.additional_kwargs['tool_calls']:
185
- tool_name = call['function']['name']
186
- args = call['function']['arguments'][:100] # Truncate long args
187
- steps.append(f"Used {tool_name} with args: {args}")
188
- return steps
189
 
190
-
191
  def run_and_submit_all( profile: gr.OAuthProfile | None):
192
  """
193
  Fetches all questions, runs the BasicAgent on them, submits all answers,
@@ -315,11 +164,9 @@ with gr.Blocks() as demo:
315
  gr.Markdown(
316
  """
317
  **Instructions:**
318
-
319
  1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
320
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
321
  3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
322
-
323
  ---
324
  **Disclaimers:**
325
  Once clicking on the "submit button, it can take quite some time ( this is the time for the agent to go through all the questions).
 
3
  import requests
4
  import inspect
5
  import pandas as pd
6
+ from langchain_core.messages import HumanMessage
7
+ from agent import build_graph
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
  # (Keep Constants as is)
10
  # --- Constants ---
 
14
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
15
 
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  class BasicAgent:
18
+ def __init__(self):
19
+ print("BasicAgent initialized.")
20
+ def __call__(self, question: str) -> str:
21
+ print(f"Agent received question (first 50 chars): {question[:50]}...")
22
+ fixed_answer = "This is a default answer."
23
+ print(f"Agent returning fixed answer: {fixed_answer}")
24
+ return fixed_answer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
+ class BasicAgent:
27
+ """A langgraph agent."""
28
+ def __init__(self):
29
+ print("BasicAgent initialized.")
30
+ self.graph = build_graph()
31
+
32
+ def __call__(self, question: str) -> str:
33
+ print(f"Agent received question (first 50 chars): {question[:50]}...")
34
+ # Wrap the question in a HumanMessage from langchain_core
35
+ messages = [HumanMessage(content=question)]
36
+ messages = self.graph.invoke({"messages": messages})
37
+ answer = messages['messages'][-1].content
38
+ return answer[14:]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
 
40
  def run_and_submit_all( profile: gr.OAuthProfile | None):
41
  """
42
  Fetches all questions, runs the BasicAgent on them, submits all answers,
 
164
  gr.Markdown(
165
  """
166
  **Instructions:**
 
167
  1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
168
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
169
  3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
 
170
  ---
171
  **Disclaimers:**
172
  Once clicking on the "submit button, it can take quite some time ( this is the time for the agent to go through all the questions).