<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Geoffrey Logovi</title>
    <description>The latest articles on DEV Community by Geoffrey Logovi (@geoffreylgv).</description>
    <link>https://dev.to/geoffreylgv</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1207025%2Fe745b108-551d-4ce1-b1a6-b86322e0d77e.jpg</url>
      <title>DEV Community: Geoffrey Logovi</title>
      <link>https://dev.to/geoffreylgv</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/geoffreylgv"/>
    <language>en</language>
    <item>
      <title>Atelier : construire une app d'IA avec Gemma 4, pas à pas</title>
      <dc:creator>Geoffrey Logovi</dc:creator>
      <pubDate>Sat, 24 Oct 2026 06:52:49 +0000</pubDate>
      <link>https://dev.to/geoffreylgv/atelier-construire-une-app-dia-avec-gemma-4-pas-a-pas-1dl7</link>
      <guid>https://dev.to/geoffreylgv/atelier-construire-une-app-dia-avec-gemma-4-pas-a-pas-1dl7</guid>
      <description>&lt;p&gt;En 45 minutes, on construit une petite API qui envoie la photo d'une feuille de maïs à Gemma 4 et renvoie un diagnostic en JSON. On applique au passage le guide « Coder avec l'IA : le guide complet, du premier prompt à la production » : fichiers de contexte, prompts rangés, sortie structurée, tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ce qu'on construit
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AgriScan&lt;/strong&gt; : une API qui reçoit la photo d'une feuille de maïs et répond avec un diagnostic simple, en français, au format JSON.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"maladie"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rouille commune"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"confiance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"moyenne"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"conseil"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Retire les feuilles touchées et surveille les plants voisins."&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Le trajet d'une requête : l'utilisateur envoie une photo → FastAPI la vérifie → &lt;code&gt;gemma.py&lt;/code&gt; l'envoie à Gemma 4 avec le prompt de &lt;code&gt;prompts.py&lt;/code&gt; → on lit le JSON → on le renvoie.&lt;/p&gt;

&lt;p&gt;Gemma 4 est un modèle &lt;em&gt;open-weight&lt;/em&gt; de Google qui comprend le texte et les images. On l'appelle ici via l'API Gemini, ce qui évite de le faire tourner sur ton ordinateur.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ce projet sert d'exemple. Pendant le Hack Day, remplace le maïs par ton propre problème : la structure reste la même.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Prérequis
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.11 ou plus récent (&lt;code&gt;python --version&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Git et un compte GitHub&lt;/li&gt;
&lt;li&gt;Un éditeur, idéalement VS Code avec GitHub Copilot&lt;/li&gt;
&lt;li&gt;Une clé d'API Gemini, gratuite, créée sur &lt;a href="https://aistudio.google.com/" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt; (bouton &lt;em&gt;Get API key&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Une ou deux photos de feuilles pour tester (n'importe quelle plante convient)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Étape 1 : créer le dépôt et ses fichiers de contexte
&lt;/h2&gt;

&lt;p&gt;Sur GitHub, crée un dépôt &lt;strong&gt;public&lt;/strong&gt; &lt;code&gt;agriscan&lt;/code&gt; avec un README, une licence &lt;strong&gt;MIT&lt;/strong&gt; et le &lt;code&gt;.gitignore&lt;/code&gt; &lt;em&gt;Python&lt;/em&gt;. Puis :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/TON-PSEUDO/agriscan.git
&lt;span class="nb"&gt;cd &lt;/span&gt;agriscan
&lt;span class="nb"&gt;mkdir &lt;/span&gt;app tests
&lt;span class="nb"&gt;touch &lt;/span&gt;app/__init__.py app/main.py app/gemma.py app/prompts.py tests/test_main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ajoute &lt;code&gt;AGENTS.md&lt;/code&gt; à la racine, avant d'écrire le moindre code. C'est lui qui guidera Copilot pendant tout l'atelier (modèle complet dans le guide) :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Instructions pour l'assistant IA&lt;/span&gt;

&lt;span class="gu"&gt;## Le projet&lt;/span&gt;
AgriScan : une API qui diagnostique une maladie du maïs à partir d'une photo.

&lt;span class="gu"&gt;## Stack&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Python 3.11, FastAPI
&lt;span class="p"&gt;-&lt;/span&gt; Gemma 4 via l'API Gemini, SDK google-genai, modèle gemma-4-26b-a4b-it

&lt;span class="gu"&gt;## Commandes&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Lancer : fastapi dev app/main.py
&lt;span class="p"&gt;-&lt;/span&gt; Tester : pytest

&lt;span class="gu"&gt;## Règles&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; La clé d'API vient de GEMINI_API_KEY, jamais du code.
&lt;span class="p"&gt;-&lt;/span&gt; Tous les appels au modèle passent par app/gemma.py.
&lt;span class="p"&gt;-&lt;/span&gt; Tous les prompts sont dans app/prompts.py.
&lt;span class="p"&gt;-&lt;/span&gt; Chaque route a un test pytest qui n'appelle pas le vrai modèle.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Crée aussi &lt;code&gt;requirements.txt&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fastapi[standard]
google-genai
pytest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Étape 2 : installer et configurer la clé d'API
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate        &lt;span class="c"&gt;# Windows : .venv\Scripts\activate&lt;/span&gt;
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Le SDK lit la clé dans la variable d'environnement &lt;code&gt;GEMINI_API_KEY&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ta-cle"&lt;/span&gt;          &lt;span class="c"&gt;# macOS / Linux&lt;/span&gt;
&lt;span class="nv"&gt;$env&lt;/span&gt;:GEMINI_API_KEY&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ta-cle"&lt;/span&gt;            &lt;span class="c"&gt;# Windows PowerShell&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ne l'écris jamais dans un fichier du dépôt. Si tu la mets dans un fichier &lt;code&gt;.env&lt;/code&gt;, vérifie que &lt;code&gt;.env&lt;/code&gt; figure bien dans &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Étape 3 : premier appel à Gemma 4
&lt;/h2&gt;

