Spaces:
Build error
Build error
| from smolagents import DuckDuckGoSearchTool, GoogleSearchTool | |
| from youtube_transcript_api import YouTubeTranscriptApi | |
| from supadata import Supadata, SupadataError | |
| import wikipedia | |
| from wikipedia_tables_parser import fetch_wikipedia_tables | |
| import pandas as pd | |
| from typing import Any | |
| import os | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| import importlib.util | |
| import sys | |
| import io | |
| import contextlib | |
| from llama_index.llms.openrouter import OpenRouter | |
| from llama_index.core.types import ChatMessage | |
| llm = OpenRouter( | |
| api_key=os.getenv("OPENROUTER_API_KEY"), | |
| model="google/gemini-2.5-flash-preview", | |
| temperature=0.7, | |
| ) | |
| supadata = Supadata(api_key=os.getenv("SUPADATA_API_KEY")) | |
| def reverse_text(text: str, **kwargs) -> str: | |
| """ | |
| Returns the reversed version of the text. | |
| If you receive some unknown text, that can't be recognized and analyzed, then you need to use this tool to make it clear. | |
| Args: | |
| text: text to be reversed | |
| Return: | |
| The reversed text. | |
| """ | |
| try: | |
| print(text[::-1]) | |
| return text[::-1] | |
| except Exception as e: | |
| raise ValueError(f"Can't reverse text: {e}") | |
| def fetch_historical_event_data(event_name: str, year: str, **kwargs) -> str: | |
| """ | |
| Fetches data about historical event that occured in certain year. | |
| Some examples of events: Olympics games, Footbal games, NBA etc. | |
| Args: | |
| event_name: String name of the event | |
| year: String year of the event | |
| Return: | |
| String with data about the event | |
| """ | |
| result = wikipedia.page(f"{event_name} in {year}") | |
| url = result.url | |
| content = result.content | |
| try: | |
| tables = pd.read_html(url) | |
| except Exception as e: | |
| tables = fetch_wikipedia_tables(url) | |
| result = f"Content: {content}\nTables: {tables}" | |
| return result | |
| def classify_fruit_vegitable(item: str, **kwargs) -> str: | |
| """ | |
| Classifies items to fruits and vegitables | |
| Args: | |
| item: Item to classify | |
| Returns: | |
| Text with explanation whether it is a fruit or vegetable. | |
| """ | |
| response = llm.chat( | |
| messages=[ | |
| ChatMessage( | |
| content=f"Classify whether it is fruit or vegetable: {item}. Return only `fruit` or `vegetable` without explanations" | |
| ) | |
| ] | |
| ) | |
| return response.message.content | |
| def web_search(query: str, **kwargs) -> str: | |
| """ | |
| Returns web search results for the provided query. | |
| Don't use it for Wikipedia queries. For Wikipedia queries use wikipedia_search tool. | |
| Important, query is human-language string input, not the URL or key. | |
| Args: | |
| query: query to search in WEB | |
| Return: | |
| String with web search results. | |
| """ | |
| result = DuckDuckGoSearchTool().forward(query) | |
| # result = GoogleSearchTool(provider="serpapi").forward(query) | |
| print(result) | |
| return result | |
| def wikipedia_search(query: str, **kwargs) -> Any: | |
| """ | |
| Returns wikipedia search results for the provided query. | |
| Args: | |
| query: query to search in WIKIPEDIA | |
| Return: | |
| Wikipedia search results. | |
| """ | |
| result = wikipedia.page(query) | |
| url = result.url | |
| content = result.content | |
| try: | |
| tables = pd.read_html(url) | |
| except: | |
| tables = fetch_wikipedia_tables(url) | |
| result = f"Content: {content}\nTables: {tables}" | |
| return result | |
| def multiply(a: float, b: float, **kwargs) -> float: | |
| """ | |
| Multiply two numbers. | |
| Args: | |
| a: First number | |
| b: Second number | |
| Return: | |
| The product of the two numbers. | |
| """ | |
| return a * b | |
| def compute_sum(values: list[int | float], **kwargs) -> float: | |
| """ | |
| Computes sum of provided values | |
| Args: | |
| values: list of integer or float values | |
| Return: | |
| Sum of the values | |
| """ | |
| return sum(values) | |
| def length(iterable: Any, **kwargs) -> int: | |
| """ | |
| Return the length of an iterable. | |
| Args: | |
| iterable: Any iterable | |
| Return: | |
| The length of the iterable. | |
| """ | |
| return len(iterable) | |
| def execute_python_file(file_path: str) -> Any: | |
| """ | |
| Executes a Python file and returns its result. | |
| This function takes a path to a Python file, executes it by importing it as a module, | |
| and returns the result. The file should contain a function call that produces | |
| the result to be returned. This version also executes code under the | |
| 'if __name__ == "__main__":' block. | |
| Args: | |
| file_path (str): Path to the Python file to execute. | |
| Returns: | |
| Any: The result of executing the Python file. If the file sets a variable | |
| named 'result', that value will be returned. | |
| Raises: | |
| FileNotFoundError: If the specified file does not exist. | |
| ImportError: If there was an error importing the Python file. | |
| Example: | |
| >>> # If example.py contains: result = 2 + 3 | |
| >>> execute_python_file('example.py') | |
| 5 | |
| """ | |
| # Verify file exists | |
| if not os.path.isfile(file_path): | |
| raise FileNotFoundError(f"File not found: {file_path}") | |
| # Get the directory and filename | |
| file_dir = os.path.dirname(os.path.abspath(file_path)) | |
| file_name = os.path.basename(file_path) | |
| module_name = file_name.replace(".py", "") | |
| # Store original sys.path and add the file's directory | |
| original_sys_path = sys.path.copy() | |
| sys.path.insert(0, file_dir) | |
| # Prepare stdout/stderr capture | |
| stdout_capture = io.StringIO() | |
| stderr_capture = io.StringIO() | |
| # First approach: Import normally to get module definitions | |
| try: | |
| spec = importlib.util.spec_from_file_location(module_name, file_path) | |
| if spec is None or spec.loader is None: | |
| raise ImportError(f"Could not load module spec from {file_path}") | |
| module = importlib.util.module_from_spec(spec) | |
| sys.modules[module_name] = module | |
| # Execute the module | |
| with contextlib.redirect_stdout(stdout_capture), contextlib.redirect_stderr( | |
| stderr_capture | |
| ): | |
| spec.loader.exec_module(module) | |
| # After module is loaded, directly execute the main block by reading the file | |
| # and executing the content with __name__ = "__main__" | |
| with open(file_path, "r") as f: | |
| file_content = f.read() | |
| # Create a namespace with everything from the module | |
| namespace = {**module.__dict__} | |
| namespace["__name__"] = "__main__" | |
| exec(file_content, namespace) | |
| if hasattr(module, "result"): | |
| return module.result | |
| else: | |
| output = stdout_capture.getvalue().strip() | |
| print(f"RESULT PYTHON: {output}") | |
| return output | |
| except Exception as e: | |
| error_output = stderr_capture.getvalue() | |
| if error_output: | |
| raise type(e)(f"{str(e)}\nProgram output: {error_output}") from None | |
| else: | |
| raise | |
| finally: | |
| sys.path = original_sys_path | |
| if module_name in sys.modules: | |
| del sys.modules[module_name] | |
| def trascript_youtube(video_id: str, **kwargs) -> str: | |
| """ | |
| Returns transcript of YouTube video. | |
| Args: | |
| video_id: ID of youtube video (Pass in the video ID, NOT the video URL. For a video with the URL https://www.youtube.com/watch?v=12345 the ID is 12345.) | |
| Return: | |
| Transcript of YouTube video. | |
| """ | |
| transcript = supadata.youtube.transcript(video_id=video_id, lang="en") | |
| return transcript.content | |
| def read_excel(path: str, **kwargs) -> pd.DataFrame: | |
| """ | |
| Reads xlsx file | |
| Args: | |
| path: path to xlsx file | |
| Return: | |
| Pandas dataframe | |
| """ | |
| return pd.read_excel(path) | |
| def pandas_column_sum( | |
| pandas_column_values: list[int | float], column_name: str, **kwargs | |
| ) -> float: | |
| """ | |
| Computes sum on pandas dataframe column | |
| Args: | |
| pandas_column_values: List with float or integer pandas values | |
| column_name: Name of the column | |
| Return: | |
| Sum of the column | |
| """ | |
| return sum(pandas_column_values) | |
| def final_answer(answer: str, **kwargs) -> str: | |
| """ | |
| Prepare the final answer for the user. It should be always used as a last step. | |
| Args: | |
| answer: The answer to format and return to the user | |
| Return: | |
| The final answer. | |
| """ | |
| resp = llm.chat( | |
| messages=[ | |
| ChatMessage( | |
| content=f""" | |
| Final answer from agent: {answer} | |
| Make final answer as short as possible. | |
| Final answer should be a number or as few words as possible or a comma separated list of numbers and/or strings. 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. 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. 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. | |
| There might be requested exact number, then you need to compress the output so that it was only number without any comments or explanations (float or integer). | |
| And on the other hand, the question might request some exact string value. Don't explain it, just return this value (For example, insted of `In response to the question, desired person is X` return only `X`) | |
| Again, you don't need to modify or solve answer, you just need to format it properly. | |
| """ | |
| ) | |
| ] | |
| ) | |
| return resp.message.content | |
| # print(wikipedia_search("Mercedes Sosa studio albums")) | |
| # execute_python_file("f918266a-b3e0-4914-865d-4faa564f1aef.py") | |