先週、私は光栄にもTheJam.devでプレゼンテーションを行うことができました。これは私にとって生成 AI に関する最初のプレゼンテーションであり、執筆プロセスを支援するという興味深い使用例だと思ったことを共有することができました。
ここで、明確にしておきますが、GenAI を使用してブログ記事を書くという意味ではありません。それはひどいアイデアです。 (IMO!) 代わりに、プロセスの一部でそれがどのように役立つかを検討しました。少し話を戻して背景を説明しましょう。
私は長年にわたってジョン・バーミンガムのファンです。彼は軍事/SF/その他のジャンルで執筆する作家で、非常に魅力的なアイデアを持っています。私が最初に彼を知ったのは、現代の国際海軍艦隊を 1942 年にタイムスリップさせるというアイデアを扱った「時間の軸」三部作でした。
それ自体は素晴らしいことですが、私は彼が軍事的な側面に焦点を当てるだけでなく、「アップタイマー」(未来から来た人々)と同時代人の間の文化の衝突について多くの時間を費やしたことが気に入りました。
トム クランシーに少し似ていると言えるかもしれませんが、アクションだけに焦点を当てているわけではありません。彼の本はどれもかなりお勧めします。すでに読んだことがあれば、下のコメントで知らせてください。
彼の作品のフォロワーとして、私は彼の Patreon に登録しましたが、とても興味深いものでした。彼は今後の作品の章の草稿を共有していますが、より重要なことに、彼は自分のプロセスについてもかなり語っています。私自身、作家として、これは本当に魅力的だと思います。
最近、彼は自身の GenAI の使用法について話し、より「フレームワーク」の観点から GenAI をどのように使用しているかについて話し合いました。つまり、キャラクターの動機を適切なタイミングでどのように持ち込むか、プロットポイントをどのように設定するかです。これはまだ「創造的な」仕事ですが、それ以上のことは...わかりません。仕事の管理?
でも、先ほども言いましたが、本当に面白いと思いましたし、考えさせられました。執筆プロセスを支援する方法として、ブログで GenAI を使用するにはどうすればよいですか?これが私が思いついたものです。
余談ですが、以下で説明するものはすべて Google のGemini APIとイレブンティを利用していますが、他の場所でも確かに役立つでしょう。
私が作成した最初のデモでは、ブログ投稿のタイトルを考えるのを手伝ってくれました。今では、私は通常この問題で苦労することはありませんが、GenAI がより良いタイトルの代替案を提案してくれるのではないかと興味がありました。
私はプロンプトをテストすることから始めました。
ジェミ
ブログ投稿のタイトルが次の場合、タイトルを改善して投稿へのトラフィックを増やす可能性がある 3 つの提案を共有してください:「SOME TITLE」。答えを JSON 形式で提示します。 JSON 結果の最上位キーは「suggestions」である必要があり、各提案では、提案されたタイトルには「title」キー、推論には「reasoning」キーを使用する必要があります。
私が具体的に 3 つの提案を求め、より多くのトラフィックを促進したいと述べていることがわかります。正直に言います。それはちょっとグロくてスパムっぽい感じがします。必ずしもクリックベイトのタイトルが欲しいわけではありません。そうは言っても、タイトルに関する他のアイデアを見てみたいと思いました。
このプロンプトはAI Studioのいくつかのテストでうまく機能するように思えたので、コードに進みました。 Google がエクスポートしたコードを取得し、次のコードを少し書きました。
スクリプト全体は次のとおりです。
#!/usr/bin/env node /* Given an input MD file, grab the title, and ask Google's AI APIs to offer suggestions. */ const fs = require('fs'); const fm = require('front-matter'); require('dotenv').config({path:__dirname + '/.env'}); const { GoogleGenerativeAI, HarmCategory, HarmBlockThreshold, } = require("@google/generative-ai"); const MODEL_NAME = "gemini-pro"; const API_KEY = process.env.GOOGLE_AI_KEY; async function runGenerate(title) { const genAI = new GoogleGenerativeAI(API_KEY); const model = genAI.getGenerativeModel({ model: MODEL_NAME }); const generationConfig = { temperature: 0.9, topK: 1, topP: 1, maxOutputTokens: 2048, }; const safetySettings = [ { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, { category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, { category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, ]; const parts = [ {text: `Given the following title for a blog post, share three suggestions that may improve the title and drive traffic to the post: \"${title}\". Present your answer in JSON form. The top level key of the JSON result should be "suggestions" and each suggestion should use the key "title" for the suggested title and "reasoning" for the reasoning. The returned JSON should look like the following sample: [ { title: "First suggested title", reasoning: "This is the reason for the suggestion." } ] `}, ]; const result = await model.generateContent({ contents: [{ role: "user", parts }], generationConfig, safetySettings, }); const response = result.response; // remove backticks and parse. I'm seeing ```json sometimes too // console.log('DEBUG', response.text()); return JSON.parse(response.text().replace(/```/mg, '').replace(/```json/mg,'')); } (async () => { if(process.argv.length === 2) { console.log('Usage: titlesuggestions.js <<path to md>>'); process.exit(1); } const mdPath = process.argv[2]; if(!fs.existsSync(mdPath)) { console.log(`Unable to find ${mdPath}.`); process.exit(1); } const contents = fs.readFileSync(mdPath,'utf-8'); let title = fm(contents).attributes.title; console.log(`\nGenerating suggestions for: ${title}`); console.log('------------------------------------------------------------------------'); let suggestions = (await runGenerate(title)).suggestions; //console.log(suggestions); suggestions.forEach(s => { console.log(`Suggested Title: ${s['title']}\n\nReasoning: ${s['reasoning']}\n`); console.log('------------------------------------------------------------------------'); }); })();
そしてそれはどのように機能するのでしょうか?このブログ投稿のタイトルは「Generative AI をコンテンツ アシスタントとして使用する」です。
ジェミニが提案したのは次のとおりです。
Suggested Title: The Power of Generative AI: Your New Content Assistant Reasoning: This title emphasizes the strength and potential of generative AI as a content creation tool, capturing the reader's attention and making them curious about the possibilities it offers. ------------------------------------------------------------------------ Suggested Title: Unlock Your Content Creation Potential with Generative AI Reasoning: This title suggests that generative AI can unlock new levels of productivity and creativity in content creation, attracting readers who are looking for ways to enhance their content strategy. ------------------------------------------------------------------------ Suggested Title: Revolutionize Your Content Creation: Meet Your Generative AI Assistant Reasoning: This title highlights the transformative potential of generative AI in content creation, appealing to readers who are eager to adopt cutting-edge technologies to streamline their workflow.
そうですね...それはかなりクールだと思います。しかし、ここではどれも本当に「私の」声のようには感じられません。確かに提案にはいくつかのメリットがあると思いますし、考えさせられることもありますが、当然のことながら、元のタイトルはそのままにしました。
次のデモでは、前付で使用される 1 文のdescription
値の作成という、私があまり好きではない執筆プロセスの一部を検討しました。この文字列は最終的に<meta name="description">
タグに入り、他の場所では使用されません。
これは GenAI の要約機能の優れた使い方だと思いました。私は次のようなプロンプトから始めました。
次のブログ投稿を考慮して、説明として使用する 1 文の要約を作成します。
そして、どんな内容を送るかを考えました。私のブログ投稿には通常、大量のコードサンプルが含まれているため、それがノイズになってしまうのではないかと考えました。したがって、私のロジックは次のようになりました。
このほとんどは最初の例を変更したものですが、クリーンアップの側面を見てみましょう。
function cleanup(str) { str = str.replace(/```(.*?)```/sg, ''); str = str.replace(/---(.*?)---/sg, ''); str = str.replace(/\n{3,}/g, '\n'); return str.trim(); }
これはブログ投稿の内容全体に渡されるため、前付とコード サンプルを削除しました。次に、複数の空白行も置き換えました。スクリプト全体は次のとおりです。
#!/usr/bin/env node /* Given an input MD file, grab the text, scrub code, and ask for a summary. */ const fs = require('fs'); const fm = require('front-matter'); require('dotenv').config({path:__dirname + '/.env'}); const { GoogleGenerativeAI, HarmCategory, HarmBlockThreshold, } = require("@google/generative-ai"); const MODEL_NAME = "gemini-pro"; const API_KEY = process.env.GOOGLE_AI_KEY; async function runGenerate(text) { const genAI = new GoogleGenerativeAI(API_KEY); const model = genAI.getGenerativeModel({ model: MODEL_NAME }); const generationConfig = { temperature: 0.9, topK: 1, topP: 1, maxOutputTokens: 2048, }; const safetySettings = [ { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, { category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, { category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, ]; const parts = [ {text: `Given the following blog post, write a one sentence summary to use as the description:\n${text} `}, ]; const result = await model.generateContent({ contents: [{ role: "user", parts }], generationConfig, safetySettings, }); return result.response.candidates[0].content.parts[0].text; } /* I'm responsible for 'cleaning' up the text before sending to Google. For now, I'll just remove code blocks, but in the future I may remove images too. Also remove double blank lines. Oh, also remove FM. */ function cleanup(str) { str = str.replace(/```(.*?)```/sg, ''); str = str.replace(/---(.*?)---/sg, ''); str = str.replace(/\n{3,}/g, '\n'); return str.trim(); } (async () => { if(process.argv.length === 2) { console.log('Usage: summarysuggestions.j <<path to md>>'); process.exit(1); } const mdPath = process.argv[2]; if(!fs.existsSync(mdPath)) { console.log(`Unable to find ${mdPath}.`); process.exit(1); } let contents = fs.readFileSync(mdPath,'utf-8'); let title = fm(contents).attributes.title; // Make it nicer! contents = cleanup(contents); console.log(`\nGenerating summary suggestion for: ${title}`); console.log('------------------------------------------------------------------------'); let suggestion = (await runGenerate(title)); console.log(suggestion); })();
そして、これは数日前の投稿 「生成 AI を使用して画像ファイル名を改善する」の内容を示しています。
This post explores how Generative AI can be used to enhance image filenames, making them more descriptive, accurate, and consistent.
まさにその通りだと言わざるを得ません!そのための「声」についてはそれほど心配していません。私は先に進み、(完了後)この投稿にそれを使用し、得た(そして使用した)のは次のとおりです。
仮想ライティング アシスタントとして生成 AI を利用することで、コンテンツ作成プロセスを強化します。
これに興味はありますが、レゴ デス スターを見ながら私がとりとめなく説明するのを見てみたいという方は、以下のプレゼンテーションをご覧ください。
上記の両方のスクリプトは私のリポジトリにあり、https: //github.com/cfjedimaster/raymondcamden2023/tree/main/scriptsのスクリプト ディレクトリにあります。
以下のコメントでご意見をお聞かせください。