Spaces:
Running
Running
File size: 6,542 Bytes
9bd422a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | /**
* ErrorHandler - Global error handling utility
* Classifies errors, creates user-friendly messages, logs to console,
* updates StateManager error state, and attempts recovery where possible.
* Requirements: 11.1, 11.2, 11.3, 11.4, 11.5
*/
const ErrorHandler = (function () {
// βββ Error Type Constants βββββββββββββββββββββββββββββββββββββββββββββββββ
const ErrorType = {
FILE_NOT_FOUND: 'FILE_NOT_FOUND',
INVALID_FILE_FORMAT: 'INVALID_FILE_FORMAT',
PARSE_ERROR: 'PARSE_ERROR',
LIBRARY_LOAD_ERROR: 'LIBRARY_LOAD_ERROR',
UPLOAD_ERROR: 'UPLOAD_ERROR',
EXPORT_ERROR: 'EXPORT_ERROR',
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
};
// βββ Private Helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
/**
* Classify an error object or message into a known ErrorType.
* @param {Error|string} error
* @returns {string} One of the ErrorType values
*/
function _classifyError(error) {
const msg = (error && (error.message || String(error))).toLowerCase();
if (msg.includes('not found') || msg.includes('404') || msg.includes('failed to fetch')) {
return ErrorType.FILE_NOT_FOUND;
}
if (msg.includes('invalid') && (msg.includes('format') || msg.includes('onnx'))) {
return ErrorType.INVALID_FILE_FORMAT;
}
if (msg.includes('parse') || msg.includes('protobuf') || msg.includes('corrupt')) {
return ErrorType.PARSE_ERROR;
}
if (msg.includes('library') || msg.includes('cdn') || msg.includes('script') || msg.includes('load error') || msg.includes('protobuf')) {
return ErrorType.LIBRARY_LOAD_ERROR;
}
if (msg.includes('upload')) {
return ErrorType.UPLOAD_ERROR;
}
if (msg.includes('export')) {
return ErrorType.EXPORT_ERROR;
}
return ErrorType.UNKNOWN_ERROR;
}
/**
* Map an ErrorType to a user-friendly message from CONFIG.ERRORS.
* @param {string} errorType
* @returns {string}
*/
function _getUserMessage(errorType) {
if (typeof CONFIG !== 'undefined' && CONFIG.ERRORS && CONFIG.ERRORS[errorType]) {
return CONFIG.ERRORS[errorType];
}
// Fallback messages if CONFIG is not available
const fallback = {
FILE_NOT_FOUND: 'File not found. Please check the file path.',
INVALID_FILE_FORMAT: 'Invalid file format. Please upload a valid ONNX file.',
PARSE_ERROR: 'Failed to parse the model. The file may be corrupted.',
LIBRARY_LOAD_ERROR: 'Failed to load required libraries. Please check your internet connection.',
UPLOAD_ERROR: 'Failed to upload the file. Please try again.',
EXPORT_ERROR: 'Failed to export the model information.',
UNKNOWN_ERROR: 'An unknown error occurred. Please try again.',
};
return fallback[errorType] || fallback.UNKNOWN_ERROR;
}
/**
* Attempt recovery based on error type.
* @param {string} errorType
*/
function _attemptRecovery(errorType) {
switch (errorType) {
case ErrorType.LIBRARY_LOAD_ERROR:
// Nothing we can do automatically; user must refresh
console.info('[ErrorHandler] Recovery: User should refresh the page to reload libraries.');
break;
case ErrorType.FILE_NOT_FOUND:
case ErrorType.PARSE_ERROR:
case ErrorType.INVALID_FILE_FORMAT:
// Clear the current model so the UI returns to a clean state
if (typeof StateManager !== 'undefined') {
StateManager.setCurrentModel(null);
StateManager.setLoading(false);
}
break;
case ErrorType.UPLOAD_ERROR:
// Reset loading state so the upload button is usable again
if (typeof StateManager !== 'undefined') {
StateManager.setLoading(false);
}
break;
case ErrorType.EXPORT_ERROR:
// No state change needed; export is a side-effect operation
break;
default:
// Generic recovery: ensure loading spinner is cleared
if (typeof StateManager !== 'undefined') {
StateManager.setLoading(false);
}
break;
}
}
// βββ Public API βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
return {
/**
* Handle an error: log it, classify it, show a user-friendly message,
* update StateManager, and attempt recovery.
*
* @param {Error|string} error - The error object or message
* @param {string} [context='App'] - Context label for console logging
* @param {'error'|'warning'|'info'} [severity='error'] - Display severity
*/
handleError(error, context = 'App', severity = 'error') {
// 1. Log to console
console.error(`[ErrorHandler][${context}]`, error);
// 2. Classify error type
const errorType = _classifyError(error);
// 3. Create user-friendly message
const userMessage = _getUserMessage(errorType);
// 4. Update StateManager error state
if (typeof StateManager !== 'undefined') {
StateManager.setError(userMessage, severity);
}
// 5. Attempt recovery
_attemptRecovery(errorType);
// Return structured info for callers that want it
return { errorType, userMessage };
},
/**
* Handle a warning (non-critical issue).
* @param {string} message
* @param {string} [context='App']
*/
handleWarning(message, context = 'App') {
console.warn(`[ErrorHandler][${context}]`, message);
if (typeof StateManager !== 'undefined') {
StateManager.setError(message, 'warning');
}
},
/**
* Handle an informational message.
* @param {string} message
* @param {string} [context='App']
*/
handleInfo(message, context = 'App') {
console.info(`[ErrorHandler][${context}]`, message);
if (typeof StateManager !== 'undefined') {
StateManager.setError(message, 'info');
}
},
/**
* Clear the current error state.
*/
clearError() {
if (typeof StateManager !== 'undefined') {
StateManager.clearError();
}
},
// Expose ErrorType constants for external use
ErrorType,
};
})();
// Export for global access in vanilla JS context
window.ErrorHandler = ErrorHandler;
|