@@ -426,8 +426,43 @@ class ChatGPTUI {
426426
427427 // === FILE HANDLING ===
428428 isMultiModalModel ( modelId ) {
429- const multiModalModels = [ 'gpt-4o' , 'gpt-4-turbo' , 'gpt-4-vision' ] ;
430- return multiModalModels . some ( model => modelId . includes ( model ) ) ;
429+ if ( ! modelId ) {
430+ return false ;
431+ }
432+
433+ // --- ALLOWLIST (Highest Priority) ---
434+ // If a model name is in this list, it is ALWAYS considered multimodal.
435+ const exactMatchAllowlist = [
436+ 'chatgpt-4o-latest' , // Your requested model to be found specifically
437+ 'gpt-4o' ,
438+ 'gpt-4o-mini' ,
439+ 'gpt-4.1'
440+ ] ;
441+ if ( exactMatchAllowlist . includes ( modelId ) ) {
442+ return true ;
443+ }
444+
445+ // --- BLACKLIST (Second Priority) ---
446+ // If a model name is in this list, it is NEVER multimodal,
447+ // even if it matches a prefix rule below.
448+ const exactMatchBlacklist = [
449+ 'whisper-1' , // This is a non-vision GPT-4 model
450+ 'tts-1' , // Another non-vision model
451+ 'text-embedding-3-large'
452+ ] ;
453+ if ( exactMatchBlacklist . includes ( modelId ) ) {
454+ return false ;
455+ }
456+
457+ // --- PREFIX LIST (General Rule) ---
458+ // If a model name STARTS WITH any of these strings, it is considered multimodal.
459+ const multiModalPrefixes = [
460+ 'gpt-4.1-' ,
461+ 'gpt-4o-2'
462+
463+ ] ;
464+
465+ return multiModalPrefixes . some ( prefix => modelId . startsWith ( prefix ) ) ;
431466 }
432467
433468 updateFileUploadAvailability ( ) {
@@ -650,8 +685,10 @@ class ChatGPTUI {
650685 await this . sendNonStreamingMessage ( ) ;
651686 }
652687 } catch ( error ) {
653- this . showError ( error . message ) ;
688+ // Use our new function to display the error in the chat
689+ this . addErrorMessageToChat ( error . message ) ;
654690 } finally {
691+ // This block correctly re-enables the send button and hides the typing indicator
655692 this . finishResponse ( ) ;
656693 }
657694 }
@@ -746,7 +783,7 @@ class ChatGPTUI {
746783
747784 if ( ! response . ok ) {
748785 const errorData = await response . json ( ) ;
749- throw new Error ( `API Error: ${ errorData . error ?. message || response . statusText } ` ) ;
786+ throw new Error ( `API Error - Expect this kind of messages on not know models of OpenAI, this is a simple project and may not suopport it - : ${ errorData . error ?. message || response . statusText } ` ) ;
750787 }
751788
752789 await this . processStreamingResponse ( response ) ;
@@ -892,7 +929,7 @@ class ChatGPTUI {
892929
893930 if ( ! response . ok ) {
894931 const errorData = await response . json ( ) ;
895- throw new Error ( `API Error: ${ errorData . error ?. message || response . statusText } ` ) ;
932+ throw new Error ( `API Error - Expect this kind of messages on not know models of OpenAI, this is a simple project and may not suopport it - : ${ errorData . error ?. message || response . statusText } ` ) ;
896933 }
897934
898935 const data = await response . json ( ) ;
@@ -934,10 +971,20 @@ class ChatGPTUI {
934971 role : msg . role ,
935972 content : msg . content
936973 } ) ) ,
937- max_tokens : 4000 ,
938974 stream : streaming
939975 } ;
940976
977+ const requiresMaxCompletionTokens = this . selectedModel . startsWith ( 'o1' ) ||
978+ this . selectedModel . startsWith ( 'o3' ) ||
979+ this . selectedModel . startsWith ( 'o4' ) ;
980+
981+ if ( requiresMaxCompletionTokens ) {
982+ requestBody . max_completion_tokens = 4000 ;
983+ } else {
984+ requestBody . max_tokens = 4000 ;
985+ }
986+ // === END OF FIX ===
987+
941988 if ( ! this . isSearchPreviewModel ( this . selectedModel ) ) {
942989 requestBody . temperature = 0.7 ;
943990 }
@@ -1161,7 +1208,7 @@ class ChatGPTUI {
11611208 if ( part . type === 'text' ) {
11621209 fullContent += `<div>${ this . formatMessageContent ( part . text ) } </div>` ;
11631210 } else if ( part . type === 'image_url' ) {
1164- fullContent = `<img src="${ part . image_url . url } " alt="user-uploaded-image" style="display: block; max-width: 100% ; border-radius: 8px; margin-top: 8px; margin-bottom: 8px;"><hr><br>` + fullContent ;
1211+ fullContent = `<img src="${ part . image_url . url } " alt="user-uploaded-image" style="display: block; max-width: 15vh ; border-radius: 8px; margin-top: 8px; margin-bottom: 8px;"><hr><br>` + fullContent ;
11651212 }
11661213 } ) ;
11671214 return fullContent ;
@@ -1442,6 +1489,26 @@ class ChatGPTUI {
14421489 }
14431490 // --- END NEW METHODS ---
14441491
1492+
1493+ addErrorMessageToChat ( errorMessage ) {
1494+ // We are no longer streaming, so finalize any partial message
1495+ if ( this . currentStreamingMessage ) {
1496+ this . finalizeStreamingMessage ( ) ;
1497+ }
1498+
1499+ const errorDiv = document . createElement ( 'div' ) ;
1500+ // Add both 'message' and 'error' classes to apply the new CSS
1501+ errorDiv . className = 'message error' ;
1502+
1503+ // Sanitize the message to prevent any potential HTML injection
1504+ const sanitizedMessage = this . escapeHtml ( errorMessage ) ;
1505+
1506+ errorDiv . innerHTML = `<div class="message-content"><strong>API Error - Expect this kind of messages on not know models of OpenAI, this is a simple project and may not suopport it -:</strong><br>${ sanitizedMessage } </div>` ;
1507+
1508+ this . chatMessages . appendChild ( errorDiv ) ;
1509+ this . scrollToBottom ( ) ;
1510+ }
1511+
14451512 // === ENHANCED UTILITY METHODS ===
14461513 renderMathJax ( element = null ) {
14471514 if ( ! window . MathJax ?. typesetPromise ) return ;
0 commit comments