Skip to content

Commit

Permalink
feat: add vue composables and nuxt implementation (#84)
Browse files Browse the repository at this point in the history
Co-authored-by: Max Leiter <maxwell.leiter@gmail.com>
  • Loading branch information
danielroe and MaxLeiter committed Jun 16, 2023
1 parent 4315d17 commit 71f9c51
Show file tree
Hide file tree
Showing 20 changed files with 7,942 additions and 1,655 deletions.
5 changes: 5 additions & 0 deletions .changeset/popular-pianos-hug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'ai': minor
---

This adds Vue support for `ai` via the `ai/vue` subpath export. Vue composables `useChat` and `useCompletion` are provided.
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.next
.nuxt
node_modules
dist
dist
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The Vercel AI SDK is **a library for building edge-ready AI-powered streaming te

## Features

- [SWR](https://swr.vercel.app)-powered React and Svelte helpers for streaming text responses and building chat and completion UIs
- [SWR](https://swr.vercel.app)-powered React, Svelte and Vue helpers for streaming text responses and building chat and completion UIs
- First-class support for [LangChain](js.langchain.com/docs) and [OpenAI](https://openai.com), [Anthropic](https://anthropicai.com), and [HuggingFace](https://huggingface.co)
- [Edge Runtime](https://edge-runtime.vercel.app/) compatibility
- Callbacks for saving completed streaming responses to a database (in the same request)
Expand Down
1 change: 1 addition & 0 deletions examples/nuxt-openai/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NUXT_OPENAI_API_KEY=xxxxxxx
23 changes: 23 additions & 0 deletions examples/nuxt-openai/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Nuxt dev/build outputs
.output
.nuxt
.nitro
.cache
dist

# Node dependencies
node_modules

# Logs
logs
*.log

# Misc
.DS_Store
.fleet
.idea

# Local env files
.env
.env.*
!.env.example
34 changes: 34 additions & 0 deletions examples/nuxt-openai/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Vercel AI SDK, Nuxt and OpenAI Chat Example

This example shows how to use the [Vercel AI SDK](https://sdk.vercel.ai/docs) with [Nuxt](https://nuxt.com/), and [OpenAI](https://openai.com) to create a ChatGPT-like AI-powered streaming chat bot.

## Deploy your own

Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=ai-sdk-example):

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel-labs%2Fai%2Ftree%2Fmain%2Fexamples%2Fnuxt-openai&env=NUXT_OPENAI_API_KEY&envDescription=OpenAI%20API%20Key&envLink=https%3A%2F%2Fplatform.openai.com%2Faccount%2Fapi-keys&project-name=ai-chat&repository-name=nuxt-ai-chat)

## How to use

Execute `nuxi` to bootstrap the example:

```bash
npx nuxi@latest init -t github:vercel-labs/ai/examples/nuxt-openai nuxt-openai
```

To run the example locally you need to:

1. Sign up at [OpenAI's Developer Platform](https://platform.openai.com/signup).
2. Go to [OpenAI's dashboard](https://platform.openai.com/account/api-keys) and create an API KEY.
3. Set the required OpenAI environment variable as the token value as shown [the example env file](./.env.example) but in a new file called `.env`.
4. `pnpm install` to install the required dependencies.
5. `pnpm dev` to launch the development server.

## Learn More

To learn more about OpenAI, Nuxt, and the Vercel AI SDK take a look at the following resources:

- [Vercel AI SDK docs](https://sdk.vercel.ai/docs) - learn mode about the Vercel AI SDK
- [Vercel AI Playground](https://play.vercel.ai) - compare and tune 20+ AI models side-by-side
- [OpenAI Documentation](https://platform.openai.com/docs) - learn about OpenAI features and API.
- [Nuxt Documentation](https://nuxt.com/docs) - learn about Nuxt features and API.
23 changes: 23 additions & 0 deletions examples/nuxt-openai/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup>
import { useChat } from 'ai/vue'
const { messages, input, handleInputChange, handleSubmit } = useChat()
</script>

<template>
<div class="flex flex-col w-full max-w-md py-24 mx-auto stretch">
<div v-for="m in messages" key="m.id" class="whitespace-pre-wrap">
{{ m.role === 'user' ? 'User: ' : 'AI: ' }}
{{ m.content }}
</div>

<form @submit="handleSubmit">
<input
class="fixed bottom-0 w-full max-w-md p-2 mb-8 border border-gray-300 rounded shadow-xl"
v-model="input"
placeholder="Say something..."
@change="handleInputChange"
/>
</form>
</div>
</template>
8 changes: 8 additions & 0 deletions examples/nuxt-openai/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
devtools: { enabled: true },
modules: ['@nuxtjs/tailwindcss'],
runtimeConfig: {
openaiApiKey: ''
}
})
26 changes: 26 additions & 0 deletions examples/nuxt-openai/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "nuxt-openai",
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
"devDependencies": {
"@nuxt/devtools": "latest",
"@nuxtjs/tailwindcss": "^6.7.2",
"@types/node": "^18",
"@vue/reactivity": "^3.3.4",
"@vue/runtime-core": "^3.3.4",
"@vue/runtime-dom": "^3.3.4",
"@vue/shared": "^3.3.4",
"ai": "2.0.1",
"nuxt": "^3.5.2",
"openai-edge": "^0.5.1",
"tailwindcss": "^3.3.2",
"unctx": "^2.3.1",
"vue": "^3.3.4"
}
}
30 changes: 30 additions & 0 deletions examples/nuxt-openai/server/api/chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// ./api/chat.ts
import { Configuration, OpenAIApi } from 'openai-edge'
import { OpenAIStream, streamToResponse } from 'ai'

// Create an OpenAI API client (that's edge friendly!)
const config = new Configuration({
// eslint-disable-next-line react-hooks/rules-of-hooks
apiKey: useRuntimeConfig().openaiApiKey
})
const openai = new OpenAIApi(config)

export default defineEventHandler(async event => {
// Extract the `prompt` from the body of the request
const { messages } = await readBody(event)

// Ask OpenAI for a streaming chat completion given the prompt
const response = await openai.createChatCompletion({
model: 'gpt-3.5-turbo',
stream: true,
messages: messages.map((message: any) => ({
content: message.content,
role: message.role
}))
})

// Convert the response into a friendly text-stream
const stream = OpenAIStream(response)
// Respond with the stream
streamToResponse(stream, event.node.res)
})
3 changes: 3 additions & 0 deletions examples/nuxt-openai/server/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "../.nuxt/tsconfig.server.json"
}
4 changes: 4 additions & 0 deletions examples/nuxt-openai/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
// https://nuxt.com/docs/guide/concepts/typescript
"extends": "./.nuxt/tsconfig.json"
}
20 changes: 16 additions & 4 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
"files": [
"dist/**/*",
"react/dist/**/*",
"svelte/dist/**/*"
"svelte/dist/**/*",
"vue/dist/**/*"
],
"scripts": {
"build": "tsup",
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist && rm -rf react/dist && rm -rf svelte/dist",
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist && rm -rf react/dist && rm -rf svelte/dist && rm -rf vue/dist",
"dev": "tsup --watch",
"lint": "eslint \"./**/*.ts*\"",
"type-check": "tsc --noEmit",
Expand All @@ -39,6 +40,12 @@
"import": "./svelte/dist/index.mjs",
"module": "./svelte/dist/index.mjs",
"require": "./svelte/dist/index.js"
},
"./vue": {
"types": "./vue/dist/index.d.ts",
"import": "./vue/dist/index.mjs",
"module": "./vue/dist/index.mjs",
"require": "./vue/dist/index.js"
}
},
"jest": {
Expand All @@ -49,7 +56,8 @@
"eventsource-parser": "1.0.0",
"nanoid": "^3.3.6",
"sswr": "^1.10.0",
"swr": "2.1.5"
"swr": "2.1.5",
"swrv": "1.0.3"
},
"devDependencies": {
"@edge-runtime/jest-environment": "1.1.0-beta.31",
Expand All @@ -67,14 +75,18 @@
},
"peerDependencies": {
"react": "^18.0.0",
"svelte": "^3.29.0"
"svelte": "^3.29.0",
"vue": "^3.3.4"
},
"peerDependenciesMeta": {
"react": {
"optional": true
},
"svelte": {
"optional": true
},
"vue": {
"optional": true
}
},
"engines": {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"extends": "@vercel/ai-tsconfig/react-library.json",
"extends": "./node_modules/@vercel/ai-tsconfig/react-library.json",
"include": ["."],
"exclude": ["dist", "build", "node_modules"]
}
15 changes: 12 additions & 3 deletions packages/core/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default defineConfig([
{
entry: ['streams/*.{ts,tsx}'],
format: ['cjs', 'esm'],
external: ['react', 'svelte'],
external: ['react', 'svelte', 'vue'],
dts: true
},
// React APIs
Expand All @@ -17,7 +17,7 @@ export default defineConfig([
js: "'use client'"
},
format: ['cjs', 'esm'],
external: ['react', 'svelte'],
external: ['react', 'svelte', 'vue'],
dts: true
},
// Svelte APIs
Expand All @@ -26,10 +26,19 @@ export default defineConfig([
outDir: 'svelte/dist',
banner: {},
format: ['cjs', 'esm'],
external: ['react', 'svelte'],
external: ['react', 'svelte', 'vue'],
dts: true,
// `sswr` has some issue with `.es.js` that can't be resolved correctly by
// vite so we have to bundle it here.
noExternal: ['sswr']
},
// Vue APIs
{
entry: ['vue/*.ts'],
outDir: 'vue/dist',
banner: {},
format: ['cjs', 'esm'],
external: ['react', 'svelte', 'vue'],
dts: true
}
])
2 changes: 2 additions & 0 deletions packages/core/vue/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './use-chat'
export * from './use-completion'
10 changes: 10 additions & 0 deletions packages/core/vue/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": "./dist/index.mjs",
"private": true,
"peerDependencies": {
"vue": "*"
}
}

1 comment on commit 71f9c51

@vercel
Copy link

@vercel vercel bot commented on 71f9c51 Jun 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

ai – ./

ai-vercel-labs.vercel.app
ai-git-main-vercel-labs.vercel.app
ai-three-xi.vercel.app

Please sign in to comment.