alexmec's picture
Upload folder using huggingface_hub
a9f90bf verified
"""
Core Fantasy Draft Agent using any-agent framework.
Supports multi-turn conversations and maintains draft state.
"""
import os
from typing import List, Dict, Optional, Annotated
from dotenv import load_dotenv
from any_agent import AnyAgent, AgentConfig
from .data import TOP_PLAYERS, get_player_info, get_best_available, get_players_by_position
# Load environment variables from .env file
load_dotenv()
# Check if API key is available
if not os.getenv("OPENAI_API_KEY"):
print("WARNING: OPENAI_API_KEY not found in environment")
# Try to get it from HF Spaces secrets
import os
api_key = os.environ.get("OPENAI_API_KEY", "")
if api_key:
os.environ["OPENAI_API_KEY"] = api_key
print("Successfully loaded API key from environment")
class FantasyDraftAgent:
def __init__(self, framework: str = "tinyagent", model_id: str = "gpt-4o-mini", custom_instructions: Optional[str] = None):
"""Initialize the Fantasy Draft Agent."""
self.framework = framework
self.model_id = model_id
self.custom_instructions = custom_instructions
# Draft state management
self.draft_state = {
"my_picks": [],
"all_picks": [],
"round": 1,
"pick_number": 5, # Default to 5th pick
"league_size": 12,
"roster_needs": {
"QB": 1, "RB": 2, "WR": 2, "TE": 1, "FLEX": 1
},
"conversation_history": []
}
# Initialize the agent with tools
try:
# Get API key
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
raise ValueError("OPENAI_API_KEY not found in environment")
# Create agent configuration with explicit API key
agent_config = AgentConfig(
model_id=model_id,
instructions=self._get_instructions(),
tools=[
self._get_player_stats,
self._check_best_available,
self._analyze_position_scarcity,
self._get_team_stack_options,
],
model_args={
"temperature": 0.7,
"api_key": api_key # Explicitly pass API key
}
)
self.agent = AnyAgent.create(framework, agent_config)
except Exception as e:
print(f"Error creating agent: {e}")
# Try without tools as a fallback
try:
api_key = os.getenv("OPENAI_API_KEY", "")
self.agent = AnyAgent.create(
framework,
AgentConfig(
model_id=model_id,
instructions=self._get_instructions(),
model_args={
"temperature": 0.7,
"api_key": api_key
}
)
)
except Exception as e2:
print(f"Fallback also failed: {e2}")
raise e2
def _get_instructions(self) -> str:
"""Get the agent's system instructions."""
# Use custom instructions if provided, otherwise use default
if self.custom_instructions:
return self.custom_instructions
return """You are an expert fantasy football draft assistant with deep knowledge of:
- Player values, tiers, and ADP (Average Draft Position)
- Draft strategy (Zero RB, Hero RB, Robust RB, etc.)
- Position scarcity and value-based drafting
- Team stacking strategies
- Injury concerns and player situations
Your role is to:
1. Provide draft advice based on the current situation
2. Remember previous picks and conversations in the draft
3. Adapt strategy based on how the draft unfolds
4. Explain your reasoning clearly
5. Consider both floor and ceiling when recommending players
Always maintain context from previous turns in our conversation.
Reference specific players and situations we've discussed.
Be conversational but authoritative in your recommendations."""
def _get_player_stats(
self,
player_name: Annotated[str, "The name of the player to look up"]
) -> str:
"""Get detailed stats for a specific player."""
info = get_player_info(player_name)
if not info:
return f"No data found for {player_name}"
return (f"{player_name} ({info['pos']}, {info['team']}) - "
f"ADP: {info['adp']}, Tier: {info['tier']}, "
f"2023 PPG: {info['ppg_2023']}")
def _check_best_available(
self,
position: Annotated[Optional[str], "Position to filter by (RB, WR, QB, TE)"] = None
) -> str:
"""Check the best available player overall or by position."""
best = get_best_available(self.draft_state["all_picks"], position)
if not best or not best[0]:
pos_str = f" at {position}" if position else ""
return f"No players available{pos_str}"
name, info = best
return (f"Best available{' ' + position if position else ''}: "
f"{name} ({info['pos']}, {info['team']}) - "
f"ADP: {info['adp']}, Tier: {info['tier']}, "
f"2023 PPG: {info['ppg_2023']}")
def _analyze_position_scarcity(
self,
position: Annotated[str, "Position to analyze (RB, WR, QB, TE)"]
) -> str:
"""Analyze scarcity at a position based on remaining players."""
available = get_players_by_position(position)
drafted = [p for p in self.draft_state["all_picks"] if p in available]
remaining = len(available) - len(drafted)
# Count by tier
tier_counts = {}
for name, info in available.items():
if name not in drafted:
tier = info['tier']
tier_counts[tier] = tier_counts.get(tier, 0) + 1
analysis = f"Position analysis for {position}:\n"
analysis += f"Total remaining: {remaining}\n"
for tier in sorted(tier_counts.keys()):
analysis += f"Tier {tier}: {tier_counts[tier]} players\n"
return analysis
def _get_team_stack_options(
self,
team: Annotated[str, "Team abbreviation (e.g., KC, BUF, MIA)"]
) -> str:
"""Get stacking options for a specific team."""
team_players = {name: info for name, info in TOP_PLAYERS.items()
if info.get('team') == team and name not in self.draft_state["all_picks"]}
if not team_players:
return f"No available players from {team}"
result = f"Available {team} players for stacking:\n"
for name, info in sorted(team_players.items(), key=lambda x: x[1]['adp']):
result += f"- {name} ({info['pos']}) - ADP: {info['adp']}\n"
return result
def update_draft_state(self, pick: str, is_my_pick: bool = False):
"""Update the draft state with a new pick."""
self.draft_state["all_picks"].append(pick)
if is_my_pick:
self.draft_state["my_picks"].append(pick)
# Update round
total_picks = len(self.draft_state["all_picks"])
self.draft_state["round"] = (total_picks // self.draft_state["league_size"]) + 1
def run(self, prompt: str, maintain_context: bool = True) -> str:
"""Run the agent with a prompt, maintaining conversation context."""
try:
# Build context from previous conversation if needed
if maintain_context and self.draft_state["conversation_history"]:
context = self._build_conversation_context()
full_prompt = f"{context}\n\nCurrent message: {prompt}"
else:
full_prompt = prompt
# Add current draft state to prompt
draft_context = self._build_draft_context()
full_prompt = f"{draft_context}\n\n{full_prompt}"
# Run the agent
trace = self.agent.run(full_prompt)
# Store conversation turn
self.draft_state["conversation_history"].append({
"user": prompt,
"agent": trace.final_output
})
return trace.final_output
except Exception as e:
print(f"Error in agent.run(): {e}")
print(f"Prompt was: {prompt[:200]}...")
# Return a fallback response
return f"I encountered an error: {str(e)}. Please check your API key configuration."
def _build_conversation_context(self) -> str:
"""Build context from conversation history."""
if not self.draft_state["conversation_history"]:
return ""
context = "Previous conversation:\n"
# Include last 3 exchanges for context
recent_history = self.draft_state["conversation_history"][-3:]
for turn in recent_history:
context += f"User: {turn['user']}\n"
context += f"Assistant: {turn['agent']}\n\n"
return context
def _build_draft_context(self) -> str:
"""Build context about current draft state."""
context = f"Current draft state:\n"
context += f"Round: {self.draft_state['round']}\n"
context += f"Your pick number: {self.draft_state['pick_number']}\n"
if self.draft_state["my_picks"]:
context += f"Your picks: {', '.join(self.draft_state['my_picks'])}\n"
if self.draft_state["all_picks"]:
recent_picks = self.draft_state["all_picks"][-5:]
context += f"Recent picks: {', '.join(recent_picks)}\n"
return context
def reset_draft(self):
"""Reset the draft state for a new draft."""
self.draft_state = {
"my_picks": [],
"all_picks": [],
"round": 1,
"pick_number": 5,
"league_size": 12,
"roster_needs": {
"QB": 1, "RB": 2, "WR": 2, "TE": 1, "FLEX": 1
},
"conversation_history": []
}
# Simple test function
def test_agent():
"""Test the fantasy draft agent."""
agent = FantasyDraftAgent()
# Test basic question
response = agent.run("What are the top 3 RBs available?")
print("Agent:", response)
print("\n" + "="*50 + "\n")
# Test multi-turn conversation
response = agent.run("I have the 5th pick. The first 4 picks were McCaffrey, Jefferson, Lamb, and Hill. What should I do?")
print("Agent:", response)
print("\n" + "="*50 + "\n")
# Follow-up that should remember context
response = agent.run("What about taking a WR instead?")
print("Agent:", response)
if __name__ == "__main__":
test_agent()