Skip to content

Commit 5a22aa9

Browse files
Fix vss-ui, search-ms, dataprep for bugs (open-edge-platform#2057)
Co-authored-by: Yogesh Pandey <yogesh.pandey@intel.com>
1 parent faa6304 commit 5a22aa9

File tree

9 files changed

+198
-53
lines changed

9 files changed

+198
-53
lines changed

microservices/visual-data-preparation-for-retrieval/vdms/src/core/embedding/sdk_client.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -415,13 +415,29 @@ def _store_embeddings(
415415
batch_size=batch_size,
416416
)
417417
except Exception as exc:
418-
logger.error(
419-
"VDMS add_from failed for batch %d-%d: %s",
418+
logger.warning(
419+
"VDMS add_from failed for batch %d-%d. Reinitializing VDMS client and retrying once. Error: %s",
420420
start_idx,
421421
end_idx - 1,
422422
exc,
423423
)
424-
raise
424+
self._init_vdms()
425+
try:
426+
inserted_ids = self.video_db.add_from(
427+
texts=batch_texts,
428+
embeddings=batch_embeddings,
429+
metadatas=batch_metadatas,
430+
ids=batch_ids,
431+
batch_size=batch_size,
432+
)
433+
except Exception as retry_exc:
434+
logger.error(
435+
"VDMS add_from retry failed for batch %d-%d: %s",
436+
start_idx,
437+
end_idx - 1,
438+
retry_exc,
439+
)
440+
raise
425441

426442
if not inserted_ids or len(inserted_ids) != len(batch_ids):
427443
raise ValueError(

microservices/visual-data-preparation-for-retrieval/vdms/src/core/embedding/simple_client.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,29 @@ def _store_embeddings(
230230
batch_size=batch_size,
231231
)
232232
except Exception as exc:
233-
logger.error(
234-
"VDMS add_from failed for batch %d-%d: %s",
233+
logger.warning(
234+
"VDMS add_from failed for batch %d-%d. Reinitializing VDMS client and retrying once. Error: %s",
235235
start_idx,
236236
end_idx - 1,
237237
exc,
238238
)
239-
raise
239+
self.init_db()
240+
try:
241+
inserted_ids = self.video_db.add_from(
242+
texts=batch_texts,
243+
embeddings=batch_embeddings,
244+
metadatas=batch_metadatas,
245+
ids=batch_ids,
246+
batch_size=batch_size,
247+
)
248+
except Exception as retry_exc:
249+
logger.error(
250+
"VDMS add_from retry failed for batch %d-%d: %s",
251+
start_idx,
252+
end_idx - 1,
253+
retry_exc,
254+
)
255+
raise
240256

241257
if not inserted_ids or len(inserted_ids) != len(batch_ids):
242258
raise ValueError(

sample-applications/video-search-and-summarization/search-ms/server.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -199,16 +199,34 @@ async def process_query(query_request):
199199
logger.debug(f"Searching with initial_k={initial_k}")
200200

201201
vdms_start = time.perf_counter()
202-
docs_with_score: List[Tuple[Any, float]] = db.similarity_search_with_score(
203-
query_request.query,
204-
k=initial_k,
205-
fetch_k=initial_k + 1, # ensure fetch_k > k for langchain_vdms
206-
filter=vdms_filter,
207-
# normalize_distance=True
208-
)
202+
vdms_attempt = 1
203+
try:
204+
docs_with_score: List[Tuple[Any, float]] = db.similarity_search_with_score(
205+
query_request.query,
206+
k=initial_k,
207+
fetch_k=initial_k + 1, # ensure fetch_k > k for langchain_vdms
208+
filter=vdms_filter,
209+
# normalize_distance=True
210+
)
211+
except Exception as first_error:
212+
first_attempt_duration_ms = (time.perf_counter() - vdms_start) * 1000
213+
logger.warning(
214+
"VDMS similarity search failed on first attempt after %.2f ms; refreshing client and retrying once. Error: %s",
215+
first_attempt_duration_ms,
216+
first_error,
217+
)
218+
refreshed_db: VDMS = get_vectordb()
219+
vdms_attempt = 2
220+
vdms_start = time.perf_counter()
221+
docs_with_score = refreshed_db.similarity_search_with_score(
222+
query_request.query,
223+
k=initial_k,
224+
fetch_k=initial_k + 1,
225+
filter=vdms_filter,
226+
)
209227
vdms_duration_ms = (time.perf_counter() - vdms_start) * 1000
210228
logger.info(
211-
f"VDMS similarity search (embedding + retrieval) completed in {vdms_duration_ms:.2f} ms with {len(docs_with_score)} results"
229+
f"VDMS similarity search (attempt {vdms_attempt}, embedding + retrieval) completed in {vdms_duration_ms:.2f} ms with {len(docs_with_score)} results"
212230
)
213231

214232
logger.info(f"Raw search returned {len(docs_with_score)} results")

sample-applications/video-search-and-summarization/search-ms/src/vdms_retriever/retriever.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from src.vdms_retriever.embedding_wrapper import EmbeddingAPI
1111

1212
DEBUG = False
13-
client = VDMS_Client(settings.VDMS_VDB_HOST, settings.VDMS_VDB_PORT)
1413

1514

1615
# Frame-to-Video Aggregation Configuration
@@ -639,20 +638,25 @@ def get_vectordb() -> VDMS:
639638
tuple: The vector database instance
640639
"""
641640

642-
embeddings = EmbeddingAPI(
643-
api_url=settings.EMBEDDINGS_ENDPOINT,
644-
model_name=settings.EMBEDDINGS_MODEL_NAME,
645-
)
641+
try:
642+
embeddings = EmbeddingAPI(
643+
api_url=settings.EMBEDDINGS_ENDPOINT,
644+
model_name=settings.EMBEDDINGS_MODEL_NAME,
645+
)
646646

647-
vector_dimensions = embeddings.get_embedding_length()
647+
vector_dimensions = embeddings.get_embedding_length()
648+
client = VDMS_Client(settings.VDMS_VDB_HOST, settings.VDMS_VDB_PORT)
648649

649-
vector_db = VDMS(
650-
client=client,
651-
embedding=embeddings,
652-
collection_name=settings.INDEX_NAME,
653-
distance_strategy=settings.DISTANCE_STRATEGY,
654-
embedding_dimensions=vector_dimensions,
655-
engine=settings.SEARCH_ENGINE,
656-
)
650+
vector_db = VDMS(
651+
client=client,
652+
embedding=embeddings,
653+
collection_name=settings.INDEX_NAME,
654+
distance_strategy=settings.DISTANCE_STRATEGY,
655+
embedding_dimensions=vector_dimensions,
656+
engine=settings.SEARCH_ENGINE,
657+
)
657658

658-
return vector_db
659+
return vector_db
660+
except Exception as exc:
661+
logger.error(f"Failed to initialize VDMS vector DB client: {exc}")
662+
raise

sample-applications/video-search-and-summarization/ui/react/src/components/VideoGroups/VideoGroupsView.tsx

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ import { useTranslation } from 'react-i18next';
55
import styled from 'styled-components';
66
import { useAppSelector } from '../../redux/store';
77
import { Video } from '../../redux/video/video';
8+
import { SearchResult } from '../../redux/search/search';
89
import { videosSelector } from '../../redux/video/videoSlice';
910
import { SearchSelector } from '../../redux/search/searchSlice';
11+
import { ASSETS_ENDPOINT } from '../../config';
12+
import { resolveVideoUrl } from '../../redux/video/videoUrl';
1013

1114
const VideoGroupsContainer = styled.div`
1215
padding: 1rem;
@@ -147,6 +150,16 @@ interface TagGroup {
147150
color: string;
148151
}
149152

153+
const toPlayableMetadataUrl = (value: unknown): string => {
154+
if (typeof value !== 'string') return '';
155+
const trimmed = value.trim();
156+
if (!trimmed) return '';
157+
if (trimmed.includes('/videos/download?video_id=')) return '';
158+
if (/^https?:\/\//i.test(trimmed)) return trimmed;
159+
if (trimmed.startsWith('/')) return `${ASSETS_ENDPOINT}${trimmed}`;
160+
return `${ASSETS_ENDPOINT}/${trimmed}`;
161+
};
162+
150163
export const VideoGroupsView: FC = () => {
151164
const { t } = useTranslation();
152165
const { getVideoUrl } = useAppSelector(videosSelector);
@@ -155,7 +168,7 @@ export const VideoGroupsView: FC = () => {
155168
// Build a map of relevance scores from search results
156169
const videoRelevanceMap = useMemo(() => {
157170
const map = new Map<string, number>();
158-
selectedResults?.forEach((result) => {
171+
selectedResults?.forEach((result: SearchResult) => {
159172
const vid = result.metadata?.video_id;
160173
const score = result.metadata?.relevance_score;
161174
if (vid && typeof score === 'number') map.set(vid, score);
@@ -167,7 +180,7 @@ export const VideoGroupsView: FC = () => {
167180
const searchVideos: Video[] = useMemo(() => {
168181
if (!selectedResults || selectedResults.length === 0) return [];
169182
return selectedResults
170-
.map((result) => {
183+
.map((result: SearchResult) => {
171184
const meta: any = result.metadata ?? {};
172185
const vid = meta.video_id || meta.id;
173186
if (!vid) return null;
@@ -195,13 +208,18 @@ export const VideoGroupsView: FC = () => {
195208
return {
196209
videoId: vid,
197210
name: meta.name ?? meta.title ?? vid,
198-
url: '',
211+
url:
212+
resolveVideoUrl(result.video, ASSETS_ENDPOINT) ||
213+
toPlayableMetadataUrl(meta.video_rel_url) ||
214+
toPlayableMetadataUrl(meta.video_url) ||
215+
'',
199216
tags: tagsArr,
200217
createdAt: (meta.date_time as string) ?? (meta.date as string) ?? '',
201218
updatedAt: '',
219+
dataStore: result.video?.dataStore,
202220
} as Video;
203221
})
204-
.filter((v): v is Video => v !== null);
222+
.filter((v: Video | null): v is Video => v !== null);
205223
}, [selectedResults]);
206224

207225
// If no search results, show a helpful empty state
@@ -229,13 +247,19 @@ export const VideoGroupsView: FC = () => {
229247
if (validTags.length === 0) {
230248
// Video has no valid tags - add to Untagged group
231249
if (!groups.has('Untagged')) groups.set('Untagged', []);
232-
groups.get('Untagged')!.push(video);
250+
const untaggedVideos = groups.get('Untagged')!;
251+
if (!untaggedVideos.some((existing) => existing.videoId === video.videoId)) {
252+
untaggedVideos.push(video);
253+
}
233254
} else {
234255
// Video has valid tags - add to each tag group
235256
validTags.forEach((tag) => {
236257
const trimmedTag = tag.trim();
237258
if (!groups.has(trimmedTag)) groups.set(trimmedTag, []);
238-
groups.get(trimmedTag)!.push(video);
259+
const tagVideos = groups.get(trimmedTag)!;
260+
if (!tagVideos.some((existing) => existing.videoId === video.videoId)) {
261+
tagVideos.push(video);
262+
}
239263
});
240264
}
241265
});
@@ -277,11 +301,12 @@ export const VideoGroupsView: FC = () => {
277301

278302
<VideoGrid>
279303
{group.videos.map((video) => {
280-
const videoUrl = getVideoUrl ? getVideoUrl(video.videoId) : video.url;
304+
const reduxVideoUrl = getVideoUrl ? getVideoUrl(video.videoId) : null;
305+
const videoUrl = reduxVideoUrl || video.url;
281306
const relevanceScore = videoRelevanceMap.get(video.videoId) ?? 0;
282307

283308
return (
284-
<VideoCard key={video.videoId}>
309+
<VideoCard key={`${group.tag}-${video.videoId}`}>
285310
<VideoCardWrapper>
286311
{videoUrl ? (
287312
<VideoPlayer controls preload="metadata">

sample-applications/video-search-and-summarization/ui/react/src/redux/search/VideoTile.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next';
55
import { ASSETS_ENDPOINT } from '../../config';
66
import { useAppSelector } from '../store';
77
import { SearchSelector } from './searchSlice';
8+
import { resolveVideoUrl } from '../video/videoUrl';
89

910
export interface VideoTileProps {
1011
resultIndex: number; // Index in the selectedResults array
@@ -20,14 +21,7 @@ export const VideoTile: FC<VideoTileProps> = ({ resultIndex }) => {
2021

2122
const { metadata, video } = searchResult || {};
2223

23-
const getVideoUrl = () => {
24-
if (video?.dataStore) {
25-
return `${ASSETS_ENDPOINT}/${video.dataStore.bucket}/${video.url}`;
26-
}
27-
return null;
28-
};
29-
30-
const videoUrl = getVideoUrl();
24+
const videoUrl = resolveVideoUrl(video, ASSETS_ENDPOINT);
3125

3226
useEffect(() => {
3327
if (videoRef.current && metadata?.timestamp && typeof metadata.timestamp === 'number') {

sample-applications/video-search-and-summarization/ui/react/src/redux/video/videoSlice.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { RootState } from '../store';
66
import axios from 'axios';
77
import { APP_URL, ASSETS_ENDPOINT } from '../../config';
88
import { StateActionStatus } from '../summary/summary';
9+
import { resolveVideoUrl } from './videoUrl';
910

1011
const initialState: VideosState = {
1112
videos: [],
@@ -58,14 +59,7 @@ export const videosSelector = createSelector([selectVideoState], (videosState) =
5859
},
5960
getVideoUrl: (videoId: string) => {
6061
const video = videosState.videos.find((video) => video.videoId === videoId);
61-
62-
console.log(video);
63-
64-
if (video?.dataStore) {
65-
return `${ASSETS_ENDPOINT}/${video.dataStore.bucket}/${video.url}`;
66-
}
67-
68-
return null;
62+
return resolveVideoUrl(video, ASSETS_ENDPOINT);
6963
},
7064
}));
7165

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (C) 2025 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
import { Video } from './video';
4+
5+
export const resolveVideoUrl = (video?: Video | null, assetsEndpoint = ''): string | null => {
6+
if (!video) return null;
7+
8+
if (video.dataStore?.bucket && video.url) {
9+
return `${assetsEndpoint}/${video.dataStore.bucket}/${video.url}`;
10+
}
11+
12+
if (video.url) {
13+
return video.url;
14+
}
15+
16+
return null;
17+
};

0 commit comments

Comments
 (0)