Contenu

Tutoriel

Objectifs

Initialisé un projet Next.js App Router avec TypeScript et Tailwind.

Créé une route API serverless.

Consommé l’API OpenAI (modèle GPT-4o-mini) en back-end.

Géré l’état et les appels asynchrones en React.

Déployé une application fullstack avec variables d’environnement sécurisées.

Prérequis

Node.js 18+ installé (téléchargement)

Visual Studio Code

Un compte GitHub (pour le déploiement)

Un compte OpenAI avec une clé API – platform.openai.com

Tu obtiens des crédits gratuits à l’inscription, largement suffisants pour ce projet.

Un compte Vercel (gratuit, connexion via GitHub).

Programme détaillé

Étape 1 – Créer le projet Next.js

Ouvre un terminal et tape :

bash
npx create-next-app@latest mon-generateur-portfolio

Pendant l’installation, réponds ainsi aux questions :

text
✔ Would you like to use TypeScript? … No / Yes  → Yes
✔ Would you like to use ESLint? … Yes
✔ Would you like to use Tailwind CSS? … Yes
✔ Would you like to use `src/` directory? … Yes
✔ Would you like to use App Router? … Yes
✔ Would you like to customize the default import alias? … No

Quand c’est terminé, rends-toi dans le dossier :

bash
cd mon-generateur-portfolio

Ouvre le projet dans VS Code :

bash
code .

Lance le serveur de développement pour vérifier :

bash
npm run dev

Rendez-vous sur http://localhost:3000 : la page par défaut de Next.js apparaît.


Étape 2 – Mise en place de l’interface

On va construire une page simple avec un champ texte et un bouton.

Remplace le contenu de src/app/page.tsx par :

tsx
'use client';

import { useState } from 'react';

export default function Home() {
  const [title, setTitle] = useState('');
  const [result, setResult] = useState('');
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    // Appel à l'API à venir à l'étape 3
    setLoading(false);
  };

  return (
    <main className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-900 to-indigo-950 p-4">
      <div className="bg-white/10 backdrop-blur-md rounded-xl p-8 w-full max-w-2xl shadow-2xl border border-white/20">
        <h1 className="text-3xl font-bold text-white mb-2">Générateur de description de projet</h1>
        <p className="text-gray-300 mb-6">
          Donne le titre de ton projet, l&apos;IA rédige une description prête pour ton portfolio.
        </p>
        <form onSubmit={handleSubmit} className="flex flex-col gap-4">
          <input
            type="text"
            value={title}
            onChange={(e) => setTitle(e.target.value)}
            placeholder="Ex : Application de chat en temps réel avec Socket.io"
            className="p-3 rounded-md bg-gray-800 text-white border border-gray-600 focus:outline-none focus:ring-2 focus:ring-indigo-500"
            required
          />
          <button
            type="submit"
            disabled={loading}
            className="bg-indigo-600 hover:bg-indigo-700 disabled:bg-gray-600 text-white font-semibold py-3 rounded-md transition"
          >
            {loading ? 'Génération en cours...' : 'Générer la description'}
          </button>
        </form>
        {result && (
          <div className="mt-6 p-4 bg-gray-800 rounded-md border border-gray-700">
            <h2 className="text-sm text-indigo-400 mb-1">Résultat :</h2>
            <p className="text-white whitespace-pre-wrap">{result}</p>
          </div>
        )}
      </div>
    </main>
  );
}

Quelques explications :

  • On utilise le hook useState pour gérer le titre et le résultat.

  • Le composant est en 'use client' car il y a des interactions (formulaire).

  • Le style est entièrement en Tailwind, avec un fond dégradé et un conteneur vitré.

Tu peux déjà tester l’affichage. Le bouton ne fait rien pour l’instant, on s’en occupe maintenant.


Étape 3 – Créer la route API Next.js qui appelle OpenAI

L’intelligence artificielle sera appelée côté serveur pour ne pas exposer ta clé API. Next.js permet de créer des routes API très simplement.

  1. Crée un fichier .env.local à la racine du projet :

env
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Remplace par ta clé réelle (ne la partage jamais, ni sur GitHub).

  1. Crée le dossier src/app/api/generate/route.ts. Oui, il faut créer les sous-dossiers.

  2. À l’intérieur, écris :

ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const { title } = await request.json();

  if (!title) {
    return NextResponse.json({ error: 'Titre requis' }, { status: 400 });
  }

  const prompt = `Tu es un assistant qui aide les étudiants à rédiger des descriptions de projets tech pour leur portfolio.
Écris une description professionnelle et attrayante pour un projet intitulé "${title}".
Structure la réponse en deux parties :
1. Une phrase d'accroche.
2. Un court paragraphe (3-4 lignes) détaillant les fonctionnalités, la stack technique et la valeur ajoutée.
Sois enthousiaste mais crédible.`;

  try {
    const response = await fetch('https://api.openai.com/v1/chat/completions', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
      },
      body: JSON.stringify({
        model: 'gpt-4o-mini', // le modèle le moins cher et très rapide
        messages: [{ role: 'user', content: prompt }],
        temperature: 0.7,
      }),
    });

    const data = await response.json();

    if (data.error) {
      return NextResponse.json({ error: data.error.message }, { status: 500 });
    }

    const generatedText = data.choices[0].message.content;
    return NextResponse.json({ result: generatedText });
  } catch (error) {
    return NextResponse.json({ error: 'Erreur serveur' }, { status: 500 });
  }
}

Explication rapide :

  • On reçoit le titre via POST.

  • On construit un prompt clair.

  • On envoie à l’API OpenAI.

  • On renvoie le texte généré.

Redémarre le serveur (Ctrl+C puis npm run dev) pour prendre en compte le fichier .env.local.


Étape 4 – Relier le front-end à l’API

Retourne dans src/app/page.tsx et complète la fonction handleSubmit :

tsx
const handleSubmit = async (e: React.FormEvent) => {
  e.preventDefault();
  setLoading(true);
  setResult('');
  try {
    const res = await fetch('/api/generate', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ title }),
    });
    const data = await res.json();
    if (data.error) {
      setResult(`Erreur : ${data.error}`);
    } else {
      setResult(data.result);
    }
  } catch (err) {
    setResult('Impossible de générer la description.');
  } finally {
    setLoading(false);
  }
};

Teste l’application : écris un titre comme “To-Do List collaborative en React et Firebase” et clique sur le bouton. Après quelques secondes, la description apparaît.

🎉 Félicitations, tu as intégré l’IA dans ton app !


Étape 5 – Déployer gratuitement sur Vercel

  1. Initialise un dépôt Git :

bash
git init
git add .
git commit -m "Initial commit"
  1. Pousse vers GitHub (crée un repo vide sur GitHub auparavant) :

bash
git remote add origin https://github.com/ton-utilisateur/mon-generateur-portfolio.git
git branch -M main
git push -u origin main
  1. Va sur vercel.com, connecte-toi avec GitHub, et importe ce dépôt.

  2. Dans les paramètres du projet sur Vercel, ajoute la variable d’environnement OPENAI_API_KEY avec ta clé.

  3. Lance le déploiement. En 30 secondes, ton app est en ligne avec une URL publique !


Étape 6 – Mettre en valeur le projet sur ton portfolio

Pour que ce projet brille, fais ceci :

  • Rédige un README : description du projet, technologies, capture d’écran, lien vers la démo.

  • Ajoute une page “projet” dédiée sur ton site perso, avec un lien direct.

  • Poste sur LinkedIn : “J’ai créé une app qui génère des descriptions de projets avec l’IA – tech : Next.js, Tailwind, OpenAI API”. Les recruteurs adorent ce type d’initiative.

  • Améliore l’application (optionnel) :

    • Ajoute un bouton pour copier la description.

    • Gère deux langues (français / anglais).

    • Permet de générer plusieurs variantes.

Programme

Étape 1 – Créer le projet Next.js

Ouvre un terminal et tape :

bash
npx create-next-app@latest mon-generateur-portfolio

Pendant l’installation, réponds ainsi aux questions :

text
✔ Would you like to use TypeScript? … No / Yes  → Yes
✔ Would you like to use ESLint? … Yes
✔ Would you like to use Tailwind CSS? … Yes
✔ Would you like to use `src/` directory? … Yes
✔ Would you like to use App Router? … Yes
✔ Would you like to customize the default import alias? … No

Quand c’est terminé, rends-toi dans le dossier :

bash
cd mon-generateur-portfolio

Ouvre le projet dans VS Code :

bash
code .

Lance le serveur de développement pour vérifier :

bash
npm run dev

Rendez-vous sur http://localhost:3000 : la page par défaut de Next.js apparaît.


Étape 2 – Mise en place de l’interface

On va construire une page simple avec un champ texte et un bouton.

Remplace le contenu de src/app/page.tsx par :

tsx
'use client';

import { useState } from 'react';

export default function Home() {
  const [title, setTitle] = useState('');
  const [result, setResult] = useState('');
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    // Appel à l'API à venir à l'étape 3
    setLoading(false);
  };

  return (
    <main className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-900 to-indigo-950 p-4">
      <div className="bg-white/10 backdrop-blur-md rounded-xl p-8 w-full max-w-2xl shadow-2xl border border-white/20">
        <h1 className="text-3xl font-bold text-white mb-2">Générateur de description de projet</h1>
        <p className="text-gray-300 mb-6">
          Donne le titre de ton projet, l&apos;IA rédige une description prête pour ton portfolio.
        </p>
        <form onSubmit={handleSubmit} className="flex flex-col gap-4">
          <input
            type="text"
            value={title}
            onChange={(e) => setTitle(e.target.value)}
            placeholder="Ex : Application de chat en temps réel avec Socket.io"
            className="p-3 rounded-md bg-gray-800 text-white border border-gray-600 focus:outline-none focus:ring-2 focus:ring-indigo-500"
            required
          />
          <button
            type="submit"
            disabled={loading}
            className="bg-indigo-600 hover:bg-indigo-700 disabled:bg-gray-600 text-white font-semibold py-3 rounded-md transition"
          >
            {loading ? 'Génération en cours...' : 'Générer la description'}
          </button>
        </form>
        {result && (
          <div className="mt-6 p-4 bg-gray-800 rounded-md border border-gray-700">
            <h2 className="text-sm text-indigo-400 mb-1">Résultat :</h2>
            <p className="text-white whitespace-pre-wrap">{result}</p>
          </div>
        )}
      </div>
    </main>
  );
}

