Skip to content

Commit

Permalink
Support REACT_APP_ env var lookups (#135)
Browse files Browse the repository at this point in the history
  • Loading branch information
NickHeiner committed Jun 22, 2023
1 parent 8691e53 commit 3267098
Show file tree
Hide file tree
Showing 9 changed files with 39 additions and 22 deletions.
2 changes: 1 addition & 1 deletion packages/ai-jsx/package.json
Expand Up @@ -4,7 +4,7 @@
"repository": "fixie-ai/ai-jsx",
"bugs": "https://github.com/fixie-ai/ai-jsx/issues",
"homepage": "https://ai-jsx.com",
"version": "0.5.1",
"version": "0.5.2",
"volta": {
"extends": "../../package.json"
},
Expand Down
7 changes: 3 additions & 4 deletions packages/ai-jsx/src/batteries/docs.tsx
Expand Up @@ -13,6 +13,7 @@ import { similarity } from 'ml-distance';
import { Jsonifiable } from 'type-fest';
import { ChatCompletion, SystemMessage, UserMessage } from '../core/completion.js';
import { Node } from '../index.js';
import { getEnvVar } from '../lib/util.js';

/**
* A raw document loaded from an arbitrary source that has not yet been parsed.
Expand Down Expand Up @@ -322,10 +323,8 @@ export class LangChainEmbeddingWrapper implements Embedding {

/** A default embedding useful for DocsQA. Note that this requires `OPENAI_API_KEY` to be set. */
function defaultEmbedding() {
if (!process.env.OPENAI_API_KEY) {
throw new Error('OPENAI_API_KEY not set');
}
return new LangChainEmbeddingWrapper(new OpenAIEmbeddings({ openAIApiKey: process.env.OPENAI_API_KEY }));
const apiKey = getEnvVar('OPENAI_API_KEY');
return new LangChainEmbeddingWrapper(new OpenAIEmbeddings({ openAIApiKey: apiKey }));
}

/**
Expand Down
13 changes: 7 additions & 6 deletions packages/ai-jsx/src/core/completion.tsx
Expand Up @@ -6,6 +6,7 @@
import * as AI from '../index.js';
import { Node, Component, RenderContext } from '../index.js';
import { OpenAIChatModel, OpenAICompletionModel } from '../lib/openai.js';
import { getEnvVar } from '../lib/util.js';

/**
* Represents properties passed to a given Large Language Model.
Expand Down Expand Up @@ -55,7 +56,7 @@ export interface FunctionParameter {
* This is internal and users should not need to access this directly.
*/
function AutomaticCompletionModel({ children, ...props }: ModelPropsWithChildren) {
if (process.env.OPENAI_API_KEY || process.env.OPENAI_API_BASE) {
if (getEnvVar('OPENAI_API_KEY', false) || getEnvVar('OPENAI_API_BASE', false)) {
return (
<OpenAICompletionModel model="text-davinci-003" {...props}>
{children}
Expand All @@ -65,8 +66,8 @@ function AutomaticCompletionModel({ children, ...props }: ModelPropsWithChildren

throw new Error(`No completion model was specified. To fix this, do one of the following:
1. Set the OPENAI_API_KEY environment variable.
2. Set the OPENAI_API_BASE environment variable.
1. Set the OPENAI_API_KEY or REACT_APP_OPENAI_API_KEY environment variable.
2. Set the OPENAI_API_BASE or REACT_APP_OPENAI_API_BASE environment variable.
3. use an explicit CompletionProvider component.`);
}

Expand All @@ -76,7 +77,7 @@ function AutomaticCompletionModel({ children, ...props }: ModelPropsWithChildren
* This is internal and users should not need to access this directly.
*/
function AutomaticChatModel({ children, ...props }: ModelPropsWithChildren) {
if (process.env.OPENAI_API_KEY || process.env.OPENAI_API_BASE) {
if (getEnvVar('OPENAI_API_KEY', false) || getEnvVar('OPENAI_API_BASE', false)) {
return (
<OpenAIChatModel model="gpt-3.5-turbo" {...props}>
{children}
Expand All @@ -85,8 +86,8 @@ function AutomaticChatModel({ children, ...props }: ModelPropsWithChildren) {
}
throw new Error(`No chat model was specified. To fix this, do one of the following:
1. Set the OPENAI_API_KEY environment variable.
2. Set the OPENAI_API_BASE environment variable.
1. Set the OPENAI_API_KEY or REACT_APP_OPENAI_API_KEY environment variable.
2. Set the OPENAI_API_BASE or REACT_APP_OPENAI_API_BASE environment variable.
3. use an explicit ChatProvider component.`);
}

Expand Down
3 changes: 2 additions & 1 deletion packages/ai-jsx/src/core/image-gen.tsx
Expand Up @@ -6,6 +6,7 @@
import * as AI from '../index.js';
import { Node, Component, RenderContext } from '../index.js';
import { DalleImageGen } from '../lib/openai.js';
import { getEnvVar } from '../lib/util.js';

/**
* Represents properties passed to the {@link ImageGen} component.
Expand All @@ -29,7 +30,7 @@ export type ImageGenComponent<T extends ImageGenPropsWithChildren> = Component<T
* This is internal and users should not need to access this directly.
*/
function AutomaticImageGenModel({ children, ...props }: ImageGenPropsWithChildren) {
if (process.env.OPENAI_API_KEY) {
if (getEnvVar('OPENAI_API_KEY', false) || getEnvVar('OPENAI_API_BASE', false)) {
return <DalleImageGen {...props}>{children}</DalleImageGen>;
}

Expand Down
8 changes: 6 additions & 2 deletions packages/ai-jsx/src/lib/openai.tsx
Expand Up @@ -35,6 +35,7 @@ import { Merge } from 'type-fest';
import { Logger } from '../core/log.js';
import { HttpError } from '../core/errors.js';
import _ from 'lodash';
import { getEnvVar } from './util.js';

// https://platform.openai.com/docs/models/model-endpoint-compatibility
type ValidCompletionModel =
Expand All @@ -55,9 +56,12 @@ const decoder = new TextDecoder();
function createOpenAIClient() {
return new OpenAIApi(
new Configuration({
apiKey: process.env.OPENAI_API_KEY,
apiKey: getEnvVar('OPENAI_API_KEY', false),
}),
process.env.OPENAI_API_BASE,
// We actually want the nullish coalescing behavior in this case,
// because if the env var is '', we want to pass `undefined` instead.
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
getEnvVar('OPENAI_API_BASE', false) || undefined,
// TODO: Figure out a better way to work around NextJS fetch blocking streaming
(globalThis as any)._nextOriginalFetch ?? globalThis.fetch
);
Expand Down
11 changes: 9 additions & 2 deletions packages/ai-jsx/src/lib/util.ts
@@ -1,7 +1,14 @@
/** @hidden */
export function ensureProcessEnvVar(name: string): string {
export function getEnvVar(name: string, shouldThrow: boolean = true) {
// We actually want the nullish coalescing behavior in this case,
// because we want to treat '' as undefined.
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
return getEnvVarByName(name, shouldThrow) || getEnvVarByName(`REACT_APP_${name}`, shouldThrow);
}

function getEnvVarByName(name: string, shouldThrow: boolean) {
const value = process.env[name];
if (!value) {
if (!value && shouldThrow) {
throw new Error(`Please specify env var "${name}".`);
}
return value;
Expand Down
3 changes: 0 additions & 3 deletions packages/create-react-app-demo/config/env.cjs
Expand Up @@ -86,9 +86,6 @@ function getClientEnvironment(publicUrl) {
// Whether or not react-refresh is enabled.
// It is defined here so it is available in the webpackHotDevClient.
FAST_REFRESH: process.env.FAST_REFRESH !== 'false',

OPENAI_API_KEY: process.env.OPENAI_API_KEY,
OPENAI_API_BASE: process.env.OPENAI_API_BASE,
}
);
// Stringify all values so we can feed into webpack DefinePlugin
Expand Down
6 changes: 3 additions & 3 deletions packages/create-react-app-demo/package.json
Expand Up @@ -75,9 +75,9 @@
"type": "module",
"scripts": {
"start:backend": "rm -rf backend/dist && tsc -p backend/tsconfig.json && node backend/dist/index.js",
"start:arch-2": "concurrently \"yarn run start\" \"yarn run start:backend\"",
"start": "node scripts/start.cjs",
"build": "node scripts/build.cjs",
"start:arch-2": "concurrently \"REACT_APP_OPENAI_API_BASE=${OPENAI_API_BASE:-\"\"} yarn run start\" \"yarn run start:backend\"",
"start": "REACT_APP_OPENAI_API_KEY=${OPENAI_API_KEY:-\"\"} node scripts/start.cjs",
"build": "REACT_APP_OPENAI_API_KEY=${OPENAI_API_KEY:-\"\"}REACT_APP_OPENAI_API_BASE=${OPENAI_API_BASE:-\"\"} node scripts/build.cjs node scripts/build.cjs",
"test": "yarn run lint; yarn run typecheck",
"dev": "bash ./scripts/pick-start-version.bash",
"lint": "eslint src --max-warnings 0",
Expand Down
8 changes: 8 additions & 0 deletions packages/docs/docs/guides/openai.md
Expand Up @@ -10,6 +10,10 @@ You may do this with any of the [Architecture Patterns](./architecture.mdx).

**How to do this:** Set the `OPENAI_API_KEY` env var. (You can get this key from the [OpenAI API dashboard](https://platform.openai.com/account/api-keys))

:::note create-react-app
If your project is build on create-react-app, you'll want to set `REACT_APP_OPENAI_API_KEY` instead. ([More detail.](https://create-react-app.dev/docs/adding-custom-environment-variables/))
:::

## Set a proxy env var

**When to do this:** you have a proxy server that you'd like to use for OpenAI calls.
Expand All @@ -28,6 +32,10 @@ OPENAI_API_BASE=https://my-proxy-server/api
OPENAI_API_BASE=/openai-proxy
```

:::note create-react-app
If your project is build on create-react-app, you'll want to set `REACT_APP_OPENAI_API_BASE` instead. ([More detail.](https://create-react-app.dev/docs/adding-custom-environment-variables/))
:::

## Set a model provider in your JSX

:::caution
Expand Down

3 comments on commit 3267098

@vercel
Copy link

@vercel vercel bot commented on 3267098 Jun 22, 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-jsx-nextjs-demo – ./packages/nextjs-demo

ai-jsx-nextjs-demo.vercel.app
ai-jsx-nextjs-demo-fixie-ai.vercel.app
ai-jsx-nextjs-demo-git-main-fixie-ai.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 3267098 Jun 22, 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-jsx-docs – ./packages/docs

ai-jsx-docs.vercel.app
docs.ai-jsx.com
ai-jsx-docs-git-main-fixie-ai.vercel.app
ai-jsx-docs-fixie-ai.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 3267098 Jun 22, 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-jsx-tutorial-nextjs – ./packages/tutorial-nextjs

ai-jsx-tutorial-nextjs.vercel.app
ai-jsx-tutorial-nextjs-git-main-fixie-ai.vercel.app
ai-jsx-tutorial-nextjs-fixie-ai.vercel.app

Please sign in to comment.