Skip to content

Commit

Permalink
feat: add api key inputs for gemini and anthropic
Browse files Browse the repository at this point in the history
  • Loading branch information
laginha committed Sep 27, 2024
1 parent f027b5a commit 6e31291
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 52 deletions.
10 changes: 5 additions & 5 deletions src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,9 @@ function App() {

if (!modelList.includes(settings.model)) {
const oldModel = settings.model;
const newModel = modelList.includes(DEFAULT_SETTINGS.model) ? DEFAULT_SETTINGS.model : modelList[0];
const newModel = modelList.includes(DEFAULT_SETTINGS.model)
? DEFAULT_SETTINGS.model
: modelList[0];

setSettings((settings) => ({ ...settings, model: newModel }));

Expand All @@ -913,7 +915,7 @@ function App() {
}, [apiKey]);

const isAnythingSaving = isSavingReactFlow || isSavingSettings;
const isAnythingLoading = isAnythingSaving || (availableModels === null);
const isAnythingLoading = isAnythingSaving || availableModels === null;

useBeforeunload((event: BeforeUnloadEvent) => {
// Prevent leaving the page before saving.
Expand Down Expand Up @@ -1040,15 +1042,13 @@ function App() {

return (
<>
{!isValidAPIKey(apiKey) && <APIKeyModal apiKey={apiKey} setApiKey={setApiKey} />}
{!isValidAPIKey(apiKey) && <APIKeyModal />}

<SettingsModal
settings={settings}
setSettings={setSettings}
isOpen={isSettingsModalOpen}
onClose={onCloseSettingsModal}
apiKey={apiKey}
setApiKey={setApiKey}
availableModels={availableModels}
/>
<Column
Expand Down
31 changes: 4 additions & 27 deletions src/components/modals/APIKeyModal.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,9 @@
import mixpanel from "mixpanel-browser";

import { Modal, ModalOverlay, ModalContent, Link, Text } from "@chakra-ui/react";

import { MIXPANEL_TOKEN } from "../../main";
import { Modal, ModalOverlay, ModalContent, Text } from "@chakra-ui/react";

import { Column } from "../../utils/chakra";
import { isValidAPIKey } from "../../utils/apikey";
import { APIKeyInput } from "../utils/APIKeyInput";

export function APIKeyModal({
apiKey,
setApiKey,
}: {
apiKey: string | null;
setApiKey: (apiKey: string) => void;
}) {
const setApiKeyTracked = (apiKey: string) => {
setApiKey(apiKey);

if (isValidAPIKey(apiKey)) {
if (MIXPANEL_TOKEN) mixpanel.track("Entered API Key"); // KPI

// Hacky way to get the prompt box to focus after the
// modal closes. Long term should probably use a ref.
setTimeout(() => window.document.getElementById("promptBox")?.focus(), 50);
}
};
import { APIKeyInputs } from "../utils/APIKeyInput";

export function APIKeyModal() {
return (
<Modal
isOpen={true}
Expand All @@ -38,7 +15,7 @@ export function APIKeyModal({
<ModalOverlay />
<ModalContent>
<Column mainAxisAlignment="center" crossAxisAlignment="center" height="500px">
<APIKeyInput apiKey={apiKey} setApiKey={setApiKeyTracked} />
<APIKeyInputs />
<Text mt={5} width="80%" textAlign="center" fontSize="md">
API key is stored in the Browser with LocalStorage.
</Text>
Expand Down
10 changes: 3 additions & 7 deletions src/components/modals/SettingsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { MIXPANEL_TOKEN } from "../../main";
import { getFluxNodeTypeDarkColor } from "../../utils/color";
import { DEFAULT_SETTINGS } from "../../utils/constants";
import { Settings, FluxNodeType } from "../../utils/types";
import { APIKeyInput } from "../utils/APIKeyInput";
import { APIKeyInputs } from "../utils/APIKeyInput";
import { LabeledSelect, LabeledSlider } from "../utils/LabeledInputs";

import {
Expand All @@ -24,16 +24,12 @@ export const SettingsModal = memo(function SettingsModal({
onClose,
settings,
setSettings,
apiKey,
setApiKey,
availableModels
availableModels,
}: {
isOpen: boolean;
onClose: () => void;
settings: Settings;
setSettings: (settings: Settings) => void;
apiKey: string | null;
setApiKey: (apiKey: string) => void;
availableModels: string[] | null;
}) {
const reset = () => {
Expand Down Expand Up @@ -88,7 +84,7 @@ export const SettingsModal = memo(function SettingsModal({
}}
/>

<APIKeyInput mt={4} width="100%" apiKey={apiKey} setApiKey={setApiKey} />
<APIKeyInputs />

<LabeledSlider
mt={4}
Expand Down
59 changes: 48 additions & 11 deletions src/components/utils/APIKeyInput.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,63 @@
import mixpanel from "mixpanel-browser";

import { BoxProps } from "@chakra-ui/react";
import { LabeledPasswordInputWithLink } from "./LabeledInputs";
import { useLocalStorage } from "../../utils/lstore";
import {
API_KEY_LOCAL_STORAGE_KEY,
FLUX_ANTHROPIC_API_KEY,
FLUX_GOOGLE_API_KEY,
} from "../../utils/constants";
import { ApiKeyProvider, isValidAPIKey } from "../../utils/apikey";
import { MIXPANEL_TOKEN } from "../../main";

const url = import.meta.env.VITE_OPENAI_GET_KEY;

export function APIKeyInput({
apiKey,
setApiKey,
...others
}: {
apiKey: string | null;
setApiKey: (apiKey: string) => void;
} & BoxProps) {
interface APIKeyInputProps extends BoxProps {
provider: ApiKeyProvider;
label: string;
}

const STORAGE_KEYS = {
openai: API_KEY_LOCAL_STORAGE_KEY,
anthropic: FLUX_ANTHROPIC_API_KEY,
google: FLUX_GOOGLE_API_KEY,
};

export function APIKeyInput({ provider, ...others }: APIKeyInputProps) {
const [apiKey, setApiKey] = useLocalStorage<string>(STORAGE_KEYS[provider]);

const setValue = (key: string) => {
setApiKey(key);

if (isValidAPIKey(apiKey, provider)) {
if (MIXPANEL_TOKEN) mixpanel.track("Entered API Key"); // KPI

// Hacky way to get the prompt box to focus after the
// modal closes. Long term should probably use a ref.
setTimeout(() => window.document.getElementById("promptBox")?.focus(), 50);
}
};

return (
<LabeledPasswordInputWithLink
width="80%"
label="OpenAI API Key"
width="100%"
linkLabel="Get a key"
placeholder="sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
link={url}
value={apiKey ?? ""}
setValue={setApiKey}
setValue={setValue}
{...others}
/>
);
}

export function APIKeyInputs() {
return (
<>
<APIKeyInput label="OpenAI API Key" provider="openai" />
<APIKeyInput label="Anthropic API Key" provider="anthropic" />
<APIKeyInput label="Google API Key" provider="google" />
</>
);
}
16 changes: 14 additions & 2 deletions src/utils/apikey.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
export function isValidAPIKey(apiKey: string | null) {
return (apiKey?.length === 51 && apiKey.startsWith("sk-")) || (apiKey?.length === 56 && apiKey.startsWith("sk-proj-"));
export type ApiKeyProvider = "openai" | "anthropic" | "google";

export function isValidAPIKey(apiKey: string | null, provider?: ApiKeyProvider) {
if (!apiKey) return false;
if (provider === "anthropic") {
return apiKey.length > 100 && apiKey?.startsWith("sk-ant-");
}
if (provider === "google") {
return apiKey.length >= 50;
}
return (
(apiKey.length === 51 && apiKey.startsWith("sk-")) ||
(apiKey.length === 56 && apiKey.startsWith("sk-proj-"))
);
}
2 changes: 2 additions & 0 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export const MAX_HISTORY_SIZE = 256;
export const OVERLAP_RANDOMNESS_MAX = 20;

export const API_KEY_LOCAL_STORAGE_KEY = "FLUX_OPENAI_API_KEY";
export const FLUX_ANTHROPIC_API_KEY = "FLUX_ANTHROPIC_API_KEY";
export const FLUX_GOOGLE_API_KEY = "FLUX_GOOGLE_API_KEY";
export const REACT_FLOW_LOCAL_STORAGE_KEY = "FLUX_REACT_FLOW_DATA";
export const MODEL_SETTINGS_LOCAL_STORAGE_KEY = "FLUX_MODEL_SETTINGS";
export const SAVED_CHAT_SIZE_LOCAL_STORAGE_KEY = "FLUX_SAVED_CHAT_SIZE";
Expand Down

0 comments on commit 6e31291

Please sign in to comment.