MatteoFalcioni commited on
Commit
f1a20fe
·
1 Parent(s): 81917a3

building own agent code

Browse files
Files changed (4) hide show
  1. .gitignore +2 -0
  2. app.py +65 -10
  3. prompt.py +8 -0
  4. tools.py +78 -0
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ .env
2
+ try.py
app.py CHANGED
@@ -3,6 +3,14 @@ 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,55 @@ 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
  """
@@ -40,7 +89,7 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
40
 
41
  # 1. Instantiate Agent ( modify this part to create your agent)
42
  try:
43
- agent = BasicAgent()
44
  except Exception as e:
45
  print(f"Error instantiating agent: {e}")
46
  return f"Error initializing agent: {e}", None
@@ -80,7 +129,13 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
80
  print(f"Skipping item with missing task_id or question: {item}")
81
  continue
82
  try:
83
- submitted_answer = agent(question_text)
 
 
 
 
 
 
84
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
85
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
86
  except Exception as e:
 
3
  import requests
4
  import inspect
5
  import pandas as pd
6
+ from langchain_openai import ChatOpenAI
7
+ from dotenv import load_dotenv
8
+ from typing import TypedDict, Annotated
9
+ from langgraph.graph.message import add_messages
10
+ from langchain_core.messages import AnyMessage, HumanMessage, SystemMessage
11
+ from langgraph.prebuilt import ToolNode
12
+ from langgraph.graph import START, StateGraph
13
+ from langgraph.prebuilt import tools_condition
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
+ # load system prompt
23
+ system_prompt = SystemMessage(content="""
24
+ You are a general AI assistant. I will ask you a question.
25
+ Report your thoughts, and finish your answer by reporting just your answer, nothing else.
26
+ Your final answer should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.
27
+ If you are asked for a number, don't use comma to write your number neither use units such as $ or percent sign unless specified otherwise.
28
+ If you are asked for a string, don't use articles, neither abbreviations (e.g. for cities), and write the digits in plain text unless specified otherwise.
29
+ If you are asked for a comma separated list, apply the above rules depending of whether the element to be put in the list is a number or a string.
30
+ """)
31
+
32
+ load_dotenv() # Load variables from .env into environment
33
+ api_key = os.getenv("OPENAI_API_KEY")
34
+ chat = ChatOpenAI(
35
+ api_key=api_key,
36
+ model="gpt-4o"
37
+ )
38
+
39
+ tools = []
40
+ chat_with_tools = chat.bind_tools(tools)
41
+
42
+ # Generate the AgentState and Agent graph
43
+ class AgentState(TypedDict):
44
+ messages: Annotated[list[AnyMessage], add_messages]
45
+
46
+ def assistant(state: AgentState):
47
+ return {
48
+ "messages": [chat_with_tools.invoke(state["messages"])],
49
+ }
50
+
51
+ ## The graph
52
+ builder = StateGraph(AgentState)
53
+
54
+ # Define nodes
55
+ builder.add_node("assistant", assistant)
56
+ builder.add_node("tools", ToolNode(tools))
57
+
58
+ # Define edges
59
+ builder.add_edge(START, "assistant")
60
+ builder.add_conditional_edges(
61
+ "assistant",
62
+ # If the latest message requires a tool, route to tools
63
+ # Otherwise, provide a direct response
64
+ tools_condition,
65
+ )
66
+ builder.add_edge("tools", "assistant")
67
+
68
+
69
+ #------------------------------------SUBMISSION------------------------------------------------
70
 
71
  def run_and_submit_all( profile: gr.OAuthProfile | None):
72
  """
 
89
 
90
  # 1. Instantiate Agent ( modify this part to create your agent)
91
  try:
92
+ agent = builder.compile()
93
  except Exception as e:
94
  print(f"Error instantiating agent: {e}")
95
  return f"Error initializing agent: {e}", None
 
129
  print(f"Skipping item with missing task_id or question: {item}")
130
  continue
131
  try:
132
+ response = agent.invoke({
133
+ "messages": [
134
+ system_prompt,
135
+ HumanMessage(content=question_text)
136
+ ]
137
+ })
138
+ submitted_answer = response["messages"][-1].content
139
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
140
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
141
  except Exception as e:
prompt.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ prompt = """
2
+ You are a general AI assistant. I will ask you a question.
3
+ Report your thoughts, and finish your answer by reporting just your answer, nothing else.
4
+ Your final answer should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.
5
+ If you are asked for a number, don't use comma to write your number neither use units such as $ or percent sign unless specified otherwise.
6
+ If you are asked for a string, don't use articles, neither abbreviations (e.g. for cities), and write the digits in plain text unless specified otherwise.
7
+ If you are asked for a comma separated list, apply the above rules depending of whether the element to be put in the list is a number or a string.
8
+ """
tools.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional
2
+ from langchain_core.tools import tool
3
+ import math
4
+ import pandas as pd
5
+ import requests
6
+ import io
7
+
8
+
9
+ @tool
10
+ def compute_expression(expr: str) -> float:
11
+ """
12
+ Safely evaluate basic math expressions.
13
+ Supports +, -, *, /, **, %, and parentheses.
14
+ Example: "(2 + 3) * 4"
15
+ """
16
+ try:
17
+ result = eval(expr, {"__builtins__": None}, math.__dict__)
18
+ return float(result)
19
+ except Exception as e:
20
+ return f"Math error: {str(e)}"
21
+
22
+
23
+ @tool
24
+ def describe_table_from_url(file_url: str) -> str:
25
+ """
26
+ Download a CSV or Excel file from a URL and describe the columns and types.
27
+ Useful for understanding tabular data.
28
+ """
29
+ try:
30
+ response = requests.get(file_url, timeout=10)
31
+ response.raise_for_status()
32
+ content = io.BytesIO(response.content)
33
+
34
+ if file_url.endswith(".csv"):
35
+ df = pd.read_csv(content)
36
+ elif file_url.endswith(".xls") or file_url.endswith(".xlsx"):
37
+ df = pd.read_excel(content)
38
+ else:
39
+ return "Unsupported file format. Please use CSV or Excel."
40
+
41
+ desc = f"Columns: {list(df.columns)}\nTypes:\n{df.dtypes}"
42
+ return desc
43
+ except Exception as e:
44
+ return f"Error loading table: {e}"
45
+
46
+
47
+ @tool
48
+ def search_web(query: str) -> str:
49
+ """
50
+ Perform a simple web search using DuckDuckGo Instant Answer API.
51
+ Returns a short summary or answer.
52
+ """
53
+ try:
54
+ response = requests.get("https://api.duckduckgo.com/", params={
55
+ "q": query,
56
+ "format": "json",
57
+ "no_redirect": 1,
58
+ "no_html": 1
59
+ }, timeout=10)
60
+ data = response.json()
61
+ if data.get("AbstractText"):
62
+ return data["AbstractText"]
63
+ elif data.get("Answer"):
64
+ return data["Answer"]
65
+ elif data.get("RelatedTopics"):
66
+ return data["RelatedTopics"][0].get("Text", "No summary found.")
67
+ else:
68
+ return "No results found."
69
+ except Exception as e:
70
+ return f"Web search error: {e}"
71
+
72
+
73
+ # Export the tools in a list
74
+ TOOLS = [
75
+ compute_expression,
76
+ describe_table_from_url,
77
+ search_web,
78
+ ]