Skip to content

Commit a23e803

Browse files
authored
fix: empty mimeType error on Windows (#1141)
1 parent 7b2286b commit a23e803

File tree

4 files changed

+36
-8
lines changed

4 files changed

+36
-8
lines changed

packages/cdk/lambda/utils/media.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import {
33
ImageFormat,
44
VideoFormat,
55
} from '@aws-sdk/client-bedrock-runtime';
6-
import { SupportedMimeType } from '@generative-ai-use-cases/common';
6+
import {
7+
extensionToMimeType,
8+
SupportedMimeType,
9+
} from '@generative-ai-use-cases/common';
710

811
const SupportedFormat = {
912
...DocumentFormat,
@@ -27,3 +30,11 @@ export const getFormatFromMimeType = (mimeType: string) => {
2730
}
2831
throw new Error(`Unsupported MIME type: ${mimeType}`);
2932
};
33+
34+
export const getMimeTypeFromFileName = (fileName: string) => {
35+
const extension = fileName.split('.').pop()?.toLowerCase() || '';
36+
if (extension in extensionToMimeType) {
37+
return extensionToMimeType[extension];
38+
}
39+
throw new Error(`Unsupported file extension: ${fileName}`);
40+
};

packages/cdk/lambda/utils/models.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {
3131
applyAutoCacheToMessages,
3232
applyAutoCacheToSystem,
3333
} from './promptCache';
34-
import { getFormatFromMimeType } from './media';
34+
import { getFormatFromMimeType, getMimeTypeFromFileName } from './media';
3535

3636
// Default Models
3737

@@ -358,10 +358,16 @@ const createConverseCommandInput = (
358358
// Put images, videos, and documents before the task, instruction, and user query
359359
if (message.extraData) {
360360
message.extraData.forEach((extra) => {
361+
// Prior to v4.2.4, 'extra.source.mediaType' could be empty.
362+
// For resumed conversations from older versions, we fallback to detecting mimeType based on the extension.
363+
const mimeType =
364+
extra.source.mediaType || getMimeTypeFromFileName(extra.name);
365+
const format = getFormatFromMimeType(mimeType);
366+
361367
if (extra.type === 'image' && extra.source.type === 'base64') {
362368
contentBlocks.push({
363369
image: {
364-
format: getFormatFromMimeType(extra.source.mediaType),
370+
format,
365371
source: {
366372
bytes: Buffer.from(extra.source.data, 'base64'),
367373
},
@@ -370,7 +376,7 @@ const createConverseCommandInput = (
370376
} else if (extra.type === 'file' && extra.source.type === 'base64') {
371377
contentBlocks.push({
372378
document: {
373-
format: getFormatFromMimeType(extra.source.mediaType),
379+
format,
374380
name: extra.name
375381
.split('.')[0]
376382
.replace(/[^a-zA-Z0-9\s\-()[\]]/g, 'X'), // If the file name contains Japanese, it will cause an error, so convert it
@@ -382,7 +388,7 @@ const createConverseCommandInput = (
382388
} else if (extra.type === 'video' && extra.source.type === 'base64') {
383389
contentBlocks.push({
384390
video: {
385-
format: getFormatFromMimeType(extra.source.mediaType),
391+
format,
386392
source: {
387393
bytes: Buffer.from(extra.source.data, 'base64'),
388394
},
@@ -391,7 +397,7 @@ const createConverseCommandInput = (
391397
} else if (extra.type === 'video' && extra.source.type === 's3') {
392398
contentBlocks.push({
393399
video: {
394-
format: getFormatFromMimeType(extra.source.mediaType),
400+
format,
395401
source: {
396402
s3Location: {
397403
uri: extra.source.data,

packages/common/src/application/media.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,10 @@ export const mimeTypeToExtensions: Record<SupportedMimeType, string[]> = {
8383
...imageMimeTypeToExtensions,
8484
...videoMimeTypeToExtensions,
8585
};
86+
87+
export const extensionToMimeType: Record<string, SupportedMimeType> =
88+
Object.fromEntries(
89+
Object.entries(mimeTypeToExtensions).flatMap(([mimeType, extensions]) =>
90+
extensions.map((ext) => [ext, mimeType as SupportedMimeType])
91+
)
92+
);

packages/web/src/utils/MediaUtils.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
imageMimeTypeToExtensions,
77
videoMimeTypeToExtensions,
88
mimeTypeToExtensions,
9+
extensionToMimeType,
910
} from '@generative-ai-use-cases/common';
1011
import { fileTypeFromBuffer, fileTypeFromStream } from 'file-type';
1112

@@ -36,12 +37,15 @@ export const getMimeTypeFromFileHeader = async (file: File) => {
3637
throw new Error('Error reading MIME type from file');
3738
}
3839
}
40+
3941
// Some file types are not supported by the file-type library.
40-
// In this case, we fall back to using 'file.type' for the MIME type, since the file-type library covers most binary file types.
42+
// In this case, we fall back to using common MIME types based on the file extension.
4143
// https://github.com/sindresorhus/file-type/tree/main?tab=readme-ov-file#supported-file-types
4244
if (!mimeType || mimeType === 'application/x-cfb') {
43-
mimeType = file.type;
45+
const extension = file.name.split('.').pop()?.toLowerCase() || '';
46+
mimeType = extensionToMimeType[extension] || '';
4447
}
48+
4549
return (mimeTypeAlias[mimeType] || mimeType) as SupportedMimeType;
4650
};
4751

0 commit comments

Comments
 (0)