Spaces:
Runtime error
Runtime error
| """ | |
| HF Agents Course — Unit 3 use case: "Alfred at the Gala". | |
| A smolagents `CodeAgent` (Qwen 2.5-Coder-32B via HF Inference Providers) with: | |
| - guest_info_retriever — BM25 over `agents-course/unit3-invitees`. | |
| - web_search + visit_webpage — for live info about guests / topics. | |
| - fireworks_weather — pulls a tiny weather feature from open-meteo for | |
| Gotham (40.71°N, 74.01°W) and returns a textual go/no-go for fireworks. | |
| - hub_stats — looks up an AI builder's top downloaded model on the HF Hub. | |
| - final_answer — terminal tool. | |
| Wrapped in a Gradio chat UI. | |
| """ | |
| from __future__ import annotations | |
| import os | |
| from typing import Any | |
| import datasets | |
| import gradio as gr | |
| import requests | |
| from langchain_community.retrievers import BM25Retriever | |
| from langchain_core.documents import Document | |
| from smolagents import ( | |
| CodeAgent, | |
| DuckDuckGoSearchTool, | |
| InferenceClientModel, | |
| Tool, | |
| VisitWebpageTool, | |
| tool, | |
| ) | |
| from smolagents.default_tools import FinalAnswerTool | |
| # ----- Guest retriever (BM25 over the official dataset) --------------------- | |
| def _build_guest_docs() -> list[Document]: | |
| ds = datasets.load_dataset("agents-course/unit3-invitees", split="train") | |
| return [ | |
| Document( | |
| page_content="\n".join([ | |
| f"Name: {g['name']}", | |
| f"Relation: {g['relation']}", | |
| f"Description: {g['description']}", | |
| f"Email: {g['email']}", | |
| ]), | |
| metadata={"name": g["name"]}, | |
| ) | |
| for g in ds | |
| ] | |
| class GuestInfoRetrieverTool(Tool): | |
| name = "guest_info_retriever" | |
| description = ( | |
| "Retrieves detailed information about gala guests by name or relation. " | |
| "Returns up to 3 matching dossiers (name, relation, description, email)." | |
| ) | |
| inputs = { | |
| "query": { | |
| "type": "string", | |
| "description": "Name or relation to search for, e.g. 'Ada Lovelace' or 'mathematician'.", | |
| } | |
| } | |
| output_type = "string" | |
| def __init__(self, docs: list[Document]): | |
| super().__init__() | |
| self.retriever = BM25Retriever.from_documents(docs) | |
| def forward(self, query: str) -> str: | |
| results = self.retriever.invoke(query) | |
| if not results: | |
| return "No matching guest information found." | |
| return "\n\n".join(doc.page_content for doc in results[:3]) | |
| # ----- Custom tools --------------------------------------------------------- | |
| def fireworks_weather(latitude: float = 40.71, longitude: float = -74.01) -> str: | |
| """Tiny weather check for the gala's outdoor fireworks. Defaults to Gotham | |
| coordinates (lat 40.71, lon -74.01). Uses the free open-meteo API; no key. | |
| Args: | |
| latitude: Latitude in decimal degrees. | |
| longitude: Longitude in decimal degrees. | |
| Returns: | |
| Human-readable verdict including temperature, windspeed, and a | |
| go / no-go recommendation for the fireworks. | |
| """ | |
| try: | |
| r = requests.get( | |
| "https://api.open-meteo.com/v1/forecast", | |
| params={ | |
| "latitude": latitude, "longitude": longitude, | |
| "current_weather": "true", | |
| }, timeout=15, | |
| ) | |
| r.raise_for_status() | |
| cw = r.json().get("current_weather", {}) | |
| except Exception as exc: # noqa: BLE001 | |
| return f"Weather lookup failed: {exc}" | |
| temp_c = cw.get("temperature") | |
| wind = cw.get("windspeed") | |
| code = cw.get("weathercode") | |
| # open-meteo WMO weather codes: 0=clear, 1-3=mostly clear/partly cloudy, | |
| # 45/48=fog, 51-67=rain, 80-82=showers, 95-99=thunderstorm | |
| bad = (code in {45, 48} or (51 <= code <= 67) or | |
| (80 <= code <= 82) or (95 <= code <= 99) or | |
| (wind is not None and wind > 35)) | |
| verdict = ("🚫 NO-GO: weather/wind unsafe for fireworks." | |
| if bad else "✅ GO: clear-enough skies for fireworks.") | |
| return ( | |
| f"Current weather (lat={latitude}, lon={longitude}): " | |
| f"{temp_c}°C, wind {wind} km/h, WMO code {code}. → {verdict}" | |
| ) | |
| def hub_stats(author: str) -> str: | |
| """Look up the **most downloaded** model on the HF Hub for a given author | |
| or organization. Useful when Alfred needs talking points about an AI | |
| builder guest. | |
| Args: | |
| author: HF Hub username or org id (e.g. 'facebook', 'google', 'meta-llama'). | |
| Returns: | |
| Top model id and download count, or an error string. | |
| """ | |
| try: | |
| from huggingface_hub import list_models | |
| models = list(list_models(author=author, sort="downloads", limit=1)) | |
| except Exception as exc: # noqa: BLE001 | |
| return f"Hub stats lookup failed: {exc}" | |
| if not models: | |
| return f"No public models found for author {author!r}." | |
| m = models[0] | |
| return ( | |
| f"Top model for {author!r}: {m.id} " | |
| f"({getattr(m, 'downloads', '?'):,} downloads)" | |
| ) | |
| # ----- Agent factory -------------------------------------------------------- | |
| def build_agent() -> CodeAgent: | |
| docs = _build_guest_docs() | |
| guest_tool = GuestInfoRetrieverTool(docs) | |
| model_id = os.environ.get("AGENT_MODEL_ID", "Qwen/Qwen2.5-Coder-32B-Instruct") | |
| model = InferenceClientModel(model_id=model_id, max_tokens=2048, temperature=0.4) | |
| return CodeAgent( | |
| model=model, | |
| tools=[ | |
| guest_tool, | |
| DuckDuckGoSearchTool(), | |
| VisitWebpageTool(), | |
| fireworks_weather, | |
| hub_stats, | |
| FinalAnswerTool(), | |
| ], | |
| max_steps=8, | |
| verbosity_level=1, | |
| name="Alfred-Gala", | |
| description=( | |
| "Alfred, butler at Wayne Manor, helping host this evening's gala. " | |
| "Knows the guest list (via guest_info_retriever), the weather " | |
| "(fireworks_weather), and basic AI-Hub stats for any AI-builder " | |
| "guests (hub_stats). Can also search the web when needed." | |
| ), | |
| ) | |
| AGENT = None # lazy-initialized so the Space can boot before BM25 indexing | |
| def respond(message: str, _history: list[Any] | None = None) -> str: | |
| global AGENT # noqa: PLW0603 | |
| if AGENT is None: | |
| AGENT = build_agent() | |
| return str(AGENT.run(message)).strip() | |
| with gr.Blocks(title="Alfred — Unit 3 Gala Agent") as demo: | |
| gr.Markdown("# 🎩 Alfred — Unit 3 Gala Agent") | |
| gr.Markdown( | |
| "Agentic-RAG demo over the `agents-course/unit3-invitees` dataset, " | |
| "with optional web search, a weather check for the fireworks, and " | |
| "HF Hub stats lookup for AI-builder guests." | |
| ) | |
| gr.ChatInterface( | |
| fn=respond, | |
| type="messages", | |
| examples=[ | |
| "Tell me about our guest named 'Lady Ada Lovelace'.", | |
| "Which mathematicians are on the guest list?", | |
| "Is the weather good enough for fireworks tonight?", | |
| "What's the top model for the 'facebook' org on the Hub?", | |
| ], | |
| title=None, | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |