検索
ホームページウェブフロントエンドjsチュートリアルAWS JavaScript WordPress = 人工知能を使用した楽しいコンテンツ自動化戦略

数か月前、私はテクノロジー分野に焦点を当てたクライアント向けに、AI が生成したコンテンツに関するプロジェクトで共同作業を開始しました。私の役割は主に、Nuxt フロントエンドの ヘッドレス CMS として WordPress を使用して SSG をセットアップすることに重点を置いていました。

クライアントは、この分野に影響を与えるさまざまな傾向や状況について週に数回記事を書いていましたが、サイトへのトラフィックと記事の出力を増やすことを期待して、AI を使用して記事を生成することにしました。

しばらくすると、適切なプロンプトを使用すると、クライアントは人間が書いた記事と完全に一致する情報を入手できるようになり、それらが機械で作成されたものであることを見分けるのは非常に困難になります。

別の機能の開発に移ってからしばらくすると、特定のことを尋ねられるようになりました。

あの、この記事のアイキャッチ画像を更新してもらえますか?

投稿を毎日更新し続けて 2 週間後、ちょっとした発見がありました。

AWS   JavaScript   WordPress = Fun Content Automation Strategies Using Artificial Intelligence

人工知能を使用して、これらの記事のアイキャッチ画像の生成を自動化してみませんか?

投稿の作成はすでに自動化されていますが、アイキャッチ画像を自動化しないのはなぜですか?

自由時間に、コンピューター上で生成 LLM を実験していたので、このサイドクエストに取り組む方法についてはある程度の確かなアイデアを持っていました。私はクライアントに、何が問題なのか、何をしたいのか、何がメリットになるのかを詳細に伝えるメッセージを送信しました。説得する必要もなく、この機能に取り組むことにゴーサインが得られ、すぐに実行に移しました。私の最初の一歩。

1. ソリューションがどのようなものになるかを設計する。

ローカルでモデルを実行する経験があったことを考えると、それらのモデルを自己ホストするのは不可能であることがすぐに分かりました。それを捨てて、テキストプロンプトに基づいて画像を生成する API を試し始めました。

注目の画像は、メインで構成されたグラフィックとキャッチーなキャッチフレーズの 2 つの部分で構成されています。

合成されたグラフィックは、記事に関連するいくつかの要素であり、ブランディングに続いていくつかの派手な効果を実現するためにいくつかのブレンド モードが適用されたいくつかの色とテクスチャがうまく配置されています。

キャッチフレーズは、その下に単純なドロップ シャドウが付いた 8 ~ 12 単語の短い文でした。

テストの結果、画像生成に AI の道を追求するのは現実的ではないことがわかりました。画質は期待を満たしておらず、プロセスに時間がかかりすぎて使用を正当化できませんでした。これが AWS Lambda 関数として実行されることを考慮すると、実行時間はコストに直接影響します。

それを捨てて、私はプラン B を採用しました。つまり、JavaScript の Canvas API を使用して画像とデザイン アセットを一緒にマッシュするというものです。

詳しく見てみると、主に 5 つのスタイルのシンプルな投稿があり、約 4 種類のテクスチャと、そのうちの 3 つは同じテキストの配置、スタイル、位置を使用していました。いくつかの計算をした後、私は次のように考えました:

うーん、これら 3 つの画像を取得し、8 つのテクスチャを取得し、ブレンド モードで再生すると、ポスト 24 のバリエーションを回避できます

これら 3 種類の投稿のテキスト スタイルが同じであることを考えると、実質的には 1 つのテンプレートでした。

これで解決したので、タグライン ジェネレーターに移りました。記事の内容とタイトルに基づいてキャッチフレーズを作成したいと思いました。会社がすでに料金を支払っていたことを考慮して、ChatGPT の API を使用することにしました。いくつかの実験とプロンプトの調整を経て、キャッチフレーズ ジェネレーターとして非常に優れた MVP が得られました。

タスクの最も難しい 2 つの部分を理解したので、Figma で時間をかけてサービスの最終アーキテクチャの図をまとめました。

AWS   JavaScript   WordPress = Fun Content Automation Strategies Using Artificial Intelligence

2.ラムダのコーディング

計画では、投稿コンテンツの分析、キャッチフレーズの生成、注目の画像の組み立てが可能な Lambda 関数を作成し、これらすべてを WordPress とシームレスに統合することでした。

私はいくつかのコードを提供しますが、全体的なアイデアを ke に伝えるのに十分なだけです。

コンテンツの分析

Lambda 関数は、受信イベント ペイロードから必要なパラメータを抽出することから始まります。

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

  • タイトルとコンテンツ: これらは記事のコンテキストを提供します。
  • backend: 画像アップロード用の WordPress バックエンド URL。
  • app_password: Wordpress Rest API を使用してユーザーとしてアップロードするために使用する認証トークン。

キャッチフレーズの生成

この関数の最初の主要なタスクは、analyzeContent 関数を使用してキャッチフレーズを生成することです。この関数は OpenAI の API を使用して、記事のタイトルとコンテンツに基づいてクリックに値するキャッチフレーズを作成します。

私たちの関数は投稿のタイトルと内容を受け取りますが、キャッチフレーズ、投稿が肯定的、否定的、または中立的な意見であるかどうかを知る投稿のセンチメント、および S&P 指数企業からのオプションの企業シンボルを返します。

const { タグライン、センチメント、会社 } = await AnalyticContent({ title: request_title, content });

キャッチフレーズは画像の美しさに直接影響するため、このステップは非常に重要です。

アイキャッチ画像の作成

次に、generateImage 関数が開始されます。

let buffer;

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

この関数は以下を処理します:

  • 構成をデザインします。
  • テクスチャ、カラー、ブランド要素をレイヤー化します。
  • エフェクトを適用してタイトルを作成します。

これがどのように機能するかを段階的に説明します:

generateImage 関数は、空白のキャンバスを設定し、その寸法を定義し、すべてのデザイン要素を処理できるように準備することから始まります。

let buffer;

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

そこから、事前定義されたアセットのコレクションからランダムな背景画像がロードされます。これらの画像は、投稿全体に十分な多様性を持たせながら、テクノロジー指向のブランディングに合わせて厳選されました。背景画像は感情に基づいてランダムに選択されます。

各背景画像の見栄えを確実にするために、アスペクト比に基づいてその寸法を動的に計算しました。これにより、視覚的なバランスを維持しながら歪みを回避できます。

キャッチフレーズの追加

キャッチフレーズは短いですが、いくつかのルールに基づいて、このインパクトのある文は扱いやすい部分に分割され、行の単語数や単語の長さなどに基づいて長さやキャンバスのサイズに関係なく、常に読みやすいように動的にスタイル設定されています。 .

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

最後に、キャンバスが 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  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  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  (canvasWidth / 2.35)) {

                ctx.font = "84px OpenSansBold";

                assignedSize = 80

            } else {

                ctx.font = "84px OpenSansBold";

                assignedSize = 84

            }
        } else {


            if (i === headlineSentencesLength - 1 && 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);

}

ついに!!!画像をWordPressにアップロードする

画像バッファーが正常に生成された後、uploadImageToWordpress 関数が呼び出されます。

この関数は、WordPress 用に画像をエンコードすることで、REST API を使用して WordPress に画像を送信するという重労働を処理します。

この関数は、まずスペースと特殊文字をクリーンアップして、ファイル名として使用できるタグラインを準備します。

const buffer = canvas.toBuffer("image/png");
return buffer;

画像バッファーは、WordPress API との互換性を保つために Blob オブジェクトに変換されます。

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

API リクエストの準備 エンコードされた画像とタグラインを使用して、関数は FormData オブジェクトを構築し、アクセシビリティのための alt_text やコンテキストのためのキャプションなどのオプションのメタデータを追加します。

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

const image_name = createSlug(tagline);

認証のために、ユーザー名とアプリケーションのパスワードは Base64 でエンコードされ、リクエスト ヘッダーに含まれます。

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

画像の送信 準備されたデータとヘッダーを使用して WordPress メディア エンドポイントに対して POST リクエストが行われ、応答を待った後、成功かエラーかを検証します。

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

成功した場合は、同じメディア応答をラムダで返します。

これが私のラムダが最終的にどのように見えるかです。

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

これは私のスクリプトによって生成されたサンプル画像です。これは運用環境では使用されません。この例では汎用アセットを使用して作成されただけです。

AWS   JavaScript   WordPress = Fun Content Automation Strategies Using Artificial Intelligence

余波

しばらく時間が経ち、粗末で空虚に見える画像のない記事がなくなったこと、画像がデザイナーが作成したものとよく一致していること、デザイナーが注目することだけに集中できることに誰もが満足しています。会社全体の他のマーケティング活動のためのデザイン。

しかし、その後、新しい問題が発生しました。クライアントが生成された画像を気に入らないことがあり、特定の投稿用に新しい画像を生成するためにスクリプトを起動するように私に要求することがありました。

これで次のサイドクエストが始まりました: 特定の投稿に対して人工知能を使用して注目の画像を手動で生成する Wordpress プラグイン

以上がAWS JavaScript WordPress = 人工知能を使用した楽しいコンテンツ自動化戦略の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
JavaScriptの文字列文字を交換しますJavaScriptの文字列文字を交換しますMar 11, 2025 am 12:07 AM

JavaScript文字列置換法とFAQの詳細な説明 この記事では、javaScriptの文字列文字を置き換える2つの方法について説明します:内部JavaScriptコードとWebページの内部HTML。 JavaScriptコード内の文字列を交換します 最も直接的な方法は、置換()メソッドを使用することです。 str = str.replace( "find"、 "置換"); この方法は、最初の一致のみを置き換えます。すべての一致を置き換えるには、正規表現を使用して、グローバルフラグGを追加します。 str = str.replace(/fi

jQuery日付が有効かどうかを確認しますjQuery日付が有効かどうかを確認しますMar 01, 2025 am 08:51 AM

単純なJavaScript関数は、日付が有効かどうかを確認するために使用されます。 関数isvaliddate(s){ var bits = s.split( '/'); var d = new Date(bits [2] '/' bits [1] '/'ビット[0]); return !!(d &&(d.getmonth()1)== bits [1] && d.getdate()== number(bits [0])); } //テスト var

jQueryは要素のパディング/マージンを取得しますjQueryは要素のパディング/マージンを取得しますMar 01, 2025 am 08:53 AM

この記事では、jQueryを使用して、DOM要素の内側のマージン値とマージン値、特に外側の縁と要素の内側の縁の特定の位置を取得して設定する方法について説明します。 CSSを使用して要素の内側と外側の縁を設定することは可能ですが、正確な値を取得するのは難しい場合があります。 // 設定 $( "div.header")。css( "margin"、 "10px"); $( "div.header")。css( "padding"、 "10px"); このコードはそうだと思うかもしれません

10 jQuery Accordionsタブ10 jQuery AccordionsタブMar 01, 2025 am 01:34 AM

この記事では、10個の例外的なjQueryタブとアコーディオンについて説明します。 タブとアコーディオンの重要な違いは、コンテンツパネルの表示方法と非表示にあります。これらの10の例を掘り下げましょう。 関連記事:10 jQueryタブプラグイン

10 jqueryプラグインをチェックする価値があります10 jqueryプラグインをチェックする価値がありますMar 01, 2025 am 01:29 AM

ウェブサイトのダイナミズムと視覚的な魅力を高めるために、10の例外的なjQueryプラグインを発見してください!このキュレーションされたコレクションは、画像アニメーションからインタラクティブなギャラリーまで、多様な機能を提供します。これらの強力なツールを探りましょう。 関連投稿: 1

ノードとHTTPコンソールを使用したHTTPデバッグノードとHTTPコンソールを使用したHTTPデバッグMar 01, 2025 am 01:37 AM

HTTP-Consoleは、HTTPコマンドを実行するためのコマンドラインインターフェイスを提供するノードモジュールです。 Webサーバー、Web Servに対して作成されているかどうかに関係なく、HTTPリクエストで何が起こっているかをデバッグして正確に確認するのに最適です

カスタムGoogle検索APIセットアップチュートリアルカスタムGoogle検索APIセットアップチュートリアルMar 04, 2025 am 01:06 AM

このチュートリアルでは、カスタムGoogle検索APIをブログまたはWebサイトに統合する方法を示し、標準のWordPressテーマ検索関数よりも洗練された検索エクスペリエンスを提供します。 驚くほど簡単です!検索をyに制限することができます

jQueryはscrollbarをdivに追加しますjQueryはscrollbarをdivに追加しますMar 01, 2025 am 01:30 AM

次のjQueryコードスニペットを使用して、Divコンテンツがコンテナ要素領域を超えたときにスクロールバーを追加できます。 (デモンストレーションはありません、それを直接firebugにコピーしてください) // d =ドキュメント // w =ウィンドウ // $ = jQuery var contentarea = $(this)、 wintop = contentarea.scrolltop()、 docheight = $(d).height()、 winheight = $(w).height()、 divheight = $( '#c

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

MantisBT

MantisBT

Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

DVWA

DVWA

Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、