Skip to content

Commit

Permalink
Merge pull request #3 from zerodays/feat/use-chat-hook
Browse files Browse the repository at this point in the history
Feat/use chat hook
  • Loading branch information
horvatz authored Apr 8, 2024
2 parents fe4cdad + 7f72f14 commit 523b233
Show file tree
Hide file tree
Showing 15 changed files with 7,935 additions and 1,339 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
src/types/global.d.ts
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module.exports = {
'node/no-missing-import': 'off',
'node/no-empty-function': 'off',
'node/no-unsupported-features/es-syntax': 'off',
'@typescript-eslint/ban-types': 'off',
'node/no-missing-require': 'off',
'node/shebang': 'off',
'@typescript-eslint/no-use-before-define': 'off',
Expand Down
6 changes: 0 additions & 6 deletions .prettierrc

This file was deleted.

34 changes: 34 additions & 0 deletions .prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */
module.exports = {
printWidth: 80,
tabWidth: 2,
useTabs: false,
semi: true,
singleQuote: true,
quoteProps: 'as-needed',
jsxSingleQuote: false,
trailingComma: 'all',
bracketSpacing: true,
bracketSameLine: true,
arrowParens: 'always',
endOfLine: 'lf',
// // Import sorting, uses @ianvs/prettier-plugin-sort-imports
importOrder: [
'react',
'<BUILTIN_MODULES>',
'<THIRD_PARTY_MODULES>',
'<TYPES>',
'',
'^@/lib/(.*)$',
'^@/hooks/(.*)$',
'^@/components/(.*)$',
'^@/app/(.*)$',
'',
'^(?!.*[.]css$)[./].*$',
'.css$',
'',
'^[./]',
],
importOrderParserPlugins: ['typescript', 'jsx', 'decorators-legacy'],
importOrderTypeScriptVersion: '5.0.0',
};
168 changes: 166 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,172 @@

Inspired by Vercel's [Generative UI](https://sdk.vercel.ai/docs/concepts/ai-rsc) for React Server Components.

TODO: More info here
Offers a seamless integration of OpenAI's advanced AI capabilities within React Native applications. Library provides components and helpers for building AI-powered streaming text and chat UIs.

# License
## Features

- React Native (with Expo) type-safe helpers for streaming text responses + components for building chat UIs
- First-class support for [Function calling](https://platform.openai.com/docs/guides/function-calling) with component support that LLM decides to render for interactive user interfaces
- Easy UI implementation with powerful `useChat` hook
- Support for [OpenAI models](https://platform.openai.com/docs/guides/text-generation)
- Streaming responses (only streaming is supported ATM).
- Supports OpenAI's [Chat completions](https://platform.openai.com/docs/guides/text-generation/chat-completions-api) API.

## Installation :rocket:

It's easy to get started - just install package with your favorite package manager:

### Yarn

```bash
yarn add react-native-gen-ui
```

### NPM

```bash
npm install react-native-gen-ui
```

## Basic usage :tada:

Ensure you have the OpenAI API key and the desired model environment variables set up in your project. These are stored as environment variables (in Expo):

### Initialization

```
EXPO_PUBLIC_OPENAI_API_KEY=sk.... # Required, you can get one in OpenAi dashboard
EXPO_PUBLIC_OPENAI_MODEL=model_name_here # Optional, model name from OpenAI (defaults to 'gpt-4')
```

### Import

To get started, import `useChat` hook in any React component:

```ts
import { useChat } from 'react-native-gen-ui';
```

### Use the hook

Initialize the `useChat` hook inside your component. You can optionally pass **initial messages**, **success** and **error handlers**, and any tools the model will have access to.

```ts
const { input, messages, isLoading, handleSubmit, onInputChange } = useChat({
// Optional initial messages
initialMessages: [
{ content: 'Hi! How can I help you today?', role: 'system' },
],
// Optional success handler
onSuccess: (messages) => console.log('Chat success:', messages),
// Optional error handler
onError: (error) => console.error('Chat error:', error),
});
```

Create the UI for your chat interface that includes input, submit button and a view to display the chat messages.

```ts
return (
<View>
{messages.map((msg, index) => {
// Message can be react component or string (see function calling section for more details)
if (React.isValidElement(msg)) {
return msg;
}

return <Text key={index}>{msg.content}</Text>
})}
<TextInput value={input} onChangeText={onInputChange} />
<Button
onPress={() => handleSubmit(input)}
title="Send"
disabled={isLoading}
/>
</View>
);
```

Ensure you pass the input state to the `TextInput` component, `onInputChange` to handle text changes, and `handleSubmit` for sending messages.

Congrats :tada: you successfully implemented chat using OpenAI model!

## Function calling (Tools) :wrench:

The `useChat` hook supports the integration of [Tools](https://platform.openai.com/docs/api-reference/chat/create#chat-create-tools), a powerful feature allowing you to incorporate custom functions or external API calls directly into your chat flow.

### Defining a Tool

Tools are defined as part of the `tools` parameter when initializing the `useChat` hook. Parameters are validated using [zod schema](https://zod.dev/). Below is example of weather forecast defined as tool:

```ts
const { input, messages, isLoading, handleSubmit, onInputChange } = useChat({
...
tools: {
getWeather: {
description: "Get weather for a location",
// Validate tool parameters using zod
parameters: z.object({
// In this case, tool accepts date and location for weather
date: z.date().default(() => new Date()),
location: z.string(),
}),
// Render component for weather - can yield loading state
render: async function* (args) {
// With 'yield' we can show loading while fetching weather data
yield <Spinner />;

// Call API for current weather
const weatherData = await fetchWeatherData(args.location);

// We can yield again to replace the loading component at any time.
// This can be useful for showing progress or intermediate states.
yield <Loading />

// Return the final result
return {
// The data will be seen by the model
data: weatherData,
// The component will be rendered to the user
component: (
<Weather
location={args.location}
current={weatherData[0]}
forecast={weatherData}
/>
),
};
}
}
}
});
```

Tools framework within `useChat` is highly extensible. You can define multiple tools to perform various functions based on your chat application's requirements.

## Reference

```ts
const {
input, // State of user input (i.e. in TextInput component)
messages, // List of all messages for current chat session
error, // Error that can occur during streaming
isLoading, // Loading state - true immediately after user message submission
isStreaming, // Streaming state - true while streaming response
onInputChange, // Updates internal state of user input
handleSubmit, // Handles user message submission
} = useChat({
initialMessages: [], // Initial messages chat messages
onSuccess: () => {...}, // Called when streaming response is completed
onError: (error) => {...}, // Called when an error occurs while streaming
tools: ... // Tools for custom API calls or functions
});
```
## Examples
TODO
## License
Published under MIT License, more details at [LICENSE](LICENSE) file.
Loading

0 comments on commit 523b233

Please sign in to comment.