from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel, load_tool, tool import datetime import requests import pytz import yaml import os from tools.final_answer import FinalAnswerTool from Gradio_UI import GradioUI @tool def my_cutom_tool(arg1: str, arg2: int) -> str: """A tool that does nothing yet Args: arg1: the first argument arg2: the second argument """ return "What magic will you build ?" @tool def get_current_time_in_timezone(timezone: str) -> str: """A tool that fetches the current local time in a specified timezone. Args: timezone: A string representing a valid timezone (e.g., 'America/New_York'). Returns: A string stating the current local time in the specified timezone. """ try: tz = pytz.timezone(timezone) local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"The current local time in {timezone} is: {local_time}" except Exception as e: return f"Error fetching time for timezone '{timezone}': {str(e)}" # --- Helper functions for Spotify and environmental data --- def fetch_spotify_access_token(): url = "https://accounts.spotify.com/api/token" headers = {"Content-Type": "application/x-www-form-urlencoded"} data = { "grant_type": "client_credentials", "client_id": os.getenv("SPOTIFY_CLIENT_ID"), "client_secret": os.getenv("SPOTIFY_CLIENT_SECRET") } response = requests.post(url, headers=headers, data=data) return response.json().get("access_token") def fetch_user_location_data(): url = "http://ip-api.com/json/" response = requests.get(url) if response.status_code == 200: data = response.json() return data.get("city"), data.get("country"), data.get("timezone") return None, None, None def fetch_weather_for_city(city: str): WEATHER_API_KEY = os.getenv("WEATHER_API_KEY") url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={WEATHER_API_KEY}&units=metric" response = requests.get(url) if response.status_code == 200: data = response.json() return data["weather"][0]["main"] return None def map_mood_to_params(mood: str, weather_condition: str = None) -> dict: # Base mapping of mood words to Spotify's target parameters and seed genre default_mappings = { "happy": {"target_valence": 0.9, "target_energy": 0.8, "seed_genre": "pop"}, "sad": {"target_valence": 0.2, "target_energy": 0.3, "seed_genre": "acoustic"}, "energetic": {"target_valence": 0.7, "target_energy": 0.9, "seed_genre": "work-out"}, "chill": {"target_valence": 0.6, "target_energy": 0.4, "seed_genre": "chill"} } mapping = default_mappings.get(mood.lower(), {"target_valence": 0.5, "target_energy": 0.5, "seed_genre": "pop"}) # Adjust parameters based on weather conditions if provided if weather_condition: weather = weather_condition.lower() if weather in ["rain", "thunderstorm"]: mapping["target_energy"] = max(mapping["target_energy"] - 0.2, 0.0) elif weather in ["clear"]: mapping["target_energy"] = min(mapping["target_energy"] + 0.1, 1.0) return mapping # --- Environmental Tools --- @tool def get_user_location() -> str: """Fetches the user's location using ip-api.com. Returns: A string containing the city, country, and timezone, or an error message. """ city, country, timezone = fetch_user_location_data() if city and country and timezone: return f"City: {city}, Country: {country}, Timezone: {timezone}" return "Error fetching location." @tool def get_weather(city: str) -> str: """Fetches weather data for a given city using OpenWeatherMap API. Args: city: The name of the city. Returns: A string describing the current weather in the specified city, or an error message. """ weather = fetch_weather_for_city(city) if weather: return f"Current weather in {city} is {weather}." return "Error fetching weather data." @tool def get_songs_by_mood(mood: str, local: bool = False) -> str: """Fetches a playlist of songs that fits the user's mood using Spotify's Recommendations API. Args: mood: A string representing the desired mood (e.g., "happy", "sad", "energetic", "chill"). local: A boolean flag. If True, the tool fetches the user's location and current weather to adjust the mood mapping accordingly. Returns: A string containing a playlist of songs (each on a new line) that matches the mood parameters. Additional Details: Mood is expressed in terms of target_valence and target_energy (energy replaces arousal). The tool internally maps mood words to corresponding Spotify parameters. For example: - "happy": target_valence ~ 0.9, target_energy ~ 0.8, seed_genre "pop" - "sad": target_valence ~ 0.2, target_energy ~ 0.3, seed_genre "acoustic" - "energetic": target_valence ~ 0.7, target_energy ~ 0.9, seed_genre "work-out" - "chill": target_valence ~ 0.6, target_energy ~ 0.4, seed_genre "chill" If 'local' is True, the tool uses the user's location and weather to adjust the mapping (e.g., reducing energy on rainy days). """ weather_condition = None if local: city, country, timezone = fetch_user_location_data() if not city: return "Error: Unable to determine user location." weather_condition = fetch_weather_for_city(city) mapping = map_mood_to_params(mood, weather_condition) access_token = fetch_spotify_access_token() if not access_token: return "Error: Unable to retrieve Spotify access token." params = { "seed_genres": mapping["seed_genre"], "target_valence": mapping["target_valence"], "target_energy": mapping["target_energy"], "limit": 10 } url = "https://api.spotify.com/v1/recommendations" headers = {"Authorization": f"Bearer {access_token}"} response = requests.get(url, headers=headers, params=params) if response.status_code == 200: tracks = response.json().get("tracks", []) if not tracks: return "No tracks found for the specified mood." playlist = [f"{track['name']} - {track['artists'][0]['name']}" for track in tracks] return "\n".join(playlist) return f"Error: {response.json()}" final_answer = FinalAnswerTool() model = HfApiModel( max_tokens=2096, temperature=0.5, model_id='https://wxknx1kg971u7k1n.us-east-1.aws.endpoints.huggingface.cloud', custom_role_conversions=None, ) # Import tool from Hub image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True) with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) agent = CodeAgent( model=model, tools=[ final_answer, my_cutom_tool, get_current_time_in_timezone, get_user_location, get_weather, get_songs_by_mood ], max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates ) GradioUI(agent).launch()