AI blog post recommendations
This site uses TailwindUI's Spotlight template. It's been an amazing base for me to build from, but it's missing "tags" and "recommended" content by default.
With how approachable AI is now, I was wondering if I could easily add recommended posts to the bottom of my articles.
Markdown, OpenAI's embeddings API, and PineconeDB. That's all it takes to generated semantic recommendations.
For my home page (index.tsx
), my getStaticProps
looks like this:
export async function getStaticProps() {
try {
if (process.env.NODE_ENV === 'production') {
await generateEmbeddings()
await generateRssFeed()
}
} catch (err) {
console.log('error generating embeddings or RSS', err)
}
return {
props: {
articles: (await getAllArticles())
.filter(x => x?.highlight)
.slice(0, 5)
.map(({ component, ...meta }) => meta),
},
}
}
That's all it takes for me to index my new blog content each time I push a new post.
Then, I query PineconeDB via a Next.js API endpoint to provide recommendations (yes, in a useEffect
, don't judge)
import { PineconeClient } from "@pinecone-database/pinecone";
const pinecone = new PineconeClient();
const PINECONE_API_KEY = process.env.PINECONE_API_KEY;
export const getRelatedContent = async (slug, type) => {
await pinecone.init({
environment: "us-west4-gcp",
apiKey: PINECONE_API_KEY as string,
});
const index = pinecone.Index("blog-posts");
const results = await index.query({ queryRequest: { topK: 4, includeMetadata: true, id: `/${type}/${slug}` } })
return results.matches?.slice(1, 4);
}
Overall, super easy. I actually added this functionality while flying from Austin to SF (about 3.5 hours) to visit the Vercel office.
Takeaway
Two startups ago, I remember the very, very painful work some of my colleagues were doing to fit in our product catalog into Elasticsearch for faceted search.
The search kind of worked, but keyword search required nearly perfect matches.
Now I'm pretty sure I could have done it over 3.5 hours with a single Diet Coke and a small bag of pretzels.
AI is extremely deflationary.