Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set init provider for new users to free model, added info alert banner #517

Merged
merged 1 commit into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 61 additions & 2 deletions src/Chat/ChatBase.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { Box, Button, Flex, Grid, GridItem, Text, useDisclosure } from "@chakra-ui/react";
import { useCallback, useEffect, useRef, useState } from "react";
import {
Alert,
AlertDescription,
AlertIcon,
Box,
Button,
CloseButton,
Flex,
Grid,
GridItem,
Text,
useDisclosure,
} from "@chakra-ui/react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { CgArrowDownO } from "react-icons/cg";
import { ScrollRestoration } from "react-router-dom";

Expand All @@ -25,6 +37,8 @@ import {
} from "../lib/ChatCraftMessage";
import { ChatCraftCommandRegistry } from "../lib/commands";
import ChatHeader from "./ChatHeader";
import { FreeModelProvider } from "../lib/providers/DefaultProvider/FreeModelProvider";
import PreferencesModal from "../components/PreferencesModal";

type ChatBaseProps = {
chat: ChatCraftChat;
Expand All @@ -46,6 +60,12 @@ function ChatBase({ chat }: ChatBaseProps) {
const { error } = useAlert();
const { user } = useUser();
const { clearAudioQueue } = useAudioPlayer();
const [showAlert, setShowAlert] = useState(true);
const {
isOpen: isPrefModalOpen,
onOpen: onPrefModalOpen,
onClose: onPrefModalClose,
} = useDisclosure();

// If we can't load models, it's a bad sign for API connectivity.
// Show an error so the user is aware.
Expand Down Expand Up @@ -298,6 +318,37 @@ function ChatBase({ chat }: ChatBaseProps) {
resume();
}

const defaultProviderAlert = useMemo(() => {
// If we are using default provider, show alert banner to notify user
if (showAlert && settings.currentProvider instanceof FreeModelProvider) {
return (
<Alert status="info" variant="solid" sx={{ py: 1 }}>
<AlertIcon boxSize="4" />
<AlertDescription fontSize="sm">
You are using the default free AI Provider, which has limited features.{" "}
<Text
as="span"
cursor="pointer"
fontSize="sm"
textDecoration="underline"
onClick={onPrefModalOpen}
>
Click here
</Text>{" "}
to add other AI providers.
</AlertDescription>
<CloseButton
position="absolute"
right="8px"
top="4px"
size="sm"
onClick={() => setShowAlert(false)}
/>
</Alert>
);
}
}, [onPrefModalOpen, settings.currentProvider, showAlert]);

return (
<Grid
w="100%"
Expand All @@ -312,6 +363,8 @@ function ChatBase({ chat }: ChatBaseProps) {
_dark={{ bgGradient: "linear(to-b, gray.600, gray.700)" }}
>
<GridItem colSpan={2}>
{/* Default Provider Alert Banner*/}
{defaultProviderAlert}
<Header
chatId={chat.id}
inputPromptRef={inputPromptRef}
Expand Down Expand Up @@ -385,6 +438,12 @@ function ChatBase({ chat }: ChatBaseProps) {
)}
</Box>
</GridItem>

<PreferencesModal
isOpen={isPrefModalOpen}
onClose={onPrefModalClose}
finalFocusRef={inputPromptRef}
/>
</Grid>
);
}
Expand Down
63 changes: 36 additions & 27 deletions src/components/Message/AppMessage/Instructions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,37 +65,46 @@ function Instructions(props: MessageBaseProps) {
e.preventDefault();
const data = new FormData(e.target as HTMLFormElement);
const apiKey = data.get("openai-api-key");

if (typeof apiKey !== "string") {
return;
}

// See if this API Key is valid
setIsValidating(true);
settings.currentProvider
.validateApiKey(apiKey)
.then((valid) => {
if (valid) {
setIsInvalid(false);

const newProvider = providerFromUrl(settings.currentProvider.apiUrl, apiKey.trim());

setSettings({
...settings,
currentProvider: newProvider,
providers: {
...settings.providers,
[newProvider.apiUrl]: newProvider,
},
});
} else {
if (settings.currentProvider instanceof FreeModelProvider) {
// If user chooses the free provider, no need for validation
setSettings({
...settings,
currentProvider: new FreeModelProvider(),
});
} else {
// See if this API Key is valid
setIsValidating(true);
settings.currentProvider
.validateApiKey(apiKey)
.then((valid) => {
if (valid) {
setIsInvalid(false);

const newProvider = providerFromUrl(settings.currentProvider.apiUrl, apiKey.trim());

setSettings({
...settings,
currentProvider: newProvider,
providers: {
...settings.providers,
[newProvider.apiUrl]: newProvider,
},
});
} else {
setIsInvalid(true);
}
})
.catch((err) => {
console.warn("Error validating API Key", err);
setIsInvalid(true);
}
})
.catch((err) => {
console.warn("Error validating API Key", err);
setIsInvalid(true);
})
.finally(() => setIsValidating(false));
})
.finally(() => setIsValidating(false));
}
};

const handleProviderChange = useCallback(
Expand Down Expand Up @@ -150,7 +159,7 @@ function Instructions(props: MessageBaseProps) {
name="openai-api-key"
bg="white"
_dark={{ bg: "gray.700" }}
required
required={!(settings.currentProvider instanceof FreeModelProvider)}
/>
<Button type="submit" size="sm" isLoading={isValidating}>
Save
Expand Down
6 changes: 3 additions & 3 deletions src/lib/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { ChatCraftModel } from "../lib/ChatCraftModel";
import { ProviderData, ChatCraftProvider } from "../lib/ChatCraftProvider";
import { providerFromJSON, providerFromUrl } from "./providers";
import { OpenAiProvider } from "./providers/OpenAiProvider";
import { FreeModelProvider } from "./providers/DefaultProvider/FreeModelProvider";
/**
* We can use models from OpenAI or OpenRouter (https://openrouter.ai/docs).
* If using the latter, we need to override the basePath to use the OpenRouter URL.
Expand Down Expand Up @@ -42,7 +42,7 @@ export type Settings = {
};

export const defaults: Settings = {
model: new ChatCraftModel("gpt-3.5-turbo"),
model: new ChatCraftModel("undi95/toppy-m-7b:free"),
temperature: 0,
enterBehaviour: "send",
// Disabled by default, since token parsing requires downloading larger deps
Expand All @@ -55,7 +55,7 @@ export const defaults: Settings = {
voice: TextToSpeechVoices.ALLOY,
},
providers: {},
currentProvider: new OpenAiProvider(),
currentProvider: new FreeModelProvider(),
};

export const key = "settings";
Expand Down
Loading