feat: OCR independent chunks + TMDb seed with file_uuid
- Rule 1 now creates OCR-only chunks instead of merging into ASRX - generate_seed_embeddings.py supports --file-uuid parameter - get_seeds() filters by file_uuid - identity_matcher.py uses file_uuid for seed matching - Push QDRANT_API_KEY to Python subprocesses - Face clustering uses frame+bbox matching instead of face_id - Portal uses JWT authentication - FilesView filter logic fixed
This commit is contained in:
@@ -75,7 +75,7 @@ export interface UnregisterResponse {
|
||||
// ── Config (browser-only, stored in localStorage) ───────────────────────
|
||||
|
||||
const DEFAULT_CONFIG: PortalConfig = {
|
||||
api_base_url: import.meta.env.VITE_API_BASE_URL || 'http://127.0.0.1:3003',
|
||||
api_base_url: import.meta.env.VITE_API_BASE_URL || 'http://127.0.0.1:3002',
|
||||
api_key: import.meta.env.VITE_API_KEY || '',
|
||||
timeout_secs: 30,
|
||||
}
|
||||
@@ -99,13 +99,20 @@ export function saveConfig(config: PortalConfig): void {
|
||||
export async function logout(): Promise<void> {
|
||||
try {
|
||||
const config = getConfig();
|
||||
const jwtToken = localStorage.getItem('momentry_jwt');
|
||||
const apiKey = config.api_key || localStorage.getItem('momentry_api_key');
|
||||
if (apiKey) {
|
||||
if (jwtToken || apiKey) {
|
||||
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
|
||||
if (jwtToken) {
|
||||
headers['Authorization'] = `Bearer ${jwtToken}`;
|
||||
} else if (apiKey) {
|
||||
headers['X-API-Key'] = apiKey;
|
||||
}
|
||||
// Call logout API to invalidate session on server side (if implemented)
|
||||
// For now, just best effort
|
||||
await fetch(`${config.api_base_url}/api/v1/auth/logout`, {
|
||||
method: 'POST',
|
||||
headers: { 'X-API-Key': apiKey }
|
||||
headers
|
||||
}).catch(() => {}); // Ignore network errors
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -129,6 +136,7 @@ function handleSessionExpired() {
|
||||
localStorage.removeItem('momentry_user');
|
||||
localStorage.removeItem('portal_config');
|
||||
localStorage.removeItem('momentry_api_key');
|
||||
localStorage.removeItem('momentry_jwt');
|
||||
if (window.location.pathname !== '/login') {
|
||||
window.location.href = '/login';
|
||||
}
|
||||
@@ -139,12 +147,15 @@ export async function httpFetch<T>(url: string, options?: RequestInit, retries =
|
||||
// Re-read config to ensure we have the latest key if it changed
|
||||
const config = getConfig();
|
||||
|
||||
// Fallback key check
|
||||
// Use JWT token if available, fallback to API key
|
||||
const jwtToken = localStorage.getItem('momentry_jwt');
|
||||
const apiKey = config.api_key || localStorage.getItem('momentry_api_key') || '';
|
||||
|
||||
const headers = new Headers(options?.headers);
|
||||
headers.set('Content-Type', 'application/json');
|
||||
if (apiKey) {
|
||||
if (jwtToken) {
|
||||
headers.set('Authorization', `Bearer ${jwtToken}`);
|
||||
} else if (apiKey) {
|
||||
headers.set('X-API-Key', apiKey);
|
||||
}
|
||||
|
||||
@@ -156,7 +167,7 @@ export async function httpFetch<T>(url: string, options?: RequestInit, retries =
|
||||
type: 'HTTP',
|
||||
method,
|
||||
url,
|
||||
headers: { ...headers, 'X-API-Key': apiKey ? apiKey.substring(0, 10) + '...' : 'none' },
|
||||
headers: { ...headers, 'Authorization': jwtToken ? 'Bearer ***' : 'none', 'X-API-Key': apiKey ? apiKey.substring(0, 10) + '...' : 'none' },
|
||||
body: options?.body ? JSON.parse(options.body as string) : null,
|
||||
status: 'loading',
|
||||
data: null,
|
||||
|
||||
@@ -116,6 +116,9 @@ const handleLogin = async () => {
|
||||
if (data.success) {
|
||||
localStorage.setItem('momentry_user', JSON.stringify(data.user))
|
||||
localStorage.setItem('momentry_api_key', data.api_key)
|
||||
if (data.jwt) {
|
||||
localStorage.setItem('momentry_jwt', data.jwt)
|
||||
}
|
||||
saveConfig({ ...config, api_key: data.api_key })
|
||||
const redirect = (route.query.redirect as string) || '/home'
|
||||
router.push(redirect)
|
||||
|
||||
Reference in New Issue
Block a user