Get started with š• AI and Grok

An introduction to š• AI and the Grok foundational models, with sample code.

#ai#webdev

Grok is š•ā€˜s new foundational AI model. AndĀ as of today, you can get $25 in credits every month to build withĀ it.

In this post, Iā€™ll show you how to build a simple app with Grok andĀ Vercel AI SDK. Weā€™ll build a full-stack application usingĀ Astro, and deploy it toĀ Cloudflare Pages. If youā€™re interested in seeing the full source code for what we build,Ā check it out onĀ GitHub.

Create a project

First, weā€™ll create a new project using theĀ npm create cloudflare CLI - selecting the ā€œAstroā€Ā framework:

Terminal window
$ npm create cloudflare@latest -- grok-starter --framework=astro
$ cd grok-starter

This will create a new project in theĀ grok-starter directory.

Add Vercel AIĀ SDK

Next, weā€™ll add the Vercel AI SDK and theĀ š• AI Provider to ourĀ project.

Terminal window
$ npm install ai @ai-sdk/openai

Letā€™s define an API endpoint that we can use to call the AIĀ model:

src/pages/api/generate.ts
import { createOpenAI } from '@ai-sdk/openai';
import { generateText } from 'ai';
export async function POST({ locals, request }: any) {
const apiKey = locals.runtime.env.XAI_API_KEY;
if (!apiKey) return new Response('No API key provided', { status: 400 });
const xai = createOpenAI({
name: 'xai',
baseURL: 'https://api.x.ai/v1',
apiKey
});
try {
const body = await request.json();
if (!body || !body.prompt) {
return new Response('No prompt provided', { status: 400 });
}
const prompt = body.prompt;
const { text } = await generateText({
model: xai('grok-beta'),
prompt,
});
return new Response(text);
} catch (error) {
console.error(error);
return new Response('Error generating text', { status: 500 });
}
}

Note: this function is typed asĀ any to simplify the tutorial. In theĀ full code, the function isĀ properly typed.

Get an APIĀ key

To use the Grok model, youā€™ll need an API key. You can get one by signing up for an account atĀ console.x.ai. After youā€™ve confirmed your email address, you can generate an APIĀ key:

Get an API key

Add the API key toĀ .dev.vars in the root of yourĀ project:

.dev.vars
XAI_API_KEY="xai-$key"

Run locally

Now we can run the appĀ locally:

Terminal window
$ npm run dev

To generate our first text from Grok, we can send a POST request to theĀ /api/generate endpoint1.

Terminal window
$ xh POST http://localhost:4321/api/generate prompt="What is the capital of France?"
"The capital of France is Paris."

Create a frontendĀ interface

Now we can create a simple frontend interface to interact with our API. InĀ src/pages/index.astro, weā€™ll replace the content generated by Astro with basic styling, and add a form with an input and aĀ button:

src/pages/index.astro
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Grok Starter</title>
<style>
body {
font-family: system-ui, sans-serif;
padding: 2rem;
}
form {
display: flex;
column-gap: 1rem;
}
input {
width: 100%;
padding: 0.5rem;
font-size: 1rem;
border-radius: 0.5rem;
border: 1px solid #ccc;
}
button {
padding: 0.5rem;
font-size: 1rem;
border-radius: 0.5rem;
border: 1px solid #ccc;
background-color: #ccc;
cursor: pointer;
}
#grok-response {
margin-top: 1rem;
white-space: pre-wrap;
word-wrap: break-word;
}
</style>
</head>
<body>
<h1>Grok Starter</h1>
<form id="form">
<input type="text" id="input" placeholder="Enter your text here..." />
<button type="submit">Generate</button>
</form>
<div id="grok-response"></div>
</body>
</html>

This form will render, but submitting it wonā€™t do anything. Letā€™s write a basic function that will take the text from the input and send it to our APIĀ endpoint:

src/pages/index.astro
<html lang="en">
52 collapsed lines
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Grok Starter</title>
<style>
body {
font-family: system-ui, sans-serif;
padding: 2rem;
}
form {
display: flex;
column-gap: 1rem;
}
input {
width: 100%;
padding: 0.5rem;
font-size: 1rem;
border-radius: 0.5rem;
border: 1px solid #ccc;
}
button {
padding: 0.5rem;
font-size: 1rem;
border-radius: 0.5rem;
border: 1px solid #ccc;
background-color: #ccc;
cursor: pointer;
}
#grok-response {
margin-top: 1rem;
white-space: pre-wrap;
word-wrap: break-word;
}
</style>
</head>
<body>
<h1>Grok Starter</h1>
<form id="form">
<input type="text" id="input" placeholder="Enter your text here..." />
<button type="submit">Generate</button>
</form>
<div id="grok-response"></div>
</body>
<script>
const button = document
.getElementById("form")!
.querySelector("button[type='submit']") as HTMLButtonElement;
const input = document.getElementById("input")! as HTMLInputElement;
const grokResponse = document.getElementById(
"grok-response",
)! as HTMLDivElement;
const generateText = async (text: string) => {
input.disabled = true;
button.disabled = true;
button.innerHTML = "Generating...";
const response = await fetch("/api/generate", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
prompt: text,
}),
});
const output = await response.text();
grokResponse.innerHTML = output;
input.disabled = false;
input.value = "";
button.disabled = false;
button.innerHTML = "Generate";
};
const form = document.getElementById("form")!;
form.addEventListener("submit", async (event) => {
event.preventDefault();
await generateText(input.value);
});
</script>
</html>

The complete implementation looks likeĀ this:

src/pages/index.astro
<html lang="en">
<head>
40 collapsed lines
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Grok Starter</title>
<style>
body {
font-family: system-ui, sans-serif;
padding: 2rem;
}
form {
display: flex;
column-gap: 1rem;
}
input {
width: 100%;
padding: 0.5rem;
font-size: 1rem;
border-radius: 0.5rem;
border: 1px solid #ccc;
}
button {
padding: 0.5rem;
font-size: 1rem;
border-radius: 0.5rem;
border: 1px solid #ccc;
background-color: #ccc;
cursor: pointer;
}
#grok-response {
margin-top: 1rem;
white-space: pre-wrap;
word-wrap: break-word;
}
</style>
</head>
<body>
<h1>Grok Starter</h1>
<form id="form">
<input type="text" id="input" placeholder="Enter your text here..." />
<button type="submit">Generate</button>
</form>
<div id="grok-response"></div>
</body>
<script>
const button = document
.getElementById("form")!
.querySelector("button[type='submit']") as HTMLButtonElement;
const input = document.getElementById("input")! as HTMLInputElement;
const grokResponse = document.getElementById(
"grok-response",
)! as HTMLDivElement;
const generateText = async (text: string) => {
input.disabled = true;
button.disabled = true;
button.innerHTML = "Generating...";
const response = await fetch("/api/generate", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
prompt: text,
}),
});
const output = await response.text();
grokResponse.innerHTML = output;
input.disabled = false;
input.value = "";
button.disabled = false;
button.innerHTML = "Generate";
};
const form = document.getElementById("form")!;
form.addEventListener("submit", async (event) => {
event.preventDefault();
await generateText(input.value);
});
</script>
</html>

The final UI can accept prompts and generateĀ responses:

Example of AI endpoint

Deployment

Now that the UI and endpoint work correctly, we can deploy the application. To do this, weā€™ll useĀ Cloudflare Pages. This is a great way to deploy a static site, and itā€™s free for smallĀ projects.

If you havenā€™t created an account already, you can do soĀ here. Once youā€™ve created your account, youā€™ll be able to create a newĀ project.

Once youā€™ve created an account, you can authenticate with the CLI byĀ running:

Terminal window
$ npx wrangler login

Finally, we can deploy our application byĀ running:

Terminal window
$ npm run pages:deploy

This will build the site, and deploy it to CloudflareĀ Pages.

Before we can use it in production, we need to set up the š• API key that we generated earlier. To do this, run the followingĀ command:

Terminal window
$ npx wrangler pages secret put XAI_API_KEY

After setting the secret, you should deploy one more time, to ensure that the secret is available to yourĀ application:

Terminal window
$ npm run pages:deploy

After doing this, you can visit the site and test itĀ out!

Securing the AI endpoint with AIĀ Gateway

We have one more trick up our sleeve. We can useĀ Cloudflare AI Gateway to help protect our application from abuse. Since weā€™re essentially deploying an unprotected API endpoint that would allow anyone to use š• AI/Grok via our application, it would be easy for a malicious actor to use up all ourĀ credits!

AI Gateway allows you to protect your API endpoints from abuse. It works by rate-limiting requests, caching responses, and adding useful logging/analytics to your AIĀ endpoints.

Hereā€™s how to integrate it into yourĀ application:

  1. Enable AI Gateway by visiting theĀ Dashboard and enablingĀ it.
  2. Create a new AI Gateway by clicking the ā€œCreate Gatewayā€Ā button.
  3. Select the ā€œAPIā€ button, and find the ā€œGrokā€ endpointĀ option
  4. Copy this value.

This AI Gateway endpoint is what we will proxy our AI requestsĀ through.

In the src/pages/api/openai.ts file, weā€™ll update the URL to use thisĀ endpoint:

src/pages/api/openai.ts
import { createOpenAI } from '@ai-sdk/openai';
import { generateText } from 'ai';
export async function POST({ locals, request }: { locals: App.Locals; request: Request }) {
const apiKey = locals.runtime.env.XAI_API_KEY;
if (!apiKey) {
return new Response('No API key provided', { status: 400 });
}
const baseURL = 'https://gateway.ai.cloudflare.com/v1/$accountId/grok-starter/grok';
const xai = createOpenAI({
name: 'xai',
baseURL: 'https://api.x.ai/v1',
baseURL
apiKey
});
try {
const body = await request.json();
if (!body || !body.prompt) {
return new Response('No prompt provided', { status: 400 });
}
const prompt = body.prompt;
const { text } = await generateText({
model: xai('grok-beta'),
prompt,
});
return new Response(text);
} catch (error) {
console.error(error);
return new Response('Error generating text', { status: 500 });
}
}

Redeploy your application, and try issuing a request from the UI to your AI endpoint. You should begin seeing logs generated in the AI GatewayĀ console.

AI Gateway log

Finally, we can turn on a few settings to make AI Gateway securely protect our APIĀ endpoint:

  1. ā€œCache Responsesā€. This will cache any response from Grok that matches a previousĀ prompt.
  2. ā€œRate Limit Requestsā€. This will limit the number of requests that can be made to the API endpoint from any given IP address. You can tweak this to be, for instance, 10 requests perĀ minute.
AI Gateway settings

Conclusion

Iā€™m impressed with š• AI and the Grok model! Itā€™s pretty smart, and itā€™s easy to integrate into applications. The $25 free monthly credit theyā€™ve announced is awesome, and Iā€™m excited to keep building with it. In the blog post, they mention support for tool calling and system prompts. This will probably get integrated into Vercel SDK AI soon, so it will be another great model to have in the toolbelt while building AIĀ apps.

If youā€™re interested in seeing the full source code for this project,Ā check it out onĀ GitHub!

Footnotes

  1. This example usesĀ xh, a great cURL alternative, for simplicity. Itā€™s a basic POST request, so adapt to cURL asĀ needed. ā†©