161 lines
4.7 KiB
Python
161 lines
4.7 KiB
Python
"""Main entry point for rss2newsletter."""
|
|
|
|
import sys
|
|
import argparse
|
|
import logging
|
|
from typing import List, Dict
|
|
|
|
from .config import get_config_from_env, setup_logging
|
|
from .rss_fetcher import get_todays_articles
|
|
from .ollama_client import create_ollama_client, summarize_articles
|
|
from .html_generator import generate_newsletter_html, save_newsletter_html
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def create_argument_parser() -> argparse.ArgumentParser:
|
|
"""Create command line argument parser."""
|
|
parser = argparse.ArgumentParser(
|
|
description="Generate HTML newsletter from RSS feed using Ollama AI summaries",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog="""
|
|
Examples:
|
|
python -m rss2newsletter https://feeds.example.com/rss
|
|
python -m rss2newsletter https://blog.example.com/feed.xml --output my_newsletter.html
|
|
python -m rss2newsletter https://news.example.com/rss --model llama3.1
|
|
""",
|
|
)
|
|
|
|
parser.add_argument("rss_url", help="RSS feed URL to process")
|
|
|
|
parser.add_argument(
|
|
"--output",
|
|
"-o",
|
|
default=None,
|
|
help="Output HTML filename (default: newsletter.html)",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--model",
|
|
"-m",
|
|
default=None,
|
|
help="Ollama model to use for summaries (default: llama3.2)",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--ollama-url",
|
|
default=None,
|
|
help="Ollama server URL (default: http://localhost:11434)",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--title", "-t", default=None, help="Newsletter title (default: RSS Newsletter)"
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--verbose", "-v", action="store_true", help="Enable verbose logging"
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--dry-run",
|
|
action="store_true",
|
|
help="Fetch articles but don't generate summaries or save HTML",
|
|
)
|
|
|
|
return parser
|
|
|
|
|
|
def merge_config_with_args(config: Dict, args: argparse.Namespace) -> Dict:
|
|
"""Merge configuration with command line arguments."""
|
|
if args.output:
|
|
config["output"]["filename"] = args.output
|
|
|
|
if args.model:
|
|
config["ollama"]["model"] = args.model
|
|
|
|
if args.ollama_url:
|
|
config["ollama"]["base_url"] = args.ollama_url
|
|
|
|
if args.title:
|
|
config["output"]["feed_title"] = args.title
|
|
|
|
if args.verbose:
|
|
config["logging"]["level"] = "DEBUG"
|
|
|
|
return config
|
|
|
|
|
|
def process_rss_to_newsletter(rss_url: str, config: Dict, dry_run: bool = False) -> str:
|
|
"""Main processing pipeline for RSS to newsletter conversion."""
|
|
logger.info(f"Starting RSS newsletter generation for: {rss_url}")
|
|
|
|
# Step 1: Fetch today's articles
|
|
logger.info("Fetching articles from RSS feed...")
|
|
articles = get_todays_articles(rss_url)
|
|
|
|
if not articles:
|
|
logger.warning("No articles found for today")
|
|
return generate_newsletter_html([], config["output"]["feed_title"])
|
|
|
|
logger.info(f"Found {len(articles)} articles from today")
|
|
|
|
if dry_run:
|
|
logger.info("Dry run mode - stopping before summarization")
|
|
for i, article in enumerate(articles, 1):
|
|
logger.info(f"Article {i}: {article['title']}")
|
|
return ""
|
|
|
|
# Step 2: Create Ollama client and summarize articles
|
|
logger.info("Generating AI summaries...")
|
|
ollama_client = create_ollama_client(config["ollama"]["base_url"])
|
|
|
|
summarized_articles = summarize_articles(
|
|
ollama_client, articles, config["ollama"]["model"]
|
|
)
|
|
|
|
# Step 3: Generate HTML newsletter
|
|
logger.info("Generating HTML newsletter...")
|
|
html_content = generate_newsletter_html(
|
|
summarized_articles, config["output"]["feed_title"]
|
|
)
|
|
|
|
return html_content
|
|
|
|
|
|
def main() -> int:
|
|
"""Main entry point."""
|
|
parser = create_argument_parser()
|
|
args = parser.parse_args()
|
|
|
|
# Load and merge configuration
|
|
config = get_config_from_env()
|
|
config = merge_config_with_args(config, args)
|
|
|
|
# Setup logging
|
|
setup_logging(config)
|
|
|
|
try:
|
|
# Process RSS feed to newsletter
|
|
html_content = process_rss_to_newsletter(args.rss_url, config, args.dry_run)
|
|
|
|
if not args.dry_run and html_content:
|
|
# Save HTML file
|
|
output_filename = save_newsletter_html(
|
|
html_content, config["output"]["filename"]
|
|
)
|
|
print(f"Newsletter saved to: {output_filename}")
|
|
|
|
return 0
|
|
|
|
except KeyboardInterrupt:
|
|
logger.info("Process interrupted by user")
|
|
return 1
|
|
except Exception as e:
|
|
logger.error(f"Error generating newsletter: {e}")
|
|
if config["logging"]["level"] == "DEBUG":
|
|
logger.exception("Full error details:")
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|