feat: pending identity sorting, face detail modal, video player fps, processor counts

This commit is contained in:
2026-06-24 02:02:33 +08:00
parent 7855983dc1
commit f915aaf794
9 changed files with 1479 additions and 324 deletions

View File

@@ -15,6 +15,36 @@ export const thumbnailsCache = ref<Record<string, string>>({})
export const profilesCache = ref<Record<string, string>>({})
export const faceThumbsCache = ref<Record<string, string>>({})
export interface ProcessorOutputInfo {
has_json: boolean
frame_count: number | null
segment_count: number | null
chunk_count: number | null
last_modified: string | null
}
export interface ProcessorProgress {
processor_type: string
status: 'pending' | 'running' | 'complete' | 'failed'
progress: number
current?: number
total?: number
eta_seconds?: number
}
export interface FileProgress {
file_uuid: string
overall_progress: number
processors: ProcessorProgress[]
cpu_percent?: number
gpu_percent?: number
memory_percent?: number
}
export const processorCountsCache = ref<Record<string, Record<string, ProcessorOutputInfo>>>({})
export const fileProgressCache = ref<Record<string, FileProgress>>({})
export const fileStatusCache = ref<Record<string, string>>({})
const thumbQueue: (() => Promise<void>)[] = []
let activeThumbLoads = 0
const MAX_CONCURRENT = 16
@@ -26,6 +56,8 @@ const MAX_PROFILE_CONCURRENT = 4
const loadingThumbs = new Set<string>()
const loadingProfiles = new Set<string>()
const loadingFaceThumbs = new Set<string>()
const loadingProcessorCounts = new Set<string>()
const pollingProgress = new Set<string>()
function drainThumbQueue() {
if (activeThumbLoads >= MAX_CONCURRENT || thumbQueue.length === 0) return
@@ -203,6 +235,111 @@ export function loadFaceThumb(key: string, uuid: string, frame: number, bbox?: a
})
}
export async function loadProcessorCounts(fileUuid: string, force = false) {
if (!fileUuid) return
if (!force && processorCountsCache.value[fileUuid]) return
if (loadingProcessorCounts.has(fileUuid)) return
loadingProcessorCounts.add(fileUuid)
try {
const data: any = await apiCall('get_processor_counts', { uuid: fileUuid })
const counts: Record<string, ProcessorOutputInfo> = {}
for (const p of data.processors || []) {
counts[p.processor] = {
has_json: p.has_json ?? false,
frame_count: p.frame_count ?? null,
segment_count: p.segment_count ?? null,
chunk_count: p.chunk_count ?? null,
last_modified: p.last_modified ?? null,
}
}
processorCountsCache.value = { ...processorCountsCache.value, [fileUuid]: counts }
} catch (e) {
console.error('loadProcessorCounts failed:', fileUuid, e)
} finally {
loadingProcessorCounts.delete(fileUuid)
}
}
export function getProcessorCounts(fileUuid: string): Record<string, ProcessorOutputInfo> {
return processorCountsCache.value[fileUuid] || {}
}
export async function pollProgress(fileUuid: string) {
if (!fileUuid || pollingProgress.has(fileUuid)) return
pollingProgress.add(fileUuid)
try {
while (pollingProgress.has(fileUuid)) {
const data: any = await apiCall('get_progress', { fileUuid })
fileProgressCache.value[fileUuid] = {
file_uuid: data.file_uuid || fileUuid,
overall_progress: data.overall_progress || 0,
processors: (data.processors || []).map((p: any) => ({
processor_type: p.processor_type,
status: p.status,
progress: p.progress || 0,
current: p.current,
total: p.total,
eta_seconds: p.eta_seconds,
})),
cpu_percent: data.cpu_percent,
gpu_percent: data.gpu_percent,
memory_percent: data.memory_percent,
}
const allComplete = data.processors?.every((p: any) => p.status === 'complete' || p.status === 'failed')
if (allComplete || data.overall_progress >= 100) {
stopPolling(fileUuid)
fileStatusCache.value[fileUuid] = 'completed'
await loadProcessorCounts(fileUuid)
break
}
await new Promise(r => setTimeout(r, 2000))
}
} catch (e) {
console.error('pollProgress failed:', fileUuid, e)
} finally {
pollingProgress.delete(fileUuid)
}
}
export function stopPolling(fileUuid: string) {
pollingProgress.delete(fileUuid)
}
export function getProgress(fileUuid: string): FileProgress | null {
return fileProgressCache.value[fileUuid] || null
}
export function getFileStatus(fileUuid: string): string {
return fileStatusCache.value[fileUuid] || ''
}
export async function refreshFileStatus(fileUuid: string) {
try {
const data: any = await apiCall('get_progress', { fileUuid })
if (data.overall_progress >= 100 || data.processors?.every((p: any) => p.status === 'complete')) {
fileStatusCache.value[fileUuid] = 'completed'
await loadProcessorCounts(fileUuid)
} else if (data.processors?.some((p: any) => p.status === 'running')) {
fileStatusCache.value[fileUuid] = 'processing'
fileProgressCache.value[fileUuid] = {
file_uuid: fileUuid,
overall_progress: data.overall_progress || 0,
processors: data.processors || [],
}
}
} catch (e) {
console.error('refreshFileStatus failed:', fileUuid, e)
}
}
export async function refreshAllFilesStatus() {
for (const f of filesCache.value) {
if (f.isRegistered && f.file_uuid) {
await refreshFileStatus(f.file_uuid)
}
}
}
export function invalidateFiles() {
filesLoaded.value = false
filesCache.value = []