@@ -37,19 +37,26 @@ export function useChatExtraContext(): ChatExtraContextApi {
37
37
break ;
38
38
}
39
39
40
- if ( mimeType . startsWith ( 'image/' ) && mimeType !== 'image/svg+xml' ) {
41
- if ( ! serverProps ?. has_multimodal ) {
40
+ if ( mimeType . startsWith ( 'image/' ) ) {
41
+ if ( ! serverProps ?. modalities ?. vision ) {
42
42
toast . error ( 'Multimodal is not supported by this server or model.' ) ;
43
43
break ;
44
44
}
45
45
const reader = new FileReader ( ) ;
46
- reader . onload = ( event ) => {
46
+ reader . onload = async ( event ) => {
47
47
if ( event . target ?. result ) {
48
+ let base64Url = event . target . result as string ;
49
+
50
+ if ( mimeType === 'image/svg+xml' ) {
51
+ // Convert SVG to PNG
52
+ base64Url = await svgBase64UrlToPngDataURL ( base64Url ) ;
53
+ }
54
+
48
55
addItems ( [
49
56
{
50
57
type : 'imageFile' ,
51
58
name : file . name ,
52
- base64Url : event . target . result as string ,
59
+ base64Url,
53
60
} ,
54
61
] ) ;
55
62
}
@@ -172,3 +179,56 @@ export function isLikelyNotBinary(str: string): boolean {
172
179
const ratio = suspiciousCharCount / sampleLength ;
173
180
return ratio <= options . suspiciousCharThresholdRatio ;
174
181
}
182
+
183
+ // WARN: vibe code below
184
+ // Converts a Base64URL encoded SVG string to a PNG Data URL using browser Canvas API.
185
+ function svgBase64UrlToPngDataURL ( base64UrlSvg : string ) : Promise < string > {
186
+ const backgroundColor = 'white' ; // Default background color for PNG
187
+
188
+ return new Promise ( ( resolve , reject ) => {
189
+ try {
190
+ const img = new Image ( ) ;
191
+
192
+ img . onload = ( ) => {
193
+ const canvas = document . createElement ( 'canvas' ) ;
194
+ const ctx = canvas . getContext ( '2d' ) ;
195
+
196
+ if ( ! ctx ) {
197
+ reject ( new Error ( 'Failed to get 2D canvas context.' ) ) ;
198
+ return ;
199
+ }
200
+
201
+ // Use provided dimensions or SVG's natural dimensions, with fallbacks
202
+ // Fallbacks (e.g., 300x300) are for SVGs without explicit width/height
203
+ // or when naturalWidth/Height might be 0 before full processing.
204
+ const targetWidth = img . naturalWidth || 300 ;
205
+ const targetHeight = img . naturalHeight || 300 ;
206
+
207
+ canvas . width = targetWidth ;
208
+ canvas . height = targetHeight ;
209
+
210
+ if ( backgroundColor ) {
211
+ ctx . fillStyle = backgroundColor ;
212
+ ctx . fillRect ( 0 , 0 , canvas . width , canvas . height ) ;
213
+ }
214
+
215
+ ctx . drawImage ( img , 0 , 0 , targetWidth , targetHeight ) ;
216
+ resolve ( canvas . toDataURL ( 'image/png' ) ) ;
217
+ } ;
218
+
219
+ img . onerror = ( ) => {
220
+ reject (
221
+ new Error ( 'Failed to load SVG image. Ensure the SVG data is valid.' )
222
+ ) ;
223
+ } ;
224
+
225
+ // Load SVG string into an Image element
226
+ img . src = base64UrlSvg ;
227
+ } catch ( error ) {
228
+ const message = error instanceof Error ? error . message : String ( error ) ;
229
+ const errorMessage = `Error converting SVG to PNG: ${ message } ` ;
230
+ toast . error ( errorMessage ) ;
231
+ reject ( new Error ( errorMessage ) ) ;
232
+ }
233
+ } ) ;
234
+ }
0 commit comments