Quelques explications :

  • On utilise le hook useState pour gérer le titre et le résultat.

  • Le composant est en 'use client' car il y a des interactions (formulaire).

  • Le style est entièrement en Tailwind, avec un fond dégradé et un conteneur vitré.

Tu peux déjà tester l’affichage. Le bouton ne fait rien pour l’instant, on s’en occupe maintenant.


Étape 3 – Créer la route API Next.js qui appelle OpenAI

L’intelligence artificielle sera appelée côté serveur pour ne pas exposer ta clé API. Next.js permet de créer des routes API très simplement.

  1. Crée un fichier .env.local à la racine du projet :

env
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Remplace par ta clé réelle (ne la partage jamais, ni sur GitHub).

  1. Crée le dossier src/app/api/generate/route.ts. Oui, il faut créer les sous-dossiers.

  2. À l’intérieur, écris :

ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const { title } = await request.json();

  if (!title) {
    return NextResponse.json({ error: 'Titre requis' }, { status: 400 });
  }

  const prompt = `Tu es un assistant qui aide les étudiants à rédiger des descriptions de projets tech pour leur portfolio.
Écris une description professionnelle et attrayante pour un projet intitulé "${title}".
Structure la réponse en deux parties :
1. Une phrase d'accroche.
2. Un court paragraphe (3-4 lignes) détaillant les fonctionnalités, la stack technique et la valeur ajoutée.
Sois enthousiaste mais crédible.`;

  try {
    const response = await fetch('https://api.openai.com/v1/chat/completions', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
      },
      body: JSON.stringify({
        model: 'gpt-4o-mini', // le modèle le moins cher et très rapide
        messages: [{ role: 'user', content: prompt }],
        temperature: 0.7,
      }),
    });

    const data = await response.json();

    if (data.error) {
      return NextResponse.json({ error: data.error.message }, { status: 500 });
    }

    const generatedText = data.choices[0].message.content;
    return NextResponse.json({ result: generatedText });
  } catch (error) {
    return NextResponse.json({ error: 'Erreur serveur' }, { status: 500 });
  }
}

Explication rapide :

  • On reçoit le titre via POST.

  • On construit un prompt clair.

  • On envoie à l’API OpenAI.

  • On renvoie le texte généré.

Redémarre le serveur (Ctrl+C puis npm run dev) pour prendre en compte le fichier .env.local.


Étape 4 – Relier le front-end à l’API

Retourne dans src/app/page.tsx et complète la fonction handleSubmit :

tsx
const handleSubmit = async (e: React.FormEvent) => {
  e.preventDefault();
  setLoading(true);
  setResult('');
  try {
    const res = await fetch('/api/generate', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ title }),
    });
    const data = await res.json();
    if (data.error) {
      setResult(`Erreur : ${data.error}`);
    } else {
      setResult(data.result);
    }
  } catch (err) {
    setResult('Impossible de générer la description.');
  } finally {
    setLoading(false);
  }
};

Teste l’application : écris un titre comme “To-Do List collaborative en React et Firebase” et clique sur le bouton. Après quelques secondes, la description apparaît.

🎉 Félicitations, tu as intégré l’IA dans ton app !


Étape 5 – Déployer gratuitement sur Vercel

  1. Initialise un dépôt Git :

bash
git init
git add .
git commit -m "Initial commit"
  1. Pousse vers GitHub (crée un repo vide sur GitHub auparavant) :

bash
git remote add origin https://github.com/ton-utilisateur/mon-generateur-portfolio.git
git branch -M main
git push -u origin main
  1. Va sur vercel.com, connecte-toi avec GitHub, et importe ce dépôt.

  2. Dans les paramètres du projet sur Vercel, ajoute la variable d’environnement OPENAI_API_KEY avec ta clé.

  3. Lance le déploiement. En 30 secondes, ton app est en ligne avec une URL publique !


Étape 6 – Mettre en valeur le projet sur ton portfolio

Pour que ce projet brille, fais ceci :

  • Rédige un README : description du projet, technologies, capture d’écran, lien vers la démo.

  • Ajoute une page “projet” dédiée sur ton site perso, avec un lien direct.

  • Poste sur LinkedIn : “J’ai créé une app qui génère des descriptions de projets avec l’IA – tech : Next.js, Tailwind, OpenAI API”. Les recruteurs adorent ce type d’initiative.

  • Améliore l’application (optionnel) :

    • Ajoute un bouton pour copier la description.

    • Gère deux langues (français / anglais).

    • Permet de générer plusieurs variantes.

Formateur / Entreprise

Contenu à venir...