functional ux standing till

This commit is contained in:
pablodanswer 2024-09-15 13:45:46 -07:00
parent 9edbb0806d
commit de18ec7ea4
5 changed files with 197 additions and 137 deletions

View File

@ -754,6 +754,7 @@ def stream_chat_message_objects(
elif isinstance(packet, StreamStopInfo):
print("PACKET IS ENINDG")
print(packet)
if packet.stop_reason is not StreamStopReason.NEW_RESPONSE:
break
@ -766,7 +767,6 @@ def stream_chat_message_objects(
)
# Saving Gen AI answer and responding with message info
if tool_result is None:
tool_call = None
else:
@ -786,7 +786,7 @@ def stream_chat_message_objects(
reference_docs=reference_db_search_docs,
files=ai_message_files,
token_count=len(llm_tokenizer_encode_func(answer.llm_answer)),
citations=db_citations,
citations=db_citations.citation_map if db_citations else None,
error=None,
tool_call=tool_call,
)
@ -823,6 +823,7 @@ def stream_chat_message_objects(
db_session=db_session,
commit=False,
)
reference_db_search_docs = None
else:
if isinstance(packet, ToolCallFinalResult):
tool_result = packet
@ -845,6 +846,7 @@ def stream_chat_message_objects(
# Post-LLM answer processing
try:
print("I am in the final ")
message_specific_citations: MessageSpecificCitations | None = None
if reference_db_search_docs:
message_specific_citations = _translate_citations(

View File

@ -488,7 +488,6 @@ def create_new_chat_message(
if reserved_message_id is not None:
# Edit existing message
existing_message = db_session.query(ChatMessage).get(reserved_message_id)
print(f"creating with reserved id {reserved_message_id}")
if existing_message is None:
raise ValueError(f"No message found with id {reserved_message_id}")

View File

@ -1143,6 +1143,7 @@ export function ChatPage({
continue;
}
console.log("PACKET IS: ", packet);
if (!initialFetchDetails) {
if (!Object.hasOwn(packet, "user_message_id")) {
console.error(
@ -1329,6 +1330,12 @@ export function ChatPage({
tool_args: (packet as ToolCallMetadata).tool_args,
tool_result: (packet as ToolCallMetadata).tool_result,
};
if (
dynamicAssistantMessage.toolCall.tool_name === SEARCH_TOOL_NAME
) {
dynamicAssistantMessage.query =
dynamicAssistantMessage.toolCall.tool_args.query;
}
if (
!dynamicAssistantMessage.toolCall ||

View File

@ -213,7 +213,10 @@ export const AIMessage = ({
return content;
}
}
if (toolCall?.tool_result) {
if (
toolCall?.tool_result &&
toolCall.tool_result.tool_name == INTERNET_SEARCH_TOOL_NAME
) {
return content + ` [${toolCall.tool_name}]()`;
}
@ -306,27 +309,35 @@ export const AIMessage = ({
) : (
<div className="w-6" />
)}
<div className="w-full">
<div className="max-w-message-max break-words">
<div className="w-full ml-4">
<div className="max-w-message-max break-words">
{!toolCall || toolCall.tool_name === SEARCH_TOOL_NAME ? (
{(!toolCall || toolCall.tool_name === SEARCH_TOOL_NAME) && (
<>
{query !== undefined &&
handleShowRetrieved !== undefined &&
isCurrentlyShowingRetrieved !== undefined &&
!retrievalDisabled && (
<div className="mb-1">
<SearchSummary
docs={docs}
filteredDocs={filteredDocs}
query={query}
finished={toolCall?.tool_result != undefined}
hasDocs={hasDocs || false}
messageId={messageId}
handleShowRetrieved={handleShowRetrieved}
finished={
toolCall?.tool_result != undefined ||
isComplete!
}
toggleDocumentSelection={
toggleDocumentSelection
}
handleSearchQueryEdit={handleSearchQueryEdit}
/>
</div>
)}
{handleForceSearch &&
!hasChildAI &&
content &&
query === undefined &&
!hasDocs &&
@ -338,7 +349,7 @@ export const AIMessage = ({
</div>
)}
</>
) : null}
)}
{toolCall &&
!TOOLS_WITH_CUSTOM_HANDLING.includes(
@ -439,10 +450,6 @@ export const AIMessage = ({
} else if (
value?.toString().startsWith("[")
) {
// for some reason <a> tags cause the onClick to not apply
// and the links are unclickable
// TODO: fix the fact that you have to double click to follow link
// for the first link
return (
<Citation link={rest?.href}>
{rest.children}
@ -489,79 +496,6 @@ export const AIMessage = ({
) : isComplete ? null : (
<></>
)}
{isComplete && docs && docs.length > 0 && (
<div className="mt-2 -mx-8 w-full mb-4 flex relative">
<div className="w-full">
<div className="px-8 flex gap-x-2">
{!settings?.isMobile &&
filteredDocs.length > 0 &&
filteredDocs.slice(0, 2).map((doc, ind) => (
<div
key={doc.document_id}
className={`w-[200px] rounded-lg flex-none transition-all duration-500 hover:bg-background-125 bg-text-100 px-4 pb-2 pt-1 border-b
`}
>
<a
href={doc.link || undefined}
target="_blank"
className="text-sm flex w-full pt-1 gap-x-1.5 overflow-hidden justify-between font-semibold text-text-700"
>
<Citation link={doc.link} index={ind + 1} />
<p className="shrink truncate ellipsis break-all">
{doc.semantic_identifier ||
doc.document_id}
</p>
<div className="ml-auto flex-none">
{doc.is_internet ? (
<InternetSearchIcon url={doc.link} />
) : (
<SourceIcon
sourceType={doc.source_type}
iconSize={18}
/>
)}
</div>
</a>
<div className="flex overscroll-x-scroll mt-.5">
<DocumentMetadataBlock document={doc} />
</div>
<div className="line-clamp-3 text-xs break-words pt-1">
{doc.blurb}
</div>
</div>
))}
<div
onClick={() => {
if (toggleDocumentSelection) {
toggleDocumentSelection();
}
}}
key={-1}
className="cursor-pointer w-[200px] rounded-lg flex-none transition-all duration-500 hover:bg-background-125 bg-text-100 px-4 py-2 border-b"
>
<div className="text-sm flex justify-between font-semibold text-text-700">
<p className="line-clamp-1">See context</p>
<div className="flex gap-x-1">
{uniqueSources.map((sourceType, ind) => {
return (
<div key={ind} className="flex-none">
<SourceIcon
sourceType={sourceType}
iconSize={18}
/>
</div>
);
})}
</div>
</div>
<div className="line-clamp-3 text-xs break-words pt-1">
See more
</div>
</div>
</div>
</div>
</div>
)}
</div>
{!hasChildAI &&

View File

@ -4,9 +4,21 @@ import {
} from "@/components/BasicClickable";
import { HoverPopup } from "@/components/HoverPopup";
import { Hoverable } from "@/components/Hoverable";
import { InternetSearchIcon } from "@/components/InternetSearchIcon";
import { SourceIcon } from "@/components/SourceIcon";
import { ChevronDownIcon, InfoIcon } from "@/components/icons/icons";
import { DocumentMetadataBlock } from "@/components/search/DocumentDisplay";
import { Citation } from "@/components/search/results/Citation";
import { SettingsContext } from "@/components/settings/SettingsProvider";
import { Tooltip } from "@/components/tooltip/Tooltip";
import { useEffect, useRef, useState } from "react";
import {
DanswerDocument,
FilteredDanswerDocument,
} from "@/lib/search/interfaces";
import { ValidSources } from "@/lib/types";
import { useContext, useEffect, useRef, useState } from "react";
import { FiCheck, FiEdit2, FiSearch, FiX } from "react-icons/fi";
import { DownChevron } from "react-select/dist/declarations/src/components/indicators";
export function ShowHideDocsButton({
messageId,
@ -37,24 +49,35 @@ export function ShowHideDocsButton({
export function SearchSummary({
query,
hasDocs,
filteredDocs,
finished,
messageId,
handleShowRetrieved,
docs,
toggleDocumentSelection,
handleSearchQueryEdit,
}: {
toggleDocumentSelection?: () => void;
docs?: DanswerDocument[] | null;
filteredDocs: FilteredDanswerDocument[];
finished: boolean;
query: string;
hasDocs: boolean;
messageId: number | null;
handleShowRetrieved: (messageId: number | null) => void;
handleSearchQueryEdit?: (query: string) => void;
}) {
const [isEditing, setIsEditing] = useState(false);
const [finalQuery, setFinalQuery] = useState(query);
const [isOverflowed, setIsOverflowed] = useState(false);
const searchingForRef = useRef<HTMLDivElement>(null);
const editQueryRef = useRef<HTMLInputElement>(null);
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const searchingForRef = useRef<HTMLDivElement | null>(null);
const editQueryRef = useRef<HTMLInputElement | null>(null);
const settings = useContext(SettingsContext);
const uniqueSourceTypes = Array.from(
new Set((docs || []).map((doc) => doc.source_type))
).slice(0, 3);
const toggleDropdown = () => {
setIsDropdownOpen(!isDropdownOpen);
};
useEffect(() => {
const checkOverflow = () => {
@ -68,7 +91,7 @@ export function SearchSummary({
};
checkOverflow();
window.addEventListener("resize", checkOverflow); // Recheck on window resize
window.addEventListener("resize", checkOverflow);
return () => window.removeEventListener("resize", checkOverflow);
}, []);
@ -86,15 +109,30 @@ export function SearchSummary({
}, [query]);
const searchingForDisplay = (
<div className={`flex p-1 rounded ${isOverflowed && "cursor-default"}`}>
<FiSearch className="flex-none mr-2 my-auto" size={14} />
<div
className={`${!finished && "loading-text"}
!text-sm !line-clamp-1 !break-all px-0.5`}
ref={searchingForRef}
>
{finished ? "Searched" : "Searching"} for: <i> {finalQuery}</i>
</div>
<div
className={`flex my-auto items-center ${isOverflowed && "cursor-default"}`}
>
{finished ? (
<>
<div
onClick={() => {
toggleDropdown();
}}
className={` transition-colors duration-300 group-hover:text-text-toolhover cursor-pointer text-text-toolrun !line-clamp-1 !break-all pr-0.5`}
ref={searchingForRef}
>
Searched {filteredDocs.length > 0 && filteredDocs.length} document
{filteredDocs.length != 1 && "s"} for {query}
</div>
</>
) : (
<div
className={`loading-text !text-sm !line-clamp-1 !break-all px-0.5`}
ref={searchingForRef}
>
Searching for: <i> {finalQuery}</i>
</div>
)}
</div>
);
@ -145,43 +183,123 @@ export function SearchSummary({
</div>
</div>
) : null;
const SearchBlock = ({ doc, ind }: { doc: DanswerDocument; ind: number }) => {
return (
<div
onClick={() => {
if (toggleDocumentSelection) {
toggleDocumentSelection();
}
}}
key={doc.document_id}
className={`flex items-start gap-3 px-4 py-3 text-token-text-secondary ${ind == 0 && "rounded-t-xl"} hover:bg-background-100 group relative text-sm`}
>
<div className="mt-1 scale-[.9] flex-none">
{doc.is_internet ? (
<InternetSearchIcon url={doc.link} />
) : (
<SourceIcon sourceType={doc.source_type} iconSize={18} />
)}
</div>
<div className="flex flex-col">
<a
href={doc.link}
target="_blank"
className="line-clamp-1 text-text-900"
>
{/* <Citation link={doc.link} index={ind + 1} /> */}
<p className="shrink truncate ellipsis break-all ">
{doc.semantic_identifier || doc.document_id}
</p>
<p className="line-clamp-3 text-text-500 break-words">
{doc.blurb}
</p>
</a>
</div>
</div>
);
};
return (
<div className="flex">
{isEditing ? (
editInput
) : (
<>
<div className="text-sm">
{isOverflowed ? (
<HoverPopup
mainContent={searchingForDisplay}
popupContent={
<div>
<b>Full query:</b>{" "}
<div className="mt-1 italic">{query}</div>
</div>
}
direction="top"
/>
) : (
searchingForDisplay
<>
<div className="flex gap-x-2 group">
{isEditing ? (
editInput
) : (
<>
<div className="my-auto text-sm">
{isOverflowed ? (
<HoverPopup
mainContent={searchingForDisplay}
popupContent={
<div>
<b>Full query:</b>{" "}
<div className="mt-1 italic">{query}</div>
</div>
}
direction="top"
/>
) : (
searchingForDisplay
)}
</div>
{handleSearchQueryEdit && (
<Tooltip delayDuration={1000} content={"Edit Search"}>
<button
className="my-auto cursor-pointer rounded"
onClick={() => {
setIsEditing(true);
}}
>
<FiEdit2 />
</button>
</Tooltip>
)}
</div>
{handleSearchQueryEdit && (
<Tooltip delayDuration={1000} content={"Edit Search"}>
<button
className="my-auto hover:bg-hover p-1.5 rounded"
<button
className="my-auto invisible group-hover:visible transition-all duration-300 hover:bg-hover rounded"
onClick={toggleDropdown}
>
<ChevronDownIcon
className={`transform transition-transform ${isDropdownOpen ? "rotate-180" : ""}`}
/>
</button>
</>
)}
</div>
{isDropdownOpen && docs && docs.length > 0 && (
<div
className={`mt-2 -mx-8 w-full mb-4 flex relative transition-all duration-300 ${isDropdownOpen ? "opacity-100 max-h-[1000px]" : "opacity-0 max-h-0"}`}
>
<div className="w-full">
<div className="mx-8 flex rounded overflow-hidden rounded-lg border-1.5 border divide-y divider-y-1.5 divider-y-border border-border flex-col gap-x-4">
{!settings?.isMobile &&
filteredDocs.length > 0 &&
filteredDocs.map((doc, ind) => (
<SearchBlock key={ind} doc={doc} ind={ind} />
))}
<div
onClick={() => {
setIsEditing(true);
if (toggleDocumentSelection) {
toggleDocumentSelection();
}
}}
key={-1}
className="cursor-pointer w-full flex transition-all duration-500 hover:bg-background-100 py-3 border-b"
>
<FiEdit2 />
</button>
</Tooltip>
)}
</>
<div key={0} className="px-3 invisible scale-[.9] flex-none">
<SourceIcon sourceType={"file"} iconSize={18} />
</div>
<div className="text-sm flex justify-between text-text-900">
<p className="line-clamp-1">See context</p>
<div className="flex gap-x-1"></div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
</>
);
}