&lt;p&gt;Crée un fichier &lt;code&gt;essai.py&lt;/code&gt; à la racine :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# lit GEMINI_API_KEY
&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemma-4-26b-a4b-it&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Explique en deux phrases ce qu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;est un modèle open-weight.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python essai.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si une réponse s'affiche, tout est en place. Deux modèles Gemma 4 sont disponibles via l'API Gemini : &lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; (celui qu'on utilise) et &lt;code&gt;gemma-4-31b-it&lt;/code&gt;. Commit maintenant :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feat: premier appel a Gemma 4"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Étape 4 : ranger le prompt dans prompts.py
&lt;/h2&gt;

&lt;p&gt;Le prompt est du code : on le met à un seul endroit, on le versionne, on le teste. Dans &lt;code&gt;app/prompts.py&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DIAGNOSTIC_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Tu es un agronome qui aide des petits producteurs au Togo.
On te montre la photo d&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;une feuille de maïs.
Réponds uniquement avec un objet JSON, sans texte autour, avec les clés :
- &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maladie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; : le nom probable de la maladie, ou &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inconnue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;
- &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confiance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; : &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;faible&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;moyenne&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; ou &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;forte&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;
- &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;conseil&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; : une action simple, en une phrase, en français
Si la photo ne montre pas une feuille de maïs, réponds
{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maladie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;photo non valide&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confiance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;forte&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;conseil&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Envoie une photo nette d&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;une feuille de maïs.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On applique ici trois techniques du guide : un &lt;strong&gt;rôle&lt;/strong&gt; et un public, un &lt;strong&gt;format de sortie&lt;/strong&gt; imposé, et un &lt;strong&gt;cas limite&lt;/strong&gt; prévu à l'avance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Étape 5 : envoyer une image à Gemma 4
&lt;/h2&gt;

&lt;p&gt;Dans &lt;code&gt;app/gemma.py&lt;/code&gt;, un seul endroit appelle le modèle. Le prompt passe en &lt;em&gt;system instruction&lt;/em&gt; ; l'image est envoyée comme une partie du contenu.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.genai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.prompts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DIAGNOSTIC_PROMPT&lt;/span&gt;

&lt;span class="n"&gt;MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemma-4-26b-a4b-it&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;analyser_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mime_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Envoie la photo à Gemma 4 et renvoie le diagnostic sous forme de dict.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# créé ici pour que les tests n'aient pas besoin de clé
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GenerateContentConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;system_instruction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DIAGNOSTIC_PROMPT&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;image_bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mime_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;mime_type&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Analyse cette photo.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;extraire_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Étape 6 : lire une sortie JSON fiable
&lt;/h2&gt;

&lt;p&gt;Même quand on demande « uniquement du JSON », un modèle ajoute parfois des balises &lt;code&gt;&lt;/code&gt;&lt;code&gt;json&lt;/code&gt;&lt;code&gt;ou une phrase autour. On extrait donc l'objet entre la première accolade et la dernière, et on refuse proprement le reste. Ajoute dans&lt;/code&gt;app/gemma.py` :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;python&lt;br&gt;
def extraire_json(texte: str) -&amp;gt; dict:&lt;br&gt;
    """Extrait le premier objet JSON d'une réponse du modèle."""&lt;br&gt;
    debut, fin = texte.find("{"), texte.rfind("}")&lt;br&gt;
    if debut == -1 or fin == -1:&lt;br&gt;
        raise ValueError(f"Pas de JSON dans la réponse : {texte[:200]}")&lt;br&gt;
    return json.loads(texte[debut : fin + 1])&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Teste-le vite dans un terminal Python avec une de tes photos :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;python&lt;br&gt;
from app.gemma import analyser_image&lt;br&gt;
print(analyser_image(open("feuille.jpg", "rb").read(), "image/jpeg"))&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Essaie aussi une photo qui n'a rien à voir (ton chat, un ordinateur) pour vérifier que le cas « photo non valide » fonctionne. Si la réponse ne te plaît pas, c'est le prompt qu'on corrige, pas le code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Étape 7 : exposer une API avec FastAPI
&lt;/h2&gt;

&lt;p&gt;On transforme la fonction en route web. &lt;code&gt;app/main.py&lt;/code&gt; vérifie l'entrée (type et taille de la photo), appelle Gemma et renvoie une erreur claire si quelque chose casse :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`python&lt;br&gt;
from fastapi import FastAPI, File, HTTPException, UploadFile&lt;/p&gt;

&lt;p&gt;from app import gemma&lt;/p&gt;

&lt;p&gt;app = FastAPI(title="AgriScan")&lt;br&gt;
TAILLE_MAX = 5 * 1024 * 1024  # 5 Mo&lt;/p&gt;

&lt;p&gt;@app.post("/diagnostic")&lt;br&gt;
async def diagnostic(photo: UploadFile = File(...)):&lt;br&gt;
    if photo.content_type not in {"image/jpeg", "image/png"}:&lt;br&gt;
        raise HTTPException(415, "Envoie une photo JPEG ou PNG.")&lt;br&gt;
    contenu = await photo.read()&lt;br&gt;
    if len(contenu) &amp;gt; TAILLE_MAX:&lt;br&gt;
        raise HTTPException(413, "Photo trop lourde : 5 Mo maximum.")&lt;br&gt;
    try:&lt;br&gt;
        return gemma.analyser_image(contenu, photo.content_type)&lt;br&gt;
    except ValueError:&lt;br&gt;
        raise HTTPException(502, "Le modèle n'a pas renvoyé un résultat lisible. Réessaie.")&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note : on écrit &lt;code&gt;gemma.analyser_image(...)&lt;/code&gt; et pas &lt;code&gt;from app.gemma import analyser_image&lt;/code&gt;. Ce détail permet au test de l'étape 8 de remplacer la fonction.&lt;/p&gt;

&lt;p&gt;Lance le serveur :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
fastapi dev app/main.py&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ouvre &lt;a href="http://127.0.0.1:8000/docs" rel="noopener noreferrer"&gt;http://127.0.0.1:8000/docs&lt;/a&gt;, clique sur &lt;strong&gt;POST /diagnostic&lt;/strong&gt;, puis &lt;strong&gt;Try it out&lt;/strong&gt;, choisis une photo et clique &lt;strong&gt;Execute&lt;/strong&gt;. Tu dois voir le JSON du diagnostic. FastAPI génère cette page tout seul : c'est aussi ta démo pour la vidéo.&lt;/p&gt;
&lt;h2&gt;
  
  
  Étape 8 : écrire un test qui ne dépend pas du modèle
&lt;/h2&gt;

&lt;p&gt;Un test qui appelle vraiment Gemma est lent, coûte du quota et échoue sans réseau. On remplace donc l'appel au modèle par une fausse réponse avec &lt;code&gt;monkeypatch&lt;/code&gt;, et on teste notre code à nous. &lt;code&gt;tests/test_main.py&lt;/code&gt; :&lt;/p&gt;

&lt;p&gt;`&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi.testclient&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TestClient&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;gemma&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.main&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TestClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_diagnostic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;monkeypatch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;faux&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maladie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rouille&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confiance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;moyenne&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;conseil&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;monkeypatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gemma&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;analyser_image&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;faux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/diagnostic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;photo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;feuille.jpg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fake&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image/jpeg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maladie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rouille&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_refuse_un_pdf&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/diagnostic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;photo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;doc.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%PDF&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;415&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_extraire_json_avec_texte_autour&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;texte&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Voici le résultat :&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;```

json&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maladie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inconnue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;

```&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;gemma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extraire_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;texte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maladie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inconnue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
`&lt;/p&gt;

&lt;p&gt;Lance les tests, puis commite :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
pytest&lt;br&gt;
git add .&lt;br&gt;
git commit -m "Ajoute la route /diagnostic et ses tests"&lt;br&gt;
git push&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Trois tests verts, aucune clé d'API nécessaire. C'est exactement ce que le guide appelait « vérifier avant de faire confiance ».&lt;/p&gt;

&lt;h2&gt;
  
  
  Étape 9 : avancer plus vite avec Copilot (et ton AGENTS.md)
&lt;/h2&gt;

&lt;p&gt;Ton &lt;code&gt;AGENTS.md&lt;/code&gt; de l'étape 2 travaille maintenant pour toi : Copilot le lit et connaît déjà le modèle, la structure et les commandes. Tes prompts peuvent donc être courts et précis. Quelques exemples à coller dans Copilot Chat (mode agent) :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;text&lt;br&gt;
Ajoute une page HTML simple dans app/static/index.html avec un champ pour choisir&lt;br&gt;
une photo et un bouton « Analyser ». Elle appelle POST /diagnostic et affiche&lt;br&gt;
maladie, confiance et conseil. Pas de framework JavaScript. Sers-la avec FastAPI.&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;text&lt;br&gt;
Dans app/main.py, si le modèle renvoie "photo non valide", réponds avec un code 422&lt;br&gt;
et le conseil du modèle. Ajoute le test correspondant dans tests/test_main.py.&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;text&lt;br&gt;
Relis app/gemma.py et liste les cas d'erreur non gérés. Ne modifie rien,&lt;br&gt;
explique seulement.&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Après chaque modification : relis le diff, lance &lt;code&gt;pytest&lt;/code&gt;, essaie dans &lt;code&gt;/docs&lt;/code&gt;, puis commite. Si Copilot part dans une mauvaise direction, annule (&lt;code&gt;git restore .&lt;/code&gt;) et reformule plutôt que de corriger à la main un code que tu ne comprends pas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Étape 10 : README, vidéo et soumission
&lt;/h2&gt;

&lt;p&gt;Le jury regarde ton repo avant ton pitch. Ton &lt;code&gt;README.md&lt;/code&gt; doit répondre à ces questions :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Le problème&lt;/strong&gt; : qui en souffre, en une ou deux phrases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;La solution&lt;/strong&gt; : ce que fait l'app et le rôle exact de Gemma 4.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lancer le projet&lt;/strong&gt; : les commandes de l'étape 3 et de l'étape 7, copiables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Le modèle&lt;/strong&gt; : &lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; via l'API Gemini, et sa licence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outils IA utilisés&lt;/strong&gt; : par exemple « GitHub Copilot pour la page HTML et les tests ; Gemma 4 pour le diagnostic ».&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L'équipe&lt;/strong&gt; : noms et profils GitHub.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;La vidéo démo&lt;/strong&gt; : le lien.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pour la vidéo (2 minutes maximum) : enregistre ton écran pendant que tu envoies une vraie photo et que le diagnostic s'affiche. Dépose-la sur Google Drive, règle le partage sur &lt;strong&gt;« Tous les utilisateurs disposant du lien »&lt;/strong&gt; et colle le lien dans le README. Ouvre ce lien dans une fenêtre privée pour vérifier qu'il marche.&lt;/p&gt;

&lt;p&gt;Enfin, sur OrganizerHQ : &lt;strong&gt;Challenges&lt;/strong&gt;, puis &lt;strong&gt;Add Submission&lt;/strong&gt;, coche les défis visés (Best Open-Source AI Project, Best Use of Gemma, Best Use of GitHub Copilot), colle l'URL du repo, puis &lt;strong&gt;Submit Project&lt;/strong&gt;. Le Hack Day ferme les soumissions à 12:35 : vise 12:20 pour garder une marge.&lt;/p&gt;

&lt;p&gt;Dernière vérification avant de soumettre :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
git status   # rien à commiter&lt;br&gt;
git log --oneline | head   # tes commits sont là&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Puis ouvre ton repo sur GitHub depuis un autre navigateur : il doit être public, avec un fichier LICENSE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dépannage
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptôme&lt;/th&gt;
&lt;th&gt;Cause probable&lt;/th&gt;
&lt;th&gt;Que faire&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;401&lt;/code&gt;, &lt;code&gt;API key not valid&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Clé absente ou mal copiée&lt;/td&gt;
&lt;td&gt;Relance &lt;code&gt;export GEMINI_API_KEY=...&lt;/code&gt; dans le terminal qui lance le serveur, sans guillemets en trop.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;429&lt;/code&gt;, &lt;code&gt;RESOURCE_EXHAUSTED&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Quota gratuit dépassé&lt;/td&gt;
&lt;td&gt;Attends une minute, évite les appels en boucle, et utilise les tests avec &lt;code&gt;monkeypatch&lt;/code&gt; pendant le développement.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;404&lt;/code&gt;, modèle introuvable&lt;/td&gt;
&lt;td&gt;Mauvais identifiant&lt;/td&gt;
&lt;td&gt;Vérifie le nom exact du modèle dans Google AI Studio et dans &lt;code&gt;MODEL&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ValueError: Pas de JSON&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Le modèle a répondu en texte libre&lt;/td&gt;
&lt;td&gt;Renforce le prompt (« uniquement un objet JSON »), affiche &lt;code&gt;response.text&lt;/code&gt; pour voir ce qu'il a dit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ModuleNotFoundError: app&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mauvais dossier&lt;/td&gt;
&lt;td&gt;Lance les commandes depuis la racine du repo, là où se trouve &lt;code&gt;app/&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;415&lt;/code&gt; sur une vraie photo&lt;/td&gt;
&lt;td&gt;Format HEIC (iPhone) ou WebP&lt;/td&gt;
&lt;td&gt;Convertis en JPEG, ou ajoute le type dans la liste autorisée.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Ressources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Gemma sur l'API Gemini, documentation officielle : &lt;a href="https://ai.google.dev/gemma/docs/core/gemma_on_gemini_api" rel="noopener noreferrer"&gt;https://ai.google.dev/gemma/docs/core/gemma_on_gemini_api&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Google AI Studio, pour créer ta clé et tester tes prompts : &lt;a href="https://aistudio.google.com" rel="noopener noreferrer"&gt;https://aistudio.google.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Démarrer avec Gemma (MLH) : &lt;a href="https://mlh.link/gemma-quickstart" rel="noopener noreferrer"&gt;https://mlh.link/gemma-quickstart&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Guide débutant Gemma (MLH) : &lt;a href="https://mlh.link/gemma-beginnerguide" rel="noopener noreferrer"&gt;https://mlh.link/gemma-beginnerguide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Documentation Gemma (MLH) : &lt;a href="https://mlh.link/gemma-docs" rel="noopener noreferrer"&gt;https://mlh.link/gemma-docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Gemma 4 avec l'API Gemini, tutoriel de Philipp Schmid : &lt;a href="https://www.philschmid.de/gemma-4-gemini-api" rel="noopener noreferrer"&gt;https://www.philschmid.de/gemma-4-gemini-api&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub Copilot gratuit pour les étudiants : &lt;a href="https://mlh.link/GitHub" rel="noopener noreferrer"&gt;https://mlh.link/GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Documentation FastAPI : &lt;a href="https://fastapi.tiangolo.com" rel="noopener noreferrer"&gt;https://fastapi.tiangolo.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Le guide compagnon de cet atelier : &lt;em&gt;Coder avec l'IA : le guide complet, du premier prompt à la production&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Une question pendant le hack ? Lève la main, un mentor passe. Après le Hack Day, on continue sur le Discord de Python Togo : &lt;a href="https://pytogo.org/discord" rel="noopener noreferrer"&gt;https://pytogo.org/discord&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>gemma</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>What I learnt during the Tublian Open Source Internship</title>
      <dc:creator>Geoffrey Logovi</dc:creator>
      <pubDate>Fri, 16 Feb 2024 17:49:13 +0000</pubDate>
      <link>https://dev.to/geoffreylgv/what-i-learnt-during-the-tublian-open-source-internship-18p7</link>
      <guid>https://dev.to/geoffreylgv/what-i-learnt-during-the-tublian-open-source-internship-18p7</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hi, welcome and I'm glad you're here. I will share things I learned during my open-source internship in this article. Back in December 2023, I applied to join &lt;a href="https://tublian.com" rel="noopener noreferrer"&gt;Tublian&lt;/a&gt; four (04) weeks internship, and guess what, I got in; it was a big pleasure joining the programme. Let's discover from my application to acceptance and my day-to-day journey as intern.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Tublian
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvewt6djxxmjo48gwzp1h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvewt6djxxmjo48gwzp1h.png" alt="Tublian's Home page" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tublian is an open-source platform that serves as a marketplace for anyone in the technology industry based on the credibility of their activities (&lt;a href="https://tublian.com/streetcred" rel="noopener noreferrer"&gt;Streetcred&lt;/a&gt;). Tublian aims to solve this issue. Their mission centers around open source, providing unparalleled opportunities for those striving to excel in the technology industry. Tublian has identified a problem with developer recruitment: the requirement for a certain number of years of experience. Tublian aims to address this issue. Open source offers transparency, accessibility, and the power of collaboration.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Tublians goal has always been to help developers to build in public. Because building in public and contributing to Open Source is one of the best ways to gain experience &amp;amp; build an amazing career in tech.&lt;/em&gt; Nilanja&lt;/strong&gt; Founder Tublian&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://hashnode.com/@Tublian" rel="noopener noreferrer"&gt;Applic&lt;/a&gt;ation and how I know about it
&lt;/h2&gt;

&lt;p&gt;I heard about the internship programme in September 2023 from one of my friends (&lt;a href="https://hashnode.com/@WassCodeur" rel="noopener noreferrer"&gt;Wachiou BOURAMA&lt;/a&gt; - Wasiu), he was very excited to share the opportunity and described very well the process, once completed you get hired and get paid. At that time I was busy with stuff and learning, so I decided to wait for the next cohort. On the 12th of December, I applied and received my application review response.&lt;/p&gt;

&lt;p&gt;I do love what &lt;a href="https://hashnode.com/@tublian" rel="noopener noreferrer"&gt;Nilanjan Raychaudhuri&lt;/a&gt; is doing, giving a huge opportunity to everyone to learn, grow, and get experience at the same time grow the open source community. Contributing to open source projects is not only by coding, and with this chance to collaborate, network, and improve skills even more, learn to code if you want to.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ucdf1071di890epnr1q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ucdf1071di890epnr1q.png" alt="Acceptance mail" width="700" height="744"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Acceptance in the programme
&lt;/h2&gt;

&lt;p&gt;Afterward, I received the mail saying I got in, and I experienced a strong sense of belonging and felt compelled to contribute to open source projects, which I have been doing for some time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2c9zm4wyz6yaxyf4cxxf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2c9zm4wyz6yaxyf4cxxf.png" alt="Mail" width="599" height="731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0tmco8uexdbc083kvvf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0tmco8uexdbc083kvvf.png" alt="mail" width="800" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tublian AI Copilot
&lt;/h2&gt;

&lt;p&gt;To make open source accessible and comprehensive manner to everyone, Tublian developed the ultimate tool that assists you in finding the perfect project and guides you through the contribution phase step by step in activities you will do to complete specific issues. Tublian AI Copilot helps you discover the project based on your interest and skills defined upon your profile, gives you tips on how to contribute, and helps you find a partner to collaborate on the issue or project.&lt;/p&gt;

&lt;p&gt;It helps me find my projects and understand the project, then contribute to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  My day-to-day journey
&lt;/h2&gt;

&lt;p&gt;Well, now you know how I got accepted into the programme, let's dive into my journey activities and challenges that I encountered.&lt;/p&gt;

&lt;p&gt;I started my journey by learning everything open source, learnt about Git and GitHub, what is open source, through community platforms such as &lt;a href="https://digitalocean.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Digital Ocean&lt;/strong&gt;&lt;/a&gt;, Open source Initiative, etc. What is nice about the internship is once you join, you have a kind of roadmap tailored to give you the essential skills needed, and each week you have learning resources and at least one contribution to make.&lt;/p&gt;

&lt;p&gt;So, contributing to some projects is kind of easy, anything related to non-technical (such as Technical Writing, Documentation, API &amp;amp; Technical Documentation, Translation, Review, Help, Guide, etc). Hence, I contributed to two projects to validate my two weeks and started struggling to find a project related to me. But hopefully, I have the community and like-minded people I can ask questions and ask for help, mentors, community members, and also fellow interns. Especially &lt;a href="https://hashnode.com/@Odunola" rel="noopener noreferrer"&gt;Harlimat&lt;/a&gt; - Lymah :), thank you for the invaluable help.&lt;/p&gt;

&lt;p&gt;Lastly, I've worked on the Million.js project improving the experience and accessibility, I contributed to the translation of a few pages where the &lt;a href="https://github.com/aidenybai/million/pull/926" rel="noopener noreferrer"&gt;foundation&lt;/a&gt; got merged.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdahjzr2qfoh57sd34rg1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdahjzr2qfoh57sd34rg1.png" alt="PR merged" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm really glad it got merged, and others as well will benefit from learning more about the Million project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways and Advices
&lt;/h2&gt;

&lt;p&gt;My involvement in the open source realm so far has led me to discover numerous opportunities and develop my communication, technical writing, public speaking, technical presentation, and leadership skills. I have had the chance to network with open-source experts and feel a deep sense of satisfaction that my contribution is benefiting many people and impacting their lives. I am grateful for this opportunity.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Communication and resilience are crucial for personal growth. Curiosity and research are key to improving oneself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Anyone can contribute to open source projects in various ways. To get started, familiarize yourself with the project and find your domain of interest.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remember your motivation for contributing and don't hesitate to seek help.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Start small and gradually tackle bigger issues. Ask questions and be patient when learning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Be open and kind. Give back to the community by helping others and getting involved in organizational activities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make an impact through open source software by sharing and speaking at conferences, etc.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;My experience during the Tublian Open Source Internship was transformative. I gained valuable insights into open-source software development, gained technical skills, especially learning about Python, and developed an appreciation for collaboration and community-driven initiatives.&lt;/p&gt;

&lt;p&gt;Learn more about open source by following my content and reading the comprehensive guide I contributed to at &lt;a href="https://opensauced.pizza" rel="noopener noreferrer"&gt;OpenSauced&lt;/a&gt; : &lt;a href="https://intro.opensauced.pizza" rel="noopener noreferrer"&gt;Intro to Open source&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Connect with me on &lt;a href="https://github.com/geoffreylgv" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. I want to learn about your experience and takeaways, kindly like and post your thoughts in the comment section, see you in a future article.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>ai</category>
      <category>developer</category>
      <category>community</category>
    </item>
    <item>
      <title>Is Developer Relations your new career path to get into tech?</title>
      <dc:creator>Geoffrey Logovi</dc:creator>
      <pubDate>Tue, 16 Jan 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/geoffreylgv/is-developer-relations-your-new-career-path-to-get-into-tech-478o</link>
      <guid>https://dev.to/geoffreylgv/is-developer-relations-your-new-career-path-to-get-into-tech-478o</guid>
      <description>&lt;h2&gt;
  
  
  Opening Hook
&lt;/h2&gt;

&lt;p&gt;Hey readers, welcome to 2024, a happy new year filled with endless opportunities and possibilities. Bref; Let's return to the subject: Developer Relations(DevRel).&lt;/p&gt;




&lt;p&gt;I will keep it simple and stupid (KISS), to respect the do not repeat myself (DRY). In 2023, I started digging into the DevRel domain and I wrote about it: &lt;a href="https://dev.to/geoffreylgv/what-is-developer-relations-245o"&gt;What is Developer Relations&lt;/a&gt;, I'm inviting you to read it, and let's start from there if it suits you as a career path.&lt;/p&gt;

&lt;p&gt;"Developer Relations (DevRel) is a strategic approach to improving business-to-business (B2B) communications between a software companys internal programmers and the external programmers who will be using the companys open APIs" Margaret Rouse. DevRel is an interdisciplinary role that sits at the intersection of product, engineering, and marketing.&lt;/p&gt;

&lt;p&gt;If you are interested in pursuing a career in DevRel, it is important to have the following skills:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Communication skills,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Public speaking,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Networking skills,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Technical skills (Coding),&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;and Community Building.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have experience building a community or organization, please share it. This could be from college, open source projects, online communities, or any other relevant experience.&lt;/p&gt;

&lt;p&gt;DevRels should have strong content creation skills, including the ability to create talks, YouTube videos, tweets, blog posts, and documentation/API documentation. If you do not have any existing content, we recommend creating some.&lt;/p&gt;

&lt;p&gt;It is worth noting that the daily responsibilities of a DevRel professional can vary significantly between companies. Additionally, since DevRel is often integrated into other departments such as product or marketing, it may not have a distinct career path. However, some companies have implemented career ladders specifically for DevRel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outro
&lt;/h2&gt;

&lt;p&gt;I hope this helps you understand the ins and outs of a Developer Relations Engineer, and it will guide you to an amazing career and even more shape your way into tech.&lt;/p&gt;




&lt;p&gt;Thank you for reading me, please do like, comment, and share; give me a follow on &lt;a href="https://github.com/geoffreylgv" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, &lt;a href="https://twitter.com/geoffreylgv" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, and let's connect on &lt;a href="https://linkedin.com/in/geoffreylgv" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://draft.dev/learn/developer-relations-career-insights-from-7-industry-leaders" rel="noopener noreferrer"&gt;DevRel career insights from 7 industry leaders&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devrel</category>
      <category>community</category>
      <category>tech</category>
      <category>career</category>
    </item>
    <item>
      <title>Docsify, a simple and lightweight documentation site generator</title>
      <dc:creator>Geoffrey Logovi</dc:creator>
      <pubDate>Fri, 27 Oct 2023 17:39:47 +0000</pubDate>
      <link>https://dev.to/geoffreylgv/docsify-a-simple-and-lightweight-documentation-site-generator-3hc</link>
      <guid>https://dev.to/geoffreylgv/docsify-a-simple-and-lightweight-documentation-site-generator-3hc</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the realm of open-source, documentation has a crucial role. Documentation boosts user adoption and fosters collaboration. That's why we're excited to share our exploration of Docsify. Docsify is a simple and lightweight documentation site generator. In this article, we are going to explore docsify.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is Docsify ?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Docsify is a documentation site generator that is simple, lightweight, and easy to use. It converts Markdown files into a static website with no build process required. This makes it a great choice for creating documentation. Also for open source projects, personal websites, and more. It helps create beautiful, responsive, and customizable documentation websites with ease.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why using Docsify ?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Markdown Compatibility:&lt;/strong&gt; Docsify supports Markdown. This allows you to write documentation using a simple and familiar syntax. Making it accessible for all team members, including non-technical folks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Single-Page Application (SPA):&lt;/strong&gt; Docsify creates a single-page application for your documentation. There are no page reloads, resulting in a smooth and fast user experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Customizable Themes:&lt;/strong&gt; Various themes, and you can also create your own. It allows you to make your documentation stand out.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automatic Sidebar and Navigation:&lt;/strong&gt; It generates navigation menus and a sidebar. This by based on your documentation structure. It saves time and ensures the documentation organization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Full-Text Search:&lt;/strong&gt; A key feature of Docsify is its built-in full-text search functionality. Users can find what they're looking for. It improves the usability of the documentation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demonstration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Installation of Docsify
&lt;/h3&gt;

&lt;p&gt;To install Docsify, you can use the following command, make sure you have Node.js installed. If not, install &lt;a href="https://nodjs.org" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;. This command will install Docsify globally, so you can use it from anywhere on your system.&lt;/p&gt;

&lt;p&gt;Create a new folder and open it in Visual Studio Code. Type the following command&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm i docsify-cli -g&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialization and deployment
&lt;/h3&gt;

&lt;p&gt;To deploy Docsify, you can use GitHub Pages, or any other tool (e.g. Vercel, Netlify etc). To do this, you will need to create a new folder. Initialize it with Docsify by running the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docsify init&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you want to write your documentation in a specific folder, like &lt;code&gt;docs&lt;/code&gt; for example, run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docsify init ./docs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will create a new &lt;code&gt;index.html&lt;/code&gt; file in&lt;code&gt;docs&lt;/code&gt;. You can edit this file to configure your Docsify documentation.&lt;/p&gt;

&lt;p&gt;Here is a minimalistic configuration of the &lt;code&gt;index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;meta charset="UTF-8"&amp;gt;
  &amp;lt;title&amp;gt;Ducumentation OSS Culture&amp;lt;/title&amp;gt;
  &amp;lt;meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /&amp;gt;
  &amp;lt;meta name="description" content="Description"&amp;gt;
  &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0"&amp;gt;
  &amp;lt;link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css"&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;div id="app"&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;script&amp;gt;
    window.$docsify = {
        themeColor: "#fefefefe",
        name: "OSS Culture",
        repo: "geoffreylgv/oss-culture",
        relativePath: true,
        subMaxLevel: 3,
        search: "auto",
      };
  &amp;lt;/script&amp;gt;
  &amp;lt;!-- Docsify v4 --&amp;gt;
  &amp;lt;script src="//cdn.jsdelivr.net/npm/docsify@4"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have configured your Docsify documentation, type the following command to deploy.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docsify serve docs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will deploy your documentation, go to the browser and type &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;localhost:3000&lt;/a&gt; to preview.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkakye1etz0fcallcv2a2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkakye1etz0fcallcv2a2.png" alt="Deploy Preview" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Docsify is a great documentation site generator. Great for open source projects and personal websites, even to showcase workshop presentations. It is simple, lightweight, and easy to use. Remember, clear and concise documentation bridges your project with its users and contributors. Adhere to metrics and units and remove non-essential fillers. In open source, a well-documented project thrives. Docsify is a valuable asset on this journey.&lt;/p&gt;

</description>
      <category>docsify</category>
      <category>opensource</category>
      <category>github</category>
      <category>documentation</category>
    </item>
    <item>
      <title>How I learned about accessibility through open source contribution</title>
      <dc:creator>Geoffrey Logovi</dc:creator>
      <pubDate>Fri, 27 Oct 2023 09:26:59 +0000</pubDate>
      <link>https://dev.to/geoffreylgv/how-i-learned-about-accessibility-through-open-source-contribution-2i</link>
      <guid>https://dev.to/geoffreylgv/how-i-learned-about-accessibility-through-open-source-contribution-2i</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hola, welcome to this blog post. Through my contribution to the open source project, I learned about accessibility. Let's talk about it in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  My experience with Accessibility
&lt;/h2&gt;

&lt;p&gt;Accessibility is how any person can use or enjoy a website, system, or app. Improving accessibility helps everyone, not only people with disabilities. It makes things easier to use, improves performance, and reaches more people.&lt;/p&gt;

&lt;p&gt;I found out about accessibility from &lt;a href="https://opensauced.pizza" rel="noopener noreferrer"&gt;Open Sauced&lt;/a&gt;, This platform helps contributors track and display their contributions to open source projects. Open Sauced offers a course called &lt;a href="https://intro.opensauced.pizza/" rel="noopener noreferrer"&gt;Intro to Open Source&lt;/a&gt;. In this course, you will learn about open source and how to contribute to open source projects. The course was available in English. It's well-designed and well-structured for everyone. Even for beginners and experienced contributors.&lt;/p&gt;

&lt;p&gt;I wondered about my French fellows. Are they able to access the same things? I checked the issue's tab. Christine Belzie (&lt;a class="mentioned-user" href="https://dev.to/cbid2"&gt;@cbid2&lt;/a&gt;) and &lt;a href="https://github.com/antonio-pedro99" rel="noopener noreferrer"&gt;Antonio Pedro&lt;/a&gt; were translating the course into Portuguese (Brazil). Afterward, I said I wanted to translate it into French to make it easier for people to understand. It was so nice how the contributors received me, working alongside Christine.&lt;/p&gt;

&lt;p&gt;This course is for everyone. It explains Harlimat (&lt;a class="mentioned-user" href="https://dev.to/lymah"&gt;@lymah&lt;/a&gt;)'s type of contribution to open source in a clear way. The website is available in English, French, and Portuguese-Brazil. We will add more languages later.&lt;/p&gt;

&lt;p&gt;I found the website very accessible. I could navigate through different sections and menus using the sidebar. I could also see and hear the information using the text-to-speech. I enjoyed contributing and using it, a handy course I recommend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This experience taught me a lot about accessibility and how to apply it in practice. I learned how to use various tools and techniques to make products more accessible to people. I learned to work with other developers and contribute to open source projects. Shout out to the maintainers of open sauced. If you want to contribute to open source, start by taking the open sauced intro course. Visit the Insights website. Make an account. Show off your contributions and resume.&lt;/p&gt;




&lt;p&gt;In future blog posts, we'll explore all about accessibility. Thank you for reading, do not forget to leave a comment, like, and share.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>a11y</category>
      <category>tublian</category>
      <category>ai</category>
    </item>
    <item>
      <title>Why companies should have a devrel team?</title>
      <dc:creator>Geoffrey Logovi</dc:creator>
      <pubDate>Mon, 25 Sep 2023 19:24:34 +0000</pubDate>
      <link>https://dev.to/geoffreylgv/why-companies-should-have-a-devrel-team-4i5f</link>
      <guid>https://dev.to/geoffreylgv/why-companies-should-have-a-devrel-team-4i5f</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hola, welcome back to this series where we navigate the developer relations (DevRel) world. In the previous one, we talked about DevRel and what it's about. As you noticed, developers don't like to stress themselves, they want to feel like they are part of the community, and there comes a developer relations role. Because no one understands developers more than developers themselves. They play a vital role in the success of your company.&lt;/p&gt;

&lt;h2&gt;
  
  
  Importance of developer relations
&lt;/h2&gt;

&lt;p&gt;Understanding what developers want will help meet their needs, so, devrel engineer will be going to champion developers and their needs within your organization. Developers are curious, have critical thinking, are innovators, and are always learning. Let's highlight key thematic that make developer relations important&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Brand impact and awareness&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fostering community&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Customer satisfaction and support deflection&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Market Insights&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The quote below summarizes why it's really important and the key definition of a developer relations engineer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57sddnzfkjjad31fixz1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57sddnzfkjjad31fixz1.png" alt="Cover for the article, why company should have devrel" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Devrel is not only beneficial for the company, but also for the developers, who can enjoy a better product experience, learn new skills, solve problems, share ideas, network with peers, and have fun. Devrel is a win-win situation for both parties. From this note, we learned about the importance of having a developer relations team. There are a bunch of reasons that point out the real importance, as we are going, we'll learn more about the developer relations engineer's day-to-day work and personas.&lt;/p&gt;




&lt;p&gt;We are almost on day four, a combination of day three, shout out to you all who are reading this note, open for feedback, and if you want to reach out to me, you can find me on &lt;a href="https://twitter.com/geoffreylgv" rel="noopener noreferrer"&gt;X (Twitter)&lt;/a&gt; or &lt;a href="https://linkedin.com/in/geoffreylgv" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devrel</category>
      <category>developer</category>
      <category>community</category>
      <category>careerpath</category>
    </item>
    <item>
      <title>What is Developer Relations</title>
      <dc:creator>Geoffrey Logovi</dc:creator>
      <pubDate>Sat, 23 Sep 2023 19:58:05 +0000</pubDate>
      <link>https://dev.to/geoffreylgv/what-is-developer-relations-245o</link>
      <guid>https://dev.to/geoffreylgv/what-is-developer-relations-245o</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Welcome to this series, where I'm going to take you into the world of Developer Relations. It's not a hidden thing, you've heard the word &lt;strong&gt;&lt;em&gt;"developer relations"&lt;/em&gt;&lt;/strong&gt; a few times now and wondered what it's all about, or you already have an idea about it; let's go through the definition of developer relations and demystify the first impression people have.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is developer relations (DevRel)
&lt;/h1&gt;

&lt;p&gt;DevRel stands for Developer Relations, as you can see, it is an umbrella term that covers the strategies and tactics for building and nurturing a community of mutually beneficial relationships between organizations and developers. It means bridging the gap between the company he is representing and the developers community he is representing as well. See it like this, DevRel engineer is the API (Application Programming Interface) collecting data from the Backend (Company) and connecting them to the Frontend (Developer's community) and vice versa.&lt;/p&gt;

&lt;p&gt;A DevRel program may include a framework built around some or all of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Developer marketing:&lt;/strong&gt; Outreach and engagement activities to build awareness and convert developers to use a product.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Developer Education:&lt;/strong&gt; Product documentation and educational resources to facilitate learning and build affinity with a product and community.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Developer Experience (DX):&lt;/strong&gt; Resources such as a developer portal, product, and documentation to activate the developer with the least amount of friction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Developer Success:&lt;/strong&gt; Activities to nurture and retain developers as they build and scale with a product.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Community Management:&lt;/strong&gt; Nurturing a community to maintain a sustainable program.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41cy6chthgf8xmuy4ltd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41cy6chthgf8xmuy4ltd.png" alt="Mary Thengvall's explanation about devrel" width="800" height="690"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What does a DevRel Engineer
&lt;/h1&gt;

&lt;p&gt;DevRel engineers generally work closely with engineering teams to understand developers' needs, provide them with useful resources (such as working on the documentation, code samples, tutorials, and discussion forums), and help them solve any problems they may encounter. They can also organize community events, such as hackathons, conferences, and meetups, to bring developers together and encourage collaboration. In the same way, attend events to promote the company's products.&lt;/p&gt;

&lt;p&gt;DevRel's ultimate goal is to build a community of enthusiastic, who can help use, and promote the company's products or services and provide valuable feedback to improve products. This can help strengthen the company's reputation as a key player in the technology industry and stimulate business growth.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In this article, you learned about developer relations, what it stands for, what a developer relations engineer does, and its key goals. As the technology landscape continues to evolve, Developer Relations is an indispensable function that persistently serves as the pivot between technology innovators and end users. In the next one, we will learn why it's important to have a developer relations engineer team.&lt;/p&gt;




&lt;p&gt;Thank you for reading me so far, this is a combination of days 1 and 2. Feel free to comment, like, follow me on &lt;a href="https://twitter.com/geoffreylgv" rel="noopener noreferrer"&gt;X (twitter)&lt;/a&gt;, or connect with me on &lt;a href="https://linkedin.com/in/geoffreylgv" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, available for feedback.&lt;/p&gt;

</description>
      <category>devrel</category>
      <category>developer</category>
      <category>devex</category>
      <category>community</category>
    </item>
  </channel>
</rss>
