Pre-cleanup commit: Current state before service layer consolidation

This commit is contained in:
Jon
2025-08-01 14:57:56 -04:00
parent 95c92946de
commit f453efb0f8
21 changed files with 2560 additions and 363 deletions

View File

@@ -10,7 +10,7 @@ import Analytics from './components/Analytics';
import UploadMonitoringDashboard from './components/UploadMonitoringDashboard';
import LogoutButton from './components/LogoutButton';
import { documentService, GCSErrorHandler, GCSError } from './services/documentService';
import { debugAuth, testAPIAuth } from './utils/authDebug';
// import { debugAuth, testAPIAuth } from './utils/authDebug';
import {
Home,
@@ -75,13 +75,14 @@ const Dashboard: React.FC = () => {
if (response.ok) {
const result = await response.json();
// The API returns an array directly, not wrapped in success/data
if (Array.isArray(result)) {
// The API returns documents wrapped in a documents property
const documentsArray = result.documents || result;
if (Array.isArray(documentsArray)) {
// Transform backend data to frontend format
const transformedDocs = result.map((doc: any) => ({
const transformedDocs = documentsArray.map((doc: any) => ({
id: doc.id,
name: doc.name || doc.originalName,
originalName: doc.originalName,
name: doc.name || doc.originalName || 'Unknown',
originalName: doc.originalName || doc.name || 'Unknown',
status: mapBackendStatus(doc.status),
uploadedAt: doc.uploadedAt,
processedAt: doc.processedAt,
@@ -216,10 +217,22 @@ const Dashboard: React.FC = () => {
return () => clearInterval(refreshInterval);
}, [fetchDocuments]);
const handleUploadComplete = (fileId: string) => {
console.log('Upload completed:', fileId);
// Refresh documents list after upload
fetchDocuments();
const handleUploadComplete = (documentId: string) => {
console.log('Upload completed:', documentId);
// Add the new document to the list with a "processing" status
// Since we only have the ID, we'll create a minimal document object
const newDocument = {
id: documentId,
status: 'processing',
name: 'Processing...',
originalName: 'Processing...',
uploadedAt: new Date().toISOString(),
fileSize: 0,
user_id: user?.id || '',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
};
setDocuments(prev => [...prev, newDocument]);
};
const handleUploadError = (error: string) => {
@@ -291,18 +304,18 @@ const Dashboard: React.FC = () => {
setViewingDocument(null);
};
// Debug functions
const handleDebugAuth = async () => {
await debugAuth();
};
// Debug functions (commented out for now)
// const handleDebugAuth = async () => {
// await debugAuth();
// };
const handleTestAPIAuth = async () => {
await testAPIAuth();
};
// const handleTestAPIAuth = async () => {
// await testAPIAuth();
// };
const filteredDocuments = documents.filter(doc =>
doc.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
doc.originalName.toLowerCase().includes(searchTerm.toLowerCase())
(doc.name?.toLowerCase() || '').includes(searchTerm.toLowerCase()) ||
(doc.originalName?.toLowerCase() || '').includes(searchTerm.toLowerCase())
);
const stats = {

View File

@@ -21,7 +21,7 @@ interface UploadedFile {
}
interface DocumentUploadProps {
onUploadComplete?: (fileId: string) => void;
onUploadComplete?: (documentId: string) => void;
onUploadError?: (error: string) => void;
}
@@ -104,15 +104,15 @@ const DocumentUpload: React.FC<DocumentUploadProps> = ({
abortController.signal
);
// Upload completed - update status to "uploaded"
// Upload completed - update status to "processing" immediately
setUploadedFiles(prev =>
prev.map(f =>
f.id === uploadedFile.id
? {
...f,
id: document.id,
documentId: document.id,
status: 'uploaded',
id: result.id,
documentId: result.id,
status: 'processing', // Changed from 'uploaded' to 'processing'
progress: 100
}
: f
@@ -120,10 +120,10 @@ const DocumentUpload: React.FC<DocumentUploadProps> = ({
);
// Call the completion callback with the document ID
onUploadComplete?.(document.id);
onUploadComplete?.(result.id);
// Start monitoring processing progress
monitorProcessingProgress(document.id, uploadedFile.id);
// Start monitoring processing progress immediately
monitorProcessingProgress(result.id, uploadedFile.id);
} catch (error) {
// Check if this was an abort error
@@ -189,8 +189,29 @@ const DocumentUpload: React.FC<DocumentUploadProps> = ({
console.warn('Attempted to monitor progress for document with invalid UUID format:', documentId);
return;
}
// Add timeout to prevent infinite polling (30 minutes max)
const startTime = Date.now();
const maxPollingTime = 30 * 60 * 1000; // 30 minutes
const checkProgress = async () => {
// Check if we've exceeded the maximum polling time
if (Date.now() - startTime > maxPollingTime) {
console.warn(`Polling timeout for document ${documentId} after ${maxPollingTime / 1000 / 60} minutes`);
setUploadedFiles(prev =>
prev.map(f =>
f.id === fileId
? {
...f,
status: 'error',
error: 'Processing timeout - please check document status manually'
}
: f
)
);
return;
}
try {
const response = await fetch(`${import.meta.env.VITE_API_BASE_URL}/documents/${documentId}/progress`, {
headers: {
@@ -203,8 +224,10 @@ const DocumentUpload: React.FC<DocumentUploadProps> = ({
const progress = await response.json();
// Update status based on progress
let newStatus: UploadedFile['status'] = 'uploaded';
if (progress.status === 'processing' || progress.status === 'extracting_text' || progress.status === 'processing_llm' || progress.status === 'generating_pdf') {
let newStatus: UploadedFile['status'] = 'processing'; // Default to processing
if (progress.status === 'uploading' || progress.status === 'uploaded') {
newStatus = 'processing'; // Still processing
} else if (progress.status === 'processing' || progress.status === 'extracting_text' || progress.status === 'processing_llm' || progress.status === 'generating_pdf') {
newStatus = 'processing';
} else if (progress.status === 'completed') {
newStatus = 'completed';
@@ -242,12 +265,12 @@ const DocumentUpload: React.FC<DocumentUploadProps> = ({
// Don't stop monitoring on network errors, just log and continue
}
// Continue monitoring
setTimeout(checkProgress, 2000);
// Continue monitoring with shorter intervals for better responsiveness
setTimeout(checkProgress, 3000); // Check every 3 seconds
};
// Start monitoring
setTimeout(checkProgress, 1000);
// Start monitoring immediately
setTimeout(checkProgress, 500); // Start checking after 500ms
}, [token]);
const { getRootProps, getInputProps, isDragActive } = useDropzone({
@@ -378,7 +401,7 @@ const DocumentUpload: React.FC<DocumentUploadProps> = ({
<h4 className="text-sm font-medium text-success-800">Upload Complete</h4>
<p className="text-sm text-success-700 mt-1">
Files have been uploaded successfully to Firebase Storage! You can now navigate away from this page.
Processing will continue in the background using Document AI + Optimized Agentic RAG. PDFs will be automatically deleted after processing to save costs.
Processing will continue in the background using Document AI + Optimized Agentic RAG. This can take several minutes. PDFs will be automatically deleted after processing to save costs.
</p>
</div>
</div>

View File

@@ -7,7 +7,7 @@ const API_BASE_URL = config.apiBaseUrl;
// Create axios instance with auth interceptor
const apiClient = axios.create({
baseURL: API_BASE_URL,
timeout: 30000, // 30 seconds
timeout: 300000, // 5 minutes
});
// Add auth token to requests
@@ -263,14 +263,46 @@ class DocumentService {
// Step 3: Confirm upload and trigger processing
onProgress?.(95); // 95% - Confirming upload
const confirmResponse = await apiClient.post(`/documents/${documentId}/confirm-upload`, {}, { signal });
console.log('🔄 Making confirm-upload request for document:', documentId);
console.log('🔄 Confirm-upload URL:', `/documents/${documentId}/confirm-upload`);
// Add retry logic for confirm-upload (based on Google Cloud best practices)
let confirmResponse;
let lastError;
for (let attempt = 1; attempt <= 3; attempt++) {
try {
console.log(`🔄 Confirm-upload attempt ${attempt}/3`);
confirmResponse = await apiClient.post(`/documents/${documentId}/confirm-upload`, {}, {
signal,
timeout: 60000 // 60 second timeout for confirm-upload
});
console.log('✅ Confirm-upload response received:', confirmResponse.status);
console.log('✅ Confirm-upload response data:', confirmResponse.data);
break; // Success, exit retry loop
} catch (error: any) {
lastError = error;
console.log(`❌ Confirm-upload attempt ${attempt} failed:`, error.message);
if (attempt < 3) {
// Wait before retry (exponential backoff)
const delay = Math.pow(2, attempt) * 1000; // 2s, 4s
console.log(`⏳ Waiting ${delay}ms before retry...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
if (!confirmResponse) {
throw lastError || new Error('Confirm-upload failed after 3 attempts');
}
onProgress?.(100); // 100% - Complete
console.log('✅ Upload confirmed and processing started');
return {
id: documentId,
...confirmResponse.data
...confirmResponse.data.document
};
} catch (error: any) {
@@ -281,6 +313,16 @@ class DocumentService {
throw new Error('Upload was cancelled.');
}
// Handle network timeouts
if (error.code === 'ECONNABORTED' || error.message?.includes('timeout')) {
throw new Error('Request timed out. Please check your connection and try again.');
}
// Handle network errors
if (error.code === 'ERR_NETWORK' || error.message?.includes('Network Error')) {
throw new Error('Network error. Please check your connection and try again.');
}
if (error.response?.status === 401) {
throw new Error('Authentication required. Please log in again.');
}