Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AI Example page #789

Merged
merged 10 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions pages/docs/examples/ai-agents-and-rag.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { ResourceGrid, Resource, ExampleGrid } from 'src/shared/Docs/Resources';
import { Example } from 'src/shared/Docs/Examples';

import { BookOpenIcon, VideoCameraIcon, MicrophoneIcon } from "@heroicons/react/24/outline";

export const description = "Learn how to use Inngest for AI automated workflows, AI agents, and RAG."

# AI Agents and RAG

Inngest offers tools to support the development of AI-powered applications. Whether you're building AI agents, automating tasks, or orchestrating and managing AI workflows, Inngest provides features that accommodate various needs and requirements, such as concurrency, debouncing, or throttling (see ["Related Concepts"](#related-concepts)).

## Quick Snippet

Below is an example of a RAG workflow (from this [example app](https://github.com/inngest/inngest-demo-app/)). This asynchronous Inngest function summarizes content via GPT-4 by following these steps:
- Query a vector database for relevant content.
- Retrieve a transcript from an S3 file.
- Combine the transcript and queried content to generate a summary using GPT-4.
- Save the summary to a database and sends a notification to the client.

The function uses [Inngest steps](/docs/learn/inngest-steps) to guarantee automatic retries on failure.

```typescript {{ title: "./inngest/functions.ts" }}
export const summarizeContent = inngest.createFunction(
{ name: 'Summarize content via GPT-4', id: 'summarize-content' },
{ event: 'ai/summarize.content' },
async ({ event, step, attempt }) => {
const results = await step.run('query-vectordb', async () => {
return {
matches: [
{
id: 'vec3',
score: 0,
values: [0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3],
text: casual.sentences(3),
},
{
id: 'vec4',
score: 0.0799999237,
values: [0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4],
text: casual.sentences(3),
},
{
id: 'vec2',
score: 0.0800000429,
values: [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2],
text: casual.sentences(3),
},
],
namespace: 'ns1',
usage: { readUnits: 6 },
};
});

const transcript = await step.run('read-s3-file', async () => {
return casual.sentences(10);
});

// We can globally share throttle limited functions like this using invoke
const completion = await step.invoke('generate-summary-via-gpt-4', {
function: chatCompletion,
data: {
messages: [
{
role: 'system',
content:
'You are a helpful assistant that summaries content for product launches.',
},
{
role: 'user',
content: `Question: Summarize my content: \n${transcript}. \nInformation: ${results.matches
.map((m) => m.text)
.join('. ')}`,
},
],
},
});
// You might use the response like this:
const summary = completion.choices[0].message.content;

await step.run('save-to-db', async () => {
return casual.uuid;
});

await step.run('websocket-push-to-client', async () => {
return casual.uuid;
});
return { success: true, summaryId: casual.uuid };
}
);
```

## App examples
Here are apps that use Inngest to power AI workflows:

<ResourceGrid cols={2}>

<Example example={{
title: "Integrate AI agents with Inngest",
technology: "Next.js, OpenAI",
description: "AI-powered task automation in Next.js using OpenAI and Inngest. Enhance productivity with automated workflows.",
pattern: 1,
demo: "https://www.loom.com/share/c43aa34205854096bcec0a96e7ba5634?sid=839b1adc-ad39-4540-9995-88967f2b6da9",
github: "https://github.com/joelhooks/inngest-partykit-nextjs-openai",
image: "/assets/docs/examples/ai-agents/vercel-openai-inngest-partykit-demo.png",
author: "Joel Hooks",
authorSocial: "https://twitter.com/jhooks"
}}/>

<Example example={{
title: "PCXI starter",
technology: "Next.js, OpenAI, Xata, Prisma, Clerk",
description: "A boilerplate project for the PCXI stack featuring an OpenAI call",
pattern: 1,
github: "https://github.com/inngest/next-pxci-starter",
image: "/assets/docs/examples/ai-agents/pcxi-starter.png",
}}/>

</ResourceGrid>

## Resources
Check the resources below to learn more about working with AI using Inngest:

<ResourceGrid cols={2}>

<Resource resource={{
href: "/blog/ai-in-production-managing-capacity-with-flow-control",
name: 'Blog: "AI in production: Managing capacity with flow control"',
icon: BookOpenIcon,
description: "Learn how to manage AI capacity in production using Inngest's flow control techniques, including throttling, concurrency, debouncing, and prioritization, to optimize performance and cost-efficiency.",
pattern: 1,
}}/>

<Resource resource={{
href: "https://a16z.com/podcast/building-production-workflows-for-ai-applications/",
name: 'Podcast: "Building Production Workflows for AI Applications"',
icon: MicrophoneIcon,
description: "Tony Holdstock-Brown and Yoko Li discuss the reality and complexity of running AI agents and other multistep AI workflows in production.",
pattern: 1,
}}/>

<Resource resource={{
href: "https://www.youtube.com/watch?v=EoFI_Bmzb4g",
name: 'Talk: "Automate All of Your Customer Interactions with AI in Next.js"',
icon: VideoCameraIcon,
description: "Joel Hooks discusses managing long-running processes like generative AI to automate customer interactions effectively.",
pattern: 1,
}}/>


<Resource resource={{
href: "/blog/semi-autonomous-ai-agents",
name: 'Blog: "Semi-Autonomous AI Agents and Collaborative Multiplayer Asynchronous Workflows"',
icon: BookOpenIcon,
description: "Build an AI agent that reads from Linear issues, returns relevant issues based on queries, and allows actions on those issues.",
pattern: 1,
}}/>

<Resource resource={{
href: "https://www.youtube.com/watch?v=PCq6DozV-mY",
name: 'Video: "Chaining Prompts The Easy Way - Using Inngest Serverless Jobs with OpenAI"',
icon: VideoCameraIcon,
description: "Doug Silkstone demonstrates how to chain together prompts and get content in next to no time at all.",
pattern: 1,
}}/>

</ResourceGrid>

## Related concepts

- [Concurrency](/docs/guides/concurrency): control the number of steps executing code at any one time.
- [Debouncing](/docs/guides/debounce): delay function execution until a series of events are no longer received.
- [Prioritization](/docs/guides/priority): dynamically execute some runs ahead or behind others based on any data.
- [Rate limiting](/docs/guides/rate-limiting): limit on how many function runs can start within a time period.
- [Steps](/docs/reference/functions/step-run): individual tasks within a function that can be executed independently with a guaranteed retrial.
- [Throttling](/docs/guides/throttling): specify how many function runs can start within a time period.
2 changes: 1 addition & 1 deletion pages/docs/examples/email-sequence.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ const signupDripCampaign = inngest.createFunction(

Here are apps which use Inngest to power email campaigns.

<Example example={{
<Example wide example={{
title: "Integrate email events with Resend webhooks",
technology: "Next.js, Resend",
description: "Transactional emails in Next.js using Resend and Inngest. Get started sending customer lifecycle emails. ",
Expand Down
10 changes: 9 additions & 1 deletion pages/docs/examples/index.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ResourceGrid, Resource } from 'src/shared/Docs/Resources'
import { EnvelopeIcon } from "@heroicons/react/24/outline";
import { EnvelopeIcon, Cog6ToothIcon } from "@heroicons/react/24/outline";
import { RiBracesFill, RiCalendarScheduleFill, RiErrorWarningFill } from "@remixicon/react";

export const hidePageSidebar = true;
Expand All @@ -10,6 +10,14 @@ Explore the features built with Inngest:

<ResourceGrid cols={2}>

<Resource resource={{
href: "/docs/examples/ai-agents-and-rag",
name: "AI Agents and RAG",
icon: Cog6ToothIcon,
description: "Use Inngest to build AI agents and RAG.",
pattern: 1,
}}/>

<Resource resource={{
href: "/docs/examples/email-sequence",
name: "Email Sequence",
Expand Down
2 changes: 1 addition & 1 deletion pages/docs/examples/track-failures-in-datadog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This page provides an example of tracking all function failures using [Datadog's

## Quick Snippet

Here is a basic function that uses the internal [`"inngest/function.failed"`](/docs/reference/system-events/inngest-function-failed) event. This event is triggered whenever any single function fails in your Inngest [environment](/docs/platform/environments).
Here is a basic function that uses the internal [`"inngest/function.failed"`](/docs/reference/system-events/inngest-function-failed) event. This event is triggered whenever any single function fails in your [Inngest environment](/docs/platform/environments).

```ts
import { client, v1 } from "@datadog/datadog-api-client";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Callout, CodeGroup, Properties, Property, Row, Col, VersionBadge } from

# `inngest/function.failed` {{ className: "not-prose" }}

The `inngest/function.failed` event is sent whenever any single function fails in your Inngest [environment](/docs/platform/environments).
The `inngest/function.failed` event is sent whenever any single function fails in your [Inngest environment](/docs/platform/environments).

This event can be used to track all function failures in a single place, enabling you to send metrics, alerts, or events to [external systems like Datadog or Sentry](/docs/examples/track-failures-in-datadog) for all of your Inngest functions.

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
76 changes: 50 additions & 26 deletions shared/Docs/Examples.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,10 @@
import React from "react";
import Link from "next/link";
import { motion, useMotionTemplate, useMotionValue } from "framer-motion";

import { GridPattern } from "./GridPattern";
import { Heading } from "./Heading";
import { ChatBubbleIcon } from "./icons/ChatBubbleIcon";
import { EnvelopeIcon } from "./icons/EnvelopeIcon";
import { UserIcon } from "./icons/UserIcon";
import { UsersIcon } from "./icons/UsersIcon";
import {
PaperAirplaneIcon,
ClockIcon,
ArrowsPointingOutIcon,
Square3Stack3DIcon,
ChevronDoubleRightIcon,
RectangleGroupIcon,
} from "@heroicons/react/24/outline";
import ParallelIcon from "src/shared/Icons/Parallel";
import clsx from "clsx";

export function Example({
example,
wide,
}: {
example: {
href: string;
Expand All @@ -31,14 +17,35 @@ export function Example({
github: string;
image?: string;
};
wide?: boolean;
}) {
return (
<div className="group relative flex flex-col sm:flex-row rounded-lg bg-slate-50 transition-shadow hover:shadow-md hover:shadow-slate-900/5 dark:bg-white/2.5 dark:hover:shadow-black/5 ring-1 ring-inset ring-slate-900/7.5 group-hover:ring-slate-900/10 dark:ring-white/10 dark:group-hover:ring-white/20">
<div className="flex p-3">
<img className="relative flex rounded-lg m-0" src={example.image} />
</div>
<div className="relative px-4">
<h3 className="mt-4 text-m font-semibold">{example.title}</h3>
<div
className={clsx(
`group relative flex rounded-lg bg-slate-50 transition-shadow hover:shadow-md hover:shadow-slate-900/5 dark:bg-white/2.5 dark:hover:shadow-black/5 ring-1 ring-inset ring-slate-900/7.5 group-hover:ring-slate-900/10 dark:ring-white/10 dark:group-hover:ring-white/2`,
wide ? `flex-row items-start p-3` : `flex-col p-4`
)}
>
{!!example.image && (
<div
className={clsx(
"flex justify-center",
wide && "relative rounded-lg m-0"
)}
>
<img
src={example.image}
alt={example.title}
className="rounded-lg h-auto w-full object-contain filter saturate-50 transition duration-300 ease-in-out group-hover:saturate-100"
style={{ marginBottom: 0, marginTop: 0 }}
/>
</div>
)}
<div
className="relative flex flex-col justify-center"
style={{ marginLeft: wide ? "16px" : "0" }}
>
<h3 className="text-m font-semibold leading-6">{example.title}</h3>
{example.description && (
<p className="mt-1 text-sm text-slate-600 dark:text-slate-400">
{example.description}
Expand All @@ -50,16 +57,33 @@ export function Example({
</ExampleInfo>
)}
<ExampleInfo label="Explore">
<Link href={example.github}>Code</Link>
<Link
href={example.github}
className="hover:text-slate-600 dark:hover:text-slate-400 hover:underline"
>
Code
</Link>
{example.demo && (
<>
{" | "} <Link href={example.demo}>Demo</Link>
{" | "}{" "}
<Link
href={example.demo}
className="hover:text-slate-600 dark:hover:text-slate-400 hover:underline"
>
Demo
</Link>
</>
)}
</ExampleInfo>
<ExampleInfo label="Made by">
{example.authorSocial ? (
<Link href={example.authorSocial}> {example.author} </Link>
<Link
href={example.authorSocial}
className="hover:text-slate-600 dark:hover:text-slate-400 hover:underline"
>
{" "}
{example.author}{" "}
</Link>
) : (
example.author ?? "Inngest Team"
)}
Expand Down
22 changes: 14 additions & 8 deletions shared/Docs/Resources.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export function Resource({
logo?: { dark: string; light: string };
pattern: 0 | 1 | 2 | 3 | object | null;
icon?: IconType | ((any) => JSX.Element);
image?: string;
};
}) {
let mouseX = useMotionValue(0);
Expand All @@ -177,6 +178,7 @@ export function Resource({
mouseX.set(clientX - left);
mouseY.set(clientY - top);
}

const pattern =
resource.pattern === null
? patterns[0]
Expand All @@ -193,19 +195,24 @@ export function Resource({
<div
key={resource.href}
onMouseMove={onMouseMove}
className="group relative flex rounded-lg bg-slate-50 transition-shadow hover:shadow-md hover:shadow-slate-900/5 dark:bg-white/2.5 dark:hover:shadow-black/5"
className="group relative flex flex-col rounded-lg bg-slate-50 transition-shadow hover:shadow-md hover:shadow-slate-900/5 dark:bg-white/2.5 dark:hover:shadow-black/5 p-4"
>
<ResourcePattern {...pattern} mouseX={mouseX} mouseY={mouseY} />
<div className="absolute inset-0 rounded-lg ring-1 ring-inset ring-slate-900/7.5 group-hover:ring-slate-900/10 dark:ring-white/10 dark:group-hover:ring-white/20" />
<Link
href={resource.href}
className="w-full text-slate-900 dark:text-slate-200 hover:text-slate-700 hover:dark:text-slate-50"
>
<div
className={`relative rounded-lg px-4 pb-4 ${
resource.logo ? "pt-4" : "pt-16"
}`}
>
<div className="relative rounded-lg px-4 py-4">
{!!resource.image && (
<div className="flex justify-center mb-4">
<img
src={resource.image}
alt={resource.name}
className="rounded-lg h-32 w-3/4 object-cover filter saturate-50 transition duration-300 ease-in-out group-hover:saturate-100"
/>
</div>
)}
{!!resource.logo && (
<>
<img
Expand All @@ -221,8 +228,7 @@ export function Resource({
</>
)}
{!!icon && <ResourceIcon icon={icon} />}
<h3 className="mt-4 text-sm font-semibold leading-7">
<span className="absolute inset-0 rounded-lg" />
<h3 className="mt-4 text-m font-semibold leading-6">
{resource.name}
</h3>
{resource.description && (
Expand Down
Loading
Loading