import json, textwrap, time
from datetime import datetime
import gradio as gr
# ----------------- SAMPLE WEEK (edit live on-air) -----------------
STORIES = [
{
"title": "Microsoft 365 Premium launches ($19.99/mo) with integrated Copilot",
"date": "2025-10-01",
"category": "Agents & Productivity",
"summary": "Microsoft bundles Office + Copilot Pro into a single individual plan with higher usage limits and advanced features (Researcher, Analyst, Actions). Copilot Pro sunsets. Agents require Azure + metered credits.",
"talk_track": [
"Copilot becomes the personal default.",
"Premium unlocks higher usage ceilings.",
"Agents: mind the Azure/Copilot credit metering."
],
"why_it_matters": "Mainstreaming AI assistants with clear pricing signals; agent workflows move into production norms.",
"sources": [
["Reuters", "https://www.reuters.com/technology/microsoft-launches-ai-powered-365-premium-bundle-1999-per-month-2025-10-01/"],
["Microsoft pricing", "https://www.microsoft.com/en-us/microsoft-365-copilot/pricing"]
]
},
{
"title": "Google 2K Nest cams for Gemini for Home + Home Premium subscription",
"date": "2025-10-01",
"category": "Edge & Devices",
"summary": "New Nest cams (wider FOV, better low light) and descriptive AI alerts + daily Home Brief. Google Home Premium replaces Nest Aware tiers.",
"talk_track": [
"First hardware built for Gemini for Home.",
"Events → summaries → routines.",
"Sub changes: Home Premium instead of Nest Aware."
],
"why_it_matters": "House-scale agents: sensor streams become structured inputs for daily briefings and automation.",
"sources": [
["The Verge", "https://www.theverge.com/"]
]
},
{
"title": "OpenAI updates GPT-5 Instant behavior for crisis-support signals",
"date": "2025-10-03",
"category": "Models & Alignment",
"summary": "Behavioral tuning for GPT-5 Instant improves distress detection and de-escalation, guided by experts.",
"talk_track": [
"Alignment over raw capability.",
"Important for support, education, first-touch contexts."
],
"why_it_matters": "Stability + safety polish for high-throughput deployments.",
"sources": [
["OpenAI release notes", "https://help.openai.com/en/articles/9624314-model-release-notes"]
]
},
{
"title": "Anthropic policy: personal Claude chats used for training (opt-out)",
"date": "2025-10-01",
"category": "Policy & Privacy",
"summary": "Non-enterprise Claude users are opted-in for training; opt-out available in settings. Enterprise/edu/gov excluded.",
"talk_track": [
"Flip the privacy toggle before sensitive work.",
"Audit retention + compliance posture."
],
"why_it_matters": "Data governance becomes a weekly habit, not a yearly policy read.",
"sources": [
["Tom’s Guide explainer", "https://www.tomsguide.com/"]
]
},
{
"title": "NVIDIA: Cosmos world models + Newton physics + Isaac GR00T updates",
"date": "2025-10-02",
"category": "Robotics & Physical AI",
"summary": "Open world-model family, open Newton physics in Isaac Lab, updated GR00T reasoning to accelerate robotics R&D.",
"talk_track": [
"Synthetic data + open physics to speed loops.",
"Bridging sim-to-real for smaller labs."
],
"why_it_matters": "Lower barrier to realistic robot learning → more pilots in 2026.",
"sources": [
["NVIDIA Newsroom", "https://nvidianews.nvidia.com/"]
]
}
]
# ----------------- Helpers -----------------
def all_categories():
return sorted(list({s["category"] for s in STORIES}))
def fmt_story(story: dict) -> str:
if not story:
return "No story selected."
date = datetime.fromisoformat(story["date"]).strftime("%b %d, %Y")
bullets = "\n".join([f"- {b}" for b in story.get("talk_track", [])])
srcs = "\n".join([f"- [{t}]({u})" for t, u in story.get("sources", [])])
return (
f"### {story['title']}\n"
f"**Date:** {date} **Category:** {story['category']}\n\n"
f"**Summary:** {story['summary']}\n\n"
f"**On-air notes:**\n{bullets}\n\n"
f"**Why it matters:** {story['why_it_matters']}\n\n"
f"**Sources:**\n{srcs}\n"
)
def teleprompter_text(story: dict) -> str:
text = f"{story['title']}\n\n{story['summary']}\n\nWhy it matters: {story['why_it_matters']}"
return textwrap.fill(text, width=90)
def list_rows(items):
return [[s["date"], s["category"], s["title"]] for s in items]
def filter_and_search(category, query):
items = STORIES
if category and category != "All":
items = [s for s in items if s["category"] == category]
if query:
q = query.lower().strip()
items = [s for s in items if q in s["title"].lower() or q in s["summary"].lower()]
return items
def build_ticker_html(text):
return (
''
'