Skip to content

Commit

Permalink
Add a little docs site
Browse files Browse the repository at this point in the history
  • Loading branch information
jaredpalmer committed May 24, 2023
1 parent ccea4b8 commit 559be1f
Show file tree
Hide file tree
Showing 26 changed files with 562 additions and 234 deletions.
52 changes: 26 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ pnpm install @vercel/ai-utils

Creating UIs with contemporary AI providers is a daunting task. Ideally, language models/providers would be fast enough where developers could just fetch complete responses data with JSON in a few hundred milliseconds, but the reality is starkly different. It's quite common for these LLMs to take 5-40s to whip up a response.

Instead of tormenting users with a seemingly endless loading spinner while these models conjure up responses or completions, the progressive approach involves streaming the text output to the frontend on the fly-—a tactic championed by OpenAI's ChatGPT. However, implementing this technique is easier said than done. Each AI provider has its own unique SDK, each has it's own envelope surrounding the tokens, and each with different metadata (whose usefulness varies drastically).
Instead of tormenting users with a seemingly endless loading spinner while these models conjure up responses or completions, the progressive approach involves streaming the text output to the frontend on the fly-—a tactic championed by OpenAI's ChatGPT. However, implementing this technique is easier said than done. Each AI provider has its own unique SDK, each has its own envelope surrounding the tokens, and each with different metadata (whose usefulness varies drastically).

Many AI utility helpers so far in the JS ecosystem tend to overcomplicate things with unnecessary magic tricks, excess levels of indirection, lossy abstractions. Here's where Vercel AI Utils comes to the rescue—a compact library designed to alleviate the headaches of constructing streaming text UIs by taking care of the most annoying parts and then getting out of your way:
Many AI utility helpers so far in the JS ecosystem tend to overcomplicate things with unnecessary magic tricks, excess levels of indirection, and lossy abstractions. Here's where Vercel AI Utils comes to the rescue—**a compact library designed to alleviate the headaches of constructing streaming text UIs** by taking care of the most annoying parts and then getting out of your way:

- Diminish the boilerplate necessary for handling streaming text responses
- Guarantee the capability to run functions at the Edge
Expand All @@ -46,21 +46,21 @@ The goal of this library lies in its commitment to work directly with each AI/Mo

```tsx
// app/api/generate/route.ts
import { Configuration, OpenAIApi } from "openai-edge";
import { OpenAITextStream, StreamingTextResponse } from "@vercel/ai-utils";
import { Configuration, OpenAIApi } from 'openai-edge';
import { OpenAITextStream, StreamingTextResponse } from '@vercel/ai-utils';

const config = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(config);

export const runtime = "edge";
export const runtime = 'edge';

export async function POST() {
const response = await openai.createChatCompletion({
model: "gpt-4",
model: 'gpt-4',
stream: true,
messages: [{ role: "user", content: "What is love?" }],
messages: [{ role: 'user', content: 'What is love?' }],
});
const stream = OpenAITextStream(response);
return new StreamingTextResponse(stream);
Expand Down Expand Up @@ -99,8 +99,8 @@ Create a Next.js Route Handler that uses the Edge Runtime that we'll use to gene

```tsx
// ./app/api/generate/route.ts
import { Configuration, OpenAIApi } from "openai-edge";
import { OpenAITextStream, StreamingTextResponse } from "@vercel/ai-utils";
import { Configuration, OpenAIApi } from 'openai-edge';
import { OpenAITextStream, StreamingTextResponse } from '@vercel/ai-utils';

// Create an OpenAI API client (that's edge friendly!)
const config = new Configuration({
Expand All @@ -109,15 +109,15 @@ const config = new Configuration({
const openai = new OpenAIApi(config);

// IMPORTANT! Set the runtime to edge
export const runtime = "edge";
export const runtime = 'edge';

export async function POST(req: Request) {
// Extract the `prompt` from the body of the request
const { prompt } = await req.json();

// Ask OpenAI for a streaming chat completion given the prompt
const response = await openai.createCompletion({
model: "gpt-3.5-turbo",
model: 'gpt-3.5-turbo',
stream: true,
prompt,
});
Expand All @@ -136,21 +136,21 @@ Create a Client component with a form that we'll use to gather the prompt from t

```tsx
// ./app/form.ts
"use client";
'use client';

import { useState } from "react";
import { useCompletion } from "@vercel/ai-utils/react"; //@todo
import { useState } from 'react';
import { useCompletion } from '@vercel/ai-utils/react'; //@todo

export function Form() {
const [value, setValue] = useState("");
const { setPrompt, completion } = useCompletion("/api/generate");
const [value, setValue] = useState('');
const { setPrompt, completion } = useCompletion('/api/generate');
return (
<div>
<form
onSubmit={(e) => {
e.preventDefault();
setPrompt(value);
setValue("");
setValue('');
}}
>
<textarea value={value} onChange={(e) => setValue(e.target.value)} />
Expand Down Expand Up @@ -208,16 +208,16 @@ A transform that will extract the text from _most_ chat and completion HuggingFa

```tsx
// app/api/generate/route.ts
import { HfInference } from "@huggingface/inference";
import { HuggingFaceStream, StreamingTextResponse } from "@vercel/ai-utils";
import { HfInference } from '@huggingface/inference';
import { HuggingFaceStream, StreamingTextResponse } from '@vercel/ai-utils';

export const runtime = "edge";
export const runtime = 'edge';

const Hf = new HfInference(process.env.HUGGINGFACE_API_KEY);

export async function POST() {
const response = await Hf.textGenerationStream({
model: "OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5",
model: 'OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5',
inputs: `<|prompter|>What's the Earth total population?<|endoftext|><|assistant|>`,
parameters: {
max_new_tokens: 200,
Expand All @@ -239,19 +239,19 @@ This is a tiny wrapper around `Response` class that makes returning `ReadableStr

```tsx
// app/api/generate/route.ts
import { OpenAITextStream, StreamingTextResponse } from "@vercel/ai-utils";
import { OpenAITextStream, StreamingTextResponse } from '@vercel/ai-utils';

export const runtime = "edge";
export const runtime = 'edge';

export async function POST() {
const response = await openai.createChatCompletion({
model: "gpt-4",
model: 'gpt-4',
stream: true,
messages: { role: "user", content: "What is love?" },
messages: { role: 'user', content: 'What is love?' },
});
const stream = OpenAITextStream(response);
return new StreamingTextResponse(stream, {
"X-RATE-LIMIT": "lol",
'X-RATE-LIMIT': 'lol',
}); // => new Response(stream, { status: 200, headers: { 'Content-Type': 'text/plain; charset=utf-8', 'X-RATE-LIMIT': 'lol' }})
}
```
3 changes: 2 additions & 1 deletion apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"dependencies": {
"@vercel/ai-utils": "workspace:*",
"@vercel/analytics": "^1.0.1",
"next": "^13.4.1",
"next": "13.4.3",
"nextra": "^2.6.0",
"nextra-theme-docs": "^2.6.0",
"react": "^18.2.0",
Expand All @@ -23,6 +23,7 @@
"@types/react": "^18.0.22",
"@types/react-dom": "^18.0.7",
"@vercel/ai-tsconfig": "workspace:*",
"autoprefixer": "^10.4.14",
"eslint-config-vercel-ai": "workspace:*",
"postcss": "^8.4.23",
"tailwindcss": "^3.3.2",
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/pages/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@
"sidebar": false
}
}
}
}
4 changes: 3 additions & 1 deletion apps/docs/pages/docs/_meta.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"index": "Introduction",
"getting-started": "Getting Started",
"guides": "Guides",
"api": "API Reference"
}
}
97 changes: 97 additions & 0 deletions apps/docs/pages/docs/api.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
title: API Reference
---

# API Reference

## `OpenAIStream(res: Response, cb: AIStreamCallbacks): ReadableStream`

A transform that will extract the text from all chat and completion OpenAI models as returned as a `ReadableStream`.

```tsx
// app/api/generate/route.ts
import { Configuration, OpenAIApi } from 'openai-edge';
import { OpenAITextStream, StreamingTextResponse } from '@vercel/ai-utils';

const config = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(config);

export const runtime = 'edge';

export async function POST() {
const response = await openai.createChatCompletion({
model: 'gpt-4',
stream: true,
messages: [{ role: 'user', content: 'What is love?' }],
});
const stream = OpenAITextStream(response, {
async onStart() {
console.log('streamin yo')
},
async onToken(token) {
console.log('token: ' + token)
},
async onCompletion(content) {
console.log('full text: ' + )
// await prisma.messages.create({ content }) or something
}
});
return new StreamingTextResponse(stream);
}
```

## `HuggingFaceStream(iter: AsyncGenerator<any>, cb?: AIStreamCallbacks): ReadableStream`

A transform that will extract the text from _most_ chat and completion HuggingFace models and return them as a `ReadableStream`.

```tsx
// app/api/generate/route.ts
import { HfInference } from '@huggingface/inference';
import { HuggingFaceStream, StreamingTextResponse } from '@vercel/ai-utils';

export const runtime = 'edge';

const Hf = new HfInference(process.env.HUGGINGFACE_API_KEY);

export async function POST() {
const response = await Hf.textGenerationStream({
model: 'OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5',
inputs: `<|prompter|>What's the Earth total population?<|endoftext|><|assistant|>`,
parameters: {
max_new_tokens: 200,
// @ts-ignore
typical_p: 0.2, // you'll need this for OpenAssistant
repetition_penalty: 1,
truncate: 1000,
return_full_text: false,
},
});
const stream = HuggingFaceStream(response);
return new StreamingTextResponse(stream);
}
```

## `StreamingTextResponse(res: ReadableStream, init?: ResponseInit)`

This is a tiny wrapper around `Response` class that makes returning `ReadableStreams` of text a one liner. Status is automatically set to `200`, with `'Content-Type': 'text/plain; charset=utf-8'` set as `headers`.

```tsx
// app/api/generate/route.ts
import { OpenAITextStream, StreamingTextResponse } from '@vercel/ai-utils';

export const runtime = 'edge';

export async function POST() {
const response = await openai.createChatCompletion({
model: 'gpt-4',
stream: true,
messages: { role: 'user', content: 'What is love?' },
});
const stream = OpenAITextStream(response);
return new StreamingTextResponse(stream, {
'X-RATE-LIMIT': 'lol',
}); // => new Response(stream, { status: 200, headers: { 'Content-Type': 'text/plain; charset=utf-8', 'X-RATE-LIMIT': 'lol' }})
}
```
Loading

0 comments on commit 559be1f

Please sign in to comment.