Construire un agent de briefing quotidien
Synthèse matinale : actualités + calendrier + résumé des e-mails transmis automatiquement.
Construire un agent de briefing quotidien est une leçon AI Agents gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Agents, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Agents comprend 4 leçons au total.
Qu’est-ce qu’un agent de briefing quotidien ?
Un agent de briefing quotidien s’exécute chaque matin à une heure programmée, recueille des informations provenant de plusieurs sources (calendrier, e-mails, actualités), les synthétise avec un LLM et fournit une synthèse personnalisée. C’est l’exemple classique d’un agent personnel programmé.
Architecture du briefing
La chaîne de traitement du briefing comporte cinq étapes :
- Déclenchement : une tâche cron de 8 h lance l’agent
- Récupération : récupérer en parallèle les événements du calendrier, les e-mails non lus et les titres de l’actualité
- Synthèse : le LLM crée un briefing cohérent à partir de toutes les données
- Personnalisation : adapter le ton et le contenu aux préférences de l’utilisateur
- Livraison : envoyer le briefing par e-mail ou par DM Slack
from dataclasses import dataclass, field
from typing import List, Dict, Any
@dataclass
class DailyBriefingData:
date: str
calendar_events: List[Dict] = field(default_factory=list)
unread_emails: List[Dict] = field(default_factory=list)
news_headlines: List[Dict] = field(default_factory=list)
weather: Dict = field(default_factory=dict)
briefing_text: str = ''
delivery_status: str = 'pending'
print('Daily briefing data structure defined')Planification avec APScheduler
Programmez l’exécution du briefing à 8 h chaque jour ouvré. Utilisez APScheduler avec une persistance SQLite afin que la tâche survive aux redémarrages du serveur.
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.triggers.cron import CronTrigger
import asyncio
scheduler = BackgroundScheduler(
jobstores={'default': SQLAlchemyJobStore(url='sqlite:///jobs.db')},
timezone='America/New_York'
)
def run_briefing_job():
print('Daily briefing job triggered')
asyncio.run(generate_and_deliver_briefing('user-42'))
# 8am Monday-Friday
scheduler.add_job(
run_briefing_job,
CronTrigger(day_of_week='mon-fri', hour=8, minute=0),
id='daily_briefing_user_42',
replace_existing=True
)
scheduler.start()
print('Briefing scheduler started: runs Mon-Fri at 8am ET')Récupération des événements du calendrier
Récupérez les événements du calendrier du jour à l’aide de l’API Google Calendar. L’agent doit connaître les réunions prévues afin de pouvoir les inclure dans le briefing.
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
from datetime import datetime, timedelta
import pytz
def get_todays_calendar_events(token_path: str = 'token.json', timezone: str = 'America/New_York') -> list:
creds = Credentials.from_authorized_user_file(token_path)
service = build('calendar', 'v3', credentials=creds)
tz = pytz.timezone(timezone)
now = datetime.now(tz)
start_of_day = now.replace(hour=0, minute=0, second=0, microsecond=0)
end_of_day = now.replace(hour=23, minute=59, second=59)
result = service.events().list(
calendarId='primary',
timeMin=start_of_day.isoformat(),
timeMax=end_of_day.isoformat(),
singleEvents=True,
orderBy='startTime'
).execute()
events = []
for item in result.get('items', []):
start = item.get('start', {}).get('dateTime', item.get('start', {}).get('date'))
events.append({
'title': item.get('summary', 'Untitled'),
'start': start,
'attendees': len(item.get('attendees', [])),
'location': item.get('location', '')
})
return eventsRécupération des e-mails non lus
Récupérez les e-mails non lus les plus récents. L’agent de briefing n’a besoin que de leurs résumés — titres et expéditeurs — et non de leur contenu complet, afin de conserver un contexte gérable pour le LLM.
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
import base64
def get_email_summaries(token_path: str = 'token.json', max_results: int = 10) -> list:
creds = Credentials.from_authorized_user_file(token_path)
service = build('gmail', 'v1', credentials=creds)
results = service.users().messages().list(
userId='me',
q='is:unread newer_than:1d',
maxResults=max_results
).execute()
summaries = []
for msg in results.get('messages', []):
detail = service.users().messages().get(
userId='me',
id=msg['id'],
format='metadata',
metadataHeaders=['From', 'Subject', 'Date']
).execute()
headers = {h['name']: h['value'] for h in detail['payload']['headers']}
summaries.append({
'from': headers.get('From', ''),
'subject': headers.get('Subject', 'No Subject'),
'date': headers.get('Date', '')
})
return summariesRécupération des titres de l’actualité
Récupérez les titres d’actualité pertinents à l’aide d’une API d’actualités. Filtrez-les selon les sujets d’intérêt configurés par l’utilisateur pour personnaliser la section consacrée à l’actualité.
import httpx
import os
NEWS_API_KEY = os.environ.get('NEWS_API_KEY', 'your-key')
async def get_news_headlines(topics: list, max_per_topic: int = 3) -> list:
headlines = []
async with httpx.AsyncClient() as client:
for topic in topics:
try:
response = await client.get(
'https://newsapi.org/v2/top-headlines',
params={
'q': topic,
'language': 'en',
'pageSize': max_per_topic,
'apiKey': NEWS_API_KEY
},
timeout=10.0
)
data = response.json()
for article in data.get('articles', []):
headlines.append({
'topic': topic,
'title': article.get('title', ''),
'source': article.get('source', {}).get('name', ''),
'url': article.get('url', '')
})
except Exception as e:
print(f'News fetch failed for {topic}: {e}')
return headlines[:10] # Cap totalRécupération parallèle des données
Récupérez en même temps les événements du calendrier, les e-mails, les actualités et la météo. Comme ces opérations sont indépendantes, la récupération parallèle réduit la durée totale d’environ 4 secondes à environ 1 seconde.
import asyncio
from datetime import datetime
async def fetch_all_briefing_data(user_prefs: dict) -> 'DailyBriefingData':
data = DailyBriefingData(date=datetime.now().strftime('%A, %B %d, %Y'))
async def safe_get_calendar():
try:
return get_todays_calendar_events()
except Exception as e:
print(f'Calendar fetch failed: {e}')
return []
async def safe_get_emails():
try:
return get_email_summaries()
except Exception as e:
print(f'Email fetch failed: {e}')
return []
async def safe_get_news():
topics = user_prefs.get('news_topics', ['technology', 'business'])
return await get_news_headlines(topics)
# Run all fetches in parallel
calendar_events, emails, news = await asyncio.gather(
safe_get_calendar(),
safe_get_emails(),
safe_get_news(),
return_exceptions=False
)
data.calendar_events = calendar_events
data.unread_emails = emails
data.news_headlines = news
return dataSynthèse par le LLM
Transmettez toutes les données récupérées au LLM et demandez-lui de rédiger un briefing naturel et personnalisé. La structure de l’invite est importante : organisez clairement les données afin que le LLM puisse produire une synthèse bien structurée.
import openai
import json
client = openai.OpenAI(api_key='sk-...')
def synthesize_briefing(data: 'DailyBriefingData', user_prefs: dict) -> str:
user_name = user_prefs.get('name', 'there')
tone = user_prefs.get('briefing_tone', 'professional') # 'casual', 'professional', 'concise'
calendar_text = json.dumps(data.calendar_events[:5], indent=2) if data.calendar_events else 'No meetings today.'
email_text = json.dumps(data.unread_emails[:5], indent=2) if data.unread_emails else 'No unread emails.'
news_text = '\n'.join([f'- [{h["topic"]}] {h["title"]} ({h["source"]})' for h in data.news_headlines[:6]])
prompt = (
f'Create a {tone} morning briefing for {user_name} for {data.date}.\n\n'
f'Today\'s calendar:\n{calendar_text}\n\n'
f'Unread emails:\n{email_text}\n\n'
f'News headlines:\n{news_text}\n\n'
'Write a concise, actionable briefing in 3-4 paragraphs. '
'Start with today\'s schedule, then email highlights, then relevant news. '
'End with one suggested priority for the day.'
)
response = client.chat.completions.create(
model='gpt-4o-mini',
messages=[{'role': 'user', 'content': prompt}],
temperature=0.3
)
return response.choices[0].message.contentLivraison par e-mail
Formatez le briefing sous forme d’e-mail HTML et envoyez-le. Un bon formatage des e-mails HTML facilite la lecture sur mobile, où la plupart des utilisateurs consultent leur synthèse matinale.
def format_briefing_email(briefing_text: str, data: 'DailyBriefingData') -> str:
paragraphs = briefing_text.split('\n\n')
html_paragraphs = ''.join([f'<p>{p}</p>' for p in paragraphs if p.strip()])
calendar_items = ''.join([
f'<li><strong>{e["start"][:16]}</strong> - {e["title"]}</li>'
for e in data.calendar_events[:5]
])
return f'''
<html><body style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
<h2 style="color: #333;">Morning Briefing — {data.date}</h2>
{html_paragraphs}
{'<h3>Today\'s Calendar</h3><ul>' + calendar_items + '</ul>' if calendar_items else ''}
<hr>
<p style="color: #666; font-size: 12px;">Generated by your Personal AI Assistant</p>
</body></html>
'''
def deliver_briefing_email(data: 'DailyBriefingData', user_prefs: dict):
html = format_briefing_email(data.briefing_text, data)
to_email = user_prefs.get('email', '')
send_email_alert(
to_email=to_email,
subject=f'Morning Briefing - {data.date}',
html_body=html
)
print('Email delivery function defined')Livraison par DM Slack
Pour les utilisateurs qui travaillent principalement dans Slack, il est souvent préférable de livrer le briefing sous forme de DM Slack mis en forme plutôt que par e-mail. Utilisez Block Kit pour obtenir une mise en forme riche.
from slack_sdk import WebClient
import os
slack_client = WebClient(token=os.environ.get('SLACK_BOT_TOKEN', 'xoxb-...'))
def deliver_briefing_slack(data: 'DailyBriefingData', user_prefs: dict):
slack_user_id = user_prefs.get('slack_user_id')
if not slack_user_id:
print('No Slack user ID configured')
return
# Split briefing into sections for blocks
paragraphs = [p for p in data.briefing_text.split('\n\n') if p.strip()]
blocks = [
{'type': 'header', 'text': {'type': 'plain_text', 'text': f'Morning Briefing - {data.date}'}},
{'type': 'divider'}
]
for para in paragraphs[:4]: # Max 4 paragraphs
blocks.append({
'type': 'section',
'text': {'type': 'mrkdwn', 'text': para}
})
if data.calendar_events:
event_list = '\n'.join([f'• {e["start"][:16]} - {e["title"]}' for e in data.calendar_events[:3]])
blocks.append({'type': 'section', 'text': {'type': 'mrkdwn', 'text': f'*Meetings*\n{event_list}'}})
slack_client.chat_postMessage(
channel=slack_user_id,
text=f'Morning Briefing - {data.date}',
blocks=blocks
)
print(f'Briefing delivered to Slack user {slack_user_id}')Orchestrateur principal du briefing
L’orchestrateur relie toutes les étapes : récupérer les données en parallèle, les synthétiser avec un LLM, les livrer via le canal préféré et enregistrer le résultat pour assurer la surveillance.
import asyncio
from datetime import datetime
async def generate_and_deliver_briefing(user_id: str):
print(f'Generating briefing for {user_id} at {datetime.now()}')
# Load user preferences
conn = init_db()
user_prefs = load_user_preferences(conn, user_id)
# Step 1: Fetch all data in parallel
data = await fetch_all_briefing_data(user_prefs)
if not data.calendar_events and not data.unread_emails and not data.news_headlines:
print('No data fetched, skipping briefing')
return
# Step 2: Synthesize with LLM
data.briefing_text = synthesize_briefing(data, user_prefs)
# Step 3: Deliver
delivery_channel = user_prefs.get('delivery_channel', 'email')
if delivery_channel == 'slack':
deliver_briefing_slack(data, user_prefs)
else:
deliver_briefing_email(data, user_prefs)
data.delivery_status = 'delivered'
# Step 4: Log
print(f'Briefing delivered via {delivery_channel}')
print(f'Data: {len(data.calendar_events)} events, {len(data.unread_emails)} emails, {len(data.news_headlines)} headlines')
print('Daily briefing orchestrator defined')Vérification des connaissances : agent de briefing quotidien
Vérifiez votre compréhension de la création d’un agent de briefing quotidien.
Résumé de l’agent de briefing quotidien
Un agent de briefing quotidien complet combine APScheduler pour l’exécution d’une tâche cron à 8 h les jours ouvrés, la récupération parallèle de données auprès des API du calendrier, de la messagerie et de l’actualité, la synthèse par un LLM pour créer un briefing cohérent et personnalisé, la personnalisation guidée par les préférences de l’utilisateur et la livraison multicanal par e-mail ou par DM Slack. Il s’agit du modèle classique d’agent personnel toujours actif, qui illustre tous les concepts de ce cours.
Questions Fréquemment Posées
La leçon « Construire un agent de briefing quotidien » est-elle gratuite ?
Oui — le texte complet de « Construire un agent de briefing quotidien » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Agents, passe à CoddyKit PRO. Le cours AI Agents comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Construire un agent de briefing quotidien » ?
Synthèse matinale : actualités + calendrier + résumé des e-mails transmis automatiquement. Tu pratiques AI Agents avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer AI Agents ?
Aucune expérience préalable n'est requise. AI Agents sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Construire un agent de briefing quotidien » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon AI Agents ?
Oui. Chaque leçon AI Agents inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Schémas de conception pour des agents toujours actifs
- Systèmes proactifs de notification et d’alerte
- Persistance du contexte entre les sessions
- Construire un agent de briefing quotidien