Mark Ku's Blog

Introduction

As we know, AI excels at text processing. However, because our German website is a relatively small operation, we lack the manpower to maintain SEO data. To solve this, we're leveraging AI's text processing capabilities to automatically generate SEO data, including titles, descriptions, and keywords. This approach not only saves significant human resources but also improves the site's search engine optimization efficiency by sending data to the AI for processing during page pre-rendering.

The Revolution Brought by AI

Bill Gates once said that much of today's software is "still quite dumb" because it requires a lot of manual input to be useful. He believes that artificial intelligence (AI) agents can change this within the next five years.

From the past's mouse-and-keyboard input and acceptance of only explicit commands, we've moved to different interaction methods involving files, images, audio, and video, and the ability to understand ambiguous human instructions. The advent of AI has changed how humans interact with computers. And with this change in human-computer interaction, every application is worth rewriting with AI.

Technologies Used: Next.js, Azure Open AI, and LangChain

  • Next.js: A React-based framework for building fast static and dynamic web applications. It allows developers to implement API routes directly within the framework, simplifying backend development.
  • Azure Open AI: Everyone knows Microsoft invested in OpenAI. As a licensed partner, whenever a new model is released, Microsoft gets access to it simultaneously, packaging it to provide customized AI services for enterprises.
  • LangChain: This is a framework for integrating multiple large AI models, making it easy to call various large language models. It provides templates, parsers, and dynamic routing, and can typically be integrated with other heterogeneous systems using FastAPI.

How Azure Open AI Works

The reason AI can understand context is that the entire conversation history is sent back with each request. This mechanism allows us to "wrap" the AI before making a request, assigning it a specific role and defining what it can and cannot do.

 You are an SEO expert. Based on the page description provided below, generate an SEO-optimized title, meta description, and keywords. Ensure that the title is engaging and concise, the meta description summarizes the product effectively while enticing users to learn more, and the keywords are relevant to the product's features and market segment. Additionally, translate all content into the language specified by the given language code.
        Company:{companyDescription}
        Ecommerce Page Description: {description}
        Translate Target Language Code: {langCode}
        FormatInstructions: {formatInstructions}

Design Concept for the SEO Meta AI API

  1. Page Request Handling: First, create an API in Next.js that accepts a page description and the target language.
  2. Language Processing: Next, use LangChain to interact with Azure Chat OpenAI to generate SEO-optimized titles, descriptions, and keywords based on the provided page description.
  3. Result Caching: Then, store the keywords based on the page slug for the next pre-render. This also helps reduce Azure AI usage.
  4. Returning the Result: Finally, the generated SEO tag data is returned and used for the page's pre-rendering, aiming for better search engine rankings.

By combining Next.js's frontend technology, Azure AI's language generation capabilities, and LangChain's structured output, we can create an efficient and automated workflow to optimize our website's SEO performance. This method not only saves human resources but also improves the site's visibility and ranking in search engines due to its precise and targeted SEO tag generation.

Automated Generation of SEO-Compliant Tag Data

The generateSEOMetadata function deployed in Next.js utilizes Azure Chat OpenAI and LangChain to process product descriptions and generate corresponding titles, descriptions, and keywords. LangChain's Output Parser ensures that the response received from the AI model meets SEO requirements by extracting only the most critical information.

Next.js Code

import { BaseOutputParser } from '@langchain/core/output_parsers';
import { ChatPromptTemplate } from '@langchain/core/prompts';
import { AzureChatOpenAI } from '@langchain/openai';
import { LogLevel } from '@utils/log/const-logging';
import { serverSideLog } from '@utils/log/server-side-log';
import { genOnceEncodedURI } from '@utils/product/gear';
import { RedisBase } from '@utils/redis/redis-base';
import { NextApiRequest, NextApiResponse } from 'next';


class CustomOutputParser extends BaseOutputParser<string[]> {
    async parse(output: any) {
        const result = output.replaceAll('```json', '').replaceAll('```', ''); // for gpt4
        const json = await JSON.parse(result);

        return json;
    }

    getFormatInstructions() {
        return 'Only the title, description and keywords of the json structure are returned. example :{"title":"","description":"","keywords":""} Please delete any other unnecessary information. Such as python code, Python Flask API, etc.  Give me json result. Do not send back any other information such as python code, Python Flask API, etc.';
    }
}

async function generateSEOMetadata(description: string, langCode: string) {
    // https://{InstanceName}.openai.azure.com/openai/deployments/my-openai-deployment/
    const model = new AzureChatOpenAI({
        azureOpenAIApiKey: 'YOUR_AZURE_OPENAI_API_KEY',
        azureOpenAIApiDeploymentName: 'YOUR_DEPLOYMENT_NAME', // gpt4
        azureOpenAIApiInstanceName: 'YOUR_INSTANCE_NAME', 
        azureOpenAIApiVersion: '2024-02-01', // '2024-02-01',
        temperature: 0, // 控制模型生成的隨機性或創造性
        maxTokens: 500, // 指定模型生成的回應中最大可用的 token(詞的數量)
    });

    const prompt = ChatPromptTemplate.fromTemplate(
        `
        You are an SEO expert. Based on the page description provided below, generate an SEO-optimized title, meta description, and keywords. Ensure that the title is engaging and concise, the meta description summarizes the product effectively while enticing users to learn more, and the keywords are relevant to the product's features and market segment. Additionally, translate all content into the language specified by the given language code.
        Company:{companyDescription}
        Ecommerce Page Description: {description}
        Translate Target Language Code: {langCode}
        FormatInstructions: {formatInstructions}
        `
    );
    const parser = new CustomOutputParser();

    const companyDescription = `NXPower GmbH markets iBUYPOWER® Computer products in Germany, aiming to offer high-quality products at reasonable prices without compromising service.
We produce custom-made PC systems tailored to individual or business needs, ensuring the best possible system within your budget. Each PC is built with care, reflecting our passion and profession.
Every custom PC includes a 3-year pickup and return warranty, extensive testing, and a 24-hour burn-in test. Our sales team ensures you only pay for components you need, and our top IT technicians provide quick assistance for any issues.
We create dream computers to impress and delight you for years. Partnering with experienced and successful online retailers, we benefit from excellent support.
`;

    const chain = prompt.pipe(model).pipe(parser);

    const response = await chain.invoke({
        companyDescription: companyDescription,
        description: description,
        langCode: langCode,
        formatInstructions: parser.getFormatInstructions(),
    });
    
    return response;
}


export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    try {
        const { description = '', slug = '', forceUpdate = false, langCode = 'en' } = req.query;

        if (!description || !slug) {
            return res.status(400).json({ error: 'Description must be a valid string.' });
        }

        const redis = new RedisBase();
        const seoKey = 'SeoMata:' + langCode + ':' + genOnceEncodedURI(slug as string);

        const seoResult = await redis.get(seoKey);

        if (seoResult && !forceUpdate) {
            return res.status(200).json(JSON.parse(seoResult));
        }

        // Process the description with Langchain and Azure AI
        const metadata = await generateSEOMetadata(description as string, langCode as string);

        await redis.setCacheKey(seoKey, JSON.stringify(metadata), -1);
        // Save the metadata by slug to the database

        // return data for pre-rendering
        res.status(200).json(metadata);
    } catch (err) {
        serverSideLog('SEO Schema Error' + JSON.stringify(err), LogLevel.Error);
        return res.status(500).json({ error: err });
    }
}

In a Next.js 14 App Router, call the wrapped Azure AI API from the page's generateMetadata function.

export async function generateMetadata({ params }: Props): Promise<Metadata> {
    // 構建URL

    const pathname = new URL(headers().get('x-url')!).pathname;

    const productData: IStoreModel | null = await getStoreModelData(params.locale, params.slug);

    const description = generateTitleAndDescription(productData);

    if (description === '') {
        return generateDefaultMetadata(params.locale, params.slug);
    }

    const imageUrl = (productData && getAbsoluteImageUrl(productData.desc.info.image)) || '';

    try {
        const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;
        const queryParams = new URLSearchParams({
            description: description,
            langCode: params.locale,
            slug: pathname,
            // forceUpdate: 'true',
        });

        const url = `${baseUrl}/api/lang-chain/seo-schema?${queryParams.toString()}`;

        // 獲取數據
        const response = await fetch(url);
        const seoMeta = await response.json();

        const image: ImageProps = {
            url: imageUrl,
            width: 640,
            height: 640,
            alt: seoMeta.title,
        };

        // 返回Metadata
        return {
            title: seoMeta.title,
            keywords: seoMeta.keywords,
            description: seoMeta.description,
            openGraph: {
                title: seoMeta.title,
                description: seoMeta.description,
                ...(imageUrl && {
                    images: image,
                }),
            },
            twitter: {
                title: seoMeta.title,
                description: seoMeta.description,
                card: 'summary_large_image',
            },
        };
    } catch (e) {
        return generateDefaultMetadata(params.locale, pathname);
    }
}

And in the Middleware, get the slug and pass it in the header.

export default function middleware(request: NextRequest) {
    const pathname = request.nextUrl.pathname;

    request.headers.set('x-url', request.nextUrl.href);
      

    return nextIntlMiddleware(request);
}

PS: The JavaScript version of LangChain isn't very stable. Much of the documentation is incorrect or describes fewer features compared to the Python version. It also tends to produce extra characters with different models, requiring a custom parser to handle. The ecosystem isn't as complete, so for complex scenarios, the Python version is recommended.

How to use

http://www.xxxx.de/api/lang-chain/seo-schema?description={page description }&langCode={translate to lang code}

Example

http://www.xxxx.de/api/lang-chain/seo-schema?description=Case:%20NZXT%20H5%20Flow%20Gaming%20Geh%C3%A4use%20-%20Schwarz%20Processor:%20AMD%20Ryzen%205%205600X%20Processor%20(6x%203.7GHz/32MB%20L3%20Cache)%20Memory:%2016GB%20DDR4/3200MHz%20Memory(G.Skill%20,Corsair,Kingston)%20Storage:%20Video%20Card:%20NVIDIA%20GeForce%20RTX%203050%20-%208GB%20GDDR6X%20(VR-Ready)%20Motherboard:%20ASRock%20B450%20PRO%204%20ATX%20USB%203.1,%20SATA3,%201x%20M.2&langCode=tw

Result

{"title":"頂級遊戲體驗:NZXT H5 Flow 黑色遊戲機殼配備 AMD Ryzen 5 與 RTX 3050","meta_description":"探索 NZXT H5 Flow 遊戲機殼,搭載 AMD Ryzen 5 5600X 處理器、16GB DDR4 記憶體、NVIDIA GeForce RTX 3050 顯示卡,為您的遊戲體驗帶來革命性提升。立即了解更多。","keywords":"NZXT H5 Flow, 遊戲機殼, AMD Ryzen 5 5600X, 16GB DDR4, NVIDIA GeForce RTX 3050, VR準備, ASRock B450 PRO 4, 高性能遊戲電腦"}

Author

Mark Ku

擁有 10+ 年經驗的資深軟體工程師,現為 AI 應用 Builder,專注於大型平台架構與簡化複雜系統設計,從電商系統到訂閱與收費平台,結合 AI Agent、AI 整合與自動化開發,打造高效率且可持續演進的產品技術基礎。Read More

Found this useful?

The author's free tools, daily podcasts and newsletter are all here.

Mark Ku · This article is licensed under CC BY 4.0. Credit the author and link back to the original when reusing it.

Comments

Subscribe to Newsletter

Subscribe to get new posts delivered instantly — never miss a tech share.

By submitting, you agree to receive emails. You can anytime.

Popular Posts

View all
Mark Ku
··602

Oracle Cloud Always Free Tier: Linux Host and Static IP for a $0 Cloud Solution

Oracle Cloud Always Free Tier: Linux Host and Static IP for a $0 Cloud Solution
Mark Ku
··492

Say Goodbye to Postman's Fee Trap! A Hands-on Guide to Bruno, the Open-Source Git-Native API Testing Powerhouse.

Say Goodbye to Postman's Fee Trap! A Hands-on Guide to Bruno, the Open-Source Git-Native API Testing Powerhouse.
Mark Ku
··334

A Free, Open-Source, Notion-like Knowledge Base — A Complete Guide to Deploying and Backing Up Outline Wiki

A Free, Open-Source, Notion-like Knowledge Base — A Complete Guide to Deploying and Backing Up Outline Wiki
Mark Ku
··268

Training Your Own AI Voice: Hardware Requirements, Open-Source Model Comparison, and LoRA Fine-Tuning

Training Your Own AI Voice: Hardware Requirements, Open-Source Model Comparison, and LoRA Fine-Tuning
Mark Ku
··218

Building an Efficient API Management Platform: Deploying Kong Gateway from Scratch - Part 1

Building an Efficient API Management Platform: Deploying Kong Gateway from Scratch - Part 1
Mark Ku
··217

Setting Up Samba on Ubuntu to Share Folders with Windows 11

Setting Up Samba on Ubuntu to Share Folders with Windows 11
利用 Azure AI、LangChain 搭配 Next.js 提升 SEO 效益 - Mark Ku's Tech Notes