Add news API integration and related configurations

- Update .env.example to include NEWS_API_KEY configuration
- Add newsapi-python dependency in pyproject.toml
- Implement NewsAPI class for fetching news articles
- Create Article model for structured news data
- Add tests for NewsAPI functionality in test_news_api.py
- Update pytest configuration to include news marker
This commit is contained in:
2025-09-29 15:15:18 +02:00
parent 2be9e0f319
commit badd3e2a6c
8 changed files with 91 additions and 1 deletions

View File

@@ -1,4 +1,4 @@
########################################################################### ###############################################################################
# Configurazioni per i modelli di linguaggio # Configurazioni per i modelli di linguaggio
############################################################################### ###############################################################################
@@ -22,3 +22,10 @@ CRYPTOCOMPARE_API_KEY=
# Binance API per Market Agent (alternativa) # Binance API per Market Agent (alternativa)
BINANCE_API_KEY= BINANCE_API_KEY=
BINANCE_API_SECRET= BINANCE_API_SECRET=
###############################################################################
# Configurazioni per gli agenti di notizie
###############################################################################
# Ottenibile da: https://newsapi.org/docs
NEWS_API_KEY=

View File

@@ -31,6 +31,9 @@ dependencies = [
# ✅ per interagire con API di exchange di criptovalute # ✅ per interagire con API di exchange di criptovalute
"coinbase-advanced-py", "coinbase-advanced-py",
"python-binance", "python-binance",
# ✅ per interagire con API di notizie
"newsapi-python",
] ]
[tool.pytest.ini_options] [tool.pytest.ini_options]

3
src/app/news/__init__.py Normal file
View File

@@ -0,0 +1,3 @@
from .news_api import NewsAPI
__all__ = ["NewsAPI"]

8
src/app/news/base.py Normal file
View File

@@ -0,0 +1,8 @@
from pydantic import BaseModel
class Article(BaseModel):
source: str = ""
time: str = ""
title: str = ""
description: str = ""

34
src/app/news/news_api.py Normal file
View File

@@ -0,0 +1,34 @@
import os
import newsapi
from .base import Article
def result_to_article(result: dict) -> Article:
article = Article()
article.source = result.get("source", {}).get("name", "")
article.time = result.get("publishedAt", "")
article.title = result.get("title", "")
article.description = result.get("description", "")
return article
class NewsAPI:
def __init__(self):
api_key = os.getenv("NEWS_API_KEY")
assert api_key is not None, "NEWS_API_KEY environment variable not set"
self.client = newsapi.NewsApiClient(api_key=api_key)
self.category = "business"
self.language = "en"
self.page_size = 100
def get_top_headlines(self, query:str, total:int=100) -> list[Article]:
page_size = min(self.page_size, total)
pages = (total // page_size) + (1 if total % page_size > 0 else 0)
articles = []
for page in range(1, pages + 1):
headlines = self.client.get_top_headlines(category=self.category, language=self.language, page_size=page_size, page=page)
results = [result_to_article(article) for article in headlines.get("articles", [])]
articles.extend(results)
return articles

View File

@@ -0,0 +1,19 @@
from app.news import NewsAPI
class TestNewsAPI:
def test_news_api_initialization(self):
news_api = NewsAPI()
assert news_api.client is not None
def test_news_api_get_top_headlines(self):
news_api = NewsAPI()
articles = news_api.get_top_headlines(query="crypto", total=2)
assert isinstance(articles, list)
assert len(articles) == 2
for article in articles:
assert hasattr(article, 'source')
assert hasattr(article, 'time')
assert hasattr(article, 'title')
assert hasattr(article, 'description')

View File

@@ -20,6 +20,7 @@ def pytest_configure(config:pytest.Config):
("gemini", "marks tests that use Gemini model"), ("gemini", "marks tests that use Gemini model"),
("ollama_gpt", "marks tests that use Ollama GPT model"), ("ollama_gpt", "marks tests that use Ollama GPT model"),
("ollama_qwen", "marks tests that use Ollama Qwen model"), ("ollama_qwen", "marks tests that use Ollama Qwen model"),
("news", "marks tests that use news"),
] ]
for marker in markers: for marker in markers:
line = f"{marker[0]}: {marker[1]}" line = f"{marker[0]}: {marker[1]}"
@@ -37,6 +38,7 @@ def pytest_collection_modifyitems(config, items):
"gemini": pytest.mark.gemini, "gemini": pytest.mark.gemini,
"ollama_gpt": pytest.mark.ollama_gpt, "ollama_gpt": pytest.mark.ollama_gpt,
"ollama_qwen": pytest.mark.ollama_qwen, "ollama_qwen": pytest.mark.ollama_qwen,
"news": pytest.mark.news,
} }
for item in items: for item in items:

14
uv.lock generated
View File

@@ -686,6 +686,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fd/69/b547032297c7e63ba2af494edba695d781af8a0c6e89e4d06cf848b21d80/multidict-6.6.4-py3-none-any.whl", hash = "sha256:27d8f8e125c07cb954e54d75d04905a9bba8a439c1d84aca94949d4d03d8601c", size = 12313, upload-time = "2025-08-11T12:08:46.891Z" }, { url = "https://files.pythonhosted.org/packages/fd/69/b547032297c7e63ba2af494edba695d781af8a0c6e89e4d06cf848b21d80/multidict-6.6.4-py3-none-any.whl", hash = "sha256:27d8f8e125c07cb954e54d75d04905a9bba8a439c1d84aca94949d4d03d8601c", size = 12313, upload-time = "2025-08-11T12:08:46.891Z" },
] ]
[[package]]
name = "newsapi-python"
version = "0.2.7"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "requests" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f8/4b/12fb9495211fc5a6d3a96968759c1a48444124a1654aaf65d0de80b46794/newsapi-python-0.2.7.tar.gz", hash = "sha256:a4b66d5dd9892198cdaa476f7542f2625cdd218e5e3121c8f880b2ace717a3c2", size = 7485, upload-time = "2023-03-02T13:15:35.89Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/74/47/e3b099102f0c826d37841d2266e19f1568dcf58ba86e4c6948e2a124f91d/newsapi_python-0.2.7-py2.py3-none-any.whl", hash = "sha256:11d34013a24d92ca7b7cbdac84ed2d504862b1e22467bc2a9a6913a70962318e", size = 7942, upload-time = "2023-03-02T13:15:34.475Z" },
]
[[package]] [[package]]
name = "numpy" name = "numpy"
version = "2.3.3" version = "2.3.3"
@@ -1298,6 +1310,7 @@ dependencies = [
{ name = "dotenv" }, { name = "dotenv" },
{ name = "google-genai" }, { name = "google-genai" },
{ name = "gradio" }, { name = "gradio" },
{ name = "newsapi-python" },
{ name = "ollama" }, { name = "ollama" },
{ name = "pytest" }, { name = "pytest" },
{ name = "python-binance" }, { name = "python-binance" },
@@ -1310,6 +1323,7 @@ requires-dist = [
{ name = "dotenv" }, { name = "dotenv" },
{ name = "google-genai" }, { name = "google-genai" },
{ name = "gradio" }, { name = "gradio" },
{ name = "newsapi-python" },
{ name = "ollama" }, { name = "ollama" },
{ name = "pytest" }, { name = "pytest" },
{ name = "python-binance" }, { name = "python-binance" },