This commit is contained in:
pablodanswer 2024-09-04 18:45:52 -07:00 committed by GitHub
parent 61a17319c9
commit 420aabc963
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 176 additions and 89 deletions

View File

@ -1,3 +1,13 @@
import {
AnthropicIcon,
AWSIcon,
AzureIcon,
CPUIcon,
OpenAIIcon,
OpenSourceIcon,
} from "@/components/icons/icons";
import { FaRobot } from "react-icons/fa";
export interface CustomConfigKey {
name: string;
description: string | null;
@ -53,3 +63,18 @@ export interface LLMProviderDescriptor {
groups: number[];
display_model_names: string[] | null;
}
export const getProviderIcon = (providerName: string) => {
switch (providerName) {
case "openai":
return OpenAIIcon;
case "anthropic":
return AnthropicIcon;
case "bedrock":
return AWSIcon;
case "azure":
return AzureIcon;
default:
return CPUIcon;
}
};

View File

@ -482,7 +482,7 @@ export function CCPairIndexingStatusTable({
if (sourceMatches || matchingConnectors.length > 0) {
return (
<React.Fragment key={ind}>
<div className="mt-4" />
<br className="mt-4" />
<SummaryRow
source={source}

View File

@ -57,6 +57,7 @@ export function ChatBanner() {
className={`${settings.enterpriseSettings.two_lines_for_chat_header ? "line-clamp-2" : "line-clamp-1"} text-center w-full overflow-hidden pr-8`}
>
<MinimalMarkdown
className="prose text-sm max-w-full"
content={settings.enterpriseSettings.custom_header_content}
/>
</div>
@ -65,6 +66,7 @@ export function ChatBanner() {
className="absolute top-0 left-0 invisible w-full"
>
<MinimalMarkdown
className="prose text-sm max-w-full"
content={settings.enterpriseSettings.custom_header_content}
/>
</div>

View File

@ -338,10 +338,10 @@ export function ChatInputBar({
updateInputPrompt(currentPrompt);
}}
>
<p className="font-bold">{currentPrompt.prompt}</p>
<p className="line-clamp-1">
<p className="font-bold">{currentPrompt.prompt}:</p>
<p className="text-left flex-grow mr-auto line-clamp-1">
{currentPrompt.id == selectedAssistant.id && "(default) "}
{currentPrompt.content}
{currentPrompt.content?.trim()}
</p>
</button>
))}

View File

@ -46,6 +46,7 @@ export function ChatSessionDisplay({
showDeleteModal?: (chatSession: ChatSession) => void;
}) {
const router = useRouter();
const [isHovering, setIsHovering] = useState(false);
const [isRenamingChat, setIsRenamingChat] = useState(false);
const [isMoreOptionsDropdownOpen, setIsMoreOptionsDropdownOpen] =
useState(false);
@ -97,6 +98,11 @@ export function ChatSessionDisplay({
<Link
className="flex my-1 group relative"
key={chatSession.id}
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => {
setIsMoreOptionsDropdownOpen(false);
setIsHovering(false);
}}
onClick={() => {
if (settings?.isMobile && closeSidebar) {
closeSidebar();
@ -145,7 +151,7 @@ export function ChatSessionDisplay({
</p>
)}
{isSelected &&
{isHovering &&
(isRenamingChat ? (
<div className="ml-auto my-auto items-center flex">
<div
@ -185,54 +191,68 @@ export function ChatSessionDisplay({
)}
<div>
<div
onClick={() => {
setIsMoreOptionsDropdownOpen(
!isMoreOptionsDropdownOpen
);
}}
className={"-my-1"}
>
<Popover
open={isMoreOptionsDropdownOpen}
onOpenChange={(open: boolean) =>
setIsMoreOptionsDropdownOpen(open)
}
content={
<div className="hover:bg-black/10 p-1 rounded">
<FiMoreHorizontal size={16} />
</div>
}
popover={
<div className="border border-border rounded-lg bg-background z-50 w-32">
{showShareModal && (
<DefaultDropdownElement
name="Share"
icon={FiShare2}
onSelect={() => showShareModal(chatSession)}
/>
)}
<DefaultDropdownElement
name="Rename"
icon={FiEdit2}
onSelect={() => setIsRenamingChat(true)}
/>
</div>
}
requiresContentPadding
sideOffset={6}
triggerMaxWidth
/>
</div>
{search ? (
showDeleteModal && (
<div
onClick={() => showDeleteModal(chatSession)}
className={`p-1 -m-1 rounded ml-1`}
>
<FiTrash size={16} />
</div>
)
) : (
<div
onClick={() => {
setIsMoreOptionsDropdownOpen(
!isMoreOptionsDropdownOpen
);
}}
className="-my-1"
>
<Popover
open={isMoreOptionsDropdownOpen}
onOpenChange={(open: boolean) =>
setIsMoreOptionsDropdownOpen(open)
}
content={
<div className="p-1 rounded">
<FiMoreHorizontal size={16} />
</div>
}
popover={
<div className="border border-border rounded-lg bg-background z-50 w-32">
{showShareModal && (
<DefaultDropdownElement
name="Share"
icon={FiShare2}
onSelect={() => showShareModal(chatSession)}
/>
)}
{!search && (
<DefaultDropdownElement
name="Rename"
icon={FiEdit2}
onSelect={() => setIsRenamingChat(true)}
/>
)}
{showDeleteModal && (
<DefaultDropdownElement
name="Delete"
icon={FiTrash}
onSelect={() =>
showDeleteModal(chatSession)
}
/>
)}
</div>
}
requiresContentPadding
sideOffset={6}
triggerMaxWidth
/>
</div>
)}
</div>
{showDeleteModal && (
<div
onClick={() => showDeleteModal(chatSession)}
className={`hover:bg-black/10 p-1 -m-1 rounded ml-1`}
>
<FiTrash size={16} />
</div>
)}
</div>
))}
</div>

View File

@ -53,9 +53,14 @@ const ToggleSwitch = () => {
onClick={() => handleTabChange("search")}
>
<SearchIcon size={16} className="mr-2" />
<div className="flex items-end">
<div className="flex items-center">
Search
<div className="ml-2 flex items-end">{commandSymbol}S</div>
<div className="ml-2 flex content-center">
<span className="leading-none pb-[1px] my-auto">
{commandSymbol}
</span>
<span className="my-auto">S</span>
</div>
</div>
</button>
<button
@ -69,7 +74,12 @@ const ToggleSwitch = () => {
<ChatIcon size={16} className="mr-2" />
<div className="items-end flex">
Chat
<div className="ml-2 flex items-end">{commandSymbol}D</div>
<div className="ml-2 flex content-center">
<span className="leading-none pb-[1px] my-auto">
{commandSymbol}
</span>
<span className="my-auto">D</span>
</div>
</div>
</button>
</div>

View File

@ -36,7 +36,7 @@
.include-scrollbar {
scrollbar-width: thin;
scrollbar-color: #888 #f1f1f1;
scrollbar-color: #888 transparent;
}
.inputscroll::-webkit-scrollbar-track {

View File

@ -1,3 +1,4 @@
import { CodeBlock } from "@/app/chat/message/CodeBlock";
import React from "react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
@ -5,11 +6,13 @@ import remarkGfm from "remark-gfm";
interface MinimalMarkdownProps {
content: string;
className?: string;
useCodeBlock?: boolean;
}
export const MinimalMarkdown: React.FC<MinimalMarkdownProps> = ({
content,
className = "",
useCodeBlock = false,
}) => {
return (
<ReactMarkdown
@ -26,6 +29,11 @@ export const MinimalMarkdown: React.FC<MinimalMarkdownProps> = ({
p: ({ node, ...props }) => (
<p {...props} className="text-wrap break-word text-sm m-0 w-full" />
),
code: useCodeBlock
? (props) => (
<CodeBlock className="w-full" {...props} content={content} />
)
: (props) => <code {...props} />,
}}
remarkPlugins={[remarkGfm]}
>

View File

@ -1,7 +1,10 @@
import React from "react";
import { getDisplayNameForModel } from "@/lib/hooks";
import { structureValue } from "@/lib/llm/utils";
import { LLMProviderDescriptor } from "@/app/admin/configuration/llm/interfaces";
import {
getProviderIcon,
LLMProviderDescriptor,
} from "@/app/admin/configuration/llm/interfaces";
interface LlmListProps {
llmProviders: LLMProviderDescriptor[];
@ -9,6 +12,7 @@ interface LlmListProps {
onSelect: (value: string | null) => void;
userDefault?: string | null;
scrollable?: boolean;
hideProviderIcon?: boolean;
}
export const LlmList: React.FC<LlmListProps> = ({
@ -19,7 +23,11 @@ export const LlmList: React.FC<LlmListProps> = ({
scrollable,
}) => {
const llmOptionsByProvider: {
[provider: string]: { name: string; value: string }[];
[provider: string]: {
name: string;
value: string;
icon: React.FC<{ size?: number; className?: string }>;
}[];
} = {};
const uniqueModelNames = new Set<string>();
@ -39,6 +47,7 @@ export const LlmList: React.FC<LlmListProps> = ({
llmProvider.provider,
modelName
),
icon: getProviderIcon(llmProvider.provider),
});
}
}
@ -67,17 +76,18 @@ export const LlmList: React.FC<LlmListProps> = ({
User Default (currently {getDisplayNameForModel(userDefault)})
</button>
)}
{llmOptions.map(({ name, value }, index) => (
{llmOptions.map(({ name, icon, value }, index) => (
<button
type="button"
key={index}
className={`w-full py-1.5 px-2 text-sm ${
className={`w-full py-1.5 flex gap-x-2 px-2 text-sm ${
currentLlm == name
? "bg-background-200"
: "bg-background hover:bg-background-100"
} text-left rounded`}
onClick={() => onSelect(value)}
>
{icon({ size: 16 })}
{getDisplayNameForModel(name)}
</button>
))}

View File

@ -71,7 +71,7 @@ export const AnimatedToggle = ({
Get quality results immediately, best suited for instant access to
your documents.
</p>
<p className="mt-2 text-xs">Shortcut: ({commandSymbol}/)</p>
<p className="mt-2 flex text-xs">Shortcut: ({commandSymbol}/)</p>
</div>
}
>

View File

@ -34,8 +34,9 @@ import FixedLogo from "@/app/chat/shared_chat_search/FixedLogo";
import { usePopup } from "../admin/connectors/Popup";
import { FeedbackType } from "@/app/chat/types";
import { FeedbackModal } from "@/app/chat/modal/FeedbackModal";
import { handleChatFeedback } from "@/app/chat/lib";
import { deleteChatSession, handleChatFeedback } from "@/app/chat/lib";
import SearchAnswer from "./SearchAnswer";
import { DeleteEntityModal } from "../modals/DeleteEntityModal";
export type searchState =
| "input"
@ -511,7 +512,12 @@ export const SearchSection = ({
};
const [firstSearch, setFirstSearch] = useState(true);
const [searchState, setSearchState] = useState<searchState>("input");
const [deletingChatSession, setDeletingChatSession] =
useState<ChatSession | null>();
const showDeleteModal = (chatSession: ChatSession) => {
setDeletingChatSession(chatSession);
};
// Used to maintain a "time out" for history sidebar so our existing refs can have time to process change
const [untoggled, setUntoggled] = useState(false);
@ -591,6 +597,24 @@ export const SearchSection = ({
<>
<div className="flex relative pr-[8px] h-full text-default">
{popup}
{deletingChatSession && (
<DeleteEntityModal
entityType="search"
entityName={deletingChatSession.name}
onClose={() => setDeletingChatSession(null)}
onSubmit={async () => {
const response = await deleteChatSession(deletingChatSession.id);
if (response.ok) {
setDeletingChatSession(null);
// go back to the main page
router.push("/search");
} else {
alert("Failed to delete chat session");
}
}}
/>
)}
{currentFeedback && (
<FeedbackModal
feedbackType={currentFeedback[0]}
@ -628,6 +652,7 @@ export const SearchSection = ({
>
<div className="w-full relative">
<HistorySidebar
showDeleteModal={showDeleteModal}
explicitlyUntoggle={explicitlyUntoggle}
reset={() => setQuery("")}
page="search"
@ -672,7 +697,7 @@ export const SearchSection = ({
(ccPairs.length > 0 || documentSets.length > 0) && (
<SourceSelector
{...filterManager}
showDocSidebar={showDocSidebar || toggledSidebar}
showDocSidebar={toggledSidebar}
availableDocumentSets={finalAvailableDocumentSets}
existingSources={finalAvailableSources}
availableTags={tags}
@ -727,7 +752,7 @@ export const SearchSection = ({
toggleAgentic={
disabledAgentic ? undefined : toggleAgentic
}
showingSidebar={showDocSidebar || toggledSidebar}
showingSidebar={toggledSidebar}
agentic={agentic}
query={query}
setQuery={setQuery}

View File

@ -115,7 +115,7 @@ export function TagFilter({
<FiTag className="mr-1 my-auto" />
Tags
</div>
<div className="flex overflow-y-scroll max-h-96 flex-wrap gap-x-1 gap-y-1">
<div className="flex overflow-y-scroll overflow-x-hidden input-scrollbar max-h-96 flex-wrap gap-x-1 gap-y-1">
{filteredTags.length > 0 ? (
filteredTags.map((tag) => (
<div

View File

@ -2,6 +2,7 @@ import { Quote } from "@/lib/search/interfaces";
import { ResponseSection, StatusOptions } from "./ResponseSection";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { MinimalMarkdown } from "@/components/chat_search/MinimalMarkdown";
const TEMP_STRING = "__$%^TEMP$%^__";
@ -40,12 +41,10 @@ export const AnswerSection = (props: AnswerSectionProps) => {
header = <></>;
body = (
<ReactMarkdown
className="prose text-sm max-w-full"
remarkPlugins={[remarkGfm]}
>
{replaceNewlines(props.answer || "")}
</ReactMarkdown>
<MinimalMarkdown
useCodeBlock
content={replaceNewlines(props.answer || "")}
/>
);
// error while building answer (NOTE: if error occurs during quote generation
@ -63,12 +62,7 @@ export const AnswerSection = (props: AnswerSectionProps) => {
status = "success";
header = <></>;
body = (
<ReactMarkdown
className="prose text-sm max-w-full"
remarkPlugins={[remarkGfm]}
>
{replaceNewlines(props.answer)}
</ReactMarkdown>
<MinimalMarkdown useCodeBlock content={replaceNewlines(props.answer)} />
);
}

View File

@ -2,7 +2,10 @@ import { Persona } from "@/app/admin/assistants/interfaces";
import { CCPairBasicInfo, DocumentSet, User } from "../types";
import { getCurrentUserSS } from "../userSS";
import { fetchSS } from "../utilsSS";
import { FullLLMProvider } from "@/app/admin/configuration/llm/interfaces";
import {
FullLLMProvider,
getProviderIcon,
} from "@/app/admin/configuration/llm/interfaces";
import { ToolSnapshot } from "../tools/interfaces";
import { fetchToolsSS } from "../tools/fetchTools";
import {
@ -94,17 +97,7 @@ export async function fetchAssistantEditorInfoSS(
}
for (const provider of llmProviders) {
if (provider.provider == "openai") {
provider.icon = OpenAIIcon;
} else if (provider.provider == "anthropic") {
provider.icon = AnthropicIcon;
} else if (provider.provider == "bedrock") {
provider.icon = AWSIcon;
} else if (provider.provider == "azure") {
provider.icon = AzureIcon;
} else {
provider.icon = OpenSourceIcon;
}
provider.icon = getProviderIcon(provider.provider);
}
const existingPersona = personaResponse