Skip to content

Commit 0f67286

Browse files
committed
fix(mistral): name extracted images as storage does, drop inline table format, align image switch with tool param
1 parent 82d4147 commit 0f67286

8 files changed

Lines changed: 39 additions & 31 deletions

File tree

‎apps/docs/content/docs/integrations/mistral_parse.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Use [Mistral's OCR API](https://mistral.ai/) to extract text and page structure
1515

1616
## Use the block [#usage-instructions]
1717

18-
Extract text from uploaded PDF documents, or from a URL.
18+
Extract text, tables, and images from uploaded PDF documents, or from a URL. Images come back as files an agent can pass on.
1919

2020
## Actions
2121

‎apps/sim/blocks/blocks/mistral_parse.ts‎

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,8 @@ export const MistralParseV3Block: BlockConfig = {
309309
type: 'mistral_parse_v3',
310310
name: 'Mistral Parser',
311311
description: 'Extract text, tables, and images from PDF documents',
312+
longDescription:
313+
'Extract text, tables, and images from uploaded PDF documents, or from a URL. Images come back as files an agent can pass on.',
312314
hideFromToolbar: false,
313315
/* v3 renamed the canonical pair's advanced member `filePath` -> `fileReference`,
314316
so the inherited sentence would reference a subblock this block lacks. */
@@ -374,7 +376,7 @@ export const MistralParseV3Block: BlockConfig = {
374376
value: () => 'inline',
375377
},
376378
{
377-
id: 'extractImages',
379+
id: 'includeImageBase64',
378380
title: 'Extract Images',
379381
type: 'switch',
380382
},
@@ -383,15 +385,15 @@ export const MistralParseV3Block: BlockConfig = {
383385
title: 'Max Images',
384386
type: 'short-input',
385387
placeholder: 'Up to 100 (default 100)',
386-
condition: { field: 'extractImages', value: true },
388+
condition: { field: 'includeImageBase64', value: true },
387389
mode: 'advanced',
388390
},
389391
{
390392
id: 'imageMinSize',
391393
title: 'Min Image Size (px)',
392394
type: 'short-input',
393395
placeholder: 'Skip images smaller than this on both sides',
394-
condition: { field: 'extractImages', value: true },
396+
condition: { field: 'includeImageBase64', value: true },
395397
mode: 'advanced',
396398
},
397399
{
@@ -452,11 +454,12 @@ export const MistralParseV3Block: BlockConfig = {
452454
parameters.pages = pagesArray
453455
}
454456

455-
if (params.tableFormat === 'markdown' || params.tableFormat === 'html') {
456-
parameters.tableFormat = params.tableFormat
457-
}
457+
parameters.tableFormat =
458+
params.tableFormat === 'markdown' || params.tableFormat === 'html'
459+
? params.tableFormat
460+
: undefined
458461

459-
if (params.extractImages) {
462+
if (params.includeImageBase64) {
460463
parameters.includeImageBase64 = true
461464
parameters.imageLimit = parseOptionalNumberInput(params.imageLimit, 'Max Images', {
462465
integer: true,
@@ -479,7 +482,7 @@ export const MistralParseV3Block: BlockConfig = {
479482
resultType: { type: 'string', description: 'Output format type' },
480483
pages: { type: 'string', description: 'Page selection' },
481484
tableFormat: { type: 'string', description: 'Table output: inline, markdown, or html' },
482-
extractImages: { type: 'boolean', description: 'Extract document images as files' },
485+
includeImageBase64: { type: 'boolean', description: 'Extract document images as files' },
483486
imageLimit: { type: 'number', description: 'Maximum number of images to extract' },
484487
imageMinSize: { type: 'number', description: 'Minimum image size in pixels' },
485488
},

‎apps/sim/lib/internal/mistral/images.test.ts‎

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { describe, expect, it } from 'vitest'
22
import { extractOcrImageFiles, MAX_OCR_EXTRACTED_IMAGES } from '@/lib/internal/mistral/images'
33

4-
const PNG = Buffer.from('synthetic png bytes')
5-
const dataUri = (bytes: Buffer) => `data:image/png;base64,${bytes.toString('base64')}`
4+
const JPEG = Buffer.concat([Buffer.from([0xff, 0xd8, 0xff]), Buffer.from('synthetic jpeg body')])
5+
const dataUri = (bytes: Buffer) => `data:image/jpeg;base64,${bytes.toString('base64')}`
66

77
function image(id: string, imageBase64: string | undefined) {
88
return {
@@ -16,28 +16,28 @@ function image(id: string, imageBase64: string | undefined) {
1616
}
1717

1818
describe('extractOcrImageFiles', () => {
19-
it('moves image bytes into files and leaves no base64 in the page output', () => {
19+
it('moves image bytes into files named as storage will name them, with no base64 left in the page output', () => {
2020
const { output, files } = extractOcrImageFiles({
2121
pages: [
2222
{
2323
index: 2,
24-
markdown: '![img-0.png](img-0.png)',
25-
images: [image('img-0.png', dataUri(PNG))],
24+
markdown: '![img-0.jpeg](img-0.jpeg)',
25+
images: [image('img-0.jpeg', dataUri(JPEG))],
2626
},
2727
],
2828
})
29-
expect(files).toEqual([{ buffer: PNG, name: 'page-2-img-0.png', mimeType: 'image/png' }])
30-
expect(JSON.stringify(output)).not.toContain(PNG.toString('base64'))
29+
expect(files).toEqual([{ buffer: JPEG, name: 'page-2-img-0.jpg', mimeType: 'image/jpeg' }])
30+
expect(JSON.stringify(output)).not.toContain(JPEG.toString('base64'))
3131
expect(output.pages).toEqual([
3232
expect.objectContaining({
33-
images: [expect.objectContaining({ id: 'img-0.png', file_name: 'page-2-img-0.png' })],
33+
images: [expect.objectContaining({ id: 'img-0.jpeg', file_name: 'page-2-img-0.jpg' })],
3434
}),
3535
])
3636
})
3737

3838
it('stores at most the image cap and keeps the bounding boxes of the rest without a file', () => {
3939
const images = Array.from({ length: MAX_OCR_EXTRACTED_IMAGES + 1 }, (_, i) =>
40-
image(`img-${i}.jpeg`, PNG.toString('base64'))
40+
image(`img-${i}.jpeg`, JPEG.toString('base64'))
4141
)
4242
const { output, files } = extractOcrImageFiles({ pages: [{ index: 0, images }] })
4343
expect(files).toHaveLength(MAX_OCR_EXTRACTED_IMAGES)
@@ -51,10 +51,13 @@ describe('extractOcrImageFiles', () => {
5151
const huge = Buffer.alloc(21 * 1024 * 1024)
5252
const { output, files } = extractOcrImageFiles({
5353
pages: [
54-
{ index: 0, images: [image('img-0.png', dataUri(huge)), image('img-1.png', dataUri(PNG))] },
54+
{
55+
index: 0,
56+
images: [image('img-0.png', dataUri(huge)), image('img-1.jpg', dataUri(JPEG))],
57+
},
5558
],
5659
})
57-
expect(files.map((file) => file.name)).toEqual(['page-0-img-1.png'])
60+
expect(files.map((file) => file.name)).toEqual(['page-0-img-1.jpg'])
5861
expect(JSON.stringify(output)).not.toContain('image_base64')
5962
})
6063
})

‎apps/sim/lib/internal/mistral/images.ts‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { isFileParserError } from '@/lib/file-parsers/errors'
44
import type { InternalToolFile } from '@/lib/internal/tool-operations/file-result'
55
import { MAX_BUFFERED_TRANSFER_BYTES } from '@/lib/uploads/shared/types'
66
import { resolveEffectiveMimeType } from '@/lib/uploads/utils/file'
7+
import { resolveStoredFileMetadata } from '@/lib/uploads/utils/stored-file-metadata'
78

89
/** Most images one parse stores; Mistral's `image_limit` is clamped to it. */
910
export const MAX_OCR_EXTRACTED_IMAGES = 100
@@ -51,13 +52,15 @@ export function extractOcrImageFiles(output: unknown): OcrImageFiles {
5152
if (!decoded || totalBytes + decoded.buffer.length > MAX_BUFFERED_TRANSFER_BYTES) return rest
5253
totalBytes += decoded.buffer.length
5354
const id = typeof image.id === 'string' && image.id ? image.id : `img-${files.length}.jpeg`
54-
const name = `page-${pageIndex}-${id}`
55-
files.push({
56-
buffer: decoded.buffer,
57-
name,
58-
mimeType: resolveEffectiveMimeType(decoded.mediaType, name),
59-
})
60-
return { ...rest, file_name: name }
55+
/** Storage renames an image from its bytes; naming it the same way keeps `file_name` matching. */
56+
const draftName = `page-${pageIndex}-${id}`
57+
const { fileName, mimeType } = resolveStoredFileMetadata(
58+
draftName,
59+
resolveEffectiveMimeType(decoded.mediaType, draftName),
60+
decoded.buffer
61+
)
62+
files.push({ buffer: decoded.buffer, name: fileName, mimeType })
63+
return { ...rest, file_name: fileName }
6164
})
6265
return { ...page, images }
6366
})

‎apps/sim/lib/internal/mistral/operations.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ describe('Mistral ingestion authorization', () => {
256256
)
257257

258258
it('returns extracted images as files, never as base64 in the output', async () => {
259-
const png = Buffer.from('synthetic png bytes')
259+
const png = Buffer.concat([Buffer.from([0xff, 0xd8, 0xff]), Buffer.from('synthetic jpeg body')])
260260
submit.mockResolvedValue({
261261
pages: [
262262
{

‎apps/sim/tools/mistral/parser.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ export const mistralParserV3Tool: InternalToolConfig<MistralParserV2Input, Mistr
600600
if (params.imageMinSize !== undefined) {
601601
requestBody.imageMinSize = params.imageMinSize
602602
}
603-
if (params.tableFormat) {
603+
if (params.tableFormat === 'markdown' || params.tableFormat === 'html') {
604604
requestBody.tableFormat = params.tableFormat
605605
}
606606

‎packages/deployment-config/src/integrations.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18362,7 +18362,7 @@
1836218362
"slug": "mistral-parser",
1836318363
"name": "Mistral Parser",
1836418364
"description": "Extract text, tables, and images from PDF documents",
18365-
"longDescription": "Extract text from uploaded PDF documents, or from a URL.",
18365+
"longDescription": "Extract text, tables, and images from uploaded PDF documents, or from a URL. Images come back as files an agent can pass on.",
1836618366
"bgColor": "#000000",
1836718367
"iconName": "MistralIcon",
1836818368
"docsUrl": "https://docs.sim.ai/integrations/mistral_parse",

‎scripts/check-unused-exports.baseline.json‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5577,7 +5577,6 @@
55775577
"apps/sim/tools/mistral/types.ts#MISTRAL_OCR_DIMENSIONS_OUTPUT",
55785578
"apps/sim/tools/mistral/types.ts#MISTRAL_OCR_DIMENSIONS_OUTPUT_PROPERTIES",
55795579
"apps/sim/tools/mistral/types.ts#MISTRAL_OCR_IMAGE_OUTPUT_PROPERTIES",
5580-
"apps/sim/tools/mistral/types.ts#MISTRAL_OCR_PAGE_OUTPUT_PROPERTIES",
55815580
"apps/sim/tools/mistral/types.ts#MISTRAL_OCR_USAGE_OUTPUT",
55825581
"apps/sim/tools/mistral/types.ts#MISTRAL_OCR_USAGE_OUTPUT_PROPERTIES",
55835582
"apps/sim/tools/mistral/types.ts#MISTRAL_PARSER_METADATA_OUTPUT_PROPERTIES",

0 commit comments

Comments
 (0)