USA Trending News
"""
USA Trending News Script Generator
Generates Google Veo2-friendly video scripts from US trending news.
Features:
- Fetches top headlines (NewsAPI.org) by country=us
- Generates a short, punchy news script in a modern anchor tone
- Outputs: plain .txt script, JSON with segments and timings, and optional SSML for TTS
- Configurable: number of headlines, categories, verbosity
Usage:
1) Install dependencies: pip install requests python-dotenv
2) Create a .env file with: NEWSAPI_KEY=your_api_key
(You can use NewsAPI (https://newsapi.org/) or swap the fetch function to another provider)
3) Run: python usa_trending_script_generator.py --count 5 --length short
Note: This script only *generates* text/scripts. It does not create videos. Use your Google Veo2 workflow to convert scripts to video.
"""
import os
import requests
import argparse
import json
from datetime import datetime
from textwrap import dedent
from dotenv import load_dotenv
load_dotenv()
NEWSAPI_KEY = os.getenv("NEWSAPI_KEY")
# Constants / Templates
ANCHOR_OPEN = "Breaking News from the United States — Here’s what’s making headlines today!"
ANCHOR_CLOSE = "That’s your quick U.S. update for today. Stay tuned for more — this is {channel}, bringing you the news that matters!"
# Template for a single headline segment (Veo2-friendly: short, visual cues)
SEGMENT_TEMPLATE = """{emoji} {title}
"""{spoken}"
Visual: {visual}
Duration: {duration}s
"""
# Helper: fetch top headlines from NewsAPI
def fetch_top_headlines(api_key, country='us', page_size=10):
if not api_key:
raise ValueError("NEWSAPI_KEY is not set. Create an account at https://newsapi.org/ and set NEWSAPI_KEY in your environment.")
url = 'https://newsapi.org/v2/top-headlines'
params = {
'apiKey': api_key,
'country': country,
'pageSize': page_size,
}
resp = requests.get(url, params=params, timeout=10)
resp.raise_for_status()
data = resp.json()
articles = data.get('articles', [])
return articles
# Helper: pick emoji per category or source keyword
def choose_emoji(article):
title = (article.get('title') or '').lower()
if any(k in title for k in ['apple', 'intel', 'microsoft', 'google', 'ai']):
return '📱'
if any(k in title for k in ['stock', 'sp500', 'dow', 'market', 'economy', 'inflation']):
return '💵'
if any(k in title for k in ['nasa', 'space', 'rocket', 'moon']):
return '🚀'
if any(k in title for k in ['sheriff', 'police', 'court', 'law', 'senate', 'congress', 'president']):
return '🏛️'
if any(k in title for k in ['game', 'super bowl', 'nba', 'mlb', 'football', 'soccer']):
return '🏈'
return '📰'
# Helper: craft spoken sentence (short summary) from article
# We'll use the description if available, otherwise trim the title.
def craft_spoken(article, length='short'):
title = article.get('title') or ''
desc = article.get('description') or ''
if desc and len(desc) > 30:
base = desc
else:
base = title
# shorten for 'short' length
if length == 'short':
# keep to ~18 words
words = base.split()
return ' '.join(words[:18]).rstrip('.') + ('' if len(words) <= 18 else '...')
elif length == 'medium':
words = base.split()
return ' '.join(words[:35]).rstrip('.') + ('' if len(words) <= 35 else '...')
else:
return base
# Estimate duration (seconds) based on length
def estimate_duration(text, words_per_min=150):
words = len(text.split())
minutes = words / words_per_min
seconds = max(3, int(minutes * 60))
return seconds
# Build script
def build_script(articles, count=5, voice_length='short', channel_name='Your Channel'):
selected = articles[:count]
segments = []
for art in selected:
emoji = choose_emoji(art)
title = art.get('title') or 'Untitled'
spoken = craft_spoken(art, length=voice_length)
visual = art.get('urlToImage') or art.get('source', {}).get('name') or 'Stock footage + b-roll'
duration = estimate_duration(spoken)
seg = {
'emoji': emoji,
'title': title,
'spoken': spoken,
'visual': visual,
'duration': duration,
'source_url': art.get('url')
}
segments.append(seg)
# Compose final script text in Veo-friendly style
lines = []
lines.append(f"[Opening] {ANCHOR_OPEN}")
lines.append("")
for s in segments:
lines.append(SEGMENT_TEMPLATE.format(emoji=s['emoji'], title=s['title'], spoken=s['spoken'], visual=s['visual'], duration=s['duration']))
lines.append("")
lines.append(ANCHOR_CLOSE.format(channel=channel_name))
script_text = '\n'.join(lines)
output = {
'generated_at': datetime.utcnow().isoformat() + 'Z',
'channel': channel_name,
'segments': segments,
'script_text': script_text
}
return output
# CLI
def main():
parser = argparse.ArgumentParser(description='Generate a short USA trending news script for Google Veo2.')
parser.add_argument('--count', type=int, default=5, help='Number of headlines to include')
parser.add_argument('--length', choices=['short','medium','long'], default='short', help='Verbosity of each spoken segment')
parser.add_argument('--channel', type=str, default='Your Channel', help='Channel name to use in closing line')
parser.add_argument('--out', type=str, default='usa_script.json', help='Output JSON filename')
args = parser.parse_args()
try:
articles = fetch_top_headlines(NEWSAPI_KEY, page_size=max(args.count, 10))
except Exception as e:
print('Error fetching headlines:', e)
return
result = build_script(articles, count=args.count, voice_length=args.length, channel_name=args.channel)
# save outputs
with open(args.out, 'w', encoding='utf-8') as f:
json.dump(result, f, indent=2, ensure_ascii=False)
# also save a plain text script for quick copy-paste
txt_name = args.out.replace('.json', '.txt')
with open(txt_name, 'w', encoding='utf-8') as f:
f.write(result['script_text'])
print('Generated script saved to', args.out, 'and', txt_name)
if __name__ == '__main__':
main()
Comments
Post a Comment