import { ref } from 'vue' import { getApiBase } from '@/api/config' export interface VLMTag { en: string local: string } export interface VLMScene { file_uuid: string file_name: string scene_index: number timestamp_sec: number frame_number: number thumbnail_url: string vlm_description: string vlm_description_localized?: string vlm_objects: string[] vlm_tags: VLMTag[] score: number source: string } export interface VLMTrace { file_uuid: string file_name: string trace_id: number start_frame: number end_frame: number start_time: number end_time: number timestamp_sec: number thumbnail_url: string vlm_description: string vlm_description_localized?: string vlm_objects: string[] vlm_tags: VLMTag[] score: number identity_name?: string } export interface FileScene { index: number filename: string timestamp_sec: number vlm_description: string vlm_description_localized?: string vlm_objects: string[] vlm_tags: VLMTag[] vlm_status: string } export function useVLMScenes(fileUuid: string) { const scenes = ref([]) const loading = ref(false) const error = ref(null) async function loadScenes() { loading.value = true error.value = null try { const base = getApiBase() const resp = await fetch(`${base}/api/v1/file/${fileUuid}/scenes`) if (!resp.ok) throw new Error(`HTTP ${resp.status}`) const data = await resp.json() scenes.value = Array.isArray(data) ? data : (data.scenes || []) } catch (e: any) { error.value = e.message || 'Failed to load scenes' scenes.value = [] } finally { loading.value = false } } function getThumbnailUrl(sceneIndex: number): string { const base = getApiBase() const paddedIndex = String(sceneIndex).padStart(3, '0') return `${base}/api/v1/file/${fileUuid}/scenes/scene_${paddedIndex}.jpg` } return { scenes, loading, error, loadScenes, getThumbnailUrl } } export function useVLMSearch() { const scenes = ref([]) const traces = ref([]) const loading = ref(false) const error = ref(null) const total = ref(0) async function search(query: string, options?: { page_size?: number min_score?: number output_language?: string offset?: number }) { loading.value = true error.value = null const base = getApiBase() const params = { query, page_size: options?.page_size || 20, min_score: options?.min_score ?? 0.0, output_language: options?.output_language || 'en', ...(options?.offset != null ? { offset: options.offset } : {}) } try { const [scenesRes, tracesRes] = await Promise.all([ fetch(`${base}/api/v1/search/vlm/scenes`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params) }).then(r => r.json()), fetch(`${base}/api/v1/search/vlm/traces`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params) }).then(r => r.json()) ]) scenes.value = scenesRes?.results || [] traces.value = tracesRes?.results || [] total.value = scenesRes?.total || 0 } catch (e: any) { error.value = e.message || 'Search failed' scenes.value = [] traces.value = [] } finally { loading.value = false } } function clearResults() { scenes.value = [] traces.value = [] total.value = 0 } return { scenes, traces, loading, error, total, search, clearResults } } export function useSceneThumbnail(fileUuid: string, sceneIndex: number) { const url = ref(null) const loading = ref(false) function loadThumbnail() { loading.value = true const base = getApiBase() const paddedIndex = String(sceneIndex).padStart(3, '0') url.value = `${base}/api/v1/file/${fileUuid}/scenes/scene_${paddedIndex}.jpg` loading.value = false } return { url, loading, loadThumbnail } }