


AWS JavaScript WordPress = Stratégies amusantes d'automatisation de contenu utilisant l'intelligence artificielle
Il y a quelques mois, j'ai commencé à collaborer sur un projet consacré au contenu généré par l'IA pour un client axé sur le secteur technologique. Mon rôle était principalement axé sur la mise en place de SSG en utilisant WordPress comme Headless CMS pour un front-end Nuxt.
Le client avait l'habitude d'écrire des articles plusieurs fois par semaine sur différentes tendances ou situations affectant le secteur, dans l'espoir d'augmenter le trafic vers le site et sa production d'articles, il a décidé d'utiliser l'IA pour générer des articles pour lui.
Après un certain temps, avec les bonnes invites, le client a obtenu des informations qui correspondaient presque exactement à un article écrit par un humain, il est très difficile de repérer qu'elles ont été créées par une machine.
Quelque temps après avoir commencé à travailler sur différentes fonctionnalités, on me demandait continuellement une chose spécifique.
Ey, pouvez-vous mettre à jour l'image sélectionnée pour cet article ?
Après 2 semaines de mise à jour quotidienne des messages, j'ai eu un petit moment d'eurêka.
Pourquoi ne pas automatiser la génération d'images sélectionnées pour ces articles à l'aide de l'Intelligence artificielle ?
Nous avons déjà automatisé la rédaction des articles, pourquoi ne pas automatiser les images présentées ?
Pendant mon temps libre, j'expérimentais des LLM génératifs sur mon ordinateur, j'avais donc une bonne idée de plus ou moins comment aborder cette quête secondaire. J'ai envoyé un message au client détaillant quel est le problème, ce que je veux faire et quels seraient les avantages et sans avoir à convaincre, j'ai eu le feu vert pour travailler sur cette fonctionnalité et j'ai tout de suite opté pour mon premier pas.
1. Concevoir à quoi ressemblera la solution.
Étant donné que j'ai eu une certaine exposition à l'exécution de modèles localement, j'ai tout de suite su qu'il n'était pas possible d'héberger soi-même ces modèles. Cela mis de côté, j'ai commencé à jouer avec des API qui généraient des images basées sur des invites textuelles.
Les images présentées se composaient de 2 parties : le graphique principal composé et un slogan accrocheur.
Le graphique composé serait constitué de quelques éléments liés à l'article, disposés de manière agréable avec ensuite des couleurs et des textures avec des modes de fusion appliqués pour obtenir des effets fantaisistes suivant le branding.
Les slogans étaient des phrases courtes de 8 à 12 mots avec une simple ombre portée en dessous.
Sur la base de mes tests, j'ai réalisé que poursuivre la voie de l'IA pour la génération d'images n'était pas pratique. La qualité de l’image n’était pas à la hauteur des attentes et le processus prenait trop de temps pour justifier son utilisation. Considérant que cela fonctionnerait comme une fonction AWS Lambda, où le temps d'exécution aurait un impact direct sur les coûts.
Cela étant écarté, j'ai opté pour le plan B : mélanger des images et des éléments de conception à l'aide de l'API Canvas de JavaScript.
En y regardant de plus près, nous avions principalement 5 styles de messages simples, et environ 4 types de textures, dont 3 utilisant le même alignement de texte, le même style et la même position. Après avoir fait quelques calculs, j'ai pensé :
Hmm, si je prends ces 3 images, saisis 8 textures et joue avec les modes de fusion, je peux me débrouiller avec 24 variations
Étant donné que ces 3 types de messages avaient le même style de texte, il s'agissait pratiquement d'un seul modèle.
Une fois cela réglé, je suis passé au générateur de slogan. Je voulais créer un slogan basé sur le contenu et le titre de l'article. J'ai décidé d'utiliser l'API de ChatGPT étant donné que l'entreprise payait déjà pour cela, et après quelques expérimentations et ajustements des invites, j'ai eu un très bon MVP pour mon générateur de slogan.
Une fois les 2 parties les plus difficiles de la tâche comprises, j'ai passé du temps dans Figma à assembler le schéma de l'architecture finale de mon service.
2.Codage de mon lambda
Le plan était de créer une fonction Lambda capable d'analyser le contenu de la publication, de générer un slogan et d'assembler une image sélectionnée, le tout parfaitement intégré à WordPress.
Je fournirai du code mais juste assez pour communiquer l'idée générale à ke.
Analyser le contenu
La fonction Lambda commence par extraire les paramètres nécessaires de la charge utile de l'événement entrant :
const { title : request_title, content, backend, app_password} = JSON.parse(event.body);
- titre et contenu : Ceux-ci fournissent le contexte de l’article.
- backend : L'URL du backend WordPress pour les téléchargements d'images.
- app_password : Le jeton d'authentification que je vais utiliser pour télécharger en tant qu'utilisateur à l'aide de l'API Wordpress Rest.
Générer le slogan
La première tâche principale de la fonction consiste à générer un slogan à l'aide de la fonction analyseContent, qui utilise l'API d'OpenAI pour créer un slogan digne d'un clic basé sur le titre et le contenu de l'article.
Notre fonction prend le titre et le contenu de la publication mais renvoie un slogan, un sentiment de publication pour savoir si la publication est une opinion positive, négative ou neutre et un symbole d'entreprise facultatif des sociétés de l'indice S&P.
const { slogan, sentiment, entreprise } = wait analyseContent({ titre : request_title, content });
Cette étape est cruciale, car le slogan influence directement l’esthétique de l’image.
Création de l'image sélectionnée
Ensuite, la fonction generateImage entre en jeu :
let buffer; buffer = await generateImage({ title: tagline, company_logo: company_logo, sentiment: sentiment, });
Cette fonction gère :
- Concevoir la composition.
- Superposition de textures, de couleurs et d'éléments de marque.
- Appliquer des effets et créer le titre.
Voici un aperçu étape par étape de son fonctionnement :
La fonction generateImage commence par créer un canevas vierge, définir ses dimensions et le préparer à gérer tous les éléments de conception.
let buffer; buffer = await generateImage({ title: tagline, company_logo: company_logo, sentiment: sentiment, });
À partir de là, une image d'arrière-plan aléatoire est chargée à partir d'une collection prédéfinie d'actifs. Ces images ont été organisées pour correspondre à la marque axée sur la technologie tout en permettant suffisamment de variété entre les publications. L'image d'arrière-plan est sélectionnée au hasard en fonction de son sentiment.
Pour garantir que chaque image d'arrière-plan soit superbe, j'ai calculé ses dimensions de manière dynamique en fonction du rapport hauteur/largeur. Cela évite les distorsions tout en gardant l'équilibre visuel intact.
Ajout du slogan
Le slogan est court mais basé sur certaines règles, cette phrase percutante est divisée en morceaux gérables et est stylisée de manière dynamique pour garantir qu'elle est toujours lisible, quelle que soit la longueur ou la taille du canevas en fonction du nombre de mots pour la ligne, de la longueur des mots, etc. .
const COLOURS = { BLUE: "#33b8e1", BLACK: "#000000", } const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const images_path = path.join(__dirname, 'images/'); const files_length = fs.readdirSync(images_path).length; const images_folder = process.env.ENVIRONMENT === "local" ? "./images/" : "/var/task/images/"; registerFont("/var/task/fonts/open-sans.bold.ttf", { family: "OpenSansBold" }); registerFont("/var/task/fonts/open-sans.regular.ttf", { family: "OpenSans" }); console.log("1. Created canvas"); const canvas = createCanvas(1118, 806); let image = await loadImage(`${images_folder}/${Math.floor(Math.random() * (files_length - 1 + 1)) + 1}.jpg`); let textBlockHeight = 0; console.log("2. Image loaded"); const canvasWidth = canvas.width; const canvasHeight = canvas.height; const aspectRatio = image.width / image.height; console.log("3. Defined ASPECT RATIO",) let drawWidth, drawHeight; if (image.width > image.height) { // Landscape orientation: fit by width drawWidth = canvasWidth; drawHeight = canvasWidth / aspectRatio; } else { // Portrait orientation: fit by height drawHeight = canvasHeight; drawWidth = canvasHeight * aspectRatio; } // Center the image const x = (canvasWidth - drawWidth) / 2; const y = (canvasHeight - drawHeight) / 2; const ctx = canvas.getContext("2d"); console.log("4. Centered Image") ctx.drawImage(image, x, y, drawWidth, drawHeight);
Enfin, le canevas est converti en tampon PNG.
console.log("4.1 Text splitting"); if (splitText.length === 1) { const isItWiderThanHalf = ctx.measureText(splitText[0]).width > ((canvasWidth / 2) + 160); const wordCount = splitText[0].split(" ").length; if (isItWiderThanHalf && wordCount > 4) { const refactored_line = splitText[0].split(" ").reduce((acc, curr, i) => { if (i % 3 === 0) { acc.push([curr]); } else { acc[acc.length - 1].push(curr); } return acc; }, []).map((item) => item.join(" ")); refactored_line[1] = "[s]" + refactored_line[1] + "[s]"; splitText = refactored_line } } let tagline = splitText.filter(item => item !== '' && item !== '[br]' && item !== '[s]' && item !== '[/s]' && item !== '[s]'); let headlineSentences = []; let lineCounter = { total: 0, reduced_line_counter: 0, reduced_lines_indexes: [] } console.log("4.2 Tagline Preparation", tagline); for (let i = 0; i < tagline.length; i++) { let line = tagline[i]; if (line.includes("[s]") || line.includes("[/s]")) { const finalLine = line.split(/(\[s\]|\[\/s\])/).filter(item => item !== '' && item !== '[s]' && item !== '[/s]'); const lineWidth = ctx.measureText(finalLine[0]).width const halfOfWidth = canvasWidth / 2; if (lineWidth > halfOfWidth && finalLine[0]) { let splitted_text = finalLine[0].split(" ").reduce((acc, curr, i) => { const modulus = finalLine[0].split(" ").length >= 5 ? 3 : 2; if (i % modulus === 0) { acc.push([curr]); } else { acc[acc.length - 1].push(curr); } return acc; }, []); let splitted_text_arr = [] splitted_text.forEach((item, _) => { let lineText = item.join(" "); item = lineText splitted_text_arr.push(item) }) headlineSentences[i] = splitted_text_arr[0] + '/s/' if (splitted_text_arr[1]) { headlineSentences.splice(i + 1, 0, splitted_text_arr[1] + '/s/') } } else { headlineSentences.push("/s/" + finalLine[0] + "/s/") } } else { headlineSentences.push(line) } } console.log("5. Drawing text on canvas", headlineSentences); const headlineSentencesLength = headlineSentences.length; let textHeightAccumulator = 0; for (let i = 0; i < headlineSentencesLength; i++) { headlineSentences = headlineSentences.filter(item => item !== '/s/'); const nextLine = headlineSentences[i + 1]; if (nextLine && /^\s*$/.test(nextLine)) { headlineSentences.splice(i + 1, 1); } let line = headlineSentences[i]; if (!line) continue; let lineText = line.trim(); let textY; ctx.font = " 72px OpenSans"; const cleanedUpLine = lineText.includes('/s/') ? lineText.replace(/\s+/g, ' ') : lineText; const lineWidth = ctx.measureText(cleanedUpLine).width const halfOfWidth = canvasWidth / 2; lineCounter.total += 1 const isLineTooLong = lineWidth > (halfOfWidth + 50); if (isLineTooLong) { if (lineText.includes(':')) { const split_line_arr = lineText.split(":") if (split_line_arr.length > 1) { lineText = split_line_arr[0] + ":"; if (split_line_arr[1]) { headlineSentences.splice(i + 1, 0, split_line_arr[1]) } } } ctx.font = "52px OpenSans"; lineCounter.reduced_line_counter += 1 if (i === 0 && headlineSentencesLength === 2) { is2LinesAndPreviewsWasReduced = true } lineCounter.reduced_lines_indexes.push(i) } else { if (i === 0 && headlineSentencesLength === 2) { is2LinesAndPreviewsWasReduced = false } } if (lineText.includes("/s/")) { lineText = lineText.replace(/\/s\//g, ""); if (headlineSentencesLength > (i + 1) && i < headlineSentencesLength - 1 && nextLine) { if (nextLine.slice(0, 2).includes("?") && nextLine.length < 3) { lineText += '?'; headlineSentences.pop(); } if (nextLine.slice(0, 2).includes(":")) { lineText += ':'; headlineSentences[i + 1] = headlineSentences[i + 1].slice(2); } } let lineWidth = ctx.measureText(lineText).width let assignedSize; if (lineText.split(" ").length <= 2) { if (lineWidth > (canvasWidth / 2.35)) { ctx.font = "84px OpenSansBold"; assignedSize = 80 } else { ctx.font = "84px OpenSansBold"; assignedSize = 84 } } else { if (i === headlineSentencesLength - 1 && lineWidth < (canvasWidth / 2.5) && lineText.split(" ").length === 3) { ctx.font = "84px OpenSansBold"; assignedSize = 84 } else { lineCounter.reduced_line_counter += 1; ctx.font = "52px OpenSansBold"; assignedSize = 52 } lineCounter.reduced_lines_indexes.push(i) } lineWidth = ctx.measureText(lineText).width if (lineWidth > (canvasWidth / 2) + 120) { if (assignedSize === 84) { ctx.font = "72px OpenSansBold"; } else if (assignedSize === 80) { ctx.font = "64px OpenSansBold"; textHeightAccumulator += 8 } else { ctx.font = "52px OpenSansBold"; } } } else { const textWidth = ctx.measureText(lineText).width if (textWidth > (canvasWidth / 2)) { ctx.font = "44px OpenSans"; textHeightAccumulator += 12 } else if (i === headlineSentencesLength - 1) { textHeightAccumulator += 12 } } ctx.fillStyle = "white"; ctx.textAlign = "center"; const textHeight = ctx.measureText(lineText).emHeightAscent; textHeightAccumulator += textHeight; if (headlineSentencesLength == 3) { textY = (canvasHeight / 3) } else if (headlineSentencesLength == 4) { textY = (canvasHeight / 3.5) } else { textY = 300 } textY += textHeightAccumulator; const words = lineText.split(' '); console.log("words", words, lineText, headlineSentences) const capitalizedWords = words.map(word => { if (word.length > 0) return word[0].toUpperCase() + word.slice(1) return word }); const capitalizedLineText = capitalizedWords.join(' '); ctx.fillText(capitalizedLineText, canvasWidth / 2, textY); }
Enfin!!! Téléchargement de l'image sur WordPress
Après avoir généré avec succès le tampon d'image, la fonction uploadImageToWordpress est appelée.
Cette fonction gère le gros du travail consistant à envoyer l'image à WordPress à l'aide de son API REST en codant l'image pour WordPress.
La fonction prépare d'abord le slogan à utiliser comme nom de fichier en nettoyant les espaces et les caractères spéciaux :
const buffer = canvas.toBuffer("image/png"); return buffer;
Le buffer d'image est ensuite converti en objet Blob pour le rendre compatible avec l'API WordPress :
const file = new Blob([buffer], { type : "image/png" });
Préparation de la requête API À l'aide de l'image et du slogan encodés, la fonction crée un objet FormData et j'ajoute des métadonnées facultatives, telles que alt_text pour l'accessibilité et une légende pour le contexte.
const createSlug = (string) => { return string.toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, ''); }; const image_name = createSlug(tagline);
Pour l'authentification, le nom d'utilisateur et le mot de passe de l'application sont encodés en Base64 et inclus dans les en-têtes de requête :
formData.append("file", file, image_name + ".png"); formData.append("alt_text", `${tagline} image`); formData.append("caption", "Uploaded via API");
Envoi de l'image Une requête POST est faite au point de terminaison média WordPress avec les données et en-têtes préparés et après avoir attendu la réponse, je valide le succès ou les erreurs.
const credentials = `${username}:${app_password}`; const base64Encoded = Buffer.from(credentials).toString("base64");
En cas de succès, je renvoie la même réponse médiatique dans le lambda.
Voici à quoi ressemble ma lambda au final.
const response = await fetch(`${wordpress_url}wp-json/wp/v2/media`, { method: "POST", headers: { Authorization: "Basic " + base64Encoded, contentType: "multipart/form-data", }, body: formData, }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Error uploading image: ${response.statusText}, Details: ${errorText}`); }
Ceci est un exemple d'image produit par mon script. Il n'est pas utilisé en production, juste créé avec des actifs génériques pour cet exemple.
Conséquences
Un certain temps a passé et tout le monde est heureux que nous n'ayons plus d'articles sans images de mauvaise qualité ou vides, que les images correspondent étroitement à celles que le designer crée, le designer est heureux de pouvoir se concentrer uniquement sur concevoir pour d'autres efforts de marketing à travers l'entreprise.
Mais ensuite un nouveau problème est apparu : parfois, le client n'aimait pas l'image générée et il me demandait de lancer mon script pour en générer une nouvelle pour un article spécifique.
Cela m'a amené à ma prochaine quête secondaire : un Plugin Wordpress pour générer manuellement une image en vedette à l'aide de l'intelligence artificielle pour une publication spécifique
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds











Python convient plus aux débutants, avec une courbe d'apprentissage en douceur et une syntaxe concise; JavaScript convient au développement frontal, avec une courbe d'apprentissage abrupte et une syntaxe flexible. 1. La syntaxe Python est intuitive et adaptée à la science des données et au développement back-end. 2. JavaScript est flexible et largement utilisé dans la programmation frontale et côté serveur.

Les principales utilisations de JavaScript dans le développement Web incluent l'interaction client, la vérification du formulaire et la communication asynchrone. 1) Mise à jour du contenu dynamique et interaction utilisateur via les opérations DOM; 2) La vérification du client est effectuée avant que l'utilisateur ne soumette les données pour améliorer l'expérience utilisateur; 3) La communication de rafraîchissement avec le serveur est réalisée via la technologie AJAX.

L'application de JavaScript dans le monde réel comprend un développement frontal et back-end. 1) Afficher les applications frontales en créant une application de liste TODO, impliquant les opérations DOM et le traitement des événements. 2) Construisez RestulAPI via Node.js et Express pour démontrer les applications back-end.

Comprendre le fonctionnement du moteur JavaScript en interne est important pour les développeurs car il aide à écrire du code plus efficace et à comprendre les goulots d'étranglement des performances et les stratégies d'optimisation. 1) Le flux de travail du moteur comprend trois étapes: analyse, compilation et exécution; 2) Pendant le processus d'exécution, le moteur effectuera une optimisation dynamique, comme le cache en ligne et les classes cachées; 3) Les meilleures pratiques comprennent l'évitement des variables globales, l'optimisation des boucles, l'utilisation de const et de locations et d'éviter une utilisation excessive des fermetures.

Python et JavaScript ont leurs propres avantages et inconvénients en termes de communauté, de bibliothèques et de ressources. 1) La communauté Python est amicale et adaptée aux débutants, mais les ressources de développement frontal ne sont pas aussi riches que JavaScript. 2) Python est puissant dans les bibliothèques de science des données et d'apprentissage automatique, tandis que JavaScript est meilleur dans les bibliothèques et les cadres de développement frontaux. 3) Les deux ont des ressources d'apprentissage riches, mais Python convient pour commencer par des documents officiels, tandis que JavaScript est meilleur avec MDNWEBDOCS. Le choix doit être basé sur les besoins du projet et les intérêts personnels.

Les choix de Python et JavaScript dans les environnements de développement sont importants. 1) L'environnement de développement de Python comprend Pycharm, Jupyternotebook et Anaconda, qui conviennent à la science des données et au prototypage rapide. 2) L'environnement de développement de JavaScript comprend Node.js, VScode et WebPack, qui conviennent au développement frontal et back-end. Le choix des bons outils en fonction des besoins du projet peut améliorer l'efficacité du développement et le taux de réussite du projet.

C et C jouent un rôle essentiel dans le moteur JavaScript, principalement utilisé pour implémenter des interprètes et des compilateurs JIT. 1) C est utilisé pour analyser le code source JavaScript et générer une arborescence de syntaxe abstraite. 2) C est responsable de la génération et de l'exécution de bytecode. 3) C met en œuvre le compilateur JIT, optimise et compile le code de point chaud à l'exécution et améliore considérablement l'efficacité d'exécution de JavaScript.

JavaScript est largement utilisé dans les sites Web, les applications mobiles, les applications de bureau et la programmation côté serveur. 1) Dans le développement de sites Web, JavaScript exploite DOM avec HTML et CSS pour réaliser des effets dynamiques et prend en charge des cadres tels que JQuery et React. 2) Grâce à la réactnative et ionique, JavaScript est utilisé pour développer des applications mobiles multiplateformes. 3) Le cadre électronique permet à JavaScript de créer des applications de bureau. 4) Node.js permet à JavaScript d'exécuter le côté du serveur et prend en charge les demandes simultanées élevées.
