SergeyO7 commited on
Commit
87110c1
·
verified ·
1 Parent(s): 7dc52e9

Update agent.py

Browse files
Files changed (1) hide show
  1. agent.py +22 -169
agent.py CHANGED
@@ -53,7 +53,7 @@ class VisitWebpageTool(Tool):
53
 
54
  def forward(self, url: str) -> str:
55
  try:
56
- response = requests.get(url, timeout=20)
57
  response.raise_for_status()
58
  markdown_content = markdownify(response.text).strip()
59
  markdown_content = re.sub(r"\n{3,}", "\n\n", markdown_content)
@@ -89,7 +89,7 @@ class DownloadTaskAttachmentTool(Tool):
89
  while not self.rate_limiter.consume(1):
90
  print(f"Rate limit reached for downloading file for task {task_id}. Waiting...")
91
  time.sleep(4) # Assuming 15 RPM
92
- response = requests.get(file_url, stream=True, timeout=15)
93
  response.raise_for_status()
94
 
95
  # Determine file extension based on Content-Type
@@ -204,167 +204,7 @@ class ExcelReaderTool(Tool):
204
 
205
  except Exception as e:
206
  return f"Error reading Excel file: {str(e)}"
207
-
208
-
209
-
210
-
211
-
212
- @tool
213
- def PNG2FENTool(png_file: str) -> str:
214
- """Tool for converting a PNG file containing a chess board to a FEN position string.
215
- Args:
216
- png_file (str): The path to the PNG file.
217
-
218
- Returns:
219
- str: The FEN position string representing the chess board.
220
- """
221
- # Raises:
222
- # - FileNotFoundError:
223
- # If the PNG file does not exist.
224
- # - ValueError:
225
- # If the PNG file cannot be processed or does not contain a valid chess board.
226
-
227
- try:
228
- # Open and preprocess image with modern Pillow
229
- img = Image.open(png_file)
230
- img = ImageOps.exif_transpose(img).convert("L")
231
-
232
- # Use LANCZOS instead of ANTIALIAS
233
- img = img.resize((img.width*2, img.height*2), Image.Resampling.LANCZOS)
234
-
235
- # Save temp file for OCR
236
- temp_path = "chess_temp.png"
237
- img.save(temp_path)
238
-
239
- # Perform OCR
240
- import easyocr
241
- reader = easyocr.Reader(['en'])
242
- result = reader.readtext(png_file, detail=0)
243
- fen_candidates = [text for text in result if validate_fen_format(text)]
244
-
245
- if not fen_candidates:
246
- raise ValueError("No valid FEN found in image")
247
-
248
- return fen_candidates[0]
249
-
250
- except Exception as e:
251
- raise ValueError(f"OCR processing failed: {str(e)}")
252
-
253
-
254
- # try:
255
- # # Open the PNG file using PIL
256
- # image = Image.open(png_file)
257
- #
258
- # # Use pytesseract to extract text from the image
259
- # text = pytesseract.image_to_string(image)
260
- #
261
- # # Process the extracted text to get the FEN position string
262
- # fen_position = process_text_to_fen(text)
263
- #
264
- # return fen_position
265
- #
266
- except FileNotFoundError:
267
- raise FileNotFoundError("PNG file not found.")
268
- #
269
- # except Exception as e:
270
- # raise ValueError("Error processing PNG file: " + str(e))
271
-
272
- def process_text_to_fen(text):
273
- """
274
- Processes the extracted text from the image to obtain the FEN position string.
275
-
276
- Parameters:
277
- - text: str
278
- The extracted text from the image.
279
-
280
- Returns:
281
- - str:
282
- The FEN position string representing the chess board.
283
-
284
- Raises:
285
- - ValueError:
286
- If the extracted text does not contain a valid chess board.
287
- """
288
-
289
- # Process the text to remove any unnecessary characters or spaces
290
- processed_text = text.strip().replace("\n", "").replace(" ", "")
291
-
292
- # Check if the processed text matches the expected format of a FEN position string
293
- if not validate_fen_format(processed_text):
294
- raise ValueError("Invalid chess board.")
295
-
296
- return processed_text
297
-
298
- def validate_fen_format(fen_string):
299
- """
300
- Validates if a given string matches the format of a FEN (Forsyth–Edwards Notation) position string.
301
-
302
- Parameters:
303
- - fen_string: str
304
- The string to be validated.
305
-
306
- Returns:
307
- - bool:
308
- True if the string matches the FEN format, False otherwise.
309
- """
310
-
311
- # FEN format: 8 sections separated by '/'
312
- sections = fen_string.split("/")
313
- if len(sections) != 8:
314
- return False
315
-
316
- # Check if each section contains valid characters
317
- for section in sections:
318
- if not validate_section(section):
319
- return False
320
-
321
- return True
322
-
323
- def validate_section(section):
324
- """
325
- Validates if a given section of a FEN (Forsyth–Edwards Notation) position string contains valid characters.
326
-
327
- Parameters:
328
- - section: str
329
- The section to be validated.
330
-
331
- Returns:
332
- - bool:
333
- True if the section contains valid characters, False otherwise.
334
- """
335
-
336
- # Valid characters: digits 1-8 or letters 'r', 'n', 'b', 'q', 'k', 'p', 'R', 'N', 'B', 'Q', 'K', 'P'
337
- valid_chars = set("12345678rnbqkpRNBQKP")
338
- return all(char in valid_chars for char in section)
339
-
340
- import chess
341
- import chess.engine
342
-
343
- class ChessEngineTool(Tool):
344
- name = "chess_engine"
345
- description = "Analyzes a chess position (FEN) with Stockfish and returns the best move."
346
- inputs = {
347
- "fen": {"type": "string", "description": "FEN string of the position."},
348
- "time_limit": {"type": "number", "description": "Time in seconds for engine analysis.", "nullable": True}
349
- }
350
- output_type = "string"
351
-
352
- def forward(self, fen: str, time_limit: float = 0.1) -> str:
353
- # figure out where the binary actually is
354
- sf_bin = shutil.which("stockfish") or "/usr/games/stockfish"
355
- if not sf_bin:
356
- raise RuntimeError(
357
- f"Cannot find stockfish on PATH or at /usr/games/stockfish. "
358
- "Did you install it in apt.txt or via apt-get?"
359
- )
360
-
361
- board = chess.Board(fen)
362
- engine = chess.engine.SimpleEngine.popen_uci(sf_bin)
363
- result = engine.play(board, chess.engine.Limit(time=time_limit))
364
- engine.quit()
365
- return board.san(result.move)
366
-
367
-
368
  class PythonCodeReaderTool(Tool):
