# Brouillons de réponse à des messages clients

> Un petit script qui propose une réponse courte, en français, en derja ou en anglais, à des messages clients — toujours relue par un humain avant envoi.

Source : https://developers.tuk-ai.com/cookbook/assistant-messages · Vérifié le 2026-10-04

**Ce que fait la recette** : pour chaque message d'un fichier, elle demande au modèle un brouillon de réponse de trois phrases au plus, dans la langue choisie, et l'imprime. **Rien n'est envoyé à un client** : une personne relit chaque brouillon.

**Ce qu'il vous faut** : Node.js 20 ou plus récent, une clé `tuk_sk_` (voir [Premier appel](https://developers.tuk-ai.com/docs/quickstart)) et un compte avec des crédits.

**Coût** : une génération par message. Le mode à blanc et la vérification sont gratuits.

## Les fichiers

Messages d'exemple, fictifs :

messages.json :

```json
[
  {
    "id": "M1",
    "langue_reponse": "fr",
    "texte": "Bonjour, j'ai commandé une table la semaine dernière et je n'ai pas encore reçu de date de livraison. Pouvez-vous me tenir informé ?"
  },
  {
    "id": "M2",
    "langue_reponse": "ar",
    "texte": "عسلامة، نحب نعرف كان عندكم الكرسي هذا باللون الأخضر؟"
  },
  {
    "id": "M3",
    "langue_reponse": "en",
    "texte": "Hello, can I change the delivery address of my order before it ships?"
  }
]
```

Le script :

repondre.mjs :

```typescript
// Brouillons de réponse à des messages clients, à relire par un humain avant tout envoi.
//
//   node repondre.mjs --a-blanc   affiche les requêtes sans rien envoyer (gratuit)
//   node repondre.mjs             envoie une requête par message (payant)
//
// Aucun message n'est envoyé à un client : le script imprime des brouillons.
import { readFileSync } from "node:fs";
import OpenAI from "openai";

const URL_DE_BASE = process.env.TUKAI_BASE_URL ?? "https://chat.tuk-ai.com/v1";
const MODELE = process.env.TUKAI_MODELE ?? "chat-aion-labs-aion-3-0-mini";
const LANGUES = {
  fr: "français",
  ar: "arabe tunisien (derja), en écriture arabe",
  en: "anglais",
};
const aBlanc = process.argv.includes("--a-blanc");

const messages = JSON.parse(
  readFileSync(new URL("./messages.json", import.meta.url), "utf8"),
);

function requete(message) {
  const langue = LANGUES[message.langue_reponse];
  if (!langue) throw new Error(`Langue inconnue : ${message.langue_reponse}`);
  return {
    model: MODELE,
    max_tokens: 200,
    messages: [
      {
        role: "system",
        content:
          `Tu rédiges un brouillon de réponse courte (3 phrases au plus) au message d'un client, en ${langue}. ` +
          "Ton poli et précis. N'invente ni prix, ni délai, ni engagement : si l'information manque, propose de vérifier.",
      },
      { role: "user", content: message.texte },
    ],
  };
}

if (aBlanc) {
  for (const m of messages) console.log(JSON.stringify(requete(m), null, 2));
  console.log(`\n${messages.length} requête(s) préparée(s), aucune envoyée.`);
  process.exit(0);
}

if (!process.env.TUKAI_API_KEY) {
  console.error("TUKAI_API_KEY est vide. Voir README.md, étape 2.");
  process.exit(1);
}

const client = new OpenAI({
  baseURL: URL_DE_BASE,
  apiKey: process.env.TUKAI_API_KEY,
});

for (const m of messages) {
  try {
    const { data, response } = await client.chat.completions
      .create(requete(m))
      .withResponse();
    console.log(`\n— Message ${m.id} (${m.langue_reponse})\n${m.texte}`);
    console.log(`\nBrouillon à relire :\n${data.choices[0].message.content}`);
    console.log(`(x-request-id : ${response.headers.get("x-request-id")})`);
  } catch (erreur) {
    // Pas de nouvelle tentative automatique : relancer une génération réussie la facture deux fois.
    console.error(
      `\nMessage ${m.id} : échec ${erreur.status ?? ""} ${erreur.error?.type ?? erreur.message}`,
    );
    if (erreur.status === 402) {
      console.error(
        "Solde insuffisant : rechargez sur https://chat.tuk-ai.com/pay/checkout puis relancez.",
      );
      process.exit(1);
    }
  }
}
```

Configuration (à copier en `.env` ou à exporter dans le terminal, jamais à versionner) :

.env.example :

```bash
# Copiez ce fichier en .env (non versionné) ou exportez ces variables dans votre terminal.
# La clé se crée dans https://chat.tuk-ai.com (réglages, onglet API keys) ; ne la versionnez jamais.
TUKAI_API_KEY=
# Facultatif : un modèle coché sur votre clé (identifiants : https://developers.tuk-ai.com/models)
TUKAI_MODELE=chat-aion-labs-aion-3-0-mini
```

Dépendance :

package.json :

```json
{
  "name": "tukai-exemple-assistant-messages",
  "private": true,
  "type": "module",
  "description": "Brouillons de réponse à des messages clients avec l'API Tukai, relus par un humain.",
  "engines": {
    "node": ">=20"
  },
  "scripts": {
    "a-blanc": "node repondre.mjs --a-blanc",
    "verifier": "node verifier.mjs",
    "repondre": "node repondre.mjs"
  },
  "dependencies": {
    "openai": "^7.27.0"
  }
}
```

## Lancer

1. Créez un dossier, copiez-y les quatre fichiers, puis `npm install`.
2. Exportez `TUKAI_API_KEY` (voir [Premier appel](https://developers.tuk-ai.com/docs/quickstart#2-garder-la-clé-hors-du-code)).
3. `npm run a-blanc` : affiche les requêtes, n'envoie rien.
4. `npm run verifier` : vérifie que la clé est définie (sans l'afficher) et que le modèle figure au catalogue, sans générer. Il ne vérifie pas que le modèle est coché sur la clé.
5. `npm run repondre` : génère les brouillons.

verifier.mjs :

```typescript
// Vérification gratuite : configuration, modèle présent au catalogue, URL de base joignable.
// N'envoie aucune requête de génération et n'affiche jamais la clé.
import OpenAI from "openai";

const URL_DE_BASE = process.env.TUKAI_BASE_URL ?? "https://chat.tuk-ai.com/v1";
const MODELE = process.env.TUKAI_MODELE ?? "chat-aion-labs-aion-3-0-mini";
let ok = true;

console.log(
  process.env.TUKAI_API_KEY?.startsWith("tuk_sk_")
    ? "✓ TUKAI_API_KEY est définie"
    : "✗ TUKAI_API_KEY absente ou ne commence pas par tuk_sk_",
);
if (!process.env.TUKAI_API_KEY?.startsWith("tuk_sk_")) ok = false;

// Le catalogue est public : la liste se lit sans clé, donc sans coût.
const client = new OpenAI({
  baseURL: URL_DE_BASE,
  apiKey: process.env.TUKAI_API_KEY || "non-utilisee",
});
const ids = [];
for await (const m of client.models.list()) ids.push(m.id);
console.log(
  `✓ ${URL_DE_BASE}/models répond (${ids.length} modèles au catalogue)`,
);
if (ids.includes(MODELE))
  console.log(
    `✓ ${MODELE} est au catalogue (vérifiez qu'il est coché sur votre clé)`,
  );
else {
  console.log(`✗ ${MODELE} n'est pas au catalogue`);
  ok = false;
}
process.exit(ok ? 0 : 1);
```

## Résultat attendu

Pour chaque message : le texte d'origine, un brouillon de réponse, et l'identifiant `x-request-id` de l'appel. Le texte généré varie d'un appel à l'autre.

## Limites

- La qualité de la derja dépend du modèle choisi et n'est pas garantie : faites relire par un locuteur avant tout usage réel. Le message en derja de l'exemple est lui-même un texte d'exemple non relu.
- Le script ne fait aucune nouvelle tentative automatique : relancer une génération réussie la facture deux fois.
- Les vrais messages de vos clients contiennent des données personnelles : lisez la section Données de [Mise en production](https://developers.tuk-ai.com/docs/production#données) avant de les envoyer.
