Search UI tweaks and bugfixes (#14328)

* Publish model state and embeddings reindex in dispatcher onConnect

* remove unneeded from explore

* add embeddings reindex progress to statusbar

* don't allow right click or show similar button if semantic search is disabled

* fix status bar
This commit is contained in:
Josh Hawkins 2024-10-13 20:36:49 -05:00 committed by GitHub
parent 833768172d
commit 4ca267ea17
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 56 additions and 48 deletions

View File

@ -179,6 +179,11 @@ class Dispatcher:
} }
self.publish("camera_activity", json.dumps(camera_status)) self.publish("camera_activity", json.dumps(camera_status))
self.publish("model_state", json.dumps(self.model_state.copy()))
self.publish(
"embeddings_reindex_progress",
json.dumps(self.embeddings_reindex.copy()),
)
# Dictionary mapping topic to handlers # Dictionary mapping topic to handlers
topic_handlers = { topic_handlers = {

View File

@ -1,3 +1,4 @@
import { useEmbeddingsReindexProgress } from "@/api/ws";
import { import {
StatusBarMessagesContext, StatusBarMessagesContext,
StatusMessage, StatusMessage,
@ -41,6 +42,23 @@ export default function Statusbar() {
}); });
}, [potentialProblems, addMessage, clearMessages]); }, [potentialProblems, addMessage, clearMessages]);
const { payload: reindexState } = useEmbeddingsReindexProgress();
useEffect(() => {
if (reindexState) {
if (reindexState.status == "indexing") {
clearMessages("embeddings-reindex");
addMessage(
"embeddings-reindex",
`Reindexing embeddings (${Math.floor((reindexState.processed_objects / reindexState.total_objects) * 100)}% complete)`,
);
}
if (reindexState.status === "completed") {
clearMessages("embeddings-reindex");
}
}
}, [reindexState, addMessage, clearMessages]);
return ( return (
<div className="absolute bottom-0 left-0 right-0 z-10 flex h-8 w-full items-center justify-between border-t border-secondary-highlight bg-background_alt px-4 dark:text-secondary-foreground"> <div className="absolute bottom-0 left-0 right-0 z-10 flex h-8 w-full items-center justify-between border-t border-secondary-highlight bg-background_alt px-4 dark:text-secondary-foreground">
<div className="flex h-full items-center gap-2"> <div className="flex h-full items-center gap-2">

View File

@ -396,17 +396,19 @@ function ObjectDetailsTab({
draggable={false} draggable={false}
src={`${apiHost}api/events/${search.id}/thumbnail.jpg`} src={`${apiHost}api/events/${search.id}/thumbnail.jpg`}
/> />
<Button {config?.semantic_search.enabled && (
onClick={() => { <Button
setSearch(undefined); onClick={() => {
setSearch(undefined);
if (setSimilarity) { if (setSimilarity) {
setSimilarity(); setSimilarity();
} }
}} }}
> >
Find Similar Find Similar
</Button> </Button>
)}
</div> </div>
</div> </div>
<div className="flex flex-col gap-1.5"> <div className="flex flex-col gap-1.5">

View File

@ -2,7 +2,6 @@ import {
useEmbeddingsReindexProgress, useEmbeddingsReindexProgress,
useEventUpdate, useEventUpdate,
useModelState, useModelState,
useWs,
} from "@/api/ws"; } from "@/api/ws";
import ActivityIndicator from "@/components/indicators/activity-indicator"; import ActivityIndicator from "@/components/indicators/activity-indicator";
import AnimatedCircularProgressBar from "@/components/ui/circular-progress-bar"; import AnimatedCircularProgressBar from "@/components/ui/circular-progress-bar";
@ -193,22 +192,11 @@ export default function Explore() {
// embeddings reindex progress // embeddings reindex progress
const { send: sendReindexCommand } = useWs( const { payload: reindexState } = useEmbeddingsReindexProgress();
"embeddings_reindex_progress",
"embeddingsReindexProgress",
);
useEffect(() => {
sendReindexCommand("embeddingsReindexProgress");
// only run on mount
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const { payload: reindexProgress } = useEmbeddingsReindexProgress();
const embeddingsReindexing = useMemo(() => { const embeddingsReindexing = useMemo(() => {
if (reindexProgress) { if (reindexState) {
switch (reindexProgress.status) { switch (reindexState.status) {
case "indexing": case "indexing":
return true; return true;
case "completed": case "completed":
@ -217,18 +205,10 @@ export default function Explore() {
return undefined; return undefined;
} }
} }
}, [reindexProgress]); }, [reindexState]);
// model states // model states
const { send: sendModelCommand } = useWs("model_state", "modelState");
useEffect(() => {
sendModelCommand("modelState");
// only run on mount
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const { payload: textModelState } = useModelState( const { payload: textModelState } = useModelState(
"jinaai/jina-clip-v1-text_model_fp16.onnx", "jinaai/jina-clip-v1-text_model_fp16.onnx",
); );
@ -274,7 +254,8 @@ export default function Explore() {
if ( if (
config?.semantic_search.enabled && config?.semantic_search.enabled &&
(!textModelState || (!reindexState ||
!textModelState ||
!textTokenizerState || !textTokenizerState ||
!visionModelState || !visionModelState ||
!visionFeatureExtractorState) !visionFeatureExtractorState)
@ -303,24 +284,22 @@ export default function Explore() {
<div className="pt-5 text-center"> <div className="pt-5 text-center">
<AnimatedCircularProgressBar <AnimatedCircularProgressBar
min={0} min={0}
max={reindexProgress.total_objects} max={reindexState.total_objects}
value={reindexProgress.processed_objects} value={reindexState.processed_objects}
gaugePrimaryColor="hsl(var(--selected))" gaugePrimaryColor="hsl(var(--selected))"
gaugeSecondaryColor="hsl(var(--secondary))" gaugeSecondaryColor="hsl(var(--secondary))"
/> />
</div> </div>
<div className="flex w-96 flex-col gap-2 py-5"> <div className="flex w-96 flex-col gap-2 py-5">
{reindexProgress.time_remaining !== null && ( {reindexState.time_remaining !== null && (
<div className="mb-3 flex flex-col items-center justify-center gap-1"> <div className="mb-3 flex flex-col items-center justify-center gap-1">
<div className="text-primary-variant"> <div className="text-primary-variant">
{reindexProgress.time_remaining === -1 {reindexState.time_remaining === -1
? "Starting up..." ? "Starting up..."
: "Estimated time remaining:"} : "Estimated time remaining:"}
</div> </div>
{reindexProgress.time_remaining >= 0 && {reindexState.time_remaining >= 0 &&
(formatSecondsToDuration( (formatSecondsToDuration(reindexState.time_remaining) ||
reindexProgress.time_remaining,
) ||
"Finishing shortly")} "Finishing shortly")}
</div> </div>
)} )}
@ -328,20 +307,20 @@ export default function Explore() {
<span className="text-primary-variant"> <span className="text-primary-variant">
Thumbnails embedded: Thumbnails embedded:
</span> </span>
{reindexProgress.thumbnails} {reindexState.thumbnails}
</div> </div>
<div className="flex flex-row items-center justify-center gap-3"> <div className="flex flex-row items-center justify-center gap-3">
<span className="text-primary-variant"> <span className="text-primary-variant">
Descriptions embedded: Descriptions embedded:
</span> </span>
{reindexProgress.descriptions} {reindexState.descriptions}
</div> </div>
<div className="flex flex-row items-center justify-center gap-3"> <div className="flex flex-row items-center justify-center gap-3">
<span className="text-primary-variant"> <span className="text-primary-variant">
Tracked objects processed: Tracked objects processed:
</span> </span>
{reindexProgress.processed_objects} /{" "} {reindexState.processed_objects} /{" "}
{reindexProgress.total_objects} {reindexState.total_objects}
</div> </div>
</div> </div>
</> </>

View File

@ -393,7 +393,11 @@ export default function SearchView({
> >
<SearchThumbnail <SearchThumbnail
searchResult={value} searchResult={value}
findSimilar={() => setSimilaritySearch(value)} findSimilar={() => {
if (config?.semantic_search.enabled) {
setSimilaritySearch(value);
}
}}
onClick={() => onSelectSearch(value, index)} onClick={() => onSelectSearch(value, index)}
/> />
{(searchTerm || {(searchTerm ||