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.
_10/** @type {import('next').NextConfig} */
_10 reactStrictMode: true,
Here we are using the sendText
action to handle the form submission. This action is defined in the _actions.ts
file.
_29import { sendText } from "../_actions";
_29 onSubmit={handleSubmit}
_29 className="flex w-full max-w-2xl flex-col gap-y-4"
_29 value={formState.text}
_29 setFormState({ status: "idle", text: e.target.value })
_29 disabled={formState.status === "submitting"}
_29 placeholder="Paste some long text here or an article and click Summarize."
_29 className="w-full rounded border border-charcoal-700 bg-charcoal-800 px-6 py-4 text-white"
_29 disabled={formState.text === "" || formState.status === "submitting"}
_29 {formState.status === "idle" ? "✨ Summarize ✨" : "Loading..."}
_17import { client } from "@/trigger";
_17import { redirect } from "next/navigation";
_17export async function sendText(data: FormData) {
_17 const text = data.get("text");
_17 const event = await client.sendEvent({
_17 name: "summarize.text",
_17 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.
_49// use Open AI to summarize text from the form
_49 id: "openai-summarizer",
_49 name: "OpenAI – Text Summarizer",
_49 trigger: eventTrigger({
_49 name: "summarize.text",
_49 run: async (payload, io) => {
_49 const result = await io.openai.backgroundCreateChatCompletion(
_49 "Generating summary",
_49 model: "gpt-3.5-turbo-16k",
_49 content: `Summarize the following text with the most unique and helpful points, into a numbered list of key points and takeaways: \n ${payload.text}`,
_49 if (!result.choices || !result.choices[0] || !result.choices[0].message) {
_49 "Failed to post your message to Slack. The content is undefined."
_49 const summary = result.choices[0].message.content;
_49 await io.slack.postMessage("Posting to Slack", {
_49 // replace this with your own channel ID
_49 channel: "C05HNRBV22H",
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.
_83import { CheckCircleIcon, XCircleIcon } from "@heroicons/react/24/solid";
_83import { CompanyIcon } from "@trigger.dev/companyicons";
_83import { useEventRunDetails } from "@trigger.dev/react";
_83import { ButtonLink } from "./Button";
_83import { Spinner } from "./Spinner";
_83export function Summary({ eventId }: { eventId: string }) {
_83 const { isLoading, isError, data, error } = useEventRunDetails(eventId);
_83 <div className="flex w-full flex-col gap-4">
_83 <div className="flex flex-col gap-2">
_83 data?.tasks === undefined || data.tasks.length === 0
_83 {data?.tasks?.map((task) => (
_83 task.status === "COMPLETED"
_83 : task.status === "ERRORED"
_83 name={task.displayKey ?? task.name ?? ""}
_83 {data?.output && data.status === "SUCCESS" && (
_83 <div className="flex flex-col gap-0.5">
_83 <h4 className="text-base font-semibold">Posted to Slack</h4>
_83 <p className="text-charcoal-400 mb-4 text-sm">
_83 {data.output.summary}
_83 {(data?.status === "SUCCESS" || data?.status === "FAILURE") && (
_83 <ButtonLink href={"/"}>Summarize another</ButtonLink>
_83type ProgressItemProps = {
_83 state: "progress" | "completed" | "failed";
_83function ProgressItem({ icon, state, name }: ProgressItemProps) {
_83 <div className="flex items-center gap-2">
_83 {state === "progress" ? (
_83 <Spinner className="h-6 w-6" />
_83 ) : state === "completed" ? (
_83 <CheckCircleIcon className="h-6 w-6 text-emerald-600" />
_83 <XCircleIcon className="h-6 w-6 text-red-600" />
_83 <div className="flex items-center gap-1.5">
_83 <CompanyIcon name={icon} className="h-5 w-5" variant="light" />
_83 <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.