import os import requests import gradio as gr # --- CORRECTED LANGCHAIN IMPORTS --- # create_react_agent and AgentExecutor are now imported directly from langchain.agents from langchain.agents import AgentExecutor, create_react_agent from langchain.tools import Tool # We need to import the specific ReAct prompt template from the hub from langchain import hub from langchain_google_genai import ChatGoogleGenerativeAI from typing import List, Dict # Added for Gradio ChatInterface typing # --- Configuration and Environment Setup --- # IMPORTANT: Do NOT hardcode your API key. # Define GEMINI_API_KEY as a Space Secret in your Hugging Face Space Settings. GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY") if not GEMINI_API_KEY: # This message helps the user set up their Hugging Face Space correctly print("WARNING: GEMINI_API_KEY environment variable not set. Running without API key.") # We will raise a value error later during LLM initialization if it's actually needed. # Initialize Gemini LLM try: llm = ChatGoogleGenerativeAI( model="gemini-2.5-flash", temperature=0.3, google_api_key=GEMINI_API_KEY ) except Exception as e: # Graceful exit if API key is missing during initialization raise RuntimeError( "Could not initialize ChatGoogleGenerativeAI. " "Ensure GEMINI_API_KEY is set as a Space Secret." ) from e # --- Tool Definition --- def get_crypto_price(symbol: str) -> str: """Fetches the current price of a cryptocurrency symbol.""" try: # Use lowercase symbol for CoinGecko API lookup lookup_symbol = symbol.lower() url = f"https://api.coingecko.com/api/v3/simple/price?ids={lookup_symbol}&vs_currencies=usd" res = requests.get(url).json() # Check if the symbol exists in the response price = res.get(lookup_symbol, {}).get('usd') if price: return f"💰 The current price of {symbol.capitalize()} is ${price:,.2f}" else: # Check for common partial matches as suggestions if not res and len(lookup_symbol) > 3: return f"❌ Could not find price for symbol '{symbol}'. Try the full name (e.g., 'bitcoin', 'ethereum')." return f"❌ Could not find price for symbol '{symbol}'." except Exception as e: return f"⚠️ Error fetching price: {str(e)}" # Create a Tool for the Agent crypto_tool = Tool( name="Crypto Price Checker", func=get_crypto_price, description="Fetches the current cryptocurrency price using CoinGecko. Use this tool ONLY when the user asks for a specific crypto price (e.g., 'bitcoin', 'ethereum')." ) # List of tools tools = [crypto_tool] # --- Agent Initialization (CORRECTED) --- # 1. CORRECTED PROMPT: Pull the standard ReAct prompt from LangChain Hub. # This prompt is guaranteed to have the required '{tools}' and '{tool_names}' variables. prompt = hub.pull("hwchase17/react") # 2. Create the Agent # This uses the corrected 'create_react_agent' import agent = create_react_agent(llm, tools, prompt) # 3. Create the Agent Executor # This uses the corrected 'AgentExecutor' import agent_executor = AgentExecutor( agent=agent, tools=tools, verbose=True, handle_parsing_errors=True # Good practice for ReAct agents ) # --- Gradio Interface Function --- # Added 'history' for ChatInterface compatibility def run_agent(user_query: str, history: List[List[str]]) -> str: """The main function called by Gradio to run the agent.""" if not user_query: return "Please enter a question for the agent." try: # Use the AgentExecutor's invoke method # The input must be a dictionary response: Dict = agent_executor.invoke({"input": user_query}) # Extract the final answer text return response.get("output", "Agent could not find a clear answer.") except Exception as e: # Catch and report any runtime errors gracefully return f"An error occurred while running the agent: {str(e)}" # --- Gradio App Setup (Using ChatInterface for better UX) --- gr.ChatInterface( fn=run_agent, title="💰 Gemini Crypto Price Agent (ReAct Pattern)", description="Ask the agent to check the current price of cryptocurrencies (e.g., bitcoin, ethereum). This agent uses the modern LangChain ReAct pattern (v0.1.0+).", examples=[ ["What is the current price of Bitcoin?"], ["How much is Ethereum?"], ["What about solana?"] ] ).launch()