Shafagh99/Daily_Headlines_Assistant
0
1from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, load_tool, tool2import datetime3import requests4import pytz5import yaml6import gradio as gr7from tools.final_answer import FinalAnswerTool8 9# Below is an example of a tool that does nothing. Amaze us with your creativity !10@tool11def my_custom_tool(arg1: str, arg2: int) -> str: # it's important to specify the return type12 # Keep this format for the description / args / args description but feel free to modify the tool13 """Fetch and nicely format top headlines from popular news sources for today.14 15 Args:16 arg1: Comma-separated list of sources to include (options: "bbc", "nyt", "guardian", "hn", "all").17 Use "all" or empty string to fetch from all supported sources.18 arg2: Maximum number of headlines per source (must be > 0).19 20 This tool scrapes public RSS feeds (no API key needed) and returns a21 markdown-formatted string grouped by source, with each headline on its own line22 and linked to the original article when available.23 """24 import xml.etree.ElementTree as ET25 26 if arg2 <= 0:27 return "Please provide a positive integer number of headlines per source for arg2."28 29 # Normalize requested sources30 requested = [s.strip().lower() for s in arg1.split(",")] if arg1 else []31 if not requested or "all" in requested:32 requested = ["bbc", "nyt", "guardian", "hn"]33 34 # Supported sources and their RSS URLs35 sources = {36 "bbc": {37 "name": "BBC News",38 "url": "https://feeds.bbci.co.uk/news/rss.xml",39 },40 "nyt": {41 "name": "The New York Times",42 "url": "https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml",43 },44 "guardian": {45 "name": "The Guardian",46 "url": "https://www.theguardian.com/world/rss",47 },48 "hn": {49 "name": "Hacker News (Top)",50 "url": "https://hnrss.org/frontpage",51 },52 }53 54 picked_keys = [k for k in requested if k in sources]55 if not picked_keys:56 return (57 "No valid news sources selected. Valid options: bbc, nyt, guardian, hn, all."58 )59 60 output_sections = []61 62 for key in picked_keys:63 meta = sources[key]64 name = meta["name"]65 url = meta["url"]66 67 try:68 resp = requests.get(url, timeout=8)69 resp.raise_for_status()70 root = ET.fromstring(resp.content)71 72 # RSS structure: channel/item/title/link73 items = []74 for item in root.findall(".//item"):75 title_el = item.find("title")76 link_el = item.find("link")77 if title_el is not None and title_el.text:78 title = title_el.text.strip()79 link = link_el.text.strip() if link_el is not None and link_el.text else ""80 if title:81 items.append((title, link))82 if len(items) >= arg2:83 break84 85 if not items:86 output_sections.append(f"### {name}\n\n_(no headlines found)_")87 else:88 lines = []89 for idx, (title, link) in enumerate(items, start=1):90 if link:91 lines.append(f"{idx}. [{title}]({link})")92 else:93 lines.append(f"{idx}. {title}")94 joined = "\n".join(lines)95 output_sections.append(f"### {name} (top {len(items)})\n\n{joined}")96 except Exception as e:97 output_sections.append(f"### {name}\n\n_Error fetching headlines: {e}_")98 99 header = "## Top headlines from popular news sources\n"100 return header + "\n\n" + "\n\n".join(output_sections)101 102@tool103def get_current_time_in_timezone(timezone: str) -> str:104 """A tool that fetches the current local time in a specified timezone.105 Args:106 timezone: A string representing a valid timezone (e.g., 'America/New_York').107 """108 try:109 # Create timezone object110 tz = pytz.timezone(timezone)111 # Get current time in that timezone112 local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")113 return f"The current local time in {timezone} is: {local_time}"114 except Exception as e:115 return f"Error fetching time for timezone '{timezone}': {str(e)}"116 117 118final_answer = FinalAnswerTool()119 120# 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:121# model_id='https://pflgm2locj2t89co.us-east-1.aws.endpoints.huggingface.cloud' 122 123model = InferenceClientModel(124 max_tokens=2096,125 temperature=0.5,126 model_id='Qwen/Qwen2.5-Coder-32B-Instruct', # it is possible that this model may be overloaded127 custom_role_conversions=None,128)129 130 131# Import tool from Hub132image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True)133 134with open("prompts.yaml", 'r') as stream:135 prompt_templates = yaml.safe_load(stream)136 137agent = CodeAgent(138 model=model,139 tools=[final_answer, my_custom_tool, get_current_time_in_timezone, image_generation_tool], # don't remove final_answer140 max_steps=6,141 verbosity_level=1,142 name=None,143 description=None,144)145 146 147def chat_fn(message, history):148 """Chat handler for Gradio.149 150 If the user is asking for headlines, we bypass the agent and call the151 headlines tool directly so the nicely formatted markdown is returned152 as-is. For other queries, we fall back to the CodeAgent.153 """154 text = (message or "").lower().strip()155 156 # Special handling for capability / "what can you do" questions157 if any(phrase in text for phrase in ["what can you do", "what you can do", "help me", "how can you help"]):158 return (159 "I’m your **Daily Headlines Assistant**.\n\n"160 "- I fetch today’s top headlines from **BBC**, **The New York Times**, "161 "**The Guardian**, and **Hacker News** using live RSS feeds.\n"162 "- I format them into a clean, grouped markdown view with **clickable links**.\n"163 "- I can also tell you the **current time in any timezone** and generate images from text prompts.\n\n"164 "Try asking things like:\n"165 "- \"Show me today’s top 3 headlines from BBC, NYT and Hacker News.\"\n"166 "- \"Give me the top 5 headlines from BBC only.\"\n"167 "- \"What time is it now in America/New_York?\"\n"168 )169 wants_news = any(170 kw in text171 for kw in ["headline", "headlines", "bbc", "nyt", "new york times", "guardian", "hacker news", "hn"]172 )173 174 if wants_news:175 # Simple heuristic: default to all sources and 3 headlines if user176 # does not specify numbers; otherwise, try to extract a small integer.177 import re178 179 match = re.search(r"\b(\d{1,2})\b", text)180 count = int(match.group(1)) if match else 3181 # Map some common names to our source keys182 sources = []183 if "bbc" in text:184 sources.append("bbc")185 if "nyt" in text or "new york times" in text:186 sources.append("nyt")187 if "guardian" in text:188 sources.append("guardian")189 if "hacker news" in text or "hn" in text:190 sources.append("hn")191 # If nothing specific mentioned, use all192 arg1 = ",".join(sources) if sources else "all"193 194 try:195 return my_custom_tool(arg1=arg1, arg2=count)196 except Exception as e:197 return f"Error while fetching headlines: {e}"198 199 # Fallback: use the full agent for non-news tasks200 try:201 result = agent.run(task=message)202 except Exception as e:203 result = f"Error while running the agent: {e}"204 if result is None:205 result = (206 "The agent did not produce a final answer (the upstream model may have "207 "returned an error like 502). Please try again or with a simpler request."208 )209 return str(result)210 211 212demo = gr.ChatInterface(213 fn=chat_fn,214 title="Daily Headlines Assistant",215 description=(216 "Ask for today's top headlines from BBC, The New York Times, The Guardian, "217 "and Hacker News. Results include clickable links and are grouped by source."218 ),219 examples=[220 "Show me today’s top 3 headlines from BBC, NYT and Hacker News.",221 "Give me the top 5 headlines from BBC only.",222 "Fetch today’s main stories from The Guardian and Hacker News.",223 ],224)225 226demo.launch()