Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ innovation-lab-examples/
| Example | Description | Tech Stack | Difficulty |
|---------|-------------|------------|------------|
| [contributors/community_agent](contributors/community_agent/) | AI community growth agent for events and hackathons | Python, uAgents, ASI:One, Tavily | 🟡 Intermediate |
| [contributors/news-summarizer-agent](contributors/news-summarizer-agent/) | Fetches top headlines for a topic via NewsAPI and summarizes them with ASI:One, via Chat Protocol | Python, uAgents, NewsAPI, ASI:One | 🟡 Intermediate |

### 🌐 Web3 & Blockchain

Expand Down
4 changes: 3 additions & 1 deletion contributors/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [Unreleased]

### Added

- `gemini-research-agent/`: Added Gemini-powered research assistant demonstrating the standard Agent Chat Protocol (@Kavurubuvanesh)
- `contributors/` folder and contribution guide for community agent examples
- `contributors/community_agent/` — moved from repository root; AI community growth agent for events and hackathons
- `contributors/community_agent/` — moved from repository root; AI community growth agent for events and hackathons
- `contributors/news-summarizer-agent/` — beginner-friendly agent that fetches top headlines via NewsAPI and summarizes them with ASI:One; now a uAgent with Chat Protocol support
5 changes: 5 additions & 0 deletions contributors/news-summarizer-agent/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Required: ASI:One API key for summarization (https://asi1.ai/)
ASI1_API_KEY=your_asi1_api_key_here

# Required: NewsAPI key, free tier (https://newsapi.org/register)
NEWS_API_KEY=your_news_api_key_here
115 changes: 115 additions & 0 deletions contributors/news-summarizer-agent/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# News Summarizer Agent

![uAgents](https://img.shields.io/badge/uAgents-chat--protocol-blue)
![News](https://img.shields.io/badge/news-NewsAPI-orange)
![LLM](https://img.shields.io/badge/LLM-ASI%3AOne-green)
![Python](https://img.shields.io/badge/python-3.10+-blue)

A beginner-friendly Fetch.ai agent that fetches the top news headlines for any
topic using [NewsAPI](https://newsapi.org/) and summarizes them with the
[ASI:One](https://asi1.ai/) LLM. The agent speaks the
[Chat Protocol](https://innovationlab.fetch.ai/resources/docs/agent-communication/agent-chat-protocol),
so it can be messaged directly from ASI:One or any other Agentverse-connected
agent.

## What it does

1. You send a topic (e.g. "AI", "climate", "sports") as a chat message.
2. The agent fetches the top 5 latest headlines for that topic from NewsAPI.
3. The headlines are sent to ASI:One for a short summary.
4. The agent replies with the headlines plus a 3-4 sentence summary.

## Tech stack

| Layer | Technology |
|-------|------------|
| Agent runtime | [uAgents](https://docs.fetch.ai/agents/uaagents/) + Chat Protocol |
| News data | [NewsAPI](https://newsapi.org/) free tier |
| LLM | [ASI:One](https://asi1.ai/) (`asi1-mini`) |
| HTTP client | `requests` |
| Language | Python 3.10+ |

## Prerequisites

- Python 3.10+
- A free [NewsAPI](https://newsapi.org/register) key
- An [ASI:One](https://asi1.ai/) API key

## Setup

### 1. Navigate to this folder

```bash
cd contributors/news-summarizer-agent
```

### 2. Install dependencies

```bash
pip install -r requirements.txt
```

### 3. Set up environment variables

```bash
cp .env.example .env
```

Edit `.env` and fill in your API keys:

```env
ASI1_API_KEY=your_asi1_api_key_here
NEWS_API_KEY=your_news_api_key_here
```

### 4. Run the agent

```bash
python agent.py
```

The agent starts and prints its address. Send it a Chat Protocol message
containing a topic such as `AI`, `climate`, or `sports` and it will reply
with the latest headlines and a summary.

## Example interaction

```text
You: sports
Agent: Top headlines for 'sports':
- Headline 1...
- Headline 2...

Summary:
<3-4 sentence summary generated by ASI:One>
```

## Demo

![Demo output](demo.png)

## Environment variables

| Variable | Required | Description |
|----------|----------|-------------|
| `ASI1_API_KEY` | Yes | Your ASI:One API key from [asi1.ai](https://asi1.ai/) |
| `NEWS_API_KEY` | Yes | Your NewsAPI key from [newsapi.org](https://newsapi.org/) |

## Project structure

contributors/news-summarizer-agent/

├── agent.py # uAgent with Chat Protocol, NewsAPI + ASI:One logic

├── requirements.txt # Python dependencies

├── .env.example # Environment variable template

├── demo.png # Demo screenshot

└── README.md # This file


## License

MIT (see repository root [LICENSE](../../LICENSE)).
169 changes: 169 additions & 0 deletions contributors/news-summarizer-agent/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
"""
News Summarizer Agent

A beginner-friendly Fetch.ai uAgent that fetches the latest news headlines
for a topic using NewsAPI and summarizes them with the ASI:One LLM.
Supports the Chat Protocol so it can be used directly from ASI:One
or any other Agentverse-connected agent.
"""

import os
from datetime import datetime, timezone
from uuid import uuid4

import requests
from dotenv import load_dotenv
from uagents import Agent, Context, Protocol
from uagents_core.contrib.protocols.chat import (
ChatAcknowledgement,
ChatMessage,
TextContent,
chat_protocol_spec,
)

load_dotenv()

ASI1_API_KEY = os.getenv("ASI1_API_KEY", "")
NEWS_API_KEY = os.getenv("NEWS_API_KEY", "")

NEWS_API_URL = "https://newsapi.org/v2/everything"
ASI1_API_URL = "https://api.asi1.ai/v1/chat/completions"


def fetch_headlines(topic: str) -> list[str]:
"""Fetch the top 5 news headlines for a given topic using NewsAPI."""
params = {
"q": topic,
"pageSize": 5,
"sortBy": "publishedAt",
"language": "en",
"apiKey": NEWS_API_KEY,
}
response = requests.get(NEWS_API_URL, params=params, timeout=15)
response.raise_for_status()
articles = response.json().get("articles", [])
return [a["title"] for a in articles if a.get("title")]


def summarize_with_asi1(topic: str, headlines: list[str]) -> str:
"""Send headlines to the ASI:One LLM and return a readable summary."""
headlines_text = "\n".join(f"- {h}" for h in headlines)
prompt = (
f"Here are the top {len(headlines)} recent news headlines about "
f"'{topic}':\n\n{headlines_text}\n\n"
f"Please write a short, clear, 3-4 sentence summary of what is "
f"currently happening with '{topic}' based on these headlines."
)

headers = {
"Authorization": f"Bearer {ASI1_API_KEY}",
"Content-Type": "application/json",
}
payload = {
"model": "asi1-mini",
"messages": [{"role": "user", "content": prompt}],
"temperature": 0.7,
"max_tokens": 300,
"stream": False,
}

response = requests.post(ASI1_API_URL, headers=headers, json=payload, timeout=30)
response.raise_for_status()
data = response.json()
return str(data["choices"][0]["message"]["content"])


def build_news_summary(topic: str) -> str:
"""Fetch headlines for a topic and return a formatted summary string."""
topic = topic.strip()
if not topic:
return "Please tell me a topic to summarize, e.g. 'AI', 'climate', or 'sports'."

if not NEWS_API_KEY:
return (
"This agent is missing a NEWS_API_KEY — ask the operator to configure it."
)
if not ASI1_API_KEY:
return (
"This agent is missing an ASI1_API_KEY — ask the operator to configure it."
)

headlines = fetch_headlines(topic)
if not headlines:
return f"No recent headlines found for '{topic}'. Try a different topic."

summary = summarize_with_asi1(topic, headlines)
headlines_block = "\n".join(f"- {h}" for h in headlines)
return f"Top headlines for '{topic}':\n{headlines_block}\n\nSummary:\n{summary}"


def run_cli(topic: str) -> None:
"""Run the agent's summary flow once and print the result (for local testing)."""
print(f"\nFetching top headlines for topic: '{topic}'...")
print(build_news_summary(topic))


# ─── Chat Protocol ──────────────────────────────────────────────

chat_proto = Protocol(spec=chat_protocol_spec)


@chat_proto.on_message(ChatMessage)
async def handle_chat_message(ctx: Context, sender: str, msg: ChatMessage) -> None:
await ctx.send(
sender,
ChatAcknowledgement(
timestamp=datetime.now(timezone.utc),
acknowledged_msg_id=msg.msg_id,
),
)

topic = "\n".join(
item.text for item in msg.content if isinstance(item, TextContent) and item.text
).strip()

if not topic:
reply = (
"Hi! Send me a topic (e.g. 'AI', 'climate', or 'sports') and "
"I'll fetch the latest headlines and summarize them for you."
)
else:
try:
reply = build_news_summary(topic)
except requests.RequestException as exc:
ctx.logger.exception("Upstream API request failed")
reply = f"Sorry, I couldn't fetch news for '{topic}' right now ({exc})."

await ctx.send(
sender,
ChatMessage(
timestamp=datetime.now(timezone.utc),
msg_id=uuid4(),
content=[TextContent(type="text", text=reply)],
),
)


@chat_proto.on_message(ChatAcknowledgement)
async def handle_ack(ctx: Context, sender: str, msg: ChatAcknowledgement) -> None:
ctx.logger.info(
f"Received acknowledgement from {sender} for message {msg.acknowledged_msg_id}"
)


# ─── Agent setup ─────────────────────────────────────────────────

agent = Agent()

agent.include(chat_proto, publish_manifest=True)


@agent.on_event("startup")
async def on_startup(ctx: Context) -> None:
ctx.logger.info(f"News Summarizer Agent started at address {agent.address}")
ctx.logger.info(f"NEWS_API_KEY configured: {bool(NEWS_API_KEY)}")
ctx.logger.info(f"ASI1_API_KEY configured: {bool(ASI1_API_KEY)}")


if __name__ == "__main__":
agent.run()
Binary file added contributors/news-summarizer-agent/demo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions contributors/news-summarizer-agent/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
uagents>=0.20.0
requests>=2.28.0
python-dotenv>=1.0.0
Loading