JavaScript Mapping Library
One of the use cases for generative AI that I’ve discussed before is the idea of using the tool to aid in the writing process. I’m not talking about creating content so much as creating suggestions and providing feedback about the content you yourself have created. This past weekend I worked on a "general purpose" tool with this in mind and thought I’d share it to get your feedback. ("You" being the smart readers of this blog who keep me honest when I show something stupid. 😉
The application itself is rather straightforward. It asks two questions – first, what are you trying to accomplish with your writing and what are the desired results? The idea is that you (most likely) have some sort of plan for the content. If it’s developer documentation, this could simply be "To educate a developer audience about how our tool X lets you do Y." For a school setting, it may be the exact assignment from the teacher.
The second question is simply a place to dump your content.
Here’s the UI, built nicely with Shoelace, my new favorite web component-based UI library:
Entering your data and hitting the submit button fires off the call to the server and returns the analysis. I used this as a test for requirements:
"I want to write a paper that changes the hearts and minds of my readers so that they are more open to adopting cats, and making cats as part of their lives. It should be both emotional and practical."
And then pasted in some content I got from Gemini (yes, I used GenAI to generate content I asked GenAI to evaluate) and got this in response:
"Imagine the soft rumble of a purr vibrating in your lap as a sleek, furry head butts gently against your hand, seeking affection. This is the magic of a cat’s companionship, a feeling that transcends words and melts away stress. While some worry about allergies, many hypoallergenic breeds exist, and shelters can help you find the perfect match. Don’t let these concerns prevent you from experiencing the joy of a feline friend."
Remember, writing is a process! Keep working on it, and you’ll have a persuasive and heartfelt essay encouraging cat adoption.
That’s pretty detailed. Now let’s look at the code.
I’m going to skip the frontend code as it’s literally, "take the form values and throw em at the API", so instead we’ll focus on the server, and even there, let’s just demonstrate the Gemini calls. I wrote a function that takes in the two values entered by the user and then wraps it in a prompt. I also used system instructions (in the too-short named si variable below) to guide the responses.
si
const MODEL_NAME = "gemini-1.5-pro-latest";const API_KEY = process.env.GOOGLE_API_KEY;const si = `You are an editor who will evaluate a rough draft based on how well it addresses specific criteria. You will provide feedback and suggestions for improvement.`;const genAI = new GoogleGenerativeAI(API_KEY);const model = genAI.getGenerativeModel({ model: MODEL_NAME, systemInstruction: { parts: [{ text:si }], role:"model" } });async function callGemini(description, content) { 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, }, ]; let text = `Here was the criteria for the content, including requirements and desired outcomes:$ {description}Here is the first draft of the content:$ {content} `; const parts = [ {text}, ]; const result = await model.generateContent({ contents: [{ role: "user", parts }], generationConfig, safetySettings }); //console.log(JSON.stringify(result,null,'t')); try { if(result.response.promptFeedback && result.response.promptFeedback.blockReason) { return { error: `Blocked for $ {result.response.promptFeedback.blockReason}` }; } const response = result.response.candidates[0].content.parts[0].text; return { response }; } catch(e) { // better handling return { error:e.message } } }
The net result is a block of text that is passed to the front end. Since it typically includes Markdown, I used a Markdown processor to display it nicely. Code-wise, this is nothing more than "take the input and feed it to Gemini", so technically it’s not difficult at all, but it seems to work well. Let’s consider two examples.
I began by using this post, Scraping Recipes Using Node.js, Pipedream, and JSON-LD and this set of instructions:
"I want to write a blog post targeting developers that demonstrates how to use Node.js to parse recipes from a web page. "
I then passed in my Markdown, minus frontmatter. Here’s the result:
Target Audience and Tone: While the technical content is good, the introductory section feels a bit informal for a blog post aimed at developers. Phrases like "90% crap" and "go to town" might be too colloquial. Consider a slightly more professional tone, focusing on the technical challenges and solutions.
Clearer Focus on JSON-LD: While you eventually get there, the introduction spends a lot of time discussing irrelevant details about recipe websites and Saffron. Jump into the core topic of JSON-LD and its benefits for recipe parsing more quickly.
Code Structure and Explanation:
More Engaging Conclusion:
Original: "It’s pretty well known now that most, if not all, recipes on the internet…"
Revised: "Many online recipes are structured in a way that makes it difficult to extract just the essential information…"
Original: "I’d normally explain the workflow, but it’s just an HTTP workflow…"
Revised: "To streamline the process, I’ve created a Pipedream workflow… (link to GitHub). While the workflow itself is straightforward, the core logic lies within the Node.js code, which…"
By implementing these suggestions, you can improve the clarity, focus, and engagement of your blog post, making it more informative and valuable for your target audience of developers.
As the writer, the first bullet point is accurate, but doesn’t represent the fact that I’m writing for a personal blog. However, I could have also said that in my first portion. For example, I could have mentioned it was for a personal, not a company blog post. To the second point… eh… maybe. 😉 I do tend to ramble at times. I feel like this is a valid point that I’d consider, but would be 50/50 on rather or not I’d actually do the edit.
Now, the next part, Code Structure and Explanation, is pretty badass. I wasn’t even expecting it to talk about my code samples, and actually, they feel spot on. In fact, the first item is something I noted myself.
Finally, yeah, I suck at conclusions, always have. :>
For my next demo, I reached out to the son of one of my best friends, Tyler Stroz. He had a thirty-four page Word document entitled, "The Plan Behind The Curtain: Operation Fortitude—The Allied Deception Strategy That Was Overshadowed By The Normandy Invasion". I took that Word document, exported to text (knowing it would be an imperfect translation), and used these admittedly vague instructions: "Write a paper discussing any aspect of D-Day. Your paper should include references to source materials."
Here were the results:
Overall: This is a good start to your essay! By incorporating the suggested improvements, you can create a more focused, analytical, and engaging piece of writing that effectively highlights the often-overlooked but crucial role of Operation Fortitude in the success of D-Day.
I asked Ty what he thought (love ya kid, but I’m not reading a 34 page essay on WW2 ;), and he said that the suggestions were detailed and very specific.
If you want to see more of the code, or run it yourself, you can find the repo here: https://github.com/cfjedimaster/ai-testingzone/tree/main/content_assistant. Note you will need a Google Gemini key in order to call the APIs, but you can get that for free, so there’s no reason not too, right?
As a final quick aside, a few months ago I started using code from Todd Sharp for my Gemini demos to handle creating a super simple web server. I knew my Gemini tests would need a serverside solution, and while that’s easy with Netlify or Pipedream, I really wanted something even simpler. Hence the code you’ll see in server.js. I made a change in this iteration where it now more easily handles multiple static files and I’ll probably use this version going forward, but as a reminder, this would normally be done in either something like Express, or hosted up on Netlify. Anyway, enjoy.
server.js
Raymond Camden
You must be logged in to post a comment.
This site uses Akismet to reduce spam. Learn how your comment data is processed.