I go into a lot of meetings. Client calls, partner intros, job interviews. The prep ritual is always the same: open LinkedIn, Google the person, scan a few headlines, try to remember something useful before they say hello. It's inefficient and often incomplete. Je participe à beaucoup de réunions. Appels clients, présentations de partenaires, entretiens. Le rituel de préparation est toujours le même : ouvrir LinkedIn, chercher la personne, parcourir quelques titres. C'est inefficace et souvent incomplet.

So I automated it. The result is a tool that takes a name and company, searches the web in three directions, and uses an LLM to synthesize a clean briefing. The whole thing runs serverless on AWS and costs less than a cent per use. J'ai donc automatisé ça. Un outil qui prend un nom et une entreprise, effectue trois types de recherches web, et utilise un LLM pour synthétiser une fiche propre. Le tout tourne sans serveur sur AWS pour moins d'un cent par utilisation.

→ Try the tool first, then come back and read how it was built. → Essayez l'outil d'abord, puis revenez lire comment il a été construit.

Architecture overviewVue d'ensemble de l'architecture

BrowserNavigateur
name + companynom + entreprise
API Gateway
HTTP · ca-central-1
Lambda
Container · Python 3.12Conteneur · Python 3.12
SerpAPI
3 searches3 recherches
Bedrock
Haiku 4.5 · us-east-1
BriefFiche
~3s

Why Lambda as a container image?Pourquoi Lambda avec une image conteneur ?

Lambda supports two deployment models: a zip file or a container image stored in ECR. I chose the container path intentionally — you learn Docker, ECR, and Lambda container support in one shot, at near-zero cost. The free tier covers this image (~190MB) and the first 1M Lambda invocations per month. Lambda supporte deux modèles de déploiement : un fichier zip ou une image conteneur stockée dans ECR. J'ai choisi le conteneur intentionnellement — on apprend Docker, ECR et Lambda en une seule fois, à coût quasi nul. Le niveau gratuit couvre cette image (~190 Mo) et le premier million d'invocations Lambda par mois.

What the Lambda actually doesCe que fait réellement le Lambda

1 — Validate input1 — Valider les entrées

Name, company, and context are trimmed and capped at 100/100/300 characters before touching any external API. User input goes into a clearly-labelled data block, never directly into the system prompt — this is the prompt injection guard. Le nom, l'entreprise et le contexte sont nettoyés et limités à 100/100/300 caractères avant de toucher une API externe. Les entrées utilisateur vont dans un bloc de données clairement étiqueté, jamais directement dans le système de prompt — c'est la protection contre l'injection.

2 — Run three SerpAPI searches2 — Effectuer trois recherches SerpAPI

General search, LinkedIn-targeted search, and a news search. All three run sequentially — Lambda's 30s timeout is not a bottleneck. Each failed search is caught and logged. Recherche générale, recherche ciblée LinkedIn, et actualités. Les trois s'exécutent séquentiellement — le délai Lambda de 30s n'est pas un goulot d'étranglement. Chaque recherche échouée est capturée et journalisée.

3 — Deduplicate and pack results3 — Dédupliquer et regrouper les résultats

Results from three searches overlap. A Python set handles O(1) deduplication by title. Up to 15 unique results are packed into a structured research block before being sent to Bedrock. Les résultats des trois recherches se chevauchent. Un set Python gère la déduplication O(1) par titre. Jusqu'à 15 résultats uniques sont regroupés dans un bloc de recherche structuré avant d'être envoyés à Bedrock.

4 — Call Claude Haiku on Bedrock4 — Appeler Claude Haiku sur Bedrock

The research block is sent to us.anthropic.claude-haiku-4-5-20251001-v1:0 — the cross-region inference profile ID. The us. prefix enables routing from ca-central-1 to Bedrock in us-east-1. Without it, you get a ValidationException. Le bloc est envoyé à us.anthropic.claude-haiku-4-5-20251001-v1:0 — l'ID du profil d'inférence inter-région. Le préfixe us. permet le routage depuis ca-central-1 vers Bedrock en us-east-1. Sans lui, Bedrock retourne une ValidationException.

handler.py — Bedrock call
def call_bedrock(system: str, user_message: str) -> str:
    body = json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens":        1500,
        "system":            system,
        "messages": [{"role": "user", "content": user_message}],
    })
    response = bedrock.invoke_model(
        modelId=MODEL_ID,  # us.anthropic.claude-haiku-4-5-20251001-v1:0
        body=body,
        contentType="application/json",
        accept="application/json",
    )
    return json.loads(response["body"].read())["content"][0]["text"]
Why Bedrock and not the Anthropic API?Pourquoi Bedrock et non l'API Anthropic ? Bedrock bills to your AWS account — the same account you're already monitoring. For a tool built to showcase AWS skills, keeping everything in one bill is the right call. At ~$0.004/brief, the cost difference with the Anthropic API is irrelevant; the architectural consistency is not. Bedrock facture sur votre compte AWS — le même que vous surveillez déjà. Pour un outil qui met en valeur les compétences AWS, tout garder dans une seule facture est le bon choix. À ~0,004 $/fiche, la différence de coût avec l'API Anthropic est négligeable ; la cohérence architecturale ne l'est pas.

The Docker build gotcha that will cost you an hourLe piège Docker qui vous coûtera une heure

Building on Windows with Docker Desktop and pushing to Lambda? By default, Docker BuildKit creates an OCI image index (a multi-platform manifest list) even when you target a single platform. Lambda needs a single-platform manifest and rejects the image. The fix: Vous construisez sur Windows avec Docker Desktop et poussez vers Lambda ? Par défaut, Docker BuildKit crée un index d'images OCI même pour une seule plateforme. Lambda a besoin d'un manifeste à plateforme unique et rejette l'image. La solution :

The one flag that fixes itL'option qui règle le problème
docker buildx build \
  --platform linux/amd64 \
  --provenance=false   # ← this is the fix
  --load \
  -t meeting-prep .

CORS: Lambda headers aren't enoughCORS : les en-têtes Lambda ne suffisent pas

When you add an API Gateway trigger to a Lambda, API Gateway gets its own CORS configuration — separate from whatever headers your Lambda returns. Configure CORS in two places: Lambda response headers (for the actual request) and API Gateway CORS settings (for the preflight). Both must allow the same origins. Quand vous ajoutez un déclencheur API Gateway, il obtient sa propre configuration CORS — distincte des en-têtes Lambda. Configurez CORS en deux endroits : les en-têtes Lambda (pour la vraie requête) et les paramètres CORS d'API Gateway (pour le preflight). Les deux doivent autoriser les mêmes origines.

What it costsCe que ça coûte

ServiceService UsageUtilisation Cost / briefCoût / fiche
Lambda~5s · 256MB$0.000021
API Gateway1 request1 requête$0.000001
Bedrock (Haiku 4.5)~3K in · ~1K out$0.0037
SerpAPI3 searches3 recherches$0.003
Total~$0.007

What I'd do differentlyCe que je ferais différemment


→ Try the meeting prep tool → Essayer l'outil de préparation

← Back to articles ← Retour aux articles