How to Build an AI Prompt Using CFML and/or cfScript (Part 1)

If you’re a ColdFusion developer curious about integrating AI into your projects, this quick-start guide is for you. In this first post of the series, we’ll show how to create a basic AI prompt using CFML and the OpenAI REST API. This version uses the gpt-4 model, styled with Bootstrap 5, and is designed as a simple web form that sends a user prompt and displays the AI’s response.

We’re keeping it lightweight and easy to understand, with no database or persistent storage involved. Just a single index.cfm file that includes both the form and the logic for making the API call. Later parts of this series will expand the features—but for now, this is your foundational example.


Full Code Example


<!--- index.cfm --->
<cfoutput>
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Tica AI Demo</title>
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css">
  <style>
    body { padding-top: 4rem; }
    pre { background-color: #f8f9fa; padding: 1rem; border-radius: 6px; }
    .btn-primary { background-color: #e25425; border: 5px solid #e25425; }
    .btn-primary:hover { background-color: #f68924; border: 5px solid #f68924; }
    .bg-primary { background-color: #272c69 !important; }
  </style>
</head>
<body>
<div class="container px-5" style="max-width: 800px">
  <h1 class="mb-4 text-center">Tica AI <sup class="badge text-bg-warning text-light fs-6">BETA</sup></h1>
  <form method="post" class="mb-4">
    <div class="mb-3">
      <label for="userPrompt" class="form-label">What can I help you with?</label>
      <textarea name="userPrompt" id="userPrompt" rows="4" class="form-control" required>#htmlEditFormat(form.userPrompt ?: '')#</textarea>
    </div>
    <button type="submit" class="btn btn-primary">Ask Tica <i class="bi bi-send-fill"></i></button>
  </form>

  <cfif structKeyExists(form, "userPrompt")>
    <cfset apiKey = "sk-xxxxxxxx" />
    <cfset userPrompt = trim(form.userPrompt)>

    <div id="spinner" class="text-center mb-4">
      <div class="spinner-border text-primary" role="status">
        <span class="visually-hidden">Loading...</span>
      </div>
      <p class="mt-2">Thinking...</p>
    </div>

    <cfscript>
    requestBody = {
      "model": "gpt-4",
      "messages": [
        { "role": "system", "content": "You are a helpful assistant." },
        { "role": "user", "content": userPrompt }
      ]
    };

    cfhttp(
      url = "https://api.openai.com/v1/chat/completions",
      method = "post",
      result = "openaiResponse"
    ) {
      cfhttpparam(type="header", name="Content-Type", value="application/json");
      cfhttpparam(type="header", name="Authorization", value="Bearer " & apiKey);
      cfhttpparam(type="body", value=serializeJSON(requestBody));
    }
    </cfscript>

    <div class="card mb-5">
      <div class="card-header bg-primary text-white">Tica Says</div>
      <div class="card-body">
        <cfif openaiResponse.statusCode is '200 OK'>
          <cfset jsonResponse = deserializeJSON(openaiResponse.fileContent)>
          <cfset reply = jsonResponse.choices[1].message.content>
          <pre>#htmlEditFormat(reply)#</pre>
        <cfelse>
          <div class="alert alert-danger">
            <strong>Error:</strong> #openaiResponse.statusCode#<br>
            <pre>#htmlEditFormat(openaiResponse.fileContent)#</pre>
          </div>
        </cfif>
      </div>
    </div>

    <script>
      document.getElementById("spinner")?.remove();
    </script>
  </cfif>
</div>
</body>
</html>
</cfoutput>

What’s Next?

This is just the beginning. In Part 2, we’ll add features like persistent chat history, model switching, and maybe even voice input. You’ll see how powerful and flexible CFML can be when combined with modern APIs like OpenAI’s. Stay tuned—and feel free to adapt this code for your own experiments!


About the Author

Dusty Hale
I’m a professional full stack web application developer having worked in multiple application stacks for 27+ years, since 1998. My career began in Atlanta, GA, where I worked as a developer with Kaplan Communications, Spun Logic, and b2bTech. In current times, I am the project director for hale.group. I live in Tamarindo, Costa Rica and work remotely from a dedicated work space.
Dusty Hale Signature

If you’re a ColdFusion developer curious about integrating AI into your projects, this quick-start guide is for you. In this first post of the series, we’ll show how to create a basic AI prompt using CFML and the OpenAI REST API. This version uses the gpt-4 model, styled with Bootstrap 5, and is designed as a simple web form that sends a user prompt and displays the AI’s response.

We’re keeping it lightweight and easy to understand, with no database or persistent storage involved. Just a single index.cfm file that includes both the form and the logic for making the API call. Later parts of this series will expand the features—but for now, this is your foundational example.


Full Code Example


<!--- index.cfm --->
<cfoutput>
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Tica AI Demo</title>
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css">
  <style>
    body { padding-top: 4rem; }
    pre { background-color: #f8f9fa; padding: 1rem; border-radius: 6px; }
    .btn-primary { background-color: #e25425; border: 5px solid #e25425; }
    .btn-primary:hover { background-color: #f68924; border: 5px solid #f68924; }
    .bg-primary { background-color: #272c69 !important; }
  </style>
</head>
<body>
<div class="container px-5" style="max-width: 800px">
  <h1 class="mb-4 text-center">Tica AI <sup class="badge text-bg-warning text-light fs-6">BETA</sup></h1>
  <form method="post" class="mb-4">
    <div class="mb-3">
      <label for="userPrompt" class="form-label">What can I help you with?</label>
      <textarea name="userPrompt" id="userPrompt" rows="4" class="form-control" required>#htmlEditFormat(form.userPrompt ?: '')#</textarea>
    </div>
    <button type="submit" class="btn btn-primary">Ask Tica <i class="bi bi-send-fill"></i></button>
  </form>

  <cfif structKeyExists(form, "userPrompt")>
    <cfset apiKey = "sk-xxxxxxxx" />
    <cfset userPrompt = trim(form.userPrompt)>

    <div id="spinner" class="text-center mb-4">
      <div class="spinner-border text-primary" role="status">
        <span class="visually-hidden">Loading...</span>
      </div>
      <p class="mt-2">Thinking...</p>
    </div>

    <cfscript>
    requestBody = {
      "model": "gpt-4",
      "messages": [
        { "role": "system", "content": "You are a helpful assistant." },
        { "role": "user", "content": userPrompt }
      ]
    };

    cfhttp(
      url = "https://api.openai.com/v1/chat/completions",
      method = "post",
      result = "openaiResponse"
    ) {
      cfhttpparam(type="header", name="Content-Type", value="application/json");
      cfhttpparam(type="header", name="Authorization", value="Bearer " & apiKey);
      cfhttpparam(type="body", value=serializeJSON(requestBody));
    }
    </cfscript>

    <div class="card mb-5">
      <div class="card-header bg-primary text-white">Tica Says</div>
      <div class="card-body">
        <cfif openaiResponse.statusCode is '200 OK'>
          <cfset jsonResponse = deserializeJSON(openaiResponse.fileContent)>
          <cfset reply = jsonResponse.choices[1].message.content>
          <pre>#htmlEditFormat(reply)#</pre>
        <cfelse>
          <div class="alert alert-danger">
            <strong>Error:</strong> #openaiResponse.statusCode#<br>
            <pre>#htmlEditFormat(openaiResponse.fileContent)#</pre>
          </div>
        </cfif>
      </div>
    </div>

    <script>
      document.getElementById("spinner")?.remove();
    </script>
  </cfif>
</div>
</body>
</html>
</cfoutput>

What’s Next?

This is just the beginning. In Part 2, we’ll add features like persistent chat history, model switching, and maybe even voice input. You’ll see how powerful and flexible CFML can be when combined with modern APIs like OpenAI’s. Stay tuned—and feel free to adapt this code for your own experiments!


About the Author

Dusty Hale
I’m a professional full stack web application developer having worked in multiple application stacks for 27+ years, since 1998. My career began in Atlanta, GA, where I worked as a developer with Kaplan Communications, Spun Logic, and b2bTech. In current times, I am the project director for hale.group. I live in Tamarindo, Costa Rica and work remotely from a dedicated work space.
Dusty Hale Signature

Cool Stuff

Perfectly Balanced Text: How to Use text-wrap: balance; in CSS

In modern UX design, it's often the little details that make a website feel polished and professional. One of those details? Perfectly balanced text in headings and paragraphs.

read more

Customizing the WordPress Search Form with Bootstrap 5

WordPress includes a built-in get_search_form() function to render a search field, but the default version is plain and unstyled.

read more

HTML Character Entity Codes Cheat Sheet

HTML character entity codes let you use special characters in your HTML that either can’t be typed directly or would otherwise interfere with HTML syntax.

read more