diff --git a/src/components/FaceFilterPanel.vue b/src/components/FaceFilterPanel.vue index 1bed999..d6e9439 100644 --- a/src/components/FaceFilterPanel.vue +++ b/src/components/FaceFilterPanel.vue @@ -57,7 +57,7 @@ Confidence: Bbox Size: Source: - + All Apple Vision MediaPipe @@ -93,7 +93,7 @@ Backend Status: - + All Accept Review @@ -108,7 +108,7 @@ VLM Processing @@ -120,7 +120,7 @@ Face Groups @@ -132,7 +132,7 @@ Unassigned List @@ -144,7 +144,7 @@ Single Trace Groups @@ -154,19 +154,19 @@ - {{ faceFilterSettingsLoading ? '⏳ Saving...' : '✓ Auto-saved' }} + {{ settingsLoading ? '⏳ Saving...' : '✓ Auto-saved' }} Reset to Default - - ❌ {{ faceFilterSettingsError }} + + ❌ {{ settingsError }} @@ -232,7 +232,6 @@ const emit = defineEmits<{ const { mode, - rules, filterResult, filterStats, loading, @@ -242,14 +241,14 @@ const { updateRules, applyBackendFilter, resetToDefault, - faceFilterSettings, - faceFilterSettingsLoading, - faceFilterSettingsError, - faceFilterSettingsModified, + settings, + settingsLoading, + settingsError, + settingsModified, loadSingleFrameSettings, resetSingleFrameSettings, markSingleFrameSettingsModified, - cleanupAutoSave + cleanupAutoSave, } = useFaceFilter(); const showPanel = ref(false); @@ -259,7 +258,7 @@ function togglePanel() { } function onRuleChange() { - updateRules(rules.value); + updateRules(settings.value.ui_filter_rules); } async function handleApplyBackend() { @@ -291,7 +290,7 @@ watch(showPanel, (show) => { } }); -watch(faceFilterSettingsModified, (newVal, oldVal) => { +watch(settingsModified, (newVal, oldVal) => { if (oldVal === true && newVal === false) { emit('settings-updated'); } diff --git a/src/composables/useFaceFilter.ts b/src/composables/useFaceFilter.ts index b8f9cfc..592d893 100644 --- a/src/composables/useFaceFilter.ts +++ b/src/composables/useFaceFilter.ts @@ -97,13 +97,6 @@ export interface FileProfileResponse { face_filter: FaceFilterSettings; } -const defaultRules: UiFilterRules = { - min_confidence: 0.5, - min_bbox_size: 80, - source: 'all', - backend_status: 'accept' -}; - const STORAGE_KEY = 'momentry_face_filter_preferences'; // API helpers @@ -196,7 +189,7 @@ function hybridFilter(faces: FaceMetadata[], rules: UiFilterRules): FaceMetadata export function useFaceFilter() { const mode = ref<'instant' | 'backend' | 'hybrid'>('instant'); - const rules = ref({ ...defaultRules }); + const settings = ref(FaceFilterSettingsMigration.defaults()); const allFaces = ref([]); const filteredFaces = ref([]); const filterResult = ref(null); @@ -204,10 +197,9 @@ export function useFaceFilter() { const loading = ref(false); const error = ref(null); - const faceFilterSettings = ref(FaceFilterSettingsMigration.defaults()); - const faceFilterSettingsLoading = ref(false); - const faceFilterSettingsError = ref(null); - const faceFilterSettingsModified = ref(false); + const settingsLoading = ref(false); + const settingsError = ref(null); + const settingsModified = ref(false); const currentFileUuid = ref(null); let autoSaveTimer: ReturnType | null = null; @@ -219,26 +211,24 @@ export function useFaceFilter() { removed: allFaces.value.length - filteredFaces.value.length })); - // Load preferences from localStorage function loadPreferences() { try { const stored = localStorage.getItem(STORAGE_KEY); if (stored) { const prefs = JSON.parse(stored); mode.value = prefs.mode || 'instant'; - rules.value = prefs.rules || { ...defaultRules }; + settings.value = prefs.settings || FaceFilterSettingsMigration.defaults(); } } catch (err) { console.error('Failed to load preferences:', err); } } - // Save preferences to localStorage function savePreferences() { try { localStorage.setItem(STORAGE_KEY, JSON.stringify({ mode: mode.value, - rules: rules.value + settings: settings.value })); } catch (err) { console.error('Failed to save preferences:', err); @@ -297,11 +287,10 @@ export function useFaceFilter() { }); } - // Apply local filter based on mode function applyLocalFilter() { switch (mode.value) { case 'instant': - filteredFaces.value = quickFilter(allFaces.value, rules.value); + filteredFaces.value = quickFilter(allFaces.value, settings.value.ui_filter_rules); break; case 'backend': filteredFaces.value = allFaces.value.filter(face => @@ -309,13 +298,13 @@ export function useFaceFilter() { ); break; case 'hybrid': - filteredFaces.value = hybridFilter(allFaces.value, rules.value); + filteredFaces.value = hybridFilter(allFaces.value, settings.value.ui_filter_rules); break; } } function updateRules(newRules: Partial) { - rules.value = { ...rules.value, ...newRules }; + settings.value.ui_filter_rules = { ...settings.value.ui_filter_rules, ...newRules }; applyLocalFilter(); savePreferences(); } @@ -371,52 +360,51 @@ function updateRules(newRules: Partial) { } } - // Reset to default function resetToDefault() { - rules.value = { ...defaultRules }; + settings.value = FaceFilterSettingsMigration.defaults(); applyLocalFilter(); savePreferences(); } async function loadSingleFrameSettings(fileUuid: string) { - faceFilterSettingsLoading.value = true; - faceFilterSettingsError.value = null; + settingsLoading.value = true; + settingsError.value = null; try { currentFileUuid.value = fileUuid; const profile = await getFileProfile(fileUuid); if (profile.face_filter) { - faceFilterSettings.value = profile.face_filter; + settings.value = profile.face_filter; } else { - faceFilterSettings.value = FaceFilterSettingsMigration.defaults(); + settings.value = FaceFilterSettingsMigration.defaults(); } - faceFilterSettingsModified.value = false; + settingsModified.value = false; } catch (err: any) { - faceFilterSettingsError.value = err.message || 'Failed to load settings'; + settingsError.value = err.message || 'Failed to load settings'; console.error('Failed to load single frame settings:', err); } finally { - faceFilterSettingsLoading.value = false; + settingsLoading.value = false; } } async function saveSingleFrameSettings(fileUuid: string): Promise { - faceFilterSettingsLoading.value = true; - faceFilterSettingsError.value = null; + settingsLoading.value = true; + settingsError.value = null; try { - const success = await updateFileProfile(fileUuid, faceFilterSettings.value); + const success = await updateFileProfile(fileUuid, settings.value); if (success) { - faceFilterSettingsModified.value = false; + settingsModified.value = false; } return success; } catch (err: any) { - faceFilterSettingsError.value = err.message || 'Failed to save settings'; + settingsError.value = err.message || 'Failed to save settings'; console.error('Failed to save single frame settings:', err); return false; } finally { - faceFilterSettingsLoading.value = false; + settingsLoading.value = false; } } @@ -426,7 +414,7 @@ function autoSaveSettings() { } autoSaveTimer = setTimeout(async () => { - if (currentFileUuid.value && faceFilterSettingsModified.value) { + if (currentFileUuid.value && settingsModified.value) { const success = await saveSingleFrameSettings(currentFileUuid.value); if (!success) { console.error('Auto-save failed for single frame settings'); @@ -444,19 +432,18 @@ function cleanupAutoSave() { } function resetSingleFrameSettings() { - faceFilterSettings.value = FaceFilterSettingsMigration.defaults(); - faceFilterSettingsModified.value = true; + settings.value = FaceFilterSettingsMigration.defaults(); + settingsModified.value = true; autoSaveSettings(); } function markSingleFrameSettingsModified() { - faceFilterSettingsModified.value = true; + settingsModified.value = true; autoSaveSettings(); } return { mode, - rules, allFaces, filteredFaces, filterResult, @@ -464,10 +451,10 @@ return { loading, error, stats, - faceFilterSettings, - faceFilterSettingsLoading, - faceFilterSettingsError, - faceFilterSettingsModified, + settings, + settingsLoading, + settingsError, + settingsModified, currentFileUuid, initialize, diff --git a/src/types/faceFilter.ts b/src/types/faceFilter.ts index 7314f9b..414c5a9 100644 --- a/src/types/faceFilter.ts +++ b/src/types/faceFilter.ts @@ -63,21 +63,10 @@ export interface TraceSettings { * - 新增字段: max_confidence, max_bbox_size, source, backend_status */ export interface FaceFilterSettings { + version?: string; ui_filter_rules: UiFilterRules; processing_thresholds: ProcessingThresholds; trace_settings: TraceSettings; - - min_confidence: number; - max_confidence?: number; - min_bbox_size: number; - max_bbox_size?: number; - source?: string; - backend_status?: string; - - single_frame_trace_vlm_enabled: boolean; - single_frame_trace_group_enabled: boolean; - single_frame_trace_unassigned_enabled: boolean; - single_trace_group_filter_enabled: boolean; } /** @@ -142,24 +131,16 @@ export class FaceFilterSettingsMigration { }; return { + version: "1.0", ui_filter_rules: uiFilterRules, processing_thresholds: processingThresholds, trace_settings: traceSettings, - min_confidence: minConf, - max_confidence: maxConf, - min_bbox_size: legacy.min_bbox_size ?? 80, - max_bbox_size: legacy.max_bbox_size, - source: legacy.source, - backend_status: legacy.backend_status, - single_frame_trace_vlm_enabled: traceSettings.single_frame_trace_vlm_enabled, - single_frame_trace_group_enabled: traceSettings.single_frame_trace_group_enabled, - single_frame_trace_unassigned_enabled: traceSettings.single_frame_trace_unassigned_enabled, - single_trace_group_filter_enabled: traceSettings.single_trace_group_filter_enabled, }; } static defaults(): FaceFilterSettings { return { + version: "1.0", ui_filter_rules: { min_confidence: 0.5, min_bbox_size: 80, @@ -174,12 +155,6 @@ export class FaceFilterSettingsMigration { single_frame_trace_unassigned_enabled: true, single_trace_group_filter_enabled: true, }, - min_confidence: 0.5, - min_bbox_size: 80, - single_frame_trace_vlm_enabled: true, - single_frame_trace_group_enabled: true, - single_frame_trace_unassigned_enabled: true, - single_trace_group_filter_enabled: true, }; } }