@@ -230,72 +230,129 @@ function captureImageFromPTT() {
230230 showStatus ( 'IMAGE CAPTURED! GENERATE PALETTE' , 'success' ) ;
231231}
232232
233- // Function to upload image to catbox.moe
234- async function uploadToCatbox ( imageData ) {
235- try {
236- showStatus ( 'UPLOADING TO CATBOX...' , 'info' ) ;
237- console . log ( 'Starting image upload to catbox' ) ;
238-
239- // Validate image data
240- if ( ! imageData ) {
241- throw new Error ( 'No image data provided' ) ;
242- }
243-
244- // Convert data URL to Blob
245- const blob = dataURLToBlob ( imageData ) ;
246- console . log ( 'Blob created, size:' , blob . size , 'type:' , blob . type ) ;
247-
248- // Check if blob is valid
249- if ( blob . size === 0 ) {
250- throw new Error ( 'Image blob is empty' ) ;
233+ // Function to upload image to multiple fallback services
234+ async function uploadToImageHost ( imageData ) {
235+ const services = [
236+ {
237+ name : 'catbox' ,
238+ url : 'https://catbox.moe/user/api.php' ,
239+ formData : ( blob ) => {
240+ const formData = new FormData ( ) ;
241+ formData . append ( 'reqtype' , 'fileupload' ) ;
242+ formData . append ( 'fileToUpload' , blob , 'image.jpg' ) ;
243+ return formData ;
244+ }
245+ } ,
246+ {
247+ name : 'imgur' ,
248+ url : 'https://api.imgur.com/3/image' ,
249+ headers : {
250+ 'Authorization' : 'Client-ID 546c223def8fc9a' // Anonymous client ID
251+ } ,
252+ formData : ( blob ) => {
253+ const formData = new FormData ( ) ;
254+ formData . append ( 'image' , blob ) ;
255+ return formData ;
256+ }
257+ } ,
258+ {
259+ name : 'freeimagehost' ,
260+ url : 'https://freeimage.host/api/1/upload' ,
261+ formData : ( blob ) => {
262+ const formData = new FormData ( ) ;
263+ formData . append ( 'key' , '6d207e02198a847aa98d0a2a901485a5' ) ; // Public key
264+ formData . append ( 'source' , blob ) ;
265+ formData . append ( 'format' , 'txt' ) ;
266+ return formData ;
267+ }
251268 }
252-
253- // Create FormData
254- const formData = new FormData ( ) ;
255- formData . append ( 'reqtype' , 'fileupload' ) ;
256- formData . append ( 'fileToUpload' , blob , 'image.jpg' ) ;
257-
258- // Try to upload to catbox with timeout and error handling
259- console . log ( 'Sending request to catbox.moe' ) ;
260- const controller = new AbortController ( ) ;
261- const timeoutId = setTimeout ( ( ) => controller . abort ( ) , 15000 ) ; // 15 second timeout
262-
263- const response = await fetch ( 'https://catbox.moe/user/api.php' , {
264- method : 'POST' ,
265- body : formData ,
266- signal : controller . signal
267- } ) ;
268-
269- clearTimeout ( timeoutId ) ;
270-
271- console . log ( 'Catbox response status:' , response . status ) ;
272-
273- if ( response . ok ) {
274- const responseText = await response . text ( ) ;
275- const url = responseText . trim ( ) ;
276- console . log ( 'Image uploaded successfully to:' , url ) ;
269+ ] ;
270+
271+ showStatus ( 'UPLOADING IMAGE...' , 'info' ) ;
272+
273+ for ( let i = 0 ; i < services . length ; i ++ ) {
274+ const service = services [ i ] ;
275+ try {
276+ showStatus ( `UPLOADING TO ${ service . name . toUpperCase ( ) } ...` , 'info' ) ;
277+ console . log ( `Trying to upload to ${ service . name } ` ) ;
277278
278- // Validate that we got a URL
279- if ( url && url . length > 0 && ( url . startsWith ( 'http://' ) || url . startsWith ( 'https://' ) ) ) {
280- showStatus ( 'IMAGE UPLOADED SUCCESSFULLY' , 'success' ) ;
281- return url ;
279+ // Convert data URL to Blob
280+ const blob = dataURLToBlob ( imageData ) ;
281+ console . log ( 'Blob created, size:' , blob . size , 'type:' , blob . type ) ;
282+
283+ // Check if blob is valid
284+ if ( blob . size === 0 ) {
285+ throw new Error ( 'Image blob is empty' ) ;
286+ }
287+
288+ // Create FormData
289+ const formData = service . formData ( blob ) ;
290+
291+ // Try to upload with timeout
292+ console . log ( 'Sending request to' , service . name ) ;
293+ const controller = new AbortController ( ) ;
294+ const timeoutId = setTimeout ( ( ) => controller . abort ( ) , 15000 ) ; // 15 second timeout
295+
296+ const fetchOptions = {
297+ method : 'POST' ,
298+ body : formData ,
299+ signal : controller . signal
300+ } ;
301+
302+ // Add headers if specified
303+ if ( service . headers ) {
304+ fetchOptions . headers = service . headers ;
305+ }
306+
307+ const response = await fetch ( service . url , fetchOptions ) ;
308+
309+ clearTimeout ( timeoutId ) ;
310+
311+ console . log ( `${ service . name } response status:` , response . status ) ;
312+
313+ if ( response . ok ) {
314+ let url ;
315+ if ( service . name === 'imgur' ) {
316+ const data = await response . json ( ) ;
317+ url = data . data . link ;
318+ } else if ( service . name === 'freeimagehost' ) {
319+ url = await response . text ( ) ;
320+ } else {
321+ const responseText = await response . text ( ) ;
322+ url = responseText . trim ( ) ;
323+ }
324+
325+ console . log ( 'Image uploaded successfully to:' , url ) ;
326+
327+ // Validate that we got a URL
328+ if ( url && url . length > 0 && ( url . startsWith ( 'http://' ) || url . startsWith ( 'https://' ) ) ) {
329+ showStatus ( `UPLOADED TO ${ service . name . toUpperCase ( ) } SUCCESSFULLY` , 'success' ) ;
330+ return { url, service : service . name } ;
331+ } else {
332+ throw new Error ( `Invalid URL received from ${ service . name } : ${ url } ` ) ;
333+ }
282334 } else {
283- throw new Error ( 'Invalid URL received from catbox: ' + responseText ) ;
335+ const errorText = await response . text ( ) ;
336+ throw new Error ( `Upload failed with status: ${ response . status } ${ response . statusText } - ${ errorText } ` ) ;
337+ }
338+ } catch ( error ) {
339+ console . error ( `Error uploading to ${ service . name } :` , error ) ;
340+ if ( i === services . length - 1 ) {
341+ // Last service, throw the error
342+ if ( error . name === 'AbortError' ) {
343+ showStatus ( 'UPLOAD TIMED OUT - CHECK NETWORK' , 'error' ) ;
344+ } else if ( error . message . includes ( 'fetch' ) ) {
345+ showStatus ( 'NETWORK ERROR - UPLOAD SERVICE UNAVAILABLE' , 'error' ) ;
346+ } else {
347+ showStatus ( 'UPLOAD FAILED: ' + error . message , 'error' ) ;
348+ }
349+ throw error ;
350+ } else {
351+ // Try next service
352+ showStatus ( `FAILED ${ service . name . toUpperCase ( ) } , TRYING NEXT...` , 'info' ) ;
353+ continue ;
284354 }
285- } else {
286- const errorText = await response . text ( ) ;
287- throw new Error ( 'Upload failed with status: ' + response . status + ' ' + response . statusText + ' - ' + errorText ) ;
288- }
289- } catch ( error ) {
290- console . error ( 'Catbox upload error:' , error ) ;
291- if ( error . name === 'AbortError' ) {
292- showStatus ( 'UPLOAD TIMED OUT - CHECK NETWORK' , 'error' ) ;
293- } else if ( error . message . includes ( 'fetch' ) ) {
294- showStatus ( 'NETWORK ERROR - CATBOX UNAVAILABLE' , 'error' ) ;
295- } else {
296- showStatus ( 'UPLOAD FAILED: ' + error . message , 'error' ) ;
297355 }
298- throw error ;
299356 }
300357}
301358
@@ -537,16 +594,16 @@ window.onPluginMessage = function(data) {
537594 resetApp ( ) ;
538595 } , 2000 ) ;
539596 }
540- // Handle case where LLM requests image URL (fallback) - make this more comprehensive
597+ // Handle case where LLM requests image URL (fallback) - use new multi-service function
541598 else if ( data . message . includes ( 'image' ) &&
542599 ( data . message . includes ( 'url' ) ||
543600 data . message . includes ( 'link' ) ||
544601 data . message . includes ( 'file' ) ||
545602 data . message . includes ( 'upload' ) ) ) {
546603 showStatus ( 'LLM NEEDS IMAGE URL - UPLOADING...' , 'info' ) ;
547- console . log ( 'LLM requested image URL, using catbox fallback' ) ;
548- // Use catbox as fallback only when LLM explicitly requests it
549- fallbackToCatboxAnalysis ( ) ;
604+ console . log ( 'LLM requested image URL, using multi-service fallback' ) ;
605+ // Use multi-service fallback only when LLM explicitly requests it
606+ fallbackToImageHostAnalysis ( ) ;
550607 } else if ( data . message . includes ( 'timeout' ) || data . message . includes ( 'failed' ) || data . message . includes ( 'error' ) ) {
551608 showStatus ( 'LLM ERROR: ' + data . message , 'error' ) ;
552609 } else {
@@ -678,9 +735,9 @@ function sendImageToLLM() {
678735 }
679736}
680737
681- // Fallback function to use catbox for image hosting and analysis (only when LLM requests it)
682- async function fallbackToCatboxAnalysis ( ) {
683- showStatus ( 'UPLOADING IMAGE TO CATBOX ...' , 'info' ) ;
738+ // Fallback function to use multiple image hosting services (only when LLM requests it)
739+ async function fallbackToImageHostAnalysis ( ) {
740+ showStatus ( 'UPLOADING IMAGE TO HOST ...' , 'info' ) ;
684741
685742 try {
686743 // Check if we have image data
@@ -695,21 +752,21 @@ async function fallbackToCatboxAnalysis() {
695752 throw new Error ( 'Captured image data is too small' ) ;
696753 }
697754
698- // Upload image to catbox
699- const imageUrl = await uploadToCatbox ( capturedImageData ) ;
755+ // Upload image to fallback services
756+ const { url , service } = await uploadToImageHost ( capturedImageData ) ;
700757
701- if ( imageUrl && imageUrl . length > 0 ) {
702- showStatus ( ' IMAGE UPLOADED! REQUESTING ANALYSIS...' , 'info' ) ;
703- console . log ( 'Image uploaded to:' , imageUrl ) ;
758+ if ( url && url . length > 0 ) {
759+ showStatus ( ` IMAGE UPLOADED TO ${ service . toUpperCase ( ) } ! REQUESTING ANALYSIS...` , 'info' ) ;
760+ console . log ( 'Image uploaded to:' , url ) ;
704761
705762 // Validate URL before sending to LLM
706- if ( ! imageUrl . startsWith ( 'http' ) ) {
763+ if ( ! url . startsWith ( 'http' ) ) {
707764 throw new Error ( 'Invalid image URL received' ) ;
708765 }
709766
710767 // Send image URL to LLM for analysis with clearer instructions
711768 const payload = {
712- message : `I've uploaded the image to ${ imageUrl } . Please analyze this image and extract exactly 5 dominant colors in hex format. Return ONLY a JSON object in this exact format: {"colors": ["#hex1", "#hex2", "#hex3", "#hex4", "#hex5"]}.` ,
769+ message : `I've uploaded the image to ${ url } using ${ service } . Please analyze this image and extract exactly 5 dominant colors in hex format. Return ONLY a JSON object in this exact format: {"colors": ["#hex1", "#hex2", "#hex3", "#hex4", "#hex5"]}.` ,
713770 useLLM : true ,
714771 wantsR1Response : false // Set to false to get JSON response
715772 } ;
@@ -718,10 +775,10 @@ async function fallbackToCatboxAnalysis() {
718775 showStatus ( 'REQUESTING COLOR ANALYSIS...' , 'info' ) ;
719776 PluginMessageHandler . postMessage ( JSON . stringify ( payload ) ) ;
720777 } else {
721- throw new Error ( 'Failed to get image URL from catbox ' ) ;
778+ throw new Error ( 'Failed to get image URL from hosting service ' ) ;
722779 }
723780 } catch ( error ) {
724- console . error ( 'Catbox analysis error:' , error ) ;
781+ console . error ( 'Image hosting analysis error:' , error ) ;
725782 showStatus ( 'ANALYSIS FAILED: ' + error . message , 'error' ) ;
726783 }
727784}
0 commit comments