Coopération pour des projets web avec du sens, de l’accessibilité et de l’éthique

https://www.copsae.fr

  • Comment partager une #image de façon accessible ?

    On entend souvent dire, sur les réseaux sociaux, qu’il est facile de mettre une alternative à une image pour qu’elle soit accessible. Pourtant, il y a de nombreux types d’images différents (illustrations, photographies, graphiques, textes, infographies…) et la façon de les rendre accessibles peut varier. En effet, selon les besoins d’accessibilité des différents types de handicaps concernés, les solutions ne sont pas toujours les mêmes. On pense souvent aux personnes aveugles qui ne voient pas les images, mais les personnes malvoyantes ou les personnes ayant un handicap cognitif tel que la dyslexie, par exemple, peuvent également être impactées lorsqu’une image contient du texte.

    Nous avons donc rédigé ce guide afin de guider les personnes qui contribuent des contenus : les rédacteurs et rédactrices web dont c’est le métier, mais également toute personne qui publie des contenus (réseaux sociaux, mails, blog, documents Word et PowerPoint…). Les cas présentés sont ceux qu’il est fréquent de rencontrer lorsque l’on contribue des contenus. Ce guide n’aborde pas les points techniques.

    Nous avons choisi de prendre le parti de l’accessibilité réelle et donc d’aller un peu plus loin que ce que demande la conformité aux normes d’accessibilité, notamment en ce qui concerne les images contenant du texte.

    Point de vigilance : une même image peut être concernée par plusieurs cas de figure. Par exemple, elle peut à la fois contenir du texte, être dans un lien et avoir une légende. Il faut donc bien vérifier chaque point et user de réflexion.

    Note : la forme et le fond de cet article ont notamment été inspirés par l’arbre de décision pour les alternatives d’image du W3C nommé « An alt Decision Tree ».

    Sommaire :

    Définition préalable : une alternative d’image doit être courte et concise
    L’image est-elle partagée sur un réseau social qui rend visible l’alternative d’image ?
    L’image contient-elle du texte ?
    L’image est-elle dans un lien ou un bouton qui permet de l’afficher en grand ?
    L’image a-t-elle ou doit-elle avoir une légende ?
    L’image donne-t-elle de l’information ?
    L’image est-elle purement décorative ou sans intérêt pour les personnes ?
    L’image n’est dans aucun des cas présentés ?

    Le reste à lire ici :

    https://www.copsae.fr/partager-image-accessible

    #accessibilité #alt #handicap #personnes_aveugles #cécité #personnes_malvoyantes #handicap_cognitif #dyslexie #guide #manuel

    ping @arno

  • Je viens de développer une fonction pour #SPIP qui regarde si une image (tirée de spip_documents) a son champ alt renseigné, et si ce n’est pas le cas, demande à ChatGPT de la décrire. Et la réponse est alors stockée dans le champ alt du document. (Il faut donc deux recalculs pour afficher la description de l’image sur le site.) De fait, une fois que la description a été obtenue, ça n’interroge plus l’API de ChatGTP, et si on y tient on peut corriger dans l’interface de SPIP.

    L’intérêt, c’est que tout le monde réclame d’avoir un site accessible, mais si les gens ne décrivent pas les images, hé ben c’est mort. Et les gens ne renseignent pas les champs « alt », parce que c’est du contenu qui n’est pas visible. D’où l’idée de demander à un robot de le faire.

    Pour l’instant c’est très basique, parce que je suis en train de bidouiller. Idéalement, à la fin, ça deviendrait un plugin qui fait le café.

    Évidemment, il faut un compte pour l’API chez OpenAI. Ça n’implique pas un abonnement à ChatGPT, on ne paie que pour l’utilisation de l’API (et c’est vraiment pas cher : si j’ai bien compris, avec ce modèle, c’est $0.000425 par image décrite, c’est-à-dire 9 cents pour 200 images décrites).

    function openai_vision($id, $lang = "fr") {
       $api_key = "sk-.......";
       $model = "gpt-4o-mini";

       if ($lang == "en") $prompt = "Describe this image in english";
       else if ($lang == "es") $prompt = "Describe esta imagen en español";
       else if ($lang == "it") $prompt = "Descrivi questa immagine in italiano";
       else if ($lang == "ar") $prompt = "وصف هذه الصورة باللغة العربية";
       else if ($lang == "fa") $prompt = "این تصویر را به فارسی توصیف کنید";
       else $prompt = "Décris cette image en français";

       $query = sql_select(
                    "alt, fichier",
                    "spip_documents", "id_document=$id");
            if ($row = sql_fetch($query)) {
                    $alt = $row["alt"];
           $fichier = $row["fichier"];

           if (strlen($alt) > 0) {
               return $alt;
           } else {
               // Interroger OpenAI
               $fichier = url_absolue(_DIR_IMG.$fichier);
               

               $curl = curl_init();

               curl_setopt($curl, CURLOPT_URL, "https://api.openai.com/v1/chat/completions");
               curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
               curl_setopt($curl, CURLOPT_POST, true);
               
               $jsonData = json_encode(
                   [
                       'model'=> $model,
                       "messages"=>
                       [
                           [
                               "role"=> "user",
                               "content"=>
                               [
                                   [
                                       "type"=> "text",
                                       "text"=> $prompt
                                   ],
                                   [
                                       "type"=> "image_url",
                                       "image_url" => [
                                           "url"=> $fichier,
                                           "detail" => "low"
                                       ]
                                   ]
                               ]
                           ]
                       ],
                       "max_tokens"=> 300
                     ]                          
               );
               curl_setopt($curl, CURLOPT_POSTFIELDS, $jsonData);
               curl_setopt($curl, CURLOPT_HTTPHEADER, array(
                   'Content-Type: application/json',
                   'Authorization: Bearer ' . $api_key
               ));

               $response = curl_exec($curl);
               curl_close($curl);      
           
               $response = json_decode($response, true);
               $new_alt = $response["choices"][0]["message"]["content"];

               if (strlen($new_alt) > 0) {
                   sql_updateq(
                                            "spip_documents",
                                            array(
                                                    "alt" => $new_alt
                                            ),
                                            "id_document=$id"
                       );       
               } else {
                                    return json_encode($response) ;
                            }
               return "[OPENAI] $new_alt";
           }
       }
    }

    Que j’appelle actuellement avec une boucle dans la page article.html :

            <!--
                                                            <BOUCLE(DOCUMENTS){id_article}{mode=logoon}>
                                                                    [(#ID_DOCUMENT|openai_vision{#LANG})]
                                                             </BOUCLE>
                                                             -->