Overview
This app uses OpenAI to summarize a block of text and then posts the result to Slack.
To get started with this project follow the instructions on the GitHub README page (~5 mins).
Key features:
- Uses Next.js experimental
serverActions
- Uses both our OpenAI and Slack integrations
- Uses React hooks to show the live status of the Job in the UI
Using Next.js Server Actions
This project uses Next.js Server Actions to handle the form submission. The feature is currently experimental but can be enabled in your next.config.js
file using the serverActions
flag.
/** @type {import('next').NextConfig} */
Here we are using the sendText
action to handle the form submission. This action is defined in the _actions.ts
file.
import { sendText } from "../_actions";
className="flex w-full max-w-2xl flex-col gap-y-4"
setFormState({ status: "idle", text: e.target.value })
disabled={formState.status === "submitting"}
placeholder="Paste some long text here or an article and click Summarize."
className="w-full rounded border border-charcoal-700 bg-charcoal-800 px-6 py-4 text-white"
disabled={formState.text === "" || formState.status === "submitting"}
{formState.status === "idle" ? "✨ Summarize ✨" : "Loading..."}
import { client } from "@/trigger";
import { redirect } from "next/navigation";
export async function sendText(data: FormData) {
const text = data.get("text");
const event = await client.sendEvent({
redirect(`/summarize/${event.id}`);
Using our OpenAI and Slack integrations
The Job code itself is very simple. It uses an eventTrigger
which is triggered by the summarize.text
event. The text is then summarized using our OpenAI integration (ChatGPT-3.5 in this case), and then posted to a specific Slack channel using our Slack integration.
// use Open AI to summarize text from the form
name: "OpenAI – Text Summarizer",
run: async (payload, io) => {
const result = await io.openai.backgroundCreateChatCompletion(
model: "gpt-3.5-turbo-16k",
content: `Summarize the following text with the most unique and helpful points, into a numbered list of key points and takeaways: \n ${payload.text}`,
if (!result.choices || !result.choices[0] || !result.choices[0].message) {
"Failed to post your message to Slack. The content is undefined."
const summary = result.choices[0].message.content;
await io.slack.postMessage("Posting to Slack", {
// replace this with your own channel ID
Using React hooks to show the live status of the Job in the UI
Another cool feature of this project is that it uses React hooks to show the live status of the Job using the useEventRunDetails
hook from the @trigger.dev/react
package.
import { CheckCircleIcon, XCircleIcon } from "@heroicons/react/24/solid";
import { CompanyIcon } from "@trigger.dev/companyicons";
import { useEventRunDetails } from "@trigger.dev/react";
import { ButtonLink } from "./Button";
import { Spinner } from "./Spinner";
export function Summary({ eventId }: { eventId: string }) {
const { isLoading, isError, data, error } = useEventRunDetails(eventId);
<div className="flex w-full flex-col gap-4">
<div className="flex flex-col gap-2">
data?.tasks === undefined || data.tasks.length === 0
{data?.tasks?.map((task) => (
task.status === "COMPLETED"
: task.status === "ERRORED"
name={task.displayKey ?? task.name ?? ""}
{data?.output && data.status === "SUCCESS" && (
<div className="flex flex-col gap-0.5">
<h4 className="text-base font-semibold">Posted to Slack</h4>
<p className="text-charcoal-400 mb-4 text-sm">
{(data?.status === "SUCCESS" || data?.status === "FAILURE") && (
<ButtonLink href={"/"}>Summarize another</ButtonLink>
type ProgressItemProps = {
state: "progress" | "completed" | "failed";
function ProgressItem({ icon, state, name }: ProgressItemProps) {
<div className="flex items-center gap-2">
{state === "progress" ? (
<Spinner className="h-6 w-6" />
) : state === "completed" ? (
<CheckCircleIcon className="h-6 w-6 text-emerald-600" />
<XCircleIcon className="h-6 w-6 text-red-600" />
<div className="flex items-center gap-1.5">
<CompanyIcon name={icon} className="h-5 w-5" variant="light" />
<h4 className="text-base">{name}</h4>
This is a simple example of how you can use the hook to show the job status, but of course this can be adapted for different use cases depending on the job.
Get started with this project
You can get started with this project in minutes. Simply follow the instructions on the GitHub README page.