import gradio as gr import pandas as pd import os from llama_index.llms.anthropic import Anthropic from llama_index.core.agent import ReActAgent from llama_index.core.workflow import Context from llama_index.core.tools import FunctionTool # --- Import tools class --- from tools import PokemonAdvisorTools # --- 1. Setup Tools & LLM --- # Instantiate the class to load data advisor = PokemonAdvisorTools() # Create the list of tool methods to wrap tool_methods = [ advisor.get_card_info, advisor.find_grading_opportunities, advisor.assess_risk_volatility, advisor.get_roi_metrics, advisor.get_recent_price_spikes, advisor.analyze_set_performance, advisor.find_cards_by_artist, advisor.get_market_movers ] # Wrap tools into LlamaIndex FunctionTools tools = [FunctionTool.from_defaults(fn=func) for func in tool_methods] # Initialize the LLM (Ensure OPENAI_API_KEY is set in your env) llm = Anthropic(model="claude-sonnet-4-0") # --- 2. System Prompt --- system_prompt = """ ### ROLE You are the **Poke-Alpha Investment Advisor**, an expert algorithmic trading assistant for the Pokémon TCG market. You rely **strictly** on data. You do not guess. You do not hallucinate prices. ### TOOL USAGE PROTOCOL 1. **Verify First:** If a user asks about a card, ALWAYS use `get_card_info` first to ensure it exists. 2. **Safety Check:** BEFORE recommending ANY card, you MUST call `assess_risk_volatility` (default to 6 months). 3. **Refining Search:** If the user corrects you (e.g., "Not that card"), use `get_card_info` again with the corrected name or use `analyze_set_performance` to broaden the scope. 4. **Profit Hunting:** If a user asks "What should I buy?", use `find_grading_opportunities` or `get_market_movers`. ### TONE Professional, objective, concise, and user-friendly. """ # --- 3. Initialize Agent & Global Memory --- # We use timeout=120 because deep reasoning sequences can take time agent = ReActAgent( tools=tools, llm=llm, verbose=True, system_prompt=system_prompt, timeout=120 ) # Global Context acts as the "Server Memory" for this session # In a real multi-user web app, you would create a new Context per user sessionID global_ctx = Context(agent) # --- 4. Define the Chat Function (Async) --- async def ask_advisor(user_message, history): """ Async function to handle the chat. It uses 'global_ctx' to maintain memory of previous turns/corrections. """ if not user_message: return "Please enter a message." try: # Execute the agent workflow # The 'ctx' argument passes the memory of previous interactions response = await agent.run(user_msg=user_message, ctx=global_ctx) # Return the final text response return str(response) except Exception as e: return f"⚠️ **Agent Error:** {str(e)}\n\n*Check the console logs for detailed tool output.*" # --- 5. Launch Gradio UI --- demo = gr.ChatInterface( fn=ask_advisor, title="🤖 cAsh Robo-Advisor", description=""" **Your AI Quantitative Analyst for Pokemon Cards.** Ask about: * **Arbitrage:** "What are the best grading opportunities?" * **Risk:** "Is Charizard VMAX a safe investment?" * **Trends:** "What is crashing right now?" * **Sets:** "How is Evolving Skies performing?" """, examples=[ "What are the top 3 grading opportunities right now?", "Is investing in Charizard VMAX risky?", "What cards are trending down?", "Show me profitable cards by Tomokazu Komiya." ], #retry_btn="Retry Analysis", #undo_btn="Undo", #clear_btn="Clear History", ) if __name__ == "__main__": demo.launch(theme=gr.themes.Soft())