from smolagents import CodeAgent,DuckDuckGoSearchTool, HfApiModel,load_tool,tool import datetime import requests import pytz import yaml from tools.final_answer import FinalAnswerTool from Gradio_UI import GradioUI # Below is an example of a tool that does nothing. Amaze us with your creativity ! @tool def get_current_time_in_timezone(timezone: str) -> str: """Get the current time in a specified timezone. Args: timezone: A valid timezone string (e.g., 'America/New_York', 'Asia/Tokyo'). """ try: # Validate timezone if timezone not in pytz.all_timezones: return json.dumps({ "status": "error", "message": f"Invalid timezone: '{timezone}'. Please provide a valid timezone like 'America/New_York'.", "data_source": "none" }) # Create timezone object tz = pytz.timezone(timezone) # Get current time in that timezone local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return json.dumps({ "status": "success", "message": f"The current time in {timezone} is: {local_time}", "data": { "timezone": timezone, "current_time": local_time }, "data_source": "system_time" }) except Exception as e: return json.dumps({ "status": "error", "message": f"Error fetching time for timezone '{timezone}': {str(e)}", "data_source": "none" }) @tool def get_sunrise_time(location: str, date: str = "today") -> str: """Get sunrise time and photography tips for a specified location. Args: location: Location name or coordinates (e.g., "London" or "51.5074,-0.1278") date: Date string (e.g., "2023-12-25" or "today" for current date) """ try: # Validate date format if not "today" if date != "today": try: datetime.datetime.strptime(date, "%Y-%m-%d") date_param = f"&date={date}" except ValueError: return json.dumps({ "status": "error", "message": f"Invalid date format: '{date}'. Please use YYYY-MM-DD format or 'today'.", "data_source": "none" }) else: date_param = "" # Check if location is in coordinate format if "," in location and all(part.replace('.', '', 1).replace('-', '', 1).isdigit() for part in location.split(',')): lat, lng = location.split(',') location_source = "user_coordinates" else: # Use Nominatim API for geocoding (convert location name to coordinates) try: geo_response = requests.get( f"https://nominatim.openstreetmap.org/search?q={location}&format=json&limit=1", headers={"User-Agent": "SunrisePhotographyAssistant/1.0"} ) geo_data = geo_response.json() if not geo_data: return json.dumps({ "status": "error", "message": f"Could not find location: {location}. Please try using coordinates or check the spelling.", "data_source": "none" }) lat = geo_data[0]['lat'] lng = geo_data[0]['lon'] location_source = "openstreetmap_geocoding" # Get the properly formatted name from OSM location_name = geo_data[0].get('display_name', location) except Exception as e: return json.dumps({ "status": "error", "message": f"Error geocoding location '{location}': {str(e)}", "data_source": "none" }) # Use coordinates to get sunrise data try: response = requests.get(f"https://api.sunrise-sunset.org/json?lat={lat}&lng={lng}{date_param}&formatted=0") data = response.json() if data.get('status') != 'OK': return json.dumps({ "status": "error", "message": f"Error getting sunrise data: {data.get('status', 'Unknown error')}", "data_source": "none" }) # Validate required fields required_fields = ['sunrise', 'civil_twilight_begin'] for field in required_fields: if field not in data.get('results', {}): return json.dumps({ "status": "error", "message": f"Missing required data field: {field}", "data_source": "none" }) except Exception as e: return json.dumps({ "status": "error", "message": f"Error fetching sunrise data: {str(e)}", "data_source": "none" }) # Process sunrise times (convert from UTC to local time) sunrise_utc = datetime.datetime.fromisoformat(data['results']['sunrise'].replace('Z', '+00:00')) civil_twilight_utc = datetime.datetime.fromisoformat(data['results']['civil_twilight_begin'].replace('Z', '+00:00')) # Get timezone for the location (using timezonefinder library) try: from timezonefinder import TimezoneFinder tf = TimezoneFinder() timezone_str = tf.certain_timezone_at(lat=float(lat), lng=float(lng)) if not timezone_str: timezone = pytz.UTC timezone_name = "UTC" timezone_confidence = "low" timezone_note = "(Note: Could not determine exact local timezone, using UTC instead)" else: timezone = pytz.timezone(timezone_str) timezone_name = timezone_str timezone_confidence = "high" timezone_note = "" except Exception as e: # Fallback to UTC if timezone lookup fails timezone = pytz.UTC timezone_name = "UTC" timezone_confidence = "fallback" timezone_note = f"(Note: Error determining timezone: {str(e)}. Using UTC instead)" # Convert to local time sunrise_local = sunrise_utc.astimezone(timezone) civil_twilight_local = civil_twilight_utc.astimezone(timezone) # Calculate golden hour (about 30 minutes after sunrise) golden_hour_end = sunrise_local + datetime.timedelta(minutes=30) # Format times sunrise_time = sunrise_local.strftime("%H:%M:%S") civil_twilight_time = civil_twilight_local.strftime("%H:%M:%S") golden_hour_end_time = golden_hour_end.strftime("%H:%M:%S") # Provide season-specific advice month = sunrise_local.month season = "" season_tip = "" if 3 <= month <= 5: # Spring season = "Spring" season_tip = "Spring sunrises often feature mist and soft light. Try to capture flowers in the foreground." elif 6 <= month <= 8: # Summer season = "Summer" season_tip = "Summer sunrise comes early and temperatures rise quickly. Bring insect repellent and watch for lens fog due to humidity." elif 9 <= month <= 11: # Fall/Autumn season = "Fall/Autumn" season_tip = "Fall sunrises often have fog and interesting cloud formations. Try using fallen leaves as foreground elements." else: # Winter season = "Winter" season_tip = "Winter sunrises come later with cooler light. Stay warm and bring extra batteries as cold temperatures drain them faster." # Generate factual data section factual_data = [ f"Sunrise time: {sunrise_time} {timezone_note}", f"Civil twilight begins: {civil_twilight_time}", f"Golden light ends approximately: {golden_hour_end_time}", f"Current season: {season}" ] # Generate photography recommendations photography_recommendations = [ f"Recommended arrival time: Civil twilight ({civil_twilight_time})", f"{season} photography consideration: {season_tip}", "Suggested gear: Tripod (essential), Variable ND filter, Remote shutter, Extra batteries", "Composition tip: Look for interesting foreground elements, don't just focus on the sky", "For best exposure, consider bracketing (HDR) or graduated filters" ] # Add a humorous tip humor_tips = [ "Remember to bring coffee, because your eyes might still be dreaming at dawn!", "If you see other photographers, don't stand in front of them... unless you want to be the 'silhouette art' in their photos.", "If your memory card fills up before the sunrise begins, that's why you should always bring two!", "First rule of sunrise photography: Don't oversleep. Second rule: Seriously, don't oversleep!", "Remember, the best tripod is the one you forgot at home...", "The ultimate test for your sunrise photo: If your mom says 'Wow!' instead of just politely nodding, you've succeeded.", "While waiting for sunrise in the frigid morning, remember that your bed misses you too.", "If your photos come out blurry, just tell everyone it's an 'artistic style'.", "The secret formula for the perfect sunrise shot: Weather forecast accuracy + Luck × Preparation ÷ Snooze button index" ] # Build final output result = f"== Sunrise Photography Guide for {location} ==\n\n" result += "FACTUAL DATA (from sunrise-sunset.org):\n" result += "\n".join([f"• {item}" for item in factual_data]) result += "\n\n" result += "PHOTOGRAPHY RECOMMENDATIONS:\n" result += "\n".join([f"• {item}" for item in photography_recommendations]) result += "\n\n" result += "HUMOR TIP:\n" result += f"• {random.choice(humor_tips)}\n\n" result += "NOTE: Weather conditions can significantly affect photography opportunities and are not predicted by this tool." # Prepare data for structured output output_data = { "status": "success", "message": result, "data": { "location": location, "date": date if date != "today" else datetime.datetime.now().strftime("%Y-%m-%d"), "sunrise_time": sunrise_time, "civil_twilight_time": civil_twilight_time, "golden_hour_end_time": golden_hour_end_time, "timezone": timezone_name, "season": season }, "data_sources": { "location": location_source, "astronomy": "sunrise-sunset.org", "timezone": f"timezonefinder ({timezone_confidence} confidence)" } } return json.dumps(output_data) except Exception as e: return json.dumps({ "status": "error", "message": f"Error processing request: {str(e)}", "data_source": "none" }) @tool def get_photography_tip() -> str: """Get a random sunrise photography tip.""" tips = [ "Arrive 45 minutes before sunrise to set up your equipment and have time to adjust your composition.", "Don't just shoot at the moment of sunrise - the light changes before and after are equally worth capturing.", "Use a tripod and remote shutter for sharp photos in low light conditions.", "Try using foreground elements (trees, rocks, lake reflections) to add depth to your photo.", "Use smartphone apps to predict the sunrise direction at your location and plan your composition in advance.", "Cloudy days can produce spectacular sunrise photos - don't abandon your shoot just because there's no clear sky.", "Light changes rapidly during sunrise - use exposure bracketing (HDR) to ensure you capture enough dynamic range.", "Consider using a telephoto lens for sunrise shots to magnify the sun and highlight atmospheric effects near the horizon.", "Bring graduated ND filters to balance the bright sky with a darker foreground.", "Research your location before traveling, understanding the sun's direction and terrain to find the best shooting spots.", "Try shooting panoramas to capture the full range of colors in the sky during sunrise.", "Shoot in RAW format to preserve more possibilities for post-processing.", "When shooting sunrise at the beach, check tide schedules to plan your best shooting position.", "Winter sunrises often have the most dramatic colors and longest golden hour periods.", "City sunrises can be spectacular - look for elevated positions that show the city skyline.", "In windy weather, add weight to your tripod to prevent camera shake during sunrise shoots.", "Use interval shooting (time-lapse) to document the entire sunrise process.", "Having the sky occupy 2/3 of your composition often creates more dramatic sunrise photos.", "During sunrise, sunlight has a reddish-yellow tone. Try setting your white balance to 'cloudy' to preserve these colors.", "If you want to capture star trails and sunrise in one composition, you'll need a star tracker and multiple exposure techniques." ] # Add some humorous "rescue" tips rescue_tips = [ "If you overslept and missed the sunrise, don't worry! Claim you're practicing 'minimalist photography' - not shooting is the ultimate art form.", "Lens fogged up? Tell everyone you invented the 'dream filter effect' - it might be trending next week.", "If you took 100 photos and none are satisfactory, convert them to black and white - photographers call this 'artistic redemption'.", "Forgot your memory card? Congratulations on experiencing 'mindful photography' - recording the moment with your eyes and heart.", "Sun hiding behind clouds and not coming out? Claim you were actually there to shoot 'cloud portraits' all along.", "Forgot to adjust ISO and got noisy photos? No problem, call it 'digital grain' and claim it's your signature style.", "If your sunrise photos look bland, try this pro tip: Add filters until it looks like an alien sunset, then post on social media with #NoFilter.", "Tripod collapsed? That's the universe telling you it's time to try 'stream of consciousness photography'." ] # 20% chance to return a "rescue" tip if random.random() < 0.2: tip = random.choice(rescue_tips) tip_type = "humorous_rescue" else: tip = random.choice(tips) tip_type = "practical" return json.dumps({ "status": "success", "message": tip, "data": { "tip": tip, "tip_type": tip_type }, "data_source": "curated_collection" }) @tool def parse_response(response_json: str) -> str: """Helper tool to parse JSON responses and format them for user display. Args: response_json: JSON string from one of the other tools """ try: data = json.loads(response_json) # Simply return the message for successful responses if data.get("status") == "success": return data.get("message", "Operation completed successfully, but no message was provided.") else: # For error responses, provide a clear error message return f"ERROR: {data.get('message', 'An unknown error occurred.')}" except Exception as e: return f"Error parsing response: {str(e)}" final_answer = FinalAnswerTool() # Model setup model = HfApiModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) # Import image generation 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=[ get_current_time_in_timezone, get_sunrise_time, get_photography_tip, parse_response, # Add helper tool for parsing image_generation_tool, final_answer ], max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name="Sunrise Photography Assistant", description="An intelligent assistant that helps photographers find the best times for sunrise photography and provides professional advice", prompt_templates=prompt_templates ) GradioUI(agent).launch()