369
  name = "read_python_code"
370
  description = "Reads a Python (.py) file and returns its content as a string."
@@ -382,7 +222,20 @@ class PythonCodeReaderTool(Tool):
382
  return content
383
  except Exception as e:
384
  return f"Error reading Python file: {str(e)}"
385
-
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  class MagAgent:
387
  def __init__(self, rate_limiter: Optional[Limiter] = None):
388
  """Initialize the MagAgent with search tools."""
@@ -407,26 +260,26 @@ class MagAgent:
407
  prompt_templates = yaml.safe_load(stream)
408
 
409
  # Initialize rate limiter for DuckDuckGoSearchTool
410
- search_rate_limiter = Limiter(rate=30/60, capacity=30, storage=MemoryStorage()) if not rate_limiter else rate_limiter
411
 
412
  self.agent = CodeAgent(
413
  model= model,
414
  tools=[
415
  DownloadTaskAttachmentTool(rate_limiter=rate_limiter),
416
- # DuckDuckGoSearchTool(),
417
  # WikipediaSearchTool(),
418
  SpeechToTextTool(),
419
  ExcelReaderTool(),
420
  VisitWebpageTool(),
421
  PythonCodeReaderTool(),
422
- PNG2FENTool,
423
- ChessEngineTool(),
424
  # GoogleSearchTool,
425
  # ImageAnalysisTool,
426
  ],
427
  verbosity_level=2,
428
  prompt_templates=prompt_templates,
429
- add_base_tools=True,
430
  max_steps=15
431
  )
432
  print("MagAgent initialized.")
 
53
 
54
  def forward(self, url: str) -> str:
55
  try:
56
+ response = requests.get(url, timeout=30)
57
  response.raise_for_status()
58
  markdown_content = markdownify(response.text).strip()
59
  markdown_content = re.sub(r"\n{3,}", "\n\n", markdown_content)
 
89
  while not self.rate_limiter.consume(1):
90
  print(f"Rate limit reached for downloading file for task {task_id}. Waiting...")
91
  time.sleep(4) # Assuming 15 RPM
92
+ response = requests.get(file_url, stream=True, timeout=25)
93
  response.raise_for_status()
94
 
95
  # Determine file extension based on Content-Type
 
204
 
205
  except Exception as e:
206
  return f"Error reading Excel file: {str(e)}"
207
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  class PythonCodeReaderTool(Tool):
209
  name = "read_python_code"
210
  description = "Reads a Python (.py) file and returns its content as a string."
 
222
  return content
223
  except Exception as e:
224
  return f"Error reading Python file: {str(e)}"
225
+
226
+ from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
227
+ #from smolagents.tools import DuckDuckGoSearchException # Replace with the actual exception if different
228
+
229
+ class RetryDuckDuckGoSearchTool(DuckDuckGoSearchTool):
230
+ @retry(
231
+ stop=stop_after_attempt(3), # Retry up to 3 times
232
+ wait=wait_exponential(multiplier=1, min=4, max=10), # Wait 4s, 8s, then 10s
233
+ retry=retry_if_exception_type(Exception) # Retry on any exception
234
+ )
235
+ def forward(self, query: str) -> str:
236
+ return super().forward(query)
237
+
238
+
239
  class MagAgent:
240
  def __init__(self, rate_limiter: Optional[Limiter] = None):
241
  """Initialize the MagAgent with search tools."""
 
260
  prompt_templates = yaml.safe_load(stream)
261
 
262
  # Initialize rate limiter for DuckDuckGoSearchTool
263
+ search_rate_limiter = Limiter(rate=10/60, capacity=10, storage=MemoryStorage()) if not rate_limiter else rate_limiter
264
 
265
  self.agent = CodeAgent(
266
  model= model,
267
  tools=[
268
  DownloadTaskAttachmentTool(rate_limiter=rate_limiter),
269
+ RetryDuckDuckGoSearchTool(),
270
  # WikipediaSearchTool(),
271
  SpeechToTextTool(),
272
  ExcelReaderTool(),
273
  VisitWebpageTool(),
274
  PythonCodeReaderTool(),
275
+ # PNG2FENTool,
276
+ # ChessEngineTool(),
277
  # GoogleSearchTool,
278
  # ImageAnalysisTool,
279
  ],
280
  verbosity_level=2,
281
  prompt_templates=prompt_templates,
282
+ add_base_tools=False,
283
  max_steps=15
284
  )
285
  print("MagAgent initialized.")