Spaces:
Configuration error
Configuration error
| from typing import List, TypedDict, Annotated, Optional | |
| from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage | |
| from langgraph.graph.message import add_messages | |
| from langgraph.graph import START, StateGraph | |
| from langgraph.prebuilt import ToolNode, tools_condition | |
| from langchain_groq import ChatGroq | |
| from langchain_google_genai import ChatGoogleGenerativeAI | |
| from langchain_core.tools import tool | |
| from langchain_community.tools import DuckDuckGoSearchRun | |
| from langchain_community.tools import WikipediaQueryRun | |
| from langchain_community.utilities import WikipediaAPIWrapper | |
| import requests, io, pandas as pd, PyPDF2, ast, pytesseract | |
| from PIL import Image | |
| class AgentState(TypedDict): | |
| messages: Annotated[list[AnyMessage], add_messages] | |
| def add(a: float, b: float) -> float: | |
| """ | |
| Adds two numbers. | |
| Args: | |
| a (float): First number. | |
| b (float): Second number. | |
| Returns: | |
| float: Sum of a and b. | |
| """ | |
| return a + b | |
| def subtract(a: float, b: float) -> float: | |
| """ | |
| Subtracts one number from another. | |
| Args: | |
| a (float): Minuend. | |
| b (float): Subtrahend. | |
| Returns: | |
| float: Result of a - b. | |
| """ | |
| return a - b | |
| def multiply(a: float, b: float) -> float: | |
| """ | |
| Multiplies two numbers. | |
| Args: | |
| a (float): First number. | |
| b (float): Second number. | |
| Returns: | |
| float: Product of a and b. | |
| """ | |
| return a * b | |
| def divide(a: float, b: float) -> float: | |
| """ | |
| Divides one number by another. | |
| Args: | |
| a (float): Dividend. | |
| b (float): Divisor. | |
| Raises: | |
| ValueError: If b is zero. | |
| Returns: | |
| float: Result of a / b. | |
| """ | |
| if b == 0: | |
| raise ValueError("Cannot divide by zero") | |
| return a / b | |
| def web_search(query: str) -> str: | |
| """ | |
| Searches the web for the given query. | |
| Args: | |
| query (str): The search query. | |
| Returns: | |
| str: The search results | |
| """ | |
| search = DuckDuckGoSearchRun() | |
| print("search") | |
| return search.invoke(query) | |
| def wikisearch(query: str) -> str: | |
| """ | |
| Searches wikipedia for the given query. | |
| Args: | |
| query (str): The search query. | |
| Returns: | |
| str: The wikipedia results. | |
| """ | |
| wikipedia = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper()) | |
| print("wiki") | |
| return wikipedia.run(query) | |
| def gaia_retriever_tool(task_id: str) -> str: | |
| """ | |
| Downloads a file from a Gaia task using the provided task_id and returns its raw text content. | |
| Does NOT analyze or interpret the content. | |
| Supports PDFs, Excel/CSV spreadsheets, Python scripts, and images. | |
| """ | |
| print("retriever") | |
| url = f'https://agents-course-unit4-scoring.hf.space/files/{task_id}' | |
| resp = requests.get(url) | |
| if resp.status_code != 200: | |
| return f"Failed to download file {task_id}" | |
| file_bytes = io.BytesIO(resp.content) | |
| text = "" | |
| try: | |
| df = pd.read_excel(file_bytes) | |
| text = df.to_csv(index=False) | |
| except Exception: | |
| try: | |
| file_bytes.seek(0) | |
| df = pd.read_csv(file_bytes) | |
| text = df.to_csv(index=False) | |
| except Exception: | |
| try: | |
| file_bytes.seek(0) | |
| reader = PyPDF2.PdfReader(file_bytes) | |
| text = "\n".join([p.extract_text() or "" for p in reader.pages]) | |
| except Exception: | |
| try: | |
| file_bytes.seek(0) | |
| img = Image.open(file_bytes) | |
| text = pytesseract.image_to_string(img) | |
| except Exception: | |
| file_bytes.seek(0) | |
| text = file_bytes.read().decode("utf-8", errors="ignore") | |
| return text | |
| tools = [add, subtract, multiply, divide, web_search, wikisearch, gaia_retriever_tool] | |
| llm = ChatGoogleGenerativeAI( | |
| model="gemini-2.5-flash", | |
| api_key="...", | |
| temperature=0.3, | |
| ) | |
| llm_with_tools = llm.bind_tools(tools) | |
| system_prompt = SystemMessage( | |
| content=""" | |
| You are a concise AI assistant. Use tools only when strictly necessary. | |
| **Math:** use add(a,b), subtract(a,b), multiply(a,b), divide(a,b). | |
| **Search:** | |
| - Always try wikisearch(query) first. | |
| - If wiki fails or is insufficient, use web_search(query). | |
| - Only fallback to general knowledge if both fail. | |
| **Files:** use gaia_retriever_tool(task_id) **whenever the question mentions a file, attachment, picture, Excel, CSV, PDF, or Python file.** | |
| - Variations like "attached Excel file", "following CSV file", or "image attached" count as explicit mentions. | |
| - **The agent should pass the task_id from the question to gaia_retriever_tool.** | |
| - **The tool itself handles downloading and extracting content.** | |
| - **Do NOT attempt to download or read the file outside the tool.** | |
| - **Do NOT call gaia_retriever_tool if no file is mentioned.** | |
| **Answer rules:** | |
| 1. Give **exact answer only**, no explanations. | |
| 2. Numbers → output only the number. | |
| 3. Lists → comma-separated values, no words. | |
| 4. Text → 1–5 words. | |
| 5. Conceptual questions (opposites, synonyms, meanings) → answer correctly in 1 word. | |
| 6. Never include extra context, tool names, or sentences. | |
| 7. Your answer must strictly be short | |
| **Example 1:** | |
| Question: Who is the president of France? | |
| Action: wikisearch("president of France") → returns "Emmanuel Macron" | |
| Answer: Emmanuel Macron | |
| **Example 2:** | |
| Question: Some obscure topic, task_id: 123 | |
| Action: wikisearch("Some obscure topic") → returns "" | |
| Since wiki returned nothing, call web_search("Some obscure topic") | |
| Answer: [result from web_search] | |
| **Do NOT call gaia_retriever_tool because the question does not mention a file.** | |
| **Example 3:** | |
| Question: The attached Excel file contains sales data, task_id: 7bd855d8-463d-4ed5-93ca-5fe35145f733 | |
| Action: gaia_retriever_tool("7bd855d8-463d-4ed5-93ca-5fe35145f733") → returns file content | |
| Answer: 30420.00 | |
| """ | |
| ) | |
| def assistant(state: AgentState): | |
| return { | |
| "messages": [llm_with_tools.invoke([system_prompt] + state["messages"])], | |
| } | |
| builder = StateGraph(AgentState) | |
| builder.add_node("assistant", assistant) | |
| builder.add_node("tools", ToolNode(tools)) | |
| builder.add_edge(START, "assistant") | |
| builder.add_conditional_edges("assistant", tools_condition) | |
| builder.add_edge("tools", "assistant") | |
| graph = builder.compile() | |
| def run(prompt, task_id='1'): | |
| state: AgentState = {"messages": [HumanMessage(prompt)]} | |
| output = graph.invoke(state) | |
| return output["messages"][-1].content |