Creating OpenAI GPTs for (lots of) Fun and (a little) Profit

Author:Murphy  |  View: 23452  |  Time: 2025-03-22 22:23:43
Custom GPTs, Image created using an AI image creation program, DALL-E 3, and edited by the author

OpenAI announced its intent to let customers build their own "GPTs" during their DevDay conference on November 6, 2023. Here's what they said on their corresponding blog that day.

We're rolling out custom versions of ChatGPT that you can create for a specific purpose – called GPTs. GPTs are a new way for anyone to create a tailored version of ChatGPT to be more helpful in their daily life, at specific tasks, at work, or at home – and then share that creation with others. For example, GPTs can help you learn the rules to any board game, help teach your kids math, or design stickers. – OpenAI

Creating custom versions of ChatGPT sounds excellent. But there is a caveat: you must have a Gpt Plus or Enterprise account to use the new GPTs. The cost starts at US$20 per month. However, if other GPT Plus users interact with your custom GPT, OpenAI pays you a small royalty based on the number of user interactions.

Creating Custom GPTs

I spent the last month experimenting with custom GPTs to understand the system's benefits and limitations. I built a creative writing chatbot called the RobGon Dialog Assistant, which suggests new dialog inspired by literature in the public domain. I also created two versions of a chatbot to generate musical chord progressions based on songs in the public domain. The first version, RobGon Chord Composer, loads relevant song data from a simple text file. The second version, RobGon Chord Composer Presto, gets the song data via a custom service I wrote.

Retrieval Augmented Generation

Large Language Models (LLMs), like ChatGPT, often perform better if they can access external data before answering users' questions. This technique is called Retrieval Augmented Generation (RAG) [1]. Instead of only relying on the LLM's internal memory, RAG systems can find and inject relevant text data that may help the language model handle the users' queries.

These retrieval systems can work in different ways. One method is to use a semantic text search based on the user's query to find any related material in a previously indexed database [2]. Another method is to run a pass through the LLM to have it construct queries to retrieve relevant information via an API. Both types of RAG systems are available with custom GPTs. I experimented with both, as explained in the sections below for my chord-composing GPTs.

Here's a diagram showing the components of all three of my custom GPTs.

Components and Dataflow for Custom GPTs, Diagram by Author

For the dialog assistant at the top right, it's straightforward. I created a system prompt to encourage the GPT system to draw upon literature in the public domain to help users write new dialog. I don't pass in external data. The language model uses its built-in memory for the references.

I leveraged the Enhanced Wikifonia Leadsheet Dataset (OpenEWLD) for the two chord-composing chatbots. It's a dataset containing chords, melodies, and metadata of 500 songs in the public domain. The songs are in the MusicXML format, which I converted to a more straightforward text format for music called ABC Notation. I used GPT-3.5 Turbo to get genres and styles for the songs and saved the data in text and Comma Separated Value (CSV) formats.

The first chord composer uses OpenAI's built-in text retrieval system for GPTs to find relevant data and a system to answer user questions. This data type is known as "knowledge" in the GPT system. The second chord composer calls into a custom Flask service I created to search for relevant data to help answer questions. This retrieval method is known as an "action" in the system. These composers have unique system prompts to guide the language model in answering user questions accurately and helpfully. And the second chord composer uses the service to generate a playable MIDI file to hear how the chord progressions sound.

Creating a GPT for Creative Writing

Creating a simple GPT was easy. No programming was necessary. OpenAI made an excellent conversational user interface for creating GPTs. I just answered a few questions, tested, refined, and published it.

As mentioned above, custom GPTs are only available for ChatGPT Plus subscriptions, which cost US$20 per month. As a benefit, upgrading also allows access to additional features like GPT-4, GPT-4 Vision, and DALL-E 3.

Creating my First GPT

Here are the steps I used to create my first custom GPT.

User Interface for Creating a GPT, Screenshots by Author

I logged into my ChatGPT Plus account and clicked the Explore GPTs button on the upper left and then the Create button on the upper right, as shown in the screenshots above.

GPT Builder Screen, Screenshot by Author

Clicking the Create button brought me to the GPT Builder screen, where I did all the work. The left side of the screen shows the two modes, Create and Configure. The right side shows a working preview of the progress of the GPT.

Detailed instructions for creating a GPT are here.

Working with the GPT Builder

I used the Create mode to create my first GPT, the conversational interface. I'll show my full dialog with the GPT Builder and then add my commentary afterward.

Rob: Create a creative writing assistant that draws on dialog from literature in the public domain to assist users in writing new material.

GPT Builder: How about calling it Literary Companion? Would that work for you?

Rob:Call it RobGon Dialog Assistant

GPT Builder: Here's the profile picture I've created for RobGon Dialog Assistant, featuring a quill and an open book in a hand-drawn style. Do you like it, or would you like any changes?

Initial Profile Picture for RobGon Dialog Assistant, Image created using an AI image creation program, DALL-E 3, by the author

Rob: Show items with bold colors and thick black outlines. No lightbulbs, but show red, green, and blue word balloons above, an open book, and a feather pen below.

GPT Builder: I've updated the profile picture according to your instructions, emphasizing bold colors and thick black outlines with red, green, and blue word balloons above an open book and feather pen, all in a pop art style. How does this look to you?

Image created using an AI image creation program, DALL-E 3, by the author

Rob: It's great!

GPT Builder: Fantastic! Now, let's refine how RobGon Dialog Assistant can best serve you. What kind of dialogues or literature do you want it to focus on, or how should it interact with you to make your writing process smoother?

Rob: The user should describe their characters and what they are trying to say. You should recall some relevant works in the public domain to inspire how the new characters will interact. Provide references to any works you draw from, with titles and authors.

GPT Builder: I've updated the instructions to focus on your needs better. Now, when you describe your characters and their intended dialogue, RobGon Dialog Assistant will draw from relevant public domain works to inspire how your characters interact, providing references with titles and authors for each suggestion.

I tested it a bit and saw that it worked well enough. More on this later. I then published the GPT by Clicking the Save button, choosing to publish to Everyone, choosing the Writing category, and clicking Confirm.

I found that the conversation with the GPT Builder went very smoothly. Although I didn't like its suggestions for the name of my new GPT nor the initial image it created using DALL-E 3, it quickly took my refinements and produced good results.

When it asked me how the system should work, it gathered material for the system prompt, which I found on the Configure tab under Instructions. Here is the prompt it built from our interaction.

Instructions: RobGon Dialog Assistant specializes in helping users create new dialogues by drawing inspiration from literature in the public domain. When users describe their characters and their intended interactions, I recall relevant works to inspire how the new characters might interact, providing references to these works with titles and authors. My goal is to enrich users' creative writing by integrating the depth and diversity of classical dialogues, tailoring suggestions to the characters' described personalities, settings, and themes. I ensure that all suggestions remain legally shareable and are clearly attributed to their original authors, enhancing the users' writing with authenticity and historical richness.

These instructions seem to have captured my intent for the assistant. Curiously, the system wrote the instructions in the first person, which I do not typically do when I write system prompts from scratch. The bot seems confident that it will ensure the referenced material will be "legally shareable." Because the bot is not connected to outside sources to check this, it seems to overstate what it can do.

One thing I didn't like was the four "conversation starters" it provided:

  • Help me with a dialogue for a historical scene.
  • Suggest a romantic exchange from classic literature.
  • Provide dialogue for a mystery setting.
  • Offer an example of witty banter from the 19th century.

I intend to allow the GPT to inject new dialog for current works drawing from older public domain works. These examples don't show this.

I had two options to correct this. I could either type new conversation starters manually, which I could do on the Configure tab, or use the conversational editor on the Create tab. I chose to do the latter.

GPT Builder: Welcome back! Is there anything RobGon Dialog Assistant should be doing better? Anything you'd like to change?

Rob: Adjust the conversation starters to show examples of writing new dialog for current settings. Don't mention any old-timey stuff.

GPT Builder: I've updated the conversation starters to focus on creating new dialogues for modern settings, avoiding references to old-timey themes. Is there anything else you'd like to adjust?

That was easy. Here are the updated conversation starters.

  • Create a dialog for a couple who are shopping in a big-box store.
  • Write an exchange between two detectives.
  • Compose a conversation in a virtual reality game.
  • Generate dialogue for a road trip.

These seem much better. There are no more old-timey references, and it has several current-day references, like the big-box store and the virtual reality game.

Complete instructions for using the GPT Builder are here.

Running the Dialog Assistant

Running the new GPT is easy. Simply select it from the list of pinned GPTs on the left and give it a prompt. For example, here is an excerpt from the first conversation starter.

Rob: Create dialog for a couple shoppping in a big-box store.

RobGon Dialog Assistant: For a modern take inspired by classic interactions, imagine a couple, Alex and Jamie, weaving through the aisles of a sprawling big-box store. Their dynamic can draw inspiration from Elizabeth Bennet and Mr. Darcy's witty exchanges in "Pride and Prejudice" by Jane Austen, mixed with a dash of the practicality and partnership found in the relationship between Jo March and Professor Bhaer in "Little Women" by Louisa May Alcott. However, the dialogue will be rooted in a contemporary setting, reflecting the quirks of navigating a large retail space together.

Alex: (Holding up a gigantic pack of toilet paper) "Do we really need this much? Our apartment isn't exactly a warehouse."

Jamie: (Laughing) "It's called being economical, my dear. Besides, it's not like it expires. And hey, look at it as a workout device. Who needs weights?"

Alex: "Right, because nothing says ‘home gym' quite like a twenty-four pack of two-ply."

(They move on, Jamie pushing the cart, Alex flipping through a list on their phone.)

This dialogue captures the essence of a modern couple's interaction – playful, loving, and grounded in the realities of everyday life, much like the literary couples that inspired them, but tailored to the unique setting of a big-box store.

That's pretty good, although Pride and Prejudice and Little Women are not exactly deep cuts from classic literature. I do like the adaptation to a modern setting, however. Notice that this reads more like a screenplay with set directions than literature. Of course, writers can do what they want with it and fold it into their writing style. If you would like to see the complete conversation, you can read it here.

The link below allows you to try out my new GPT. Disclaimer: If you use any of my custom GPTs, I will receive a small commission from OpenAI at no cost to you.

ChatGPT – RobGon Dialog Assistant

Creating GPTs for Composing Musical Chords

For my next set of GPTs, I started with the OpenEWLD dataset with melodies, chords, and metadata from songs in the public domain. I previously worked with this dataset in my AI-tunes project on Medium.

Working in a Google Colab, I downloaded the dataset and used a conversion tool by Wim Vree to convert the songs in MuscXML format to ABC Notation.

ABC Notation for Chords

Here's an example song from the dataset in ABC Notation, "We're In The Money" by Harry Warren.

X:1
T:We're In The Money
C:Harry Warren
M:2/2
K:C
"C" z E G3/2 E/ |"Dm7" F"G7" G3 |"C" z E G3/2 E/ |"Dm7" F"G7" G3 
"C" z e"C+" e3/2 c/ | %5 | "F" d c d"Ab7" c |"C" e c"Dm7" c"G7" d
"C" c2 z2 |"C" z E G3/2 E/ |"Dm7" F"G7" G3 | %10
"C" z E G3/2 E/ |"Dm7" F"G7" G3 |$"C" z e"C+" e3/2 c/
"F" d c d"Ab7" c |"C" e c"Dm7" c"G7" d | %15
"C" c2 z2 |"C" c2 z2 |$ z"Cmaj7" e d/c/B/A/ |"Cmaj7" B B z/ c A/
"Cmaj7" B B2 c |"Cmaj7" B4 |$ %21
"Cmaj7" z e d/c/B/A/ |"Cmaj7" B B z/ B B/ |"Bb" _B B"A7" A A
"Ab7" _A A"G7" G z |$ %25 | "C" z E G3/2 E/ |"Dm7" F"G7" G3
"C" z E G3/2 E/ |"Dm7" F"G7" G3 |$"C" z e"C+" e3/2 c/ | %30
"F" d c d"Ab7" c |"C" e c2"G7" d |"C" c3 z | %33

You can see that the ABC Notation is quite terse. X is the song number, T is the title, C is the composer, M is the meter, and K is the musical key. What follows is the chords in quotes and the melody without quotes. Bars define the measures of the song. The numbers after the percent signs indicate the measure number.

I'm only interested in chords for this project, so I wrote some Python code to extract and keep the chords. Here is the same song, simplified.

X:1
T:We're In The Money
C:Harry Warren
M:2/2
K:C
||C|Dm7 G7|C|Dm7 G7|C C+|F Ab7|C Dm7 G7|C|C|
|Cmaj7|Cmaj7|Cmaj7|Cmaj7|Cmaj7|Cmaj7|Bb A7|Ab7 G7|
|C|Dm7 G7|C|Dm7 G7|C C+|F Ab7|C G7|C|

Generating Song Metadata

To facilitate the retrieval of songs for my chatbot, I used GPT-3.5-turbo to generate metadata with genres and styles for each song. Here's the prompt I used to create the metadata.

Given this song in ABC format, create lists for genres and styles.
{abc_content}
Return with:
genres: 
styles: 

Where {abc_content} was replaced with the song in ABC Notation. Here are the results for "We're in the Money."

genres: jazz, musical
styles: big band, swing

These results are accurate because this tune was in a musical film called "Gold Diggers of 1933" and was a big band song in swing time. The songs in the OpenEWLD dataset are reasonably well known, so GPT-3.5-turbo had no problem reciting the metadata from its digital memory.

I then saved the data in plain text and CSV format to be used by new GPTs.

Setting up the New GPT

To set up the chord-composing GPTs, I followed the recipe above for creative writing. Here's what the new GPT looks like.

The automated configuration system created a profile image, system prompt, and starter conversations well.

Adding Knowledge

The only extra step I needed was to upload the text file with the song information as knowledge and add a line to the system prompt on how to use it.

I used the Upload files button in the GPT Builder screen's Configure tab to add the publice_domain_songs.txt file to the system.

Each GPT can have up to 20 files. Each file can be up to 512 MB in size. When you upload a file, the system breaks the text into chunks and creates semantic embeddings to recall the blocks of text if needed to help answer a question.

I also added this line to the system prompt to ensure that the system knows how to use the data file.

Search the knowledge before answering the request. If a suggestion for a progression comes from the dataset, list the song title and composer.

More information about the GPT knowledge feature is here.

Running the Chord Composer

RobGon Chord Composer, Screenshot by Author

The screenshot above shows that the system seems to work well. I asked it to suggest a chord progression for a love song, and it came up with a variation of the chorus chords for "Let Me Call You Sweetheart" with music by Leo Friedman and lyrics by Beth Slater Whitson. For reference, here is the original chord progression.

C                                    F    A7   D7
Let me call you "Sweetheart," I'm in love with you.

G7                               C    Cdim G7
Let me hear you whisper that you love me   too.

You can see how the suggested progression from the bot is similar but not the same.

C - C7 - F - A7 - D7 - G7 - C

It added a C7, which is fine, but it didn't show the Cdim G7 part at the end of the phrase. The main difference is how long the chords are held, shown as equal time in the suggested chord progression. However, a human composer could work with this new progression and figure out how to adjust the timing to suit their needs.

Extending the Chord Composer

For my third project, I extended the Chord Composer GPT to call into a custom service to get reference compositions. I also added the ability to download a MIDI file to hear the new chord progressions. I call this version RobGon Chord Composer Presto. Here's a system component diagram.

Components and Dataflow for RobGon Chord Composer Presto, Diagram by Author

Like the Chord Composer described above, I start with songs in the public domain in the OpenEWLD dataset. After converting the files from MusicXML to ABC format, I get genre and style info from GPT-3.5 Turbo and save it in CSV format. I set up a custom Flask service that handles queries for songs based on lists of genres and styles. The results go back into the GPT to generate a suggested chord pattern. The system can also create a MIDI file of the generated chord progression using the custom service so the user can hear how it sounds.

Using a Custom Service

I wrote Python code **** for a Flask service that reads the CSV file using the Pandas library and then searches for songs when the caller passes in a list of genres and styles via a URL. The service returns the results as JSON data.

I looked at running this service on Microsoft Azure, Amazon Web Services (AWS), or Google Cloud Platform (GCP). GCP offers perpetual "free tier" hosting on its Cloud Run platform. It's free to run in their Tier 1 regions as long as my service handles fewer than 2 million monthly requests and stays under their CPU and memory usage limits.

Deploying the Service

Deploying my Flask service on Google Cloud Run was straightforward. I followed Google's instructions to get a "Hello world" service running and then added my Python code for searching for songs.

Google Cloud Run UI, Screenshot by Author

I added the Python libraries that I used to the requirements.txt file, music21, pandas, numpy, and markdown2.

Flask==3.0.0
gunicorn==20.1.0
Werkzeug==3.0.1
music21
pandas
numpy
markdown2

Then, I deployed my service using Docker on Cloud Run.

Testing the Action

I tested the system once I got all this set up and deployed. Here is an example URL.

https://server/song_search?genre=jazz&style=blues,ballad

And here are the first two hits. I cap the results to five at most.

[
    {
        "chords": "||Ebmaj7||Bb7||Ebmaj7||D7||G|Gmaj7|G7|Cmaj7|Eb|Bb7|Ebmaj7||Eb|Bb7|Eb6|Bb9sus4|Ab Bb7||Eb||Fm7|Bb7sus4 Bb7|Ebmaj7||Fm7|Bb7sus4|Ebmaj7||D7|Gm|C7|Fm|E7 A7|Ab7 Dbm|Bb7|^D.S. al Coda|Eb Ab7|Eb|",
        "composer": "Jerome  Kern",
        "genres": "jazz, pop, musical",
        "key": "Eb",
        "meter": "2/2",
        "styles": "ballad, swing, show tune",
        "title": "Remind Me"
    },
    {
        "chords": "||F/C C||G7||||C Dm7 D#dim|C/E C G7/D C7/E|F||C G7/D|C/E Eb7|G/D G#dim|D7/A D7|G7 Gdim|G7 ^N.C.|F/C C||G7|||^F5b5|E7 E7b5/B|A7|Dm7|Dm7b5|C/G F Fm6|C ^N.C.|G7||C Cdim||G7 ^N.C.|C F Fm||C|",
        "composer": "Peter De Rose",
        "genres": "jazz, big band, classic pop",
        "key": "C",
        "meter": "4/4",
        "styles": "swing, ballad",
        "title": "Have You Ever Been Lonely"
    },

Both have jazz in the list of genres and ballad and swing in the list of styles.

Configuring GPT Actions

After I deployed and tested my Flask service on Google Cloud Run, I configured an Action in my GPT to call my service to get some song data on demand.

OpenAI's Edit GPT Actions UI, Screenshot by Author

Several configuration steps were required to get this working. I configured the authentication API key that my Flask service checks. Using a secret key prevents unauthorized use of the service. I wrote the schema for my service, which specifies the endpoints and parameters. I also wrote a Privacy policy page that OpenAI requires to inform users about any personal information my service might capture.

I then updated the system prompt by adding the following text to the instructions.

A database of songs in the public domain is available as an action. The web service allows for searching for the genre and style of songs.

It will return up to five songs in the database with the following information: chords: the chords using "|" to mark the measures composer: the composers genres: the musical genre in a comma-separated list key: the musical key meter: the time signature styles: the musical style in a comma-separated list title: the title of the song

Search the database before answering the request. Use one or more results in combination to create a new chord progression inspired by the public domain songs. Typical results for the user will be four or eight measures. List the song titles and composers if any progression suggestions come from this dataset.

These instructions tell the system how to call my custom service and what to do with the returned data.

Testing the Chord Composer Presto

I used the same prompt as last time to test the updated chord composer: "Suggest a progression for a love song."

RobGon Chord Composer Presto, Screenshot by Author

Before the system started typing, it connected to my service with a notification with a purple check mark. It then told me it used "Nice Work If You Can Get It" by George Gershwin as a reference. The system said it was an eight-measure progression but showed 16 measures in the text. However, when I downloaded and played the MIDI file, it was eight measures, with two chords per measure.

Chord Progression for a Love Song, Image by Author

Here's what the piece sounds like.

The first four measures sound great, but the second half seems to wander slightly. The Cmaj7 Fmaj7 turn seems to happen a half-note early. I could either fix it myself or ask the bot to do it. Either way, this is a decent start to creating a new song.

After experimenting with the two Chord Composers, I found that the Presto version with the direct information retrieval method performs better than the one that relies on knowledge lookup. The Presto version tends to be more precise after finding more suitable reference songs.

Further instructions for using GPT Actions are here.

Conclusion

My exploration into custom GPTs highlights the intersection of AI and creativity, mainly through projects like dialog assistants and chord composers. These tools serve as helpful partners, enriching the creative process by drawing on public domain works for inspiration. While access to these chatbots comes at a cost, the blend of AI and creativity offers potential returns and a new dimension to artistic endeavors.

I put links to all three GPTs in the appendix, including a bonus assistant called the RobGonBot that can answer questions about all of my Medium articles.

Source Code and Colab

This project's source code is available on GitHub. I released it under the CC BY-SA license.

Attribution-ShareAlike

Acknowledgments

I would like to thank Jennifer Lim for her help with this project.

References

[1] P. Lewis et al., Retrieval-augmented Generation for Knowledge-intensive NLP Tasks (2020), Advances in Neural Information Processing Systems 33: 9459–9474

[2] H. T. Nguyen, D. H. Phuc, and E. Cambria (2019), Learning short-text semantic similarity with word embeddings and external knowledge sources Knowledge-Based Systems 182: 104842

[3] D. Thulke et al., Efficient retrieval augmented generation from unstructured knowledge for task-oriented dialog (2021), arXiv preprint arXiv:2102.04643

Appendix

Here are links to the three GPTs described in this article, including a bonus bot at the end.

RobGon Dialog Assistant

ChatGPT – RobGon Dialog Assistant

RobGon Chord Composer

ChatGPT – RobGon Chord Composer

RobGon Chord Composer Presto

ChatGPT – RobGon Chord Composer Presto

RobGonBot

ChatGPT – RobGonBot

Tags: AI Data Science Gpt Machine Learning Retrieval Augmented Gen

Comment