from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml import gradio as gr from tools.final_answer import FinalAnswerTool # Below is an example of a tool that does nothing. Amaze us with your creativity ! @tool def my_custom_tool(arg1: str, arg2: int) -> str: # it's important to specify the return type # Keep this format for the description / args / args description but feel free to modify the tool """Fetch and nicely format top headlines from popular news sources for today. Args: arg1: Comma-separated list of sources to include (options: "bbc", "nyt", "guardian", "hn", "all"). Use "all" or empty string to fetch from all supported sources. arg2: Maximum number of headlines per source (must be > 0). This tool scrapes public RSS feeds (no API key needed) and returns a markdown-formatted string grouped by source, with each headline on its own line and linked to the original article when available. """ import xml.etree.ElementTree as ET if arg2 <= 0: return "Please provide a positive integer number of headlines per source for arg2." # Normalize requested sources requested = [s.strip().lower() for s in arg1.split(",")] if arg1 else [] if not requested or "all" in requested: requested = ["bbc", "nyt", "guardian", "hn"] # Supported sources and their RSS URLs sources = { "bbc": { "name": "BBC News", "url": "https://feeds.bbci.co.uk/news/rss.xml", }, "nyt": { "name": "The New York Times", "url": "https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml", }, "guardian": { "name": "The Guardian", "url": "https://www.theguardian.com/world/rss", }, "hn": { "name": "Hacker News (Top)", "url": "https://hnrss.org/frontpage", }, } picked_keys = [k for k in requested if k in sources] if not picked_keys: return ( "No valid news sources selected. Valid options: bbc, nyt, guardian, hn, all." ) output_sections = [] for key in picked_keys: meta = sources[key] name = meta["name"] url = meta["url"] try: resp = requests.get(url, timeout=8) resp.raise_for_status() root = ET.fromstring(resp.content) # RSS structure: channel/item/title/link items = [] for item in root.findall(".//item"): title_el = item.find("title") link_el = item.find("link") if title_el is not None and title_el.text: title = title_el.text.strip() link = link_el.text.strip() if link_el is not None and link_el.text else "" if title: items.append((title, link)) if len(items) >= arg2: break if not items: output_sections.append(f"### {name}\n\n_(no headlines found)_") else: lines = [] for idx, (title, link) in enumerate(items, start=1): if link: lines.append(f"{idx}. [{title}]({link})") else: lines.append(f"{idx}. {title}") joined = "\n".join(lines) output_sections.append(f"### {name} (top {len(items)})\n\n{joined}") except Exception as e: output_sections.append(f"### {name}\n\n_Error fetching headlines: {e}_") header = "## Top headlines from popular news sources\n" return header + "\n\n" + "\n\n".join(output_sections) @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'). """ try: # 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 f"The current local time in {timezone} is: {local_time}" except Exception as e: return f"Error fetching time for timezone '{timezone}': {str(e)}" final_answer = FinalAnswerTool() # If the agent does not answer, the model is overloaded, please use another model or the following Hugging Face Endpoint that also contains qwen2.5 coder: # model_id='https://pflgm2locj2t89co.us-east-1.aws.endpoints.huggingface.cloud' model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', # it is possible that this model may be overloaded 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_custom_tool, get_current_time_in_timezone, image_generation_tool], # don't remove final_answer max_steps=6, verbosity_level=1, name=None, description=None, ) def chat_fn(message, history): """Chat handler for Gradio. If the user is asking for headlines, we bypass the agent and call the headlines tool directly so the nicely formatted markdown is returned as-is. For other queries, we fall back to the CodeAgent. """ text = (message or "").lower().strip() # Special handling for capability / "what can you do" questions if any(phrase in text for phrase in ["what can you do", "what you can do", "help me", "how can you help"]): return ( "I’m your **Daily Headlines Assistant**.\n\n" "- I fetch today’s top headlines from **BBC**, **The New York Times**, " "**The Guardian**, and **Hacker News** using live RSS feeds.\n" "- I format them into a clean, grouped markdown view with **clickable links**.\n" "- I can also tell you the **current time in any timezone** and generate images from text prompts.\n\n" "Try asking things like:\n" "- \"Show me today’s top 3 headlines from BBC, NYT and Hacker News.\"\n" "- \"Give me the top 5 headlines from BBC only.\"\n" "- \"What time is it now in America/New_York?\"\n" ) wants_news = any( kw in text for kw in ["headline", "headlines", "bbc", "nyt", "new york times", "guardian", "hacker news", "hn"] ) if wants_news: # Simple heuristic: default to all sources and 3 headlines if user # does not specify numbers; otherwise, try to extract a small integer. import re match = re.search(r"\b(\d{1,2})\b", text) count = int(match.group(1)) if match else 3 # Map some common names to our source keys sources = [] if "bbc" in text: sources.append("bbc") if "nyt" in text or "new york times" in text: sources.append("nyt") if "guardian" in text: sources.append("guardian") if "hacker news" in text or "hn" in text: sources.append("hn") # If nothing specific mentioned, use all arg1 = ",".join(sources) if sources else "all" try: return my_custom_tool(arg1=arg1, arg2=count) except Exception as e: return f"Error while fetching headlines: {e}" # Fallback: use the full agent for non-news tasks try: result = agent.run(task=message) except Exception as e: result = f"Error while running the agent: {e}" if result is None: result = ( "The agent did not produce a final answer (the upstream model may have " "returned an error like 502). Please try again or with a simpler request." ) return str(result) demo = gr.ChatInterface( fn=chat_fn, title="Daily Headlines Assistant", description=( "Ask for today's top headlines from BBC, The New York Times, The Guardian, " "and Hacker News. Results include clickable links and are grouped by source." ), examples=[ "Show me today’s top 3 headlines from BBC, NYT and Hacker News.", "Give me the top 5 headlines from BBC only.", "Fetch today’s main stories from The Guardian and Hacker News.", ], ) demo.launch()