Heim > Web-Frontend > js-Tutorial > AWS JavaScript WordPress = Unterhaltsame Content-Automatisierungsstrategien mit künstlicher Intelligenz

AWS JavaScript WordPress = Unterhaltsame Content-Automatisierungsstrategien mit künstlicher Intelligenz

Susan Sarandon
Freigeben: 2025-01-05 20:40:47
Original
739 Leute haben es durchsucht

Vor Monaten begann ich mit der Zusammenarbeit an einem Projekt rund um KI-generierte Inhalte für einen Kunden mit Fokus auf den Technologiesektor. Meine Rolle konzentrierte sich hauptsächlich auf die Einrichtung von SSG mit WordPress als Headless CMS für ein Nuxt Frontend.

Der Kunde schrieb ein paar Mal pro Woche Artikel über verschiedene Trends oder Situationen, die sich auf die Branche auswirkten. In der Hoffnung, den Verkehr auf der Website und die Ausgabe von Artikeln zu erhöhen, entschied er sich, KI zur Generierung von Artikeln für ihn zu verwenden.

Nach einiger Zeit verfügte der Kunde mit den richtigen Eingabeaufforderungen über Informationen, die einem von Menschen geschriebenen Artikel nahezu genau entsprachen. Es ist sehr schwierig zu erkennen, dass sie maschinell erstellt wurden.

Irgendwann, nachdem ich an verschiedenen Funktionen gearbeitet hatte, wurde ich ständig nach einer bestimmten Sache gefragt.

Ey, kannst du das vorgestellte Bild für diesen Artikel aktualisieren?

Nach zwei Wochen täglicher Aktualisierung der Beiträge hatte ich einen kleinen Heureka-Moment.

AWS   JavaScript   WordPress = Fun Content Automation Strategies Using Artificial Intelligence

Warum automatisiere ich die Generierung der vorgestellten Bilder für diese Artikel nicht mithilfe von Künstliche Intelligenz?

Wir haben das Schreiben von Beiträgen bereits automatisiert. Warum automatisieren wir nicht auch die vorgestellten Bilder?

In meiner Freizeit habe ich auf meinem Computer mit generativen LLMs experimentiert, sodass ich mehr oder weniger eine genaue Vorstellung davon hatte, wie ich diese Nebenaufgabe angehen sollte. Ich schickte dem Kunden eine Nachricht, in der er detailliert darlegte, wo das Problem liegt, was ich tun möchte und welche Vorteile es mit sich bringen würde. Ohne überzeugend wirken zu müssen, erhielt ich grünes Licht für die Arbeit an dieser Funktion und legte sofort los mein erster Schritt.

1. Architektur, wie die Lösung aussehen wird.

Angesichts der Tatsache, dass ich einige Erfahrung damit hatte, Models vor Ort zu leiten, wusste ich sofort, dass es nicht machbar war, diese Models selbst zu hosten. Nachdem ich das verworfen hatte, fing ich an, mit APIs herumzuspielen, die Bilder basierend auf Texteingabeaufforderungen generierten.

Die vorgestellten Bilder bestanden aus zwei Teilen: der Hauptgrafik und einem einprägsamen Slogan.

Die komponierte Grafik besteht aus einigen Elementen, die sich auf den Artikel beziehen, die auf schöne Weise angeordnet sind, mit einigen Farben und Texturen und einigen angewendeten Mischmodi, um nach dem Branding einige ausgefallene Effekte zu erzielen.

Taglines waren kurze Sätze mit 8–12 Wörtern und einem einfachen Schlagschatten darunter.

Anhand meiner Tests wurde mir klar, dass es nicht praktikabel ist, den KI-Weg zur Bilderzeugung zu verfolgen. Die Bildqualität entsprach nicht den Erwartungen und der Prozess war zu zeitaufwändig, um seinen Einsatz zu rechtfertigen. Wenn man bedenkt, dass dies als AWS Lambda-Funktion ausgeführt würde, bei der sich die Ausführungszeit direkt auf die Kosten auswirkt.

Nachdem ich das verworfen hatte, entschied ich mich für Plan B: Bilder und Design-Assets mithilfe der Canvas-API von JavaScript zusammenführen.

