AWS JavaScript WordPress = 人工知能を使用した楽しいコンテンツ自動化戦略
数か月前、私はテクノロジー分野に焦点を当てたクライアント向けに、AI が生成したコンテンツに関するプロジェクトで共同作業を開始しました。私の役割は主に、Nuxt フロントエンドの ヘッドレス CMS として WordPress を使用して SSG をセットアップすることに重点を置いていました。
クライアントは、この分野に影響を与えるさまざまな傾向や状況について週に数回記事を書いていましたが、サイトへのトラフィックと記事の出力を増やすことを期待して、AI を使用して記事を生成することにしました。
しばらくすると、適切なプロンプトを使用すると、クライアントは人間が書いた記事と完全に一致する情報を入手できるようになり、それらが機械で作成されたものであることを見分けるのは非常に困難になります。
別の機能の開発に移ってからしばらくすると、特定のことを尋ねられるようになりました。
あの、この記事のアイキャッチ画像を更新してもらえますか?
投稿を毎日更新し続けて 2 週間後、ちょっとした発見がありました。
人工知能を使用して、これらの記事のアイキャッチ画像の生成を自動化してみませんか?
投稿の作成はすでに自動化されていますが、アイキャッチ画像を自動化しないのはなぜですか?
自由時間に、コンピューター上で生成 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 で時間をかけてサービスの最終アーキテクチャの図をまとめました。
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 < 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); }
ついに!!!画像を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}`); }
これは私のスクリプトによって生成されたサンプル画像です。これは運用環境では使用されません。この例では汎用アセットを使用して作成されただけです。
余波
しばらく時間が経ち、粗末で空虚に見える画像のない記事がなくなったこと、画像がデザイナーが作成したものとよく一致していること、デザイナーが注目することだけに集中できることに誰もが満足しています。会社全体の他のマーケティング活動のためのデザイン。
しかし、その後、新しい問題が発生しました。クライアントが生成された画像を気に入らないことがあり、特定の投稿用に新しい画像を生成するためにスクリプトを起動するように私に要求することがありました。
これで次のサイドクエストが始まりました: 特定の投稿に対して人工知能を使用して注目の画像を手動で生成する Wordpress プラグイン
以上がAWS JavaScript WordPress = 人工知能を使用した楽しいコンテンツ自動化戦略の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

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

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

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

ホットトピック











さまざまなJavaScriptエンジンは、各エンジンの実装原則と最適化戦略が異なるため、JavaScriptコードを解析および実行するときに異なる効果をもたらします。 1。語彙分析:ソースコードを語彙ユニットに変換します。 2。文法分析:抽象的な構文ツリーを生成します。 3。最適化とコンパイル:JITコンパイラを介してマシンコードを生成します。 4。実行:マシンコードを実行します。 V8エンジンはインスタントコンピレーションと非表示クラスを通じて最適化され、Spidermonkeyはタイプ推論システムを使用して、同じコードで異なるパフォーマンスパフォーマンスをもたらします。

Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

C/CからJavaScriptへのシフトには、動的なタイピング、ゴミ収集、非同期プログラミングへの適応が必要です。 1)C/Cは、手動メモリ管理を必要とする静的に型付けられた言語であり、JavaScriptは動的に型付けされ、ごみ収集が自動的に処理されます。 2)C/Cはマシンコードにコンパイルする必要がありますが、JavaScriptは解釈言語です。 3)JavaScriptは、閉鎖、プロトタイプチェーン、約束などの概念を導入します。これにより、柔軟性と非同期プログラミング機能が向上します。

Web開発におけるJavaScriptの主な用途には、クライアントの相互作用、フォーム検証、非同期通信が含まれます。 1)DOM操作による動的なコンテンツの更新とユーザーインタラクション。 2)ユーザーエクスペリエンスを改善するためにデータを提出する前に、クライアントの検証が実行されます。 3)サーバーとのリフレッシュレス通信は、AJAXテクノロジーを通じて達成されます。

現実世界でのJavaScriptのアプリケーションには、フロントエンドとバックエンドの開発が含まれます。 1)DOM操作とイベント処理を含むTODOリストアプリケーションを構築して、フロントエンドアプリケーションを表示します。 2)node.jsを介してRestfulapiを構築し、バックエンドアプリケーションをデモンストレーションします。

JavaScriptエンジンが内部的にどのように機能するかを理解することは、開発者にとってより効率的なコードの作成とパフォーマンスのボトルネックと最適化戦略の理解に役立つためです。 1)エンジンのワークフローには、3つの段階が含まれます。解析、コンパイル、実行。 2)実行プロセス中、エンジンはインラインキャッシュや非表示クラスなどの動的最適化を実行します。 3)ベストプラクティスには、グローバル変数の避け、ループの最適化、constとletsの使用、閉鎖の過度の使用の回避が含まれます。

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

開発環境におけるPythonとJavaScriptの両方の選択が重要です。 1)Pythonの開発環境には、Pycharm、Jupyternotebook、Anacondaが含まれます。これらは、データサイエンスと迅速なプロトタイピングに適しています。 2)JavaScriptの開発環境には、フロントエンドおよびバックエンド開発に適したnode.js、vscode、およびwebpackが含まれます。プロジェクトのニーズに応じて適切なツールを選択すると、開発効率とプロジェクトの成功率が向上する可能性があります。
