Aller au contenu principal

Votre première application ChatGPT

Mis à jour le 29 juillet 2026

Construire une app météo en 30 minutes

On apprend le Apps SDK en construisant, pas en lisant sa documentation de bout en bout. Vous allez donc créer une application météo complète, assez petite pour tenir en une demi-heure et assez représentative pour contenir tout ce qui compte : une action qui va chercher la donnée, un widget qui l’affiche, et le lien entre les deux.

Étape 1 : définir le manifest

Reprenez le projet initialisé à la leçon précédente et remplacez le contenu de chatgpt-app.json. Notez que l’app ne demande que deux permissions, actions et widgets : elle ne vend rien, elle n’a donc rien à faire du pilier commerce.

{
  "name": "Météo Express",
  "slug": "meteo-express",
  "description": "Consultez la météo en temps réel avec un affichage visuel",
  "version": "1.0.0",
  "runtime": "node",
  "entry": "src/index.ts",
  "permissions": ["actions", "widgets"]
}

Étape 2 : créer l’action météo

L’action est le pont entre ChatGPT et une API externe — ici une API météo publique. Observez la description du paramètre city : en donnant des exemples (Paris, Lyon, Marseille), vous aidez le modèle à extraire correctement le nom de ville d’une phrase comme « il fait quel temps sur Lyon ce matin ». La fonction interpretWeatherCode traduit ensuite le code numérique renvoyé par l’API en libellé lisible, parce que ni le modèle ni l’utilisateur ne savent ce que signifie un code 63.

// src/actions/weather.ts
import { defineAction } from "@openai/apps-sdk";

export const getWeather = defineAction({
  name: "getWeather",
  description: "Récupère les conditions météo actuelles pour une ville",
  parameters: {
    city: {
      type: "string",
      description: "Nom de la ville (ex: Paris, Lyon, Marseille)",
      required: true,
    },
  },
  handler: async ({ city }) => {
    const response = await fetch(
      `https://api.open-meteo.com/v1/forecast?` +
      `latitude=${await getCoords(city)}&current_weather=true`
    );
    const data = await response.json();
    const weather = data.current_weather;

    return {
      city,
      temperature: weather.temperature,
      windSpeed: weather.windspeed,
      condition: interpretWeatherCode(weather.weathercode),
      timestamp: new Date().toISOString(),
    };
  },
});

function interpretWeatherCode(code: number): string {
  const conditions: Record<number, string> = {
    0: "Ciel dégagé",
    1: "Principalement dégagé",
    2: "Partiellement nuageux",
    3: "Couvert",
    45: "Brouillard",
    61: "Pluie légère",
    63: "Pluie modérée",
    65: "Pluie forte",
    71: "Neige légère",
    80: "Averses",
    95: "Orage",
  };
  return conditions[code] ?? "Conditions inconnues";
}

Étape 3 : créer le widget météo

Le widget met en forme ce que l’action a rapporté. Il n’appelle aucune API et ne contient aucune logique métier : il reçoit un objet de données et décrit une carte. Cette séparation vous permettra plus tard de changer de fournisseur météo sans toucher une ligne d’affichage.

// src/widgets/weather-card.ts
import { defineWidget } from "@openai/apps-sdk";

export const weatherCard = defineWidget({
  name: "weatherCard",
  description: "Affiche les conditions météo d'une ville",
  render: (data) => ({
    type: "card",
    title: `Météo à ${data.city}`,
    content: [
      {
        type: "grid",
        columns: 2,
        items: [
          {
            type: "metric",
            label: "Température",
            value: `${data.temperature}°C`,
            icon: "thermometer",
          },
          {
            type: "metric",
            label: "Vent",
            value: `${data.windSpeed} km/h`,
            icon: "wind",
          },
        ],
      },
      {
        type: "text",
        value: data.condition,
        style: "subtitle",
      },
      {
        type: "text",
        value: `Mis à jour : ${new Date(data.timestamp).toLocaleTimeString("fr-FR")}`,
        style: "caption",
      },
    ],
  }),
});

Étape 4 : assembler l’application

Le fichier d’entrée enregistre l’action, enregistre le widget, puis les relie par un flow. C’est ce app.flow qui fait la différence entre deux briques isolées et une application : dès que getWeather renvoie des données, elles partent automatiquement vers weatherCard, sans que vous ayez à orchestrer quoi que ce soit.

// src/index.ts
import { ChatGPTApp } from "@openai/apps-sdk";
import { getWeather } from "./actions/weather";
import { weatherCard } from "./widgets/weather-card";

const app = new ChatGPTApp({
  slug: "meteo-express",
});

// Enregistrer l'action
app.action("getWeather", getWeather);

// Enregistrer le widget
app.widget("weatherCard", weatherCard);

// Lier l'action au widget : quand getWeather retourne des données,
// elles sont automatiquement affichées via weatherCard
app.flow("showWeather", {
  trigger: "getWeather",
  display: "weatherCard",
});

app.start();

Étape 5 : tester en local

Le SDK inclut un serveur de développement qui simule l’environnement ChatGPT. Vous testez donc votre app entière sans rien publier ni soumettre à revue.

# Lancer le serveur de développement
npx chatgpt-app dev

# Vous verrez :
# ✓ App "Météo Express" démarrée sur http://localhost:3100
# ✓ 1 action enregistrée : getWeather
# ✓ 1 widget enregistré : weatherCard
# ✓ Playground disponible sur http://localhost:3100/playground

Ouvrez le playground dans votre navigateur : vous y retrouvez une interface qui imite ChatGPT. Tapez « Quelle est la météo à Lyon ? » et suivez la chaîne complète. Le modèle détecte l’intention et appelle l’action getWeather ; votre handler contacte l’API météo ; les données récupérées sont passées au widget weatherCard ; celui-ci s’affiche enfin dans la conversation avec les informations formatées. Le playground trace chacun de ces passages, ce qui vous indique immédiatement où la chaîne se rompt quand le résultat n’arrive pas.

Essayez ensuite une formulation détournée, du type « j’hésite à sortir courir à Marseille » : si le modèle n’appelle pas l’action, ce n’est pas votre code qui est en cause mais sa description, trop étroite. Vous tenez là le réflexe de débogage le plus utile du SDK.

Structure finale du projet

meteo-express/
├── src/
│   ├── index.ts              # Point d'entrée, assemblage
│   ├── actions/
│   │   └── weather.ts        # Action : récupérer la météo
│   └── widgets/
│       └── weather-card.ts   # Widget : afficher la météo
├── chatgpt-app.json
├── tsconfig.json
├── package.json
└── .env

Ce que vous avez appris

En une seule application, vous avez défini une action avec ses paramètres et son handler, créé un widget qui met en forme des données structurées, relié les deux par un flow, et testé l’ensemble dans le playground intégré. Toutes les apps du Store, y compris les plus élaborées, reposent sur cette même colonne vertébrale — elles se contentent d’en multiplier les éléments.

Points clés à retenir

  • Une app ChatGPT minimale nécessite au moins une action ou un widget
  • Le pattern action → widget est le flux de base : récupérer puis afficher
  • Le playground local simule l’environnement ChatGPT pour tester sans publier
  • Les actions reçoivent des paramètres typés et retournent des données structurées
  • Les widgets transforment ces données en composants visuels interactifs