deepfake-forensics-api / frontend /src /hooks /useAnalysisPipeline.js
warlord123456
Deploy PDF forensic gallery upgrades to HF
24ec554
Raw
History Blame Contribute Delete
4.87 kB
import { useState, useRef } from 'react';
export const useAnalysisPipeline = () => {
const [file, setFile] = useState(null);
const [status, setStatus] = useState('idle');
const [progress, setProgress] = useState(0);
const [telemetry, setTelemetry] = useState(null);
const [logs, setLogs] = useState([]);
const [jobId, setJobId] = useState(null);
const [result, setResult] = useState(null);
const [error, setError] = useState(null);
const handleFileUpload = async (selectedFile) => {
if (!selectedFile) return;
setFile(selectedFile);
setStatus('uploading');
const formData = new FormData();
formData.append('file', selectedFile);
const API_BASE = import.meta.env.VITE_API_URL || 'http://127.0.0.1:8000';
const API_KEY = import.meta.env.VITE_API_KEY || 'deepforensics-dev-key';
try {
const response = await fetch(`${API_BASE}/api/analyze`, {
method: 'POST',
headers: {
'x-api-key': API_KEY,
},
body: formData,
});
if (!response.ok) {
if (response.status === 413) {
throw new Error('File too large. Maximum size is 100 MB.');
} else if (response.status === 400) {
throw new Error('Invalid file type or bad request.');
} else {
throw new Error('Backend processing failed or server is unreachable.');
}
}
const data = await response.json();
setJobId(data.job_id);
setStatus('processing');
setError(null);
pollStatus(data.job_id);
} catch (err) {
console.error(err);
setStatus('idle');
setError(err.message || 'Error uploading file. Please ensure the backend server is running.');
}
};
const pollStatus = async (currentJobId) => {
const API_BASE = import.meta.env.VITE_API_URL || 'http://127.0.0.1:8000';
const API_KEY = import.meta.env.VITE_API_KEY || 'deepforensics-dev-key';
// Watchdog Timer to detect silent backend drops
let watchdogTimeout;
const controller = new AbortController();
const resetWatchdog = () => {
clearTimeout(watchdogTimeout);
watchdogTimeout = setTimeout(() => {
controller.abort('Backend connection timed out (no data received for 15 seconds).');
}, 15000);
};
try {
const response = await fetch(`${API_BASE}/api/status/${currentJobId}/stream`, {
headers: {
'x-api-key': API_KEY,
},
signal: controller.signal
});
if (!response.ok) {
throw new Error(`Stream connection failed: ${response.status}`);
}
resetWatchdog();
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
resetWatchdog();
buffer += decoder.decode(value, { stream: true });
// Process complete SSE messages separated by double newlines
const parts = buffer.split('\n\n');
buffer = parts.pop(); // Keep incomplete chunk in buffer
for (const part of parts) {
if (part.startsWith('data: ')) {
const dataStr = part.substring(6);
try {
const data = JSON.parse(dataStr);
if (data.status === 'processing') {
setProgress(data.progress || 0);
if (data.telemetry) setTelemetry(data.telemetry);
if (data.logs) setLogs(data.logs);
} else if (data.status === 'completed') {
setProgress(100);
setStatus('complete');
setResult(data.result);
clearTimeout(watchdogTimeout);
return;
} else if (data.status === 'failed' || !data.status) {
setStatus('idle');
setError('Analysis failed: ' + (data.error || data.message || 'Job not found or unknown error'));
clearTimeout(watchdogTimeout);
return;
}
} catch (err) {
console.error('Error parsing stream JSON', err);
}
}
}
}
clearTimeout(watchdogTimeout);
} catch (err) {
clearTimeout(watchdogTimeout);
console.error('Stream error', err);
setStatus('idle');
setError(err.message || 'Lost connection to the backend server while streaming status.');
}
};
const resetApp = () => {
setFile(null);
setStatus('idle');
setProgress(0);
setTelemetry(null);
setLogs([]);
setJobId(null);
setResult(null);
setError(null);
};
return {
file,
status,
progress,
telemetry,
logs,
jobId,
result,
error,
setError,
handleFileUpload,
resetApp
};
};