// remplace le contenu factice du canal ia:enrichirEspece
ipcMain.handle('ia:enrichirEspece', async (event, donneesEspece) => {
try {
let prompt = construirePromptEnrichissement(donneesEspece);
let reponse = await fetch(
`https://generativelanguage.googleapis.com/v1beta/models/${config.ai.model}:generateContent`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-goog-api-key': config.ai.apiKey
},
body: JSON.stringify({
contents: [{ parts: [{ text: prompt }] }],
generationConfig: { responseMimeType: 'application/json' }
})
}
);
let corps = await reponse.json();
if (!reponse.ok) { throw new Error(corps.error.message); }
let infoEnrichie = JSON.parse(corps.candidates[0].content.parts[0].text);
infoEnrichie.dateGeneration = new Date().toISOString();
await accesseurCahier.sauvegarderDonneesEnrichies(donneesEspece._id, infoEnrichie);
return { success: true, data: infoEnrichie };
} catch (erreur) {
return { success: false, error: erreur.message };
}
});
Objectifs des semaines 10 à 12
À la fin de cette semaine, vous saurez obtenir une clé d'API sur AI Studio et la garder hors de votre dépôt, appeler l'API Gemini depuis le processus principal de votre application Electron avec fetch, construire un prompt à partir du contexte de navigation (l'espèce dont la page est affichée), demander au modèle une réponse en JSON pur et la lire, puis enregistrer ce que l'IA produit : les enrichissements dans le cahier personnel (localStorage) et les nouvelles espèces dans MongoDB Atlas. C'est l'étape 5 du Projet Bestiaire, la dernière avant les points bonus.
Déroulement : l'étape 5 du Bestiaire en cinq gestes
Il n'y a pas de diaporama cette semaine : la matière, c'est le tutoriel de l'étape 5, recopié et détaillé ici. Tout se passe dans l'application que vous avez depuis l'étape 3, qui contient déjà les emplacements à compléter.
- Générer ta clé : sur aistudio.google.com/api-keys avec un compte Google, « Create API key ». La clé va dans le bloc
aide votreconfig.js(copié deconfig.template.js, déjà dans.gitignore). Voir la section « La clé et la sécurité » plus bas. - Intégrer le HTML de la page intelligente : les deux sections existent déjà dans
client/index.html:#vue-ai(« Enrichir les données avec IA », avec son champ de recherche) et#vue-intelligence(« Données enrichies par IA », avec#boite-intelligence). À vous d'y afficher la liste des espèces avec une action « Enrichir » sur chacune, puis le résultat. - Tester la réponse de l'API : dans
electron/main.js, le canalia:enrichirEspecerenvoie pour l'instant des données factices. Remplacez-les par un vrai appel (extrait 1) avec un prompt fixe, et regardez la réponse brute dans la console avant de la mettre en page. - Personnaliser le prompt pour les deux sections : le prompt d'enrichissement reçoit le nom, la catégorie, l'habitat et la description de l'espèce affichée; le prompt de nouvelle espèce demande un document complet avec les mêmes champs que la collection
espece(extrait 2). Deux prompts différents, un second canalia:proposerEspececonstruit sur le modèle du premier. - Enregistrer : l'enrichissement reste local, par
sauvegarderDonneesEnrichies()de l'accesseur du cahier personnel (les deux méthodesDonneesEnrichiessont en TODO dansAccesseurCahierPersonnel.js, même patron que les favoris). La nouvelle espèce part dans le cloud par le canalmongo:ajouterEspece, exactement comme celles dupopulate(extrait 3). Puisgit tag LIVRAISON_AIetgit push --tags.
Trois extraits à garder sous la main
Les noms sont ceux de votre application : config.ai, le canal ia:enrichirEspece, accesseurCahier, les champs d'une espèce du populate.
// config.js, bloc ai (jamais versionné)
ai: { provider: 'gemini', apiKey: 'AIza...', model: 'gemini-2.5-flash' }
// enrichir l'espèce affichée : les champs attendus par #boite-intelligence
function construirePromptEnrichissement(espece) {
return `Tu es un naturaliste québécois. Voici une espèce de mon bestiaire :
- nom commun : ${espece.nomCommun}
- nom scientifique : ${espece.nomScientifique}
- catégorie : ${espece.category}
- habitat : ${espece.habitat}
- description : ${espece.description}
Réponds en français, uniquement avec un objet JSON ayant exactement ces champs :
faitsInteressants (tableau de 3 phrases), comportementDetaille, roleEcosysteme,
conseilsObservation, detailsConservation (chaînes de caractères).`;
}
// proposer une nouvelle espèce : les champs de la collection espece
function construirePromptNouvelleEspece(category, nomsDejaPresents) {
return `Propose une espèce réelle du Québec de la catégorie ${category},
différente de : ${nomsDejaPresents.join(', ')}.
Réponds uniquement avec un objet JSON ayant exactement ces champs :
nomCommun, nomScientifique, category, habitat, region, description,
statutConservation, diet, esperanceVie, caracteristiquesDistinctives.`;
}
// client/index.html : la fonction enrichirAvecAI() attend depuis l'étape 3
async function enrichirAvecAI(especeId) {
let espece = especes.find((candidate) => candidate._id === especeId);
let resultat = await ipcRenderer.invoke('ia:enrichirEspece', espece);
if (!resultat.success) {
console.error('Enrichissement refusé :', resultat.error);
return;
}
afficherDonneesEnrichies(espece, resultat.data); // dans #boite-intelligence
}
// la nouvelle espèce proposée par l'IA part dans Atlas, comme celles du populate
async function ajouterEspeceProposee(category) {
let noms = especes.map((espece) => espece.nomCommun);
let proposition = await ipcRenderer.invoke('ia:proposerEspece', category, noms);
if (!proposition.success) { return; }
let resultat = await ipcRenderer.invoke('mongo:ajouterEspece', proposition.data);
if (resultat.success) { await afficherEspeces(); } // la liste se recharge
}
responseMimeType: 'application/json' : sans cette option, il entoure souvent sa réponse de clôtures ```json et JSON.parse échoue. Si fetch n'existe pas dans votre version d'Electron (processus principal trop ancien), npm install node-fetch@2 puis const fetch = require('node-fetch'); en tête de main.js. Une réponse 429 veut dire que le quota gratuit par minute est atteint : on attend une minute, on ne boucle pas.La clé et la sécurité
- Obtenir la clé : aistudio.google.com/api-keys, connecté avec un compte Google, « Create API key ». Le palier gratuit d'AI Studio suffit largement pour le cours; aucune carte de crédit.
- La ranger : dans
config.jsseulement (cp config.template.js config.jssi ce n'est pas déjà fait), blocai. Le code la lit parconfig.ai.apiKey; elle ne s'écrit nulle part ailleurs. - Vérifier qu'elle ne part pas :
git statusne doit jamais listerconfig.js. Si c'est le cas, votre.gitignorea perdu la ligneconfig.js: remettez-la avant tout commit. - La garder côté processus principal : l'appel se fait dans
electron/main.js, jamais dansindex.html. La page demande par IPC, le processus principal parle à l'API. C'est le même découpage que pour MongoDB. - Si elle fuit (collée dans Discord, dans une capture d'écran, dans un commit) : on la révoque immédiatement sur AI Studio et on en génère une autre. Une clé est un mot de passe.
Où ça va dans l'application
L'application de l'étape 3 a réservé la place de chaque morceau. Voici la carte :
| Fichier | Ce qui existe déjà | Ce que vous ajoutez |
|---|---|---|
config.js | bloc ai avec provider, apiKey, model | vos valeurs : gemini, votre clé, gemini-2.5-flash |
electron/main.js | canal ia:enrichirEspece avec des données factices | l'appel réel (extrait 1), les deux fonctions de prompt (extrait 2), un canal ia:proposerEspece |
client/index.html | #vue-ai, #vue-intelligence, enrichirAvecAI() vide | la liste des espèces avec l'action « Enrichir », l'affichage du résultat, l'appel (extrait 3) |
client/accesseur/AccesseurCahierPersonnel.js | getDonneesEnrichies() et sauvegarderDonneesEnrichies() en TODO, clé donneesEnrichies déjà initialisée | les deux méthodes, sur le patron des favoris |
electron/main.js (Mongo) | canal mongo:ajouterEspece déjà fonctionnel | rien : la nouvelle espèce y passe telle quelle |
Ressources
AI Studio : générer sa clé Documentation Gemini démarrage rapide réponse en JSON quotas du palier gratuit fetch sur MDN (en français) Outils : MongoDB Atlas et les bases de données en ligne Semaines 8-10 : NoSQL, Node et le BestiaireÉvaluation : l'étape 5 du Projet Bestiaire (5 points)
La cinquième et dernière étape du Projet Bestiaire (25 %), remise par le tag LIVRAISON_AI sur votre dépôt GitHub. On regarde quatre choses : la clé absente du dépôt, un appel qui répond, deux prompts différents construits à partir du contexte de navigation, et les données enregistrées au bon endroit (enrichissements en local, nouvelles espèces dans Atlas).