tc-agent / services /challenge_service.py
togitoon's picture
Initial
bf5f290
from typing import Dict
from services.ai_service import ai_service
from services.mcp_service import mcp_service
from utils.json_parser import JSONParser
from utils.error_handler import StandardAPIResponse, handle_service_error
from prompts.challenge_prompts import ChallengePrompts
from tools.email_tool import send_email
import logging
logger = logging.getLogger(__name__)
class ChallengeService:
"""Centralized service for Topcoder challenge operations"""
def __init__(self):
self.ai_service = ai_service
self.mcp_service = mcp_service
self.json_parser = JSONParser()
def get_challenges_dry_run(self, preferences: str) -> Dict:
"""
Get challenges for dry run (immediate response without sending emails)
Args:
preferences: User preferences for filtering challenges
Returns:
Standardized response dictionary
"""
try:
logger.info(f"Getting challenges for dry run with preferences: {preferences}")
# Create MCP client for Topcoder server
topcoder_client = self.mcp_service.create_topcoder_client()
with topcoder_client:
# Get Topcoder MCP tools
mcp_tools = self.mcp_service.get_topcoder_tools(topcoder_client)
if not mcp_tools:
return StandardAPIResponse.error(
"No Topcoder MCP tools available",
status_code=503,
error_code="MCP_UNAVAILABLE"
)
# Create agent with dry run prompt
system_prompt = ChallengePrompts.get_dry_run_prompt(preferences)
agent = self.ai_service.create_agent(mcp_tools, system_prompt)
# Create user query
user_query = f"""
Please help me find Topcoder challenges that match my preferences:
User Preferences: {preferences if preferences else "No specific preferences - show all relevant challenges"}
Please:
1. Query Topcoder challenges that are currently active
2. Filter or prioritize challenges that match my preferences
3. Return the results in the specified JSON format
"""
# Get response from agent
response = agent(user_query)
logger.info(f"Agent response: {response}")
# Parse JSON from response
parsed_data = self.json_parser.extract_json_from_response(str(response))
if parsed_data is None:
return StandardAPIResponse.error(
"Could not extract JSON from response",
status_code=500,
error_code="JSON_PARSE_ERROR"
)
# Normalize challenges to consistent format
if "challenges" in parsed_data:
challenges = self.json_parser.normalize_challenges(parsed_data["challenges"])
else:
challenges = self.json_parser.normalize_challenges(parsed_data)
return StandardAPIResponse.success(
data={"challenges": challenges},
message=f"Found {len(challenges)} challenge{'s' if len(challenges) != 1 else ''}",
metadata={"preferences": preferences}
)
except Exception as e:
return handle_service_error(e, "get challenges for dry run", preferences)
def process_challenges_for_user(self, user_id: str, email: str, preferences: str) -> Dict:
"""
Process challenges for automated agent (email notifications)
Args:
user_id: User ID from database
email: User email address
preferences: User preferences
Returns:
Processing result dictionary
"""
result = {
"challenges_found": 0,
"notifications_sent": 0,
"status": "completed",
"error_message": None
}
try:
logger.info(f"Processing challenges for user {email} with preferences: {preferences}")
# Create MCP client for Topcoder server
topcoder_client = self.mcp_service.create_topcoder_client()
with topcoder_client:
# Get Topcoder MCP tools
mcp_tools = self.mcp_service.get_topcoder_tools(topcoder_client)
if not mcp_tools:
result["status"] = "failed"
result["error_message"] = "No Topcoder MCP tools available"
return result
# Combine tools with email tool
all_tools = [send_email] + mcp_tools
# Create agent with personalized prompt
system_prompt = ChallengePrompts.get_agent_prompt(preferences, email)
agent = self.ai_service.create_agent(all_tools, system_prompt)
# Create user query
user_query = f"""
Please help me find and notify about relevant Topcoder challenges:
User Email: {email}
User Preferences: {preferences if preferences else "No specific preferences - show high-value challenges"}
Steps to follow:
1. Query Topcoder for active challenges
2. Filter challenges based on user preferences
3. If relevant challenges found, send a professional email notification
4. The email should include challenge details, prizes, and registration links
IMPORTANT: Only send email if there are genuinely relevant challenges that match the user's preferences.
"""
# Execute agent
response = agent(user_query)
logger.info(f"Agent response for {email}: {response}")
# Keep it simple - don't track notification counts
result["notifications_sent"] = 0
except Exception as e:
logger.error(f"Error processing challenges for {email}: {e}")
result["status"] = "failed"
result["error_message"] = str(e)
return result
# Create a global instance
challenge_service = ChallengeService()