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:
@@ -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=
|
||||||
|
|
||||||
|
|||||||
@@ -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
3
src/app/news/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from .news_api import NewsAPI
|
||||||
|
|
||||||
|
__all__ = ["NewsAPI"]
|
||||||
8
src/app/news/base.py
Normal file
8
src/app/news/base.py
Normal 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
34
src/app/news/news_api.py
Normal 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
|
||||||
|
|
||||||
|
|
||||||
19
tests/api/test_news_api.py
Normal file
19
tests/api/test_news_api.py
Normal 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')
|
||||||
|
|
||||||
@@ -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
14
uv.lock
generated
@@ -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" },
|
||||||
|
|||||||
Reference in New Issue
Block a user