Bei näherer Betrachtung hatten wir hauptsächlich fünf Stile einfacher Beiträge und etwa vier Arten von Texturen, von denen drei die gleiche Textausrichtung, den gleichen Stil und die gleiche Position verwendeten. Nachdem ich etwas nachgerechnet hatte, dachte ich:

Hmm, wenn ich diese 3 Bilder mache, 8 Texturen nehme und mit den Mischmodi spiele, komme ich auf ungefähr 24 Variationen

Angesichts der Tatsache, dass diese drei Arten von Beiträgen den gleichen Textstil hatten, handelte es sich praktisch um eine Vorlage.

Nachdem das geklärt war, wechselte ich zum Slogan-Generator. Ich wollte einen Slogan erstellen, der auf dem Inhalt und Titel des Artikels basiert. Ich habe mich für die Verwendung der ChatGPT-API entschieden, da das Unternehmen bereits dafür bezahlt hat, und nach einigen Experimenten und Optimierungen der Eingabeaufforderungen hatte ich ein sehr gutes MVP für meinen Slogan-Generator.

Nachdem ich die beiden schwierigsten Teile der Aufgabe geklärt hatte, verbrachte ich einige Zeit in Figma, um das Diagramm für die endgültige Architektur meines Dienstes zusammenzustellen.

AWS   JavaScript   WordPress = Fun Content Automation Strategies Using Artificial Intelligence

2. Codierung meines Lambda

Der Plan bestand darin, eine Lambda-Funktion zu erstellen, die in der Lage ist, den Inhalt von Posts zu analysieren, einen Slogan zu generieren und ein vorgestelltes Bild zusammenzustellen – alles nahtlos in WordPress integriert.

Ich werde etwas Code bereitstellen, aber gerade genug, um die Gesamtidee zu vermitteln.

Analyse des Inhalts

Die Lambda-Funktion beginnt mit dem Extrahieren der erforderlichen Parameter aus der Nutzlast des eingehenden Ereignisses:

const { title: request_title, content, backend, app_password} = JSON.parse(event.body);

  • Titel und Inhalt: Diese geben den Kontext des Artikels an.
  • Backend: Die WordPress-Backend-URL für Bild-Uploads.
  • app_password: Das Authentifizierungstoken, das ich zum Hochladen als mein Benutzer mit der Wordpress Rest API verwenden werde.

Generierung des Slogans

Die erste Hauptaufgabe der Funktion besteht darin, mithilfe der Funktion „analysateContent“ einen Slogan zu generieren, der mithilfe der OpenAI-API einen anklickbaren Slogan basierend auf dem Titel und Inhalt des Artikels erstellt.

Unsere Funktion übernimmt den Beitragstitel und den Inhalt, gibt aber einen Slogan, eine Beitragsstimmung, um zu wissen, ob der Beitrag eine positive, negative oder neutrale Meinung ist, und ein optionales Firmensymbol der S&P-Indexunternehmen zurück.

const { Slogan, Sentiment, Unternehmen } = waitanalysateContent({ title: request_title, content });

Dieser Schritt ist entscheidend, da der Slogan direkten Einfluss auf die Ästhetik des Bildes hat.

Erstellen des vorgestellten Bildes

Als nächstes greift die Funktion „generateImage“:

let buffer;

buffer = await generateImage({
    title: tagline,
    company_logo: company_logo,
    sentiment: sentiment,
});

Nach dem Login kopieren
Nach dem Login kopieren

Diese Funktion behandelt:

  • Gestaltung der Komposition.
  • Schichten von Texturen, Farben und Branding-Elementen.
  • Effekte anwenden und den Titel erstellen.

Hier ist eine Schritt-für-Schritt-Anleitung, wie es funktioniert:

Die Funktion „generateImage“ beginnt damit, eine leere Leinwand einzurichten, ihre Abmessungen zu definieren und sie für die Verarbeitung aller Designelemente vorzubereiten.

let buffer;

buffer = await generateImage({
    title: tagline,
    company_logo: company_logo,
    sentiment: sentiment,
});

Nach dem Login kopieren
Nach dem Login kopieren

Von dort wird ein zufälliges Hintergrundbild aus einer vordefinierten Sammlung von Assets geladen. Diese Bilder wurden kuratiert, um zum technologieorientierten Branding zu passen und gleichzeitig genügend Abwechslung zwischen den Beiträgen zu ermöglichen. Das Hintergrundbild wird zufällig basierend auf seiner Stimmung ausgewählt.

Um sicherzustellen, dass jedes Hintergrundbild großartig aussieht, habe ich seine Abmessungen dynamisch basierend auf dem Seitenverhältnis berechnet. Dadurch werden Verzerrungen vermieden, während das visuelle Gleichgewicht erhalten bleibt.

Hinzufügen des Slogans

Der Slogan ist kurz, aber basierend auf einigen Regeln wird dieser wirkungsvolle Satz in überschaubare Teile aufgeteilt und dynamisch gestaltet, um sicherzustellen, dass er immer lesbar ist, unabhängig von Länge oder Leinwandgröße, basierend auf der Wortanzahl für die Zeile, der Wortlänge usw .

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);

Nach dem Login kopieren

Schließlich wird die Leinwand in einen PNG-Puffer umgewandelt.

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);

}

Nach dem Login kopieren

Endlich!!! Hochladen des Bildes in WordPress

Nach erfolgreicher Generierung des Bildpuffers wird die Funktion uploadImageToWordpress aufgerufen.

Diese Funktion übernimmt die schwere Arbeit, das Bild mithilfe seiner REST-API an WordPress zu senden, indem das Bild für WordPress kodiert wird.

Die Funktion bereitet zunächst den Slogan für die Verwendung als Dateiname vor, indem sie Leerzeichen und Sonderzeichen bereinigt:

const buffer = canvas.toBuffer("image/png");
return buffer;
Nach dem Login kopieren

Der Bildpuffer wird dann in ein Blob-Objekt umgewandelt, um es mit der WordPress-API kompatibel zu machen:

const file = new Blob([buffer], { type: "image/png" });

Vorbereiten der API-Anfrage Unter Verwendung des codierten Bilds und der Tagline erstellt die Funktion ein FormData-Objekt und ich füge optionale Metadaten hinzu, wie z. B. alt_text für die Barrierefreiheit und eine Beschriftung für den Kontext.

const createSlug = (string) => {
    return string.toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, '');
};

const image_name = createSlug(tagline);
Nach dem Login kopieren

Zur Authentifizierung werden der Benutzername und das Anwendungspasswort in Base64 codiert und in die Anforderungsheader aufgenommen:

formData.append("file", file, image_name + ".png");
formData.append("alt_text", `${tagline} image`);
formData.append("caption", "Uploaded via API");
Nach dem Login kopieren

Senden des Bildes Eine POST-Anfrage wird mit den vorbereiteten Daten und Headern an den WordPress-Medienendpunkt gestellt und nach dem Warten auf die Antwort überprüfe ich, ob Erfolg oder Fehler vorliegen.

const credentials = `${username}:${app_password}`;
const base64Encoded = Buffer.from(credentials).toString("base64");

Nach dem Login kopieren

Bei Erfolg gebe ich dieselbe Medienreaktion im Lambda zurück.

So sieht mein Lambda am Ende aus.

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}`);
}

Nach dem Login kopieren

Dies ist ein Beispielbild, das von meinem Skript erstellt wurde. Es wird nicht in der Produktion verwendet, sondern nur für dieses Beispiel mit generischen Assets erstellt.

AWS   JavaScript   WordPress = Fun Content Automation Strategies Using Artificial Intelligence

Nachwirkungen

Es ist einige Zeit vergangen und alle sind froh, dass wir keine schäbigen oder leer aussehenden Artikel ohne Bilder mehr haben, dass die Bilder denen, die der Designer erstellt hat, sehr nahe kommen, der Designer ist froh, dass er sich nur noch auf sie konzentrieren kann Gestaltung für andere Marketingmaßnahmen im gesamten Unternehmen.

Aber dann trat ein neues Problem auf: Manchmal gefiel dem Kunden das generierte Bild nicht und er bat mich, mein Skript zu starten, um ein neues für einen bestimmten Beitrag zu erstellen.

Das brachte mich zu meiner nächsten Nebenquest: Ein Wordpress-Plugin zum manuellen Generieren eines hervorgehobenen Bildes mithilfe künstlicher Intelligenz für einen bestimmten Beitrag

Das obige ist der detaillierte Inhalt vonAWS JavaScript WordPress = Unterhaltsame Content-Automatisierungsstrategien mit künstlicher Intelligenz. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage