Methods for controlling character length for SEO tags

I’m trying to use the chatgpt API to read an article stored in a database to generate titles, H1 tags and other metadata using a python script.

The problem is that I can’t control the length or number of characters for each title. Based on this post, it appears to be a limitation of chatgpt and also generally a difficult problem to solve.

How else can I do this? Perhaps using agentic AI? Perhaps using some kind of recursion in my python script that repeatedly goes back to chatgpt using the same prompt until it returns suitable results?

1 Like

When working with the ChatGPT API to automate content generation like creating titles, keywords, and other metadata from an article stored in a database, your common challenge is controlling the output length—specifically ensuring that titles do not exceed a certain number of characters. This is important, especially for SEO purposes where there are character limits (e.g., 75 characters for a title). The AI doesn’t do a good job of estimating character counts, since it thinks in “tokens”.

Here’s the good news: you can handle this by building a loop in your Python script that interacts with the OpenAI AI API. If the AI generates a title that’s too long, you can send a new request, asking the AI to shorten the title and providing feedback on the previous output. This “iteration” mimics a conversation with the AI, where it learns from its previous attempts and adjusts its response accordingly.

Additionally, you can ensure that automation is successful by using the response_format parameter to produce an enforced JSON output, then able to produce multiple fields for you without “chat”.

Let’s write some script. Let’s start with a fake API request that returns unreliable length response.

The function create_ai_seo will simulate an API response in the form of a JSON object with the parsed seo_title. This seo_title is a string that gets sliced to a random length between 70 to 90 characters, as defined in the function. Then, this JSON object will be returned, and the actual seo_title string is extracted and returned.

Key Points of the API call function:

  • Simulated SEO Title Generation: The function generates a random SEO title of a specific length (between 70-90 characters).
  • JSON-like Response: The simulated response mimics the structure you would get from an OpenAI API, where the content contains a dictionary with the key seo_title.
  • Response Parsing: The function will return the seo_title as an AI JSON respose, as it would be from the structured response.

Step-by-Step Iterative Solution:

  1. Initial Request: Start with a basic request to the ChatGPT API for generating an SEO-optimized title based on the article.
  2. Character Validation: Once the AI generates a title, you validate its length. If it’s too long (let’s say over 75 characters), you send another request to ask it to generate a new title, explaining that the previous title was too long.
  3. Iteration: You repeat this process until you either get a valid title or reach a limit (e.g., after 5 attempts).
  4. Automated Feedback: Each new attempt will have the previous AI response added to the conversation as feedback, guiding the AI in the process of generating shorter responses.

The process mimics human-like interaction with an iterative “conversation,” which is why it’s called “growing chat-like conversation.” Each new message sent to the AI will refer back to previous titles, making the AI more “aware” of the required title length.

The Python Script

Below is the Python script that demonstrates how to achieve this. It will allow you to simulate the interaction where the AI might fail several times before it generates an appropriate title, mimicking real-world failures and corrections in a loop:

import random
import json

# This function simulates the process of calling an API to generate an SEO title.
# In reality, you would connect this to OpenAI or another chatbot API that returns a JSON response.
def create_ai_seo(messages) -> str:
    """Simulate AI call and response generation that actually comes from parsing structured outputs
    args: message list as would be sent to OpenAI API
    Generate a random title of varying lengths between 70-90 characters."""
    print(f"messages sent to AI:\n{messages}")

    # Simulated title content
    seo_title = "SEO Optimized Title for Article " * 5
    title_length = random.randint(70, 90)
    seo_title = seo_title[:title_length]  # Slice to ensure title length matches the random value

    # Simulate the API response as a JSON string (mimicking a real structured API response)
    response = {
        "choices": [
            {
                "message": {
                    "role": "assistant", 
                    "content": json.dumps({"seo_title": seo_title})  # Content is a JSON string
                }
            }
        ]
    }

    # Return the complete JSON response string
    return json.dumps(response)

# Function to validate AI response and check length of seo_title
def validate_seo_title(response_json):
    # Parse the JSON string to extract the seo_title
    response = json.loads(response_json)
    response_content = response["choices"][0]["message"]["content"]
    parsed_response = json.loads(response_content)
    seo_title = parsed_response["seo_title"]  # Get the seo_title from the parsed JSON

    if len(seo_title) > 75:
        return False, seo_title
    return True, seo_title

# Function to simulate the iteration and validate the response
def seo_title_generation_loop(article_text):
    '''The chat history maintains a record of user and assistant exchanges.'''
    messages = [{"role": "user", "content": f"create SEO-optimized title for article: {article_text}"}]
    iteration = 0
    while iteration < 5:
        # Get AI response based on current chat history
        ai_response_json = create_ai_seo(messages)

        # Add the assistant response to chat history
        ai_response = json.loads(ai_response_json)['choices'][0]['message']
        messages.append(ai_response)

        # Validate if the AI title is valid (less than 75 characters)
        is_valid, seo_title = validate_seo_title(ai_response_json)
        
        if is_valid:
            print(f"SEO Title Generated: {seo_title}")
            return seo_title  # Successful generation of a valid title
        
        # If not valid, append a new user message indicating the issue
        print(f"Iteration {iteration + 1}: AI generated title is too long ({len(seo_title)} characters).")
        new_message = {
            "role": "user",
            "content": ("Previous AI generated title is too long. You must shorten the generated title. Try again.\n\n"
                        f"Previous title: `{seo_title}`\n\n"
                        f"The title length is {len(seo_title)} characters, but 75 characters is the maximum.")
        }
        messages.append(new_message)  # Add user correction to the chat history
        iteration += 1

    print("Failed to generate a valid title within 5 iterations.")
    return None  # Return None if the AI couldn't generate a valid title in 5 tries

# Example usage of the script
article_text = "How to Build a Scalable Web Application with Python and Django"
title = seo_title_generation_loop(article_text)
print(f"- final title:\n{title}")

How the Code Works:

  1. Simulating the AI Call (create_ai_seo):

    • This function takes a messages list (simulating the chat history).
    • It generates a random length (between 70-90 characters) for the seo_title.
    • A simulated API response is created, where the seo_title is embedded in the response in a structured format (content inside message).
    • The function then extracts the AI response from the object it just created.
  2. Validating the Title Length (validate_seo_title):

    • After getting the seo_title, the length is checked to see if it’s within the acceptable range (<= 75 characters).
    • If the title is too long, the loop continues, and a new assistant and user message is added, informing the AI about the issue.
  3. Iteration (seo_title_generation_loop):

    • The loop runs up to 5 times, checking if the AI generates a valid title (under 75 characters).
    • After each failed attempt (if the title is too long), a new message is appended to the conversation, instructing the AI to shorten the title.
  4. Final Result:

    • The loop stops either when a valid title is generated or after 5 iterations if the AI cannot generate a valid title.

Key Concepts:

  • Structured Output: The create_ai_seo function simulates returning a structured JSON response that includes the seo_title, which is extracted and returned.
  • Iteration: The script iterates multiple times if the AI fails to generate a title within the required length. Each iteration adds feedback to guide the AI.
  • Growing Chat History: The growing automated history allows the AI to adjust based on feedback, similar to how a human conversation would help refine an answer. However, this is just an internal chat to reach the final goal.

This approach ensures that your script can control the character length of generated titles and handle failures gracefully, providing an automated system for generating SEO-friendly titles while maintaining character limits. You can refine the messaging sent to the AI within.

The random length generator lets you run it again and again and see variable length of iterations if the output does not conform (the random dice roll can’t learn like the AI calling function you’d put there, though.


Example output with one failure:

messages sent to AI:
[{‘role’: ‘user’, ‘content’: ‘create SEO-optimized title for article: How to Build a Scalable Web Application with Python and Django’}]
Iteration 1: AI generated title is too long (84 characters).

messages sent to AI:
[{‘role’: ‘user’, ‘content’: ‘create SEO-optimized title for article: How to Build a Scalable Web Application with Python and Django’}, {‘role’: ‘assistant’, ‘content’: ‘{“seo_title”: "SEO Optimized Title for Article SEO Optimized Title for Article SEO Optimized Title "}’}, {‘role’: ‘user’, ‘content’: ‘Previous AI generated title is too long. You must shorten the generated title. Try again.\n\nPrevious title: SEO Optimized Title for Article SEO Optimized Title for Article SEO Optimized Title \n\nThe title length is 84 characters, but 75 characters is the maximum.’}]

SEO Title Generated: SEO Optimized Title for Article SEO Optimized Title for Article SEO Optimiz

  • final title:
    SEO Optimized Title for Article SEO Optimized Title for Article SEO Optimiz
3 Likes

One question beforehand:

Why is the character count important in your case? Then we may be able to help way better. :slight_smile:

The models generate tokens. Thus, they may interpret this one tokens. Especially if you use older models.

You can also tell either the model to use its python environment to count.
Or create an API in a GPT or so.

Another approach that may work is in the prompt to tell it to:

  • iterate, verify, criticize, etc.

So it may do this in several iterations until the result is right.

Hope that helps. :slight_smile:

1 Like

Aren’t there any methods for treating this issue using only prompts?

Why is the character count important in your case? Then we may be able to help way better.

This is for SEO, so Google will truncate or redefine your titles and H1 tags if they exceed the “best practices” length.

  • iterate, verify, criticize, etc.

Can this be done in the prompt directly? Do you have an example of a prompt that does what you recommend?

I can also provide my existing prompt, but it’s obviously very specific to my purpose.

Determine the exact number of characters in the following text, including spaces and punctuation, without the quotation marks:

The Best Soft Boiled Eggs Recipe: Tips and Tricks for Perfectly Cooked Eggs

Count all visible characters, ensuring spaces, punctuation marks, and letters are included. Return only the total character count.

Verify your result twice.

Now you could also use this as a template where you replace your text.

This resulted in:

Hope that helps.

P.S.: Use meta prompts to improve your prompts.

1 Like

The initial question is to use the API, not ChatGPT.

The AI model won’t be able to accurately count characters on its own without excessive prompting and generation, like ‘…then, produce a JSON list in format [{“index”: 0, “character_position_letter”: “A”}, {…}], where each letter of SEO title is reproduced individually and the increasing index then shows the length obtained, to then automatically produce a new candidate title if this analysis shows the string is too long.’

Using code interpreter could be an “assistants” option, but requires the AI to write even more multi-turn scripts to use a python tool. $0.03 per session.

The solution I show needs no tools or excess generation, it simply gives the “try again” error with length information if the AI were to produce output too long.

2 Likes