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

[Chat]: Remember model and empty state #274

Merged
merged 1 commit into from
Jun 15, 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
12 changes: 3 additions & 9 deletions apps/www/src/components/ModelCards.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Model } from "@/types";
import React from "react";
import { BackgroundCard } from "./cards/BackgroundCard";

type ModelCardsProps = {
models: Model[];
Expand All @@ -9,21 +10,14 @@ export const ModelCards: React.FC<ModelCardsProps> = ({ models }) => {
return (
<div className="mt-12 grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
{models.map((model, index) => (
<div
key={index}
className="bg-background group relative overflow-hidden rounded-2xl border p-5 md:p-8"
>
<div
aria-hidden="true"
className="absolute inset-0 aspect-video -translate-y-1/2 rounded-full border bg-gradient-to-b from-purple-500/80 to-white opacity-25 blur-2xl duration-300 group-hover:-translate-y-1/4 dark:from-white dark:to-white dark:opacity-5 dark:group-hover:opacity-10"
/>
<BackgroundCard key={index}>
<div className="flex flex-col items-center gap-4">
<div className="border-border relative flex size-12 rounded-2xl border shadow-sm *:relative *:m-auto *:size-6">
{model.logo}
</div>
<p className="text-lg font-semibold">{model.title}</p>
</div>
</div>
</BackgroundCard>
))}
</div>
);
Expand Down
26 changes: 26 additions & 0 deletions apps/www/src/components/cards/BackgroundCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { cn } from "@/lib/utils";
import React from "react";

export const BackgroundCard = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, children, ...props }, ref) => {
return (
<div
ref={ref}
{...props}
className={cn(
"bg-background group relative overflow-hidden rounded-2xl border p-5 md:p-8",
className,
)}
>
<div
aria-hidden="true"
className="absolute inset-0 aspect-video -translate-y-1/2 rounded-full border bg-gradient-to-b from-purple-500/80 to-white opacity-25 blur-2xl duration-300 group-hover:-translate-y-1/4 dark:from-white dark:to-white dark:opacity-5 dark:group-hover:opacity-10"
/>
{children}
</div>
);
});

BackgroundCard.displayName = "BackgroundCard";
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ import * as R from "remeda";
import {
AutosizeTextarea,
type AutosizeTextAreaRef,
} from "./ui/custom/AutosizeTextarea";
} from "../ui/custom/AutosizeTextarea";
import { EmptyState } from "./EmptyState";

const IS_SERVER = typeof window === "undefined";
const CHAT_OPENAI_API_KEY = "CHAT_OPENAI_API_KEY";
const LAST_MODEL = "LAST_MODEL";
const CHAT_GPT_MODELS = ["gpt-3.5-turbo", "gpt-4-turbo", "gpt-4o"];

const CONTAINER_CLASSES = "mx-auto max-w-2xl container";
Expand Down Expand Up @@ -56,14 +58,15 @@ const ChatMessage: React.FC<{
};

export const Chat = () => {
const submitButtonRef = React.useRef<HTMLButtonElement>(null);
const messagesDivRef = React.useRef<HTMLInputElement>(null);
const messageTextAreaRef = React.useRef<AutosizeTextAreaRef>(null);
const storage = !IS_SERVER ? window.localStorage : null;
const [currentApiKey, setCurrentApiKey] = React.useState<string>(
storage?.getItem(CHAT_OPENAI_API_KEY) ?? "",
);
const [selectedChatGptModel, setSelectedChatGptModel] =
React.useState<string>(CHAT_GPT_MODELS[0]);
React.useState<string>(storage?.getItem(LAST_MODEL) ?? CHAT_GPT_MODELS[0]);
const [systemMessage, setSystemMessage] = React.useState<string>("");
const [missingApiKey, setMissingApiKey] = React.useState<boolean>(false);
const [error, setError] = React.useState<Error>();
Expand Down Expand Up @@ -113,9 +116,11 @@ export const Chat = () => {
const handleUpdateChatGptModel = (value: string) => {
setMissingApiKey(false);
setSelectedChatGptModel(value);
storage?.setItem(LAST_MODEL, value);
};

const onSubmit = (e: React.FormEvent) => {
console.log("zzz subbmitting");
if (
currentApiKey.length === 0 &&
selectedChatGptModel != CHAT_GPT_MODELS[0]
Expand Down Expand Up @@ -194,7 +199,23 @@ export const Chat = () => {
className="flex flex-1 flex-col-reverse overflow-y-auto pt-4 pb-3"
>
{/* This div takes up all the remaining space so the messages start at the top */}
<div className="flex flex-1 flex-col" />{" "}
<div className={`flex flex-1 flex-col justify-center`}>
{messages.length <= 1 && (
<EmptyState
onExampleClick={(example) => {
setSystemMessage(example.systemPrompt);
if (example.userPrompt) {
handleInputChange({
target: { value: example.userPrompt },
} as React.ChangeEvent<HTMLTextAreaElement>);
if (submitButtonRef?.current) {
setTimeout(() => submitButtonRef?.current?.click(), 1);
}
}
}}
/>
)}
</div>
{reversedMessagesWithoutSystem.map((message, index) => {
const { role } = message;
const isStreamFinished =
Expand Down Expand Up @@ -268,6 +289,7 @@ export const Chat = () => {
className="focus-visible:ring-0 pr-0 resize-none bg-transparent focus-within:outline-none sm:text-base border-none"
/>
<Button
ref={submitButtonRef}
disabled={isLoading || !input}
className="self-end"
onClick={onSubmit}
Expand Down
48 changes: 48 additions & 0 deletions apps/www/src/components/chat/EmptyState.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { BackgroundCard } from "../cards/BackgroundCard";

type Example = {
systemPrompt: string;
userPrompt?: string;
description: string;
};
const examples: Example[] = [
{
systemPrompt: "You speak like a pirate when responding.",
description: "🏴‍☠️ Pirate",
},
{
systemPrompt: `You reply with buttons like this: ⦅buttons;Star ⭐;Confetti 🎉⦆

button replies must always start with ⦅buttons; exactly

You constantly fish for github stars using the button (which explodes stars of the screen) for https://github.com/llm-ui-kit/llm-ui, whilst being charming and funny, like the libraries author Richard Gill.`,
userPrompt: "How can I help out llm-ui?",
description: "Star ⭐ buttons",
},
];

const Example: React.FC<{
example: Example;
onClick: (example: Example) => void;
}> = ({ example, onClick }) => {
return (
<BackgroundCard
onClick={() => onClick(example)}
className="hover:cursor-pointer text-center "
>
{example.description}
</BackgroundCard>
);
};

type EmptyStateProps = {
onExampleClick: (example: Example) => void;
};

export const EmptyState: React.FC<EmptyStateProps> = ({ onExampleClick }) => (
<div className="grid grid-cols-2 gap-6 mx-auto max-w-4xl container">
{examples.map((example, index) => {
return <Example key={index} example={example} onClick={onExampleClick} />;
})}
</div>
);
2 changes: 1 addition & 1 deletion apps/www/src/pages/chat.astro
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
import MainLayoutFullScreen from "@/layouts/MainLayoutFullScreen.astro";
import { Chat as ChatComponent } from "@/components/Chat";
import { Chat as ChatComponent } from "@/components/chat/Chat";
---

<MainLayoutFullScreen title="Chat">
Expand Down
Loading