Skip to content

Instantly share code, notes, and snippets.

@bdcorps
Created March 2, 2024 22:50
Show Gist options
  • Save bdcorps/7d03f3d9109b8f6cb14cde56c2e69a07 to your computer and use it in GitHub Desktop.
Save bdcorps/7d03f3d9109b8f6cb14cde56c2e69a07 to your computer and use it in GitHub Desktop.
import { Customers } from '@/components/llm-stocks';
import { createAI, getMutableAIState, render } from 'ai/rsc';
import { OpenAI } from 'openai';
import { z } from 'zod';
import { Stripe } from "stripe";
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
async function submitUserMessage(userInput: string) {
'use server';
const aiState = getMutableAIState<typeof AI>();
// Update AI state with new message.
aiState.update([
...aiState.get(),
{
role: 'user',
content: userInput,
},
]);
// render() returns a stream of UI components
const ui = render({
model: 'gpt-4-0125-preview',
provider: openai,
messages: [
{
role: 'system', content: `
You are a CRM conversation bot and you can help users query their data from Stripe. You and the user can discuss and the user can request to create new queries or refine existing ones, in the UI.
Messages inside [] means that it's a UI element or a user event. For example:
- "[Results for query: query with format: format and title: title and description: description. with data" means that a chart/table/number card is shown to that user.
Keep the properties. prefix and the quotes around the property names when referring to properties.
Keep the quotes around the event names when referring to events.
The current time is ${new Date().toISOString()}.
Feel free to be creative with suggesting queries and follow ups based on what you think. Keep responses short and to the point.
Messages inside [] means that it's a UI element or a user event.
If you want to show recent customers, call \`list_customers\`.
If the user wants to complete another impossible task, respond that you are a demo and cannot do that.
Besides that, you can also chat with users and do some calculations if needed.` },
{ role: 'user', content: userInput }
],
// `text` is called when an AI returns a text response (as opposed to a tool call)
text: ({ content, done }) => {
// text can be streamed from the LLM, but we only want to close the stream with .done() when its completed.
// done() marks the state as available for the client to access
if (done) {
aiState.done([
...aiState.get(),
{
role: "assistant",
content
}
]);
}
return <div>{content}</div>
},
tools: {
list_customers: {
description: 'Get the list of customers from Stripe',
parameters: z.object({
noOfCustomers: z.number().describe('number of customers to get')
}).required(),
// flightNumber is inferred from the parameters passed above
render: async function* ({ noOfCustomers }) {
yield <p>Loading...</p>
const customers = await getStripeCustomers(noOfCustomers)
aiState.done([
...aiState.get(),
{
role: "function",
name: "list_customers",
// Content can be any string to provide context to the LLM in the rest of the conversation
content: JSON.stringify(customers),
}
]);
return <Customers customers={customers.data} />
}
}
}
})
return {
id: Date.now(),
display: ui
};
}
// Define the initial state of the AI. It can be any JSON object.
const initialAIState: {
role: 'user' | 'assistant' | 'system' | 'function';
content: string;
id?: string;
name?: string;
}[] = [];
// The initial UI state that the client will keep track of.
const initialUIState: {
id: number;
display: React.ReactNode;
}[] = [];
// AI is a provider you wrap your application with so you can access AI and UI state in your components.
export const AI = createAI({
actions: {
submitUserMessage
},
// Each state can be any shape of object, but for chat applications
// it makes sense to have an array of messages. Or you may prefer something like { id: number, messages: Message[] }
initialUIState,
initialAIState
});
const getStripeCustomers = async (noOfCustomers: number) => {
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2023-10-16',
});
console.log({ noOfCustomers })
const customers = await stripe.customers.list({
limit: noOfCustomers
});
return customers;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment