Last active
March 28, 2025 16:19
-
-
Save rdancer/a53e446c4c313fbf248cbe309b7894e8 to your computer and use it in GitHub Desktop.
Daily Language News Generator & TTS using OpenAI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
this file only serves for to the gist having a sensible name which isn't `env.` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
OPENAI_API_KEY=sk-Your_OpenAI_Api_Key_Here | |
NEWS_API_KEY=your_NewsApiDotOrg_Key_Here | |
NEWS_COUNTRY=us | |
TARGET_LANG=cs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Daily Language News Generator & TTS using OpenAI | |
This script: | |
1. Loads configuration from a .env file. | |
2. Accepts command-line parameters for the news country and target language. | |
3. Fetches top headlines and article details from NewsAPI. | |
4. Combines each article's title, description, and content (if available) into a raw news text. | |
5. Uses the OpenAI Chat API (gpt-4o-mini) to produce a concise daily update that explains what happened. | |
When a target language is provided, the entire output (including greeting and date) is produced exclusively in that language. | |
6. Uses OpenAI’s synchronous streaming TTS endpoint (model "gpt-4o-mini-tts") with enhanced newscaster instructions to generate audio. | |
7. Saves the generated MP3 with a filename based on the current date, country, and target language, then prints the filename. | |
Dependencies: | |
- Python 3.x | |
- Install required packages via pip: | |
pip install requests openai python-dotenv | |
Setup: | |
- Create a .env file with your API keys and default settings. | |
- Command-line parameters --country and --target_lang can override the defaults from the .env file. | |
Usage: | |
Run the script (e.g., via cron for daily execution): | |
python daily_language_news.py --country us --target_lang cs | |
The script prints the raw news text, the final daily text, and finally the saved audio filename. | |
""" | |
import os | |
import argparse | |
import requests | |
from datetime import datetime | |
from dotenv import load_dotenv | |
# Load environment variables from .env file | |
load_dotenv() | |
# Import the full OpenAI module and set its API key for TTS streaming usage | |
import openai | |
openai.api_key = os.environ.get("OPENAI_API_KEY") | |
# Also import the OpenAI client for chat completions | |
from openai import OpenAI | |
# Parse command-line arguments for country and target language | |
parser = argparse.ArgumentParser(description="Daily Language News Generator & TTS") | |
parser.add_argument("--country", type=str, help="Country code for local news (e.g., 'us', 'ye')") | |
parser.add_argument("--target_lang", type=str, help="Target language code for translation (e.g., 'es', 'cs')") | |
args = parser.parse_args() | |
# Override environment variables if command-line arguments are provided | |
if args.country: | |
os.environ["NEWS_COUNTRY"] = args.country | |
if args.target_lang: | |
os.environ["TARGET_LANG"] = args.target_lang | |
# Initialize OpenAI client for chat completions | |
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY") | |
if not OPENAI_API_KEY: | |
raise Exception("Please set the OPENAI_API_KEY environment variable.") | |
MODEL = "gpt-4o-mini" | |
openai_client = OpenAI(api_key=OPENAI_API_KEY) | |
def fetch_local_news(): | |
"""Fetch local news articles using NewsAPI.""" | |
news_api_key = os.environ.get("NEWS_API_KEY") | |
if not news_api_key: | |
raise Exception("Please set the NEWS_API_KEY environment variable.") | |
country = os.environ.get("NEWS_COUNTRY", "us") | |
url = f"https://newsapi.org/v2/top-headlines?country={country}&apiKey={news_api_key}" | |
response = requests.get(url) | |
if response.status_code != 200: | |
raise Exception(f"News API error: {response.text}") | |
data = response.json() | |
articles = data.get("articles", []) | |
return articles | |
def generate_raw_news_text(articles, max_articles=5): | |
""" | |
Generate a raw text string from fetched news articles. | |
Each article includes its title, description, and content (if available). | |
""" | |
if not articles: | |
return "No news available today." | |
lines = [] | |
count = 0 | |
for article in articles: | |
if count >= max_articles: | |
break | |
title = article.get("title", "No title") | |
description = article.get("description", "") | |
content = article.get("content", "") | |
line = f"Title: {title}" | |
if description: | |
line += f"\nDescription: {description}" | |
if content: | |
line += f"\nContent: {content}" | |
lines.append(line) | |
count += 1 | |
date_str = datetime.now().strftime("%A, %B %d, %Y") | |
raw_text = f"Date: {date_str}\n\n" + "\n\n".join(lines) | |
return raw_text | |
def openai_summarize_and_translate(raw_text, target_lang=None): | |
""" | |
Use OpenAI's Chat API to generate a clear, concise daily update. | |
The update should get straight to the point and explain what happened in the news. | |
If a target language is provided, produce the entire output exclusively in that language, | |
including the greeting and the date. | |
""" | |
if target_lang: | |
user_message = ( | |
f"Please summarize the following news articles into a concise daily update entirely in {target_lang}. " | |
f"The update should clearly explain what happened in each article, getting straight to the point. " | |
f"Include a greeting and the date (both in {target_lang}) at the beginning. " | |
f"Do not include any parts in any other language; the entire output must be in {target_lang}. " | |
f"News articles:\n\n{raw_text}" | |
) | |
else: | |
user_message = ( | |
"Please summarize the following news articles into a concise daily update that explains what happened, " | |
"getting straight to the point. Include a greeting and the date at the beginning. " | |
f"News articles:\n\n{raw_text}" | |
) | |
messages = [ | |
{"role": "system", "content": "You are a helpful assistant that creates daily news summaries for language learning."}, | |
{"role": "user", "content": user_message} | |
] | |
completion = openai_client.chat.completions.create( | |
model=MODEL, | |
messages=messages | |
) | |
summarized_text = completion.choices[0].message.content.strip() | |
return summarized_text | |
def openai_tts(text: str, output_file_path: str) -> None: | |
""" | |
Generate speech using OpenAI's synchronous streaming TTS API. | |
This function streams the TTS audio using the model "gpt-4o-mini-tts" with enhanced newscaster instructions. | |
The response_format is set to "mp3" so that the final audio is directly saved as an MP3 file. | |
""" | |
instructions = ( | |
"Voice: Newscaster.\n\n" | |
"Tone: Exciting, high-energy, and persuasive, creating urgency and anticipation.\n\n" | |
"Delivery: Rapid-fire yet clear, with dynamic inflections to keep engagement high and momentum strong.\n\n" | |
"Pronunciation: Crisp and precise, with emphasis on key action words like bid, buy, checkout, and sold to drive urgency." | |
) | |
with openai.audio.speech.with_streaming_response.create( | |
model="gpt-4o-mini-tts", | |
voice="sage", | |
input=text, | |
instructions=instructions, | |
response_format="mp3", | |
) as response: | |
response.stream_to_file(output_file_path) | |
def main(): | |
print("Fetching local news...") | |
articles = fetch_local_news() | |
raw_news_text = generate_raw_news_text(articles) | |
print("Raw news text:") | |
print(raw_news_text) | |
target_lang = os.environ.get("TARGET_LANG") | |
print("\nGenerating summarized and translated daily text via OpenAI API...") | |
try: | |
final_text = openai_summarize_and_translate(raw_news_text, target_lang=target_lang) | |
print("Final daily text:") | |
print(final_text) | |
except Exception as e: | |
print("OpenAI API call failed:", e) | |
final_text = raw_news_text # Fallback to raw text if needed | |
# Create a filename with the current date, weekday, country, and target language | |
today = datetime.now() | |
news_country = os.environ.get("NEWS_COUNTRY", "us") | |
target_code = os.environ.get("TARGET_LANG", "en") | |
filename = today.strftime("%Y_%m_%d_%A") + f"_{news_country}_{target_code}.mp3" | |
print("\nGenerating speech with OpenAI TTS...") | |
try: | |
openai_tts(final_text, filename) | |
except Exception as e: | |
print("OpenAI TTS failed:", e) | |
return | |
print("Audio generated and saved as:", filename) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment