dawid-lorek commited on
Commit
ed680f1
·
verified ·
1 Parent(s): 1d8f1ea

Update agent.py

Browse files
Files changed (1) hide show
  1. agent.py +40 -169
agent.py CHANGED
@@ -1,176 +1,47 @@
 
 
1
  import os
2
- import re
3
- import requests
4
- import tempfile
5
- import pandas as pd
6
- from openai import OpenAI
7
 
8
- try:
9
- from duckduckgo_search import DDGS
10
- except ImportError:
11
- DDGS = None
12
-
13
- PROMPT = (
14
- "You are a general AI assistant. I will ask you a question. "
15
- "Report your thoughts, and finish your answer with the following template: "
16
- "FINAL ANSWER: [YOUR FINAL ANSWER]. YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings. "
17
- "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. "
18
- "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. "
19
- "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."
20
- )
 
 
 
 
 
 
 
21
 
22
  class BasicAgent:
23
  def __init__(self):
24
- self.llm = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
25
- print("BasicAgent initialized.")
26
-
27
- def web_search(self, query: str, max_results: int = 5) -> str:
28
- if not DDGS:
29
- return ""
30
- try:
31
- with DDGS() as ddgs:
32
- results = list(ddgs.text(query, max_results=max_results))
33
- if not results:
34
- return ""
35
- formatted_results = ""
36
- for i, result in enumerate(results, 1):
37
- title = result.get('title', '')
38
- body = result.get('body', '')
39
- href = result.get('href', '')
40
- formatted_results += f"{i}. {title}\n URL: {href}\n Description: {body}\n\n"
41
- return formatted_results
42
- except Exception:
43
- return ""
44
-
45
- def excel_tool(self, file_url: str) -> str:
46
- try:
47
- r = requests.get(file_url, timeout=20)
48
- r.raise_for_status()
49
- with tempfile.NamedTemporaryFile(suffix=".xlsx", delete=False) as f:
50
- f.write(r.content)
51
- f.flush()
52
- excel_path = f.name
53
- df = pd.read_excel(excel_path)
54
- if "Type" in df.columns and "Sales" in df.columns:
55
- total = df[df["Type"].str.lower() == "food"]["Sales"].sum()
56
- return f"{round(total, 2)}"
57
- total = df.select_dtypes(include='number').sum().sum()
58
- return f"{round(total, 2)}"
59
- except Exception:
60
- return ""
61
-
62
- def fetch_file_url(self, task_id):
63
- DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
64
- try:
65
- url = f"{DEFAULT_API_URL}/files/{task_id}"
66
- r = requests.head(url, timeout=5)
67
- if r.status_code == 200:
68
- return url
69
- except Exception:
70
- pass
71
- return None
72
-
73
- def solve_chess_image(self, image_url: str) -> str:
74
- prompt = (
75
- "You are a chess engine. Only answer with the best move for Black in algebraic notation (e.g., Qd1#). "
76
- "Do not explain your reasoning, do not include any commentary, only the move."
77
  )
78
- try:
79
- response = self.llm.chat.completions.create(
80
- model="gpt-4o",
81
- messages=[
82
- {"role": "system", "content": prompt},
83
- {
84
- "role": "user",
85
- "content": [
86
- {"type": "text", "text": prompt},
87
- {"type": "image_url", "image_url": {"url": image_url}},
88
- ],
89
- }
90
- ],
91
- max_tokens=32,
92
- temperature=0.0,
93
- )
94
- result = response.choices[0].message.content.strip()
95
- move = re.findall(r"\b([KQRNB]?[a-h]?[1-8]?x?[a-h][1-8](?:=[QRNB])?#?)\b", result)
96
- if move:
97
- return move[0]
98
- return result
99
- except Exception:
100
- return ""
101
-
102
- def __call__(self, question: str, task_id: str = None) -> str:
103
- file_url = self.fetch_file_url(task_id) if task_id else None
104
- file_result = None
105
-
106
- # --- Chess image detection (priority) ---
107
- if file_url and ("chess" in question.lower() or "move" in question.lower() or "image" in question.lower() or "position" in question.lower()):
108
- move = self.solve_chess_image(file_url)
109
- if move and len(move) <= 6:
110
- return move
111
-
112
- # --- Excel file detection ---
113
- ext = file_url.split('.')[-1].lower() if file_url else ""
114
- if file_url and (ext in ["xlsx", "xls"] or "excel" in question.lower() or "spreadsheet" in question.lower()):
115
- file_result = self.excel_tool(file_url)
116
- if file_result and re.match(r'^\d+(\.\d+)?$', file_result):
117
- return file_result
118
-
119
- # --- Web search + LLM ---
120
- search_snippet = self.web_search(question)
121
- prompt = PROMPT + f"\n\nWeb search results:\n{search_snippet}\n\nQuestion: {question}"
122
- response = self.llm.chat.completions.create(
123
- model="gpt-4o",
124
- messages=[{"role": "system", "content": prompt}],
125
- temperature=0.0,
126
- max_tokens=512,
127
- )
128
- answer = response.choices[0].message.content.strip()
129
- final_line = ""
130
- for line in answer.splitlines():
131
- if line.strip().lower().startswith("final answer:"):
132
- final_line = line.split(":", 1)[-1].strip(" .\"'")
133
- break
134
 
135
- # --- Fallback for non-answers ---
136
- bads = [
137
- "", "unknown", "unable to determine", "unable to provide page numbers",
138
- "unable to access video content directly", "unable to analyze video content",
139
- "unable to determine without code", "unable to determine without file",
140
- "follow the steps to locate the paper and find the nasa award number in the acknowledgment section",
141
- "i am unable to view images or access external content directly", "unable to determine without access to the file",
142
- "no results found", "n/a", "[your final answer]", "i'm sorry", "i apologize"
143
- ]
144
- norm_final = (final_line or "").lower()
145
- if norm_final in bads or norm_final.startswith("unable") or norm_final.startswith("i'm sorry") or norm_final.startswith("i apologize"):
146
- numbers = re.findall(r'\b\d{2,}\b', search_snippet)
147
- if numbers:
148
- return numbers[0]
149
- words = re.findall(r'\b[A-Z][a-z]{2,}\b', search_snippet)
150
- if words:
151
- return words[0]
152
- if file_result:
153
- file_numbers = re.findall(r'\b\d{2,}\b', str(file_result))
154
- if file_numbers:
155
- return file_numbers[0]
156
- file_words = re.findall(r'\b[A-Z][a-z]{2,}\b', str(file_result))
157
- if file_words:
158
- return file_words[0]
159
- retry_prompt = (
160
- "Based ONLY on the search results and/or file content above, return a direct answer to the question. "
161
- "If you do not know, make your best plausible guess. Do NOT apologize or say you cannot assist. "
162
- f"File: {file_result}\n\nWeb: {search_snippet}\n\nQuestion: {question}\nFINAL ANSWER:"
163
- )
164
- response2 = self.llm.chat.completions.create(
165
- model="gpt-4o",
166
- messages=[{"role": "system", "content": retry_prompt}],
167
- temperature=0.1,
168
- max_tokens=128,
169
- )
170
- retry_answer = response2.choices[0].message.content.strip()
171
- for line in retry_answer.splitlines():
172
- if line.strip().lower().startswith("final answer:"):
173
- return line.split(":", 1)[-1].strip(" .\"'")
174
- if retry_answer:
175
- return retry_answer.strip(" .\"'")
176
- return final_line or answer
 
1
+ from smolagents import LiteLLMModel, CodeAgent, DuckDuckGoSearchTool, VisitWebpageTool, PythonInterpreterTool, tool
2
+ from youtube_transcript_api import YouTubeTranscriptApi
3
  import os
 
 
 
 
 
4
 
5
+ @tool
6
+ def reverse_sentence_tool(reverse_sentence: str) -> str:
7
+ inverted_words = reverse_sentence.split(" ")[::-1]
8
+ correct_words = [word[::-1] for word in inverted_words]
9
+ return " ".join(correct_words)
10
+
11
+ @tool
12
+ def get_youtube_transcript(video_url: str) -> str:
13
+ video_id = video_url.split("v=")[-1]
14
+ transcript = YouTubeTranscriptApi.get_transcript(video_id)
15
+ full_text = " ".join([entry['text'] for entry in transcript])
16
+ return full_text
17
+
18
+ @tool
19
+ def check_answer(answer: str) -> str:
20
+ if answer and answer[-1] == '.':
21
+ answer = answer[:-1]
22
+ if "St." in answer:
23
+ answer = answer.replace("St.", "Saint")
24
+ return answer
25
 
26
  class BasicAgent:
27
  def __init__(self):
28
+ api_key = os.environ.get("OPENAI_API_KEY", "")
29
+ # Użyj modelu openai, np. gpt-4o lub gpt-3.5-turbo
30
+ self.model = LiteLLMModel(model_id="gpt-4o", api_key=api_key)
31
+ self.agent = CodeAgent(
32
+ tools=[
33
+ DuckDuckGoSearchTool(),
34
+ PythonInterpreterTool(),
35
+ VisitWebpageTool(),
36
+ reverse_sentence_tool,
37
+ get_youtube_transcript,
38
+ check_answer
39
+ ],
40
+ model=self.model
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  )
42
+ print("BasicAgent initialized.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
+ def __call__(self, question: str) -> str:
45
+ print(f"Agent received question: {question[:50]}...")
46
+ answer = self.agent.run(question)
47
+ return answer