Cleaner initial chat screen (#2528)

* cleaner initial chat screen

* slightly cleaner animation

* cleaner cards

* use display name + minor updates to models

* minor udpate to ui

* remove logs

* update based on feedback

* minor nits

* formatting
This commit is contained in:
pablodanswer
2024-10-28 14:39:34 -07:00
committed by GitHub
parent a40082c5da
commit 678ba41321
8 changed files with 253 additions and 154 deletions

View File

@@ -41,6 +41,19 @@ personas:
icon_color: "#6FB1FF"
display_priority: 1
is_visible: true
starter_messages:
- name: "General Information"
description: "Ask about available information"
message: "Hello! I'm interested in learning more about the information available here. Could you give me an overview of the types of data or documents that might be accessible?"
- name: "Specific Topic Search"
description: "Search for specific information"
message: "Hi! I'd like to learn more about a specific topic. Could you help me find relevant documents and information?"
- name: "Recent Updates"
description: "Inquire about latest additions"
message: "Hello! I'm curious about any recent updates or additions to the knowledge base. Can you tell me what new information has been added lately?"
- name: "Cross-referencing Information"
description: "Connect information from different sources"
message: "Hi! I'm working on a project that requires connecting information from multiple sources. How can I effectively cross-reference data across different documents or categories?"
- id: 1
name: "General"
@@ -57,6 +70,19 @@ personas:
icon_color: "#FF6F6F"
display_priority: 0
is_visible: true
starter_messages:
- name: "Open Discussion"
description: "Start an open-ended conversation"
message: "Hi! Can you help me write a professional email?"
- name: "Problem Solving"
description: "Get help with a challenge"
message: "Hello! I need help managing my daily tasks better. Do you have any simple tips?"
- name: "Learn Something New"
description: "Explore a new topic"
message: "Hi! Could you explain what project management is in simple terms?"
- name: "Creative Brainstorming"
description: "Generate creative ideas"
message: "Hello! I need to brainstorm some team building activities. Do you have any fun suggestions?"
- id: 2
name: "Paraphrase"
@@ -73,7 +99,19 @@ personas:
icon_color: "#6FFF8D"
display_priority: 2
is_visible: false
starter_messages:
- name: "Document Search"
description: "Find exact information"
message: "Hi! Could you help me find information about our team structure and reporting lines from our internal documents?"
- name: "Process Verification"
description: "Find exact quotes"
message: "Hello! I need to understand our project approval process. Could you find the exact steps from our documentation?"
- name: "Technical Documentation"
description: "Search technical details"
message: "Hi there! I'm looking for information about our deployment procedures. Can you find the specific steps from our technical guides?"
- name: "Policy Reference"
description: "Check official policies"
message: "Hello! Could you help me find our official guidelines about client communication? I need the exact wording from our documentation."
- id: 3
name: "Art"
@@ -86,8 +124,21 @@ personas:
llm_filter_extraction: false
recency_bias: "no_decay"
document_sets: []
icon_shape: 234124
icon_shape: 234124
icon_color: "#9B59B6"
image_generation: true
image_generation: true
display_priority: 3
is_visible: true
starter_messages:
- name: "Landscape"
description: "Generate a landscape image"
message: "Create an image of a serene mountain lake at sunset, with snow-capped peaks reflected in the calm water and a small wooden cabin on the shore."
- name: "Character"
description: "Generate a character image"
message: "Generate an image of a futuristic robot with glowing blue eyes, sleek metallic body, and intricate circuitry visible through transparent panels on its chest and arms."
- name: "Abstract"
description: "Create an abstract image"
message: "Create an abstract image representing the concept of time, using swirling clock hands, fragmented hourglasses, and streaks of light to convey the passage of moments and eras."
- name: "Urban Scene"
description: "Generate an urban landscape"
message: "Generate an image of a bustling futuristic cityscape at night, with towering skyscrapers, flying vehicles, holographic advertisements, and a mix of neon and bioluminescent lighting."

View File

@@ -1002,6 +1002,10 @@ export function AssistantEditor({
Starter Messages (Optional){" "}
</div>
</div>
<SubLabel>
Add pre-defined messages to help users get started. Only
the first 4 will be displayed.
</SubLabel>
<FieldArray
name="starter_messages"
render={(

View File

@@ -1,96 +1,44 @@
import { getSourceMetadataForSources } from "@/lib/sources";
import { ValidSources } from "@/lib/types";
import { Persona } from "../admin/assistants/interfaces";
import { Divider } from "@tremor/react";
import { FiBookmark, FiInfo } from "react-icons/fi";
import { HoverPopup } from "@/components/HoverPopup";
import { AssistantIcon } from "@/components/assistants/AssistantIcon";
import { useState } from "react";
import { DisplayAssistantCard } from "@/components/assistants/AssistantCards";
export function ChatIntro({
availableSources,
selectedPersona,
}: {
availableSources: ValidSources[];
selectedPersona: Persona;
}) {
const availableSourceMetadata = getSourceMetadataForSources(availableSources);
export function ChatIntro({ selectedPersona }: { selectedPersona: Persona }) {
const [hoveredAssistant, setHoveredAssistant] = useState(false);
return (
<>
<div className="flex justify-center items-center h-full">
<div className="mobile:w-[90%] mobile:px-4 w-message-xs 2xl:w-message-sm 3xl:w-message">
<div className="flex">
<div className="mx-auto">
<div className="m-auto text-3xl font-strong font-bold text-strong w-fit">
{selectedPersona?.name || "How can I help you today?"}
<div className="mobile:w-[90%] mobile:px-4 w-message-xs 2xl:w-message-sm 3xl:w-message">
<div className="relative flex w-fit mx-auto justify-center">
<div className="absolute z-10 -left-20 top-1/2 -translate-y-1/2">
<div className="relative">
<div
onMouseEnter={() => setHoveredAssistant(true)}
onMouseLeave={() => setHoveredAssistant(false)}
className="p-4 scale-[.8] cursor-pointer border-dashed rounded-full flex border border-border border-2 border-dashed"
style={{
borderStyle: "dashed",
borderWidth: "1.5px",
borderSpacing: "4px",
}}
>
<AssistantIcon
disableToolip
size={"large"}
assistant={selectedPersona}
/>
</div>
<div className="absolute right-full mr-2 w-[300px] top-0">
{hoveredAssistant && (
<DisplayAssistantCard selectedPersona={selectedPersona} />
)}
</div>
{selectedPersona && (
<div className="mt-1">{selectedPersona.description}</div>
)}
</div>
</div>
{selectedPersona && selectedPersona.num_chunks !== 0 && (
<>
<Divider />
<div>
{selectedPersona.document_sets.length > 0 && (
<div className="mt-2">
<p className="font-bold mb-1 mt-4 text-emphasis">
Knowledge Sets:{" "}
</p>
<div className="flex flex-wrap gap-2">
{selectedPersona.document_sets.map((documentSet) => (
<div key={documentSet.id} className="w-fit">
<HoverPopup
mainContent={
<span className="flex w-fit p-1 rounded border border-border text-xs font-medium cursor-default">
<div className="mr-1 my-auto">
<FiBookmark />
</div>
{documentSet.name}
</span>
}
popupContent={
<div className="flex py-1 w-96">
<FiInfo className="my-auto mr-2" />
<div className="text-sm">
{documentSet.description}
</div>
</div>
}
direction="top"
/>
</div>
))}
</div>
</div>
)}
{availableSources.length > 0 && (
<div className="mt-1">
<p className="font-bold mb-1 mt-4 text-emphasis">
Connected Sources:{" "}
</p>
<div className={`flex flex-wrap gap-2`}>
{availableSourceMetadata.map((sourceMetadata) => (
<span
key={sourceMetadata.internalName}
className="flex w-fit p-1 rounded border border-border text-xs font-medium cursor-default"
>
<div className="mr-1 my-auto">
{sourceMetadata.icon({})}
</div>
<div className="my-auto">
{sourceMetadata.displayName}
</div>
</span>
))}
</div>
</div>
)}
</div>
</>
)}
<div className="text-3xl line-clamp-2 text-text-800 font-base font-semibold text-strong">
{selectedPersona?.name || "How can I help you today?"}
</div>
</div>
</div>
</>

View File

@@ -103,6 +103,7 @@ import { ApiKeyModal } from "@/components/llm/ApiKeyModal";
import BlurBackground from "./shared_chat_search/BlurBackground";
import { NoAssistantModal } from "@/components/modals/NoAssistantModal";
import { useAssistants } from "@/components/context/AssistantsContext";
import { Divider } from "@tremor/react";
const TEMP_USER_MESSAGE_ID = -1;
const TEMP_ASSISTANT_MESSAGE_ID = -2;
@@ -741,12 +742,6 @@ export function ChatPage({
}, [liveAssistant]);
const filterManager = useFilters();
const [finalAvailableSources, finalAvailableDocumentSets] =
computeAvailableFilters({
selectedPersona: selectedAssistant,
availableSources,
availableDocumentSets,
});
const [currentFeedback, setCurrentFeedback] = useState<
[FeedbackType, number] | null
@@ -2002,7 +1997,7 @@ export function ChatPage({
{...getRootProps()}
>
<div
className={`w-full h-full flex flex-col overflow-y-auto include-scrollbar overflow-x-hidden relative`}
className={`w-full h-full flex flex-col overflow-y-auto include-scrollbar overflow-x-hidden relative`}
ref={scrollableDivRef}
>
{/* ChatBanner is a custom banner that displays a admin-specified message at
@@ -2012,11 +2007,51 @@ export function ChatPage({
!isFetchingChatMessages &&
currentSessionChatState == "input" &&
!loadingError && (
<ChatIntro
availableSources={finalAvailableSources}
selectedPersona={liveAssistant}
/>
<div className="h-full flex flex-col justify-center items-center">
<ChatIntro selectedPersona={liveAssistant} />
<div
key={-4}
className={`
mx-auto
px-4
w-full
max-w-[750px]
flex
flex-wrap
justify-center
mt-2
h-40
items-start
mb-6`}
>
{currentPersona?.starter_messages &&
currentPersona.starter_messages.length >
0 && (
<>
<Divider className="mx-2" />
{currentPersona.starter_messages
.slice(0, 4)
.map((starterMessage, i) => (
<div key={i} className="w-1/2">
<StarterMessage
starterMessage={starterMessage}
onClick={() =>
onSubmit({
messageOverride:
starterMessage.message,
})
}
/>
</div>
))}
</>
)}
</div>
</div>
)}
<div
className={
"-ml-4 w-full mx-auto " +
@@ -2383,45 +2418,6 @@ export function ChatPage({
/>
</div>
)}
{currentPersona &&
currentPersona.starter_messages &&
currentPersona.starter_messages.length > 0 &&
selectedAssistant &&
messageHistory.length === 0 &&
!isFetchingChatMessages && (
<div
key={-4}
className={`
mx-auto
px-4
w-searchbar-xs
2xl:w-searchbar-sm
3xl:w-searchbar
grid
gap-4
grid-cols-1
grid-rows-1
mt-4
md:grid-cols-2
mb-6`}
>
{currentPersona.starter_messages.map(
(starterMessage, i) => (
<div key={i} className="w-full">
<StarterMessage
starterMessage={starterMessage}
onClick={() =>
onSubmit({
messageOverride:
starterMessage.message,
})
}
/>
</div>
)
)}
</div>
)}
{/* Some padding at the bottom so the search bar has space at the bottom to not cover the last message*/}
<div ref={endPaddingRef} className="h-[95px]" />

View File

@@ -1,21 +1,29 @@
import { StarterMessage } from "../admin/assistants/interfaces";
import { StarterMessage as StarterMessageType } from "../admin/assistants/interfaces";
export function StarterMessage({
starterMessage,
onClick,
}: {
starterMessage: StarterMessage;
starterMessage: StarterMessageType;
onClick: () => void;
}) {
return (
<div
className={
"py-2 px-3 rounded border border-border bg-white cursor-pointer hover:bg-hover-light h-full"
}
className="mb-4 mx-2 group relative overflow-hidden rounded-xl border border-border bg-gradient-to-br from-white to-background p-4 shadow-sm transition-all duration-300 hover:shadow-md hover:scale-[1.005] cursor-pointer"
onClick={onClick}
>
<p className="font-medium text-emphasis">{starterMessage.name}</p>
<p className="text-subtle text-sm">{starterMessage.description}</p>
<div className="absolute inset-0 bg-gradient-to-r from-blue-100 to-purple-100 opacity-0 group-hover:opacity-20 transition-opacity duration-300" />
<h3
className="text-base flex items-center font-medium text-text-800 group-hover:text-text-900 transition-colors duration-300
line-clamp-2 gap-x-2 overflow-hidden"
>
{starterMessage.name}
</h3>
<div className={`overflow-hidden transition-all duration-300 max-h-20}`}>
<p className="text-sm text-text-600 mt-2">
{starterMessage.description}
</p>
</div>
</div>
);
}

View File

@@ -115,3 +115,63 @@ export function DraggableAssistantCard(props: {
</div>
);
}
export function DisplayAssistantCard({
selectedPersona,
}: {
selectedPersona: Persona;
}) {
return (
<div className="p-4 bg-white/90 backdrop-blur-sm rounded-lg shadow-md border border-border/50 max-w-md w-full mx-auto transition-all duration-300 ease-in-out hover:shadow-lg">
<div className="flex items-center mb-3">
<AssistantIcon
disableToolip
size="medium"
assistant={selectedPersona}
/>
<h2 className="ml-3 text-xl font-semibold text-text-900">
{selectedPersona.name}
</h2>
</div>
<p className="text-sm text-text-600 mb-3 leading-relaxed">
{selectedPersona.description}
</p>
{selectedPersona.tools.length > 0 ||
selectedPersona.llm_relevance_filter ||
selectedPersona.llm_filter_extraction ? (
<div className="space-y-2">
<h3 className="text-base font-medium text-text-900">Capabilities:</h3>
<ul className="space-y-.5">
{/* display all tools */}
{selectedPersona.tools.map((tool, index) => (
<li
key={index}
className="flex items-center text-sm text-text-700"
>
<span className="mr-2 text-text-500 opacity-70"></span>{" "}
{tool.display_name}
</li>
))}
{/* Built in capabilities */}
{selectedPersona.llm_relevance_filter && (
<li className="flex items-center text-sm text-text-700">
<span className="mr-2 text-text-500 opacity-70"></span>{" "}
Advanced Relevance Filtering
</li>
)}
{selectedPersona.llm_filter_extraction && (
<li className="flex items-center text-sm text-text-700">
<span className="mr-2 text-text-500 opacity-70"></span> Smart
Information Extraction
</li>
)}
</ul>
</div>
) : (
<p className="text-sm text-text-600 italic">
No specific capabilities listed for this assistant.
</p>
)}
</div>
);
}

View File

@@ -23,22 +23,38 @@ export function AssistantIcon({
assistant,
size,
border,
disableToolip,
}: {
assistant: Persona;
size?: "small" | "medium" | "large";
size?: "small" | "medium" | "large" | "header";
border?: boolean;
disableToolip?: boolean;
}) {
const color = darkerGenerateColorFromId(assistant.id.toString());
return (
<CustomTooltip showTick line wrap content={assistant.description}>
<CustomTooltip
disabled={disableToolip}
showTick
line
wrap
content={assistant.description}
>
{
// Prioritization order: image, graph, defaults
assistant.uploaded_image_id ? (
<img
alt={assistant.name}
className={`object-cover object-center rounded-sm overflow-hidden transition-opacity duration-300 opacity-100
${size === "large" ? "w-8 h-8" : "w-6 h-6"}`}
${
size === "large"
? "w-10 h-10"
: size === "header"
? "w-14 h-14"
: size === "medium"
? "w-8 h-8"
: "w-6 h-6"
}`}
src={buildImgUrl(assistant.uploaded_image_id)}
loading="lazy"
/>
@@ -46,20 +62,36 @@ export function AssistantIcon({
<div
className={`flex-none
${border && "ring ring-[1px] ring-border-strong "}
${size === "large" ? "w-10 h-10" : "w-6 h-6"} `}
${
size === "large"
? "w-10 h-10"
: size === "header"
? "w-14 h-14"
: size === "medium"
? "w-8 h-8"
: "w-6 h-6"
} `}
>
{createSVG(
{ encodedGrid: assistant.icon_shape, filledSquares: 0 },
assistant.icon_color,
size == "large" ? 36 : 24
size === "large"
? 40
: size === "header"
? 56
: size === "medium"
? 32
: 24
)}
</div>
) : (
<div
className={`flex-none rounded-sm overflow-hidden
${border && "border border-.5 border-border-strong "}
${size === "large" && "w-12 h-12"}
${(!size || size === "small") && "w-6 h-6"} `}
${size === "large" ? "w-10 h-10" : ""}
${size === "header" ? "w-14 h-14" : ""}
${size === "medium" ? "w-8 h-8" : ""}
${!size || size === "small" ? "w-6 h-6" : ""} `}
style={{ backgroundColor: color }}
/>
)

View File

@@ -124,9 +124,9 @@ export const CustomTooltip = ({
!disabled &&
createPortal(
<div
className={`min-w-8 fixed z-[1000] ${citation ? "max-w-[350px]" : "w-40"} ${
large ? (medium ? "w-88" : "w-96") : line && "max-w-64 w-auto"
}
className={`min-w-8 fixed z-[1000] ${
citation ? "max-w-[350px]" : "w-40"
} ${large ? (medium ? "w-88" : "w-96") : line && "max-w-64 w-auto"}
transform -translate-x-1/2 text-sm
${
light