上周,我有幸在TheJam.dev上展示了一个。这是我第一次关于生成式人工智能的演讲,我分享了一个我认为有趣的用例——帮助写作过程。
现在,需要明确的是,我并不是说使用 GenAI 来撰写博客文章,那将是一个可怕的想法。 (IMO!)相反,我研究了它如何帮助完成某些过程。让我回顾一下并提供一些背景知识。
多年来我一直是约翰·伯明翰的粉丝。他是一位作家,擅长军事/科幻/等类型的写作,并且有一些非常有趣的想法。我最初是通过他的《时间轴》三部曲认识他的,该三部曲讲述了现代国际海军舰队被送回到 1942 年的想法。
现在,这本身很酷,但是,我喜欢他不仅关注军事方面,而且花了很多时间谈论“uptimers”(来自未来的人)与同时代人之间的文化冲突。
我想你可能会说它有点像《汤姆克兰西》,但不仅仅专注于动作。我几乎会推荐他的任何一本书,如果您已经读过他的书,请在下面的评论中告诉我。
作为他作品的追随者,我订阅了他的 Patreon,这真的很有趣。他分享了即将出版的作品的章节草稿,但更重要的是,他还谈论了很多他的过程。作为一名作家,我觉得这真的很有趣。
最近,他谈论了自己对 GenAI 的使用,并讨论了他如何从更多的“框架”角度使用它。即如何在适当的时候引入人物的动机,以及如何设置情节点。这仍然是“创造性”的工作,但更多……我不知道。工作管理?
正如我所说,我认为这真的很有趣,它引发了我的思考。我如何在我的博客上使用 GenAI 来帮助写作过程?这就是我的想法。
顺便说一句,我下面讨论的所有内容都使用了 Google 的Gemini API和Eleventy ,但在其他地方肯定会很有用。
我构建的第一个演示涉及帮助我想出博客文章的标题。现在,我通常不会为此烦恼,但我很好奇 GenAI 是否可以建议更好的游戏的替代方案。
我首先测试了一个提示:
双子座
鉴于博客文章的标题如下,请分享三个可能改进标题并增加帖子流量的建议:“SOME TITLE”。以 JSON 形式呈现您的答案。 JSON 结果的顶级键应该是“suggestions”,每个建议都应该使用键“title”作为建议标题,使用“reasoning”作为推理。
您会注意到,我特别询问了三个建议,并说我想帮助增加流量。现在,我说实话。这感觉有点恶心和垃圾。我不一定想要点击诱饵标题。话虽这么说,我想看到一些关于我的标题的其他想法。
该提示似乎在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('------------------------------------------------------------------------'); }); })();
它是如何运作的?这篇博文的标题是:“使用生成式人工智能作为您的内容助手”
双子座的建议是这样的:
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.
是的...我觉得这很酷。然而,这些都不像“我的”声音。我绝对看到了这些建议的一些优点,它给了我一些思考的机会,但显然,我保留了原来的标题。
在我的下一个演示中,我查看了我真正不喜欢的写作过程的一部分,编写了我的前言中使用的一句话description
值。该字符串最终进入我的<meta name="description">
标记,并且不在其他任何地方使用。
我认为这将是 GenAI 摘要功能的绝佳用途。我从这样的提示开始:
鉴于以下博客文章,写一个句子摘要作为描述
然后考虑我要发送什么内容。我的博客文章通常有很多代码示例,我认为这最终会成为噪音。所以我的逻辑变成了:
其中大部分只是第一个示例的修改版本,但让我们看一下清理方面:
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); })();
这是几天前的一篇文章 “使用生成式人工智能改进图像文件名”的内容:
This post explores how Generative AI can be used to enhance image filenames, making them more descriptive, accurate, and consistent.
我不得不说,这真是太到位了!我并不那么担心“声音”。我继续将它用于这篇文章(完成后),并得到(并使用) - 这是:
利用生成式人工智能作为您的虚拟写作助手,增强您的内容创建过程。
如果您对此感兴趣,但您希望看到我一边看乐高死星一边闲聊,您可以观看下面的演示:
上面显示的两个脚本都在我的存储库中,可以在此处的脚本目录中找到: https://github.com/cfjedimaster/raymondcamden2023/tree/main/scripts
请在下面的评论中告诉我您的想法!