@modelprofile.com/flexharness 10.18.0 → 10.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts_ocr/ocr.mistral.d.ts +20 -1
- package/dist_ts_ocr/ocr.mistral.js +66 -43
- package/package.json +3 -3
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts_ocr/ocr.mistral.ts +102 -49
- package/ts_ocr/readme.md +12 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@modelprofile.com/flexharness',
|
|
6
|
-
version: '10.
|
|
6
|
+
version: '10.19.0',
|
|
7
7
|
description: 'The FlexHarness toolbox source repository and shared dependency catalog.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSwrQkFBK0I7SUFDckMsT0FBTyxFQUFFLFNBQVM7SUFDbEIsV0FBVyxFQUFFLDBFQUEwRTtDQUN4RixDQUFBIn0=
|
|
@@ -5,6 +5,12 @@ export interface ISmartAiOcrImageInput {
|
|
|
5
5
|
dataBase64: string;
|
|
6
6
|
mimeType: TSmartAiOcrImageMimeType;
|
|
7
7
|
}
|
|
8
|
+
/** Mistral OCR reads PDF, PPTX, DOCX and other document formats. */
|
|
9
|
+
export type TSmartAiOcrDocumentMimeType = 'application/pdf' | 'application/vnd.openxmlformats-officedocument.presentationml.presentation' | 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' | string;
|
|
10
|
+
export interface ISmartAiOcrDocumentInput {
|
|
11
|
+
dataBase64: string;
|
|
12
|
+
mimeType: TSmartAiOcrDocumentMimeType;
|
|
13
|
+
}
|
|
8
14
|
export interface ISmartAiOcrPageResult {
|
|
9
15
|
index: number;
|
|
10
16
|
text: string;
|
|
@@ -19,6 +25,10 @@ export interface ISmartAiOcrResult<TRaw = unknown> {
|
|
|
19
25
|
export interface ISmartAiOcrEngine {
|
|
20
26
|
recognizeImage: (input: ISmartAiOcrImageInput, options?: ISmartAiMistralOcrRecognizeOptions) => Promise<ISmartAiOcrResult<IMistralOcrResponse>>;
|
|
21
27
|
}
|
|
28
|
+
/** The Mistral OCR engine also reads whole documents, such as a PDF with all its pages. */
|
|
29
|
+
export interface ISmartAiMistralOcrEngine extends ISmartAiOcrEngine {
|
|
30
|
+
recognizeDocument: (input: ISmartAiOcrDocumentInput, options?: ISmartAiMistralOcrRecognizeOptions) => Promise<ISmartAiOcrResult<IMistralOcrResponse>>;
|
|
31
|
+
}
|
|
22
32
|
export interface IMistralOcrPageConfidenceScores {
|
|
23
33
|
average_page_confidence_score?: number;
|
|
24
34
|
averagePageConfidenceScore?: number;
|
|
@@ -51,8 +61,17 @@ export interface IMistralOcrRequest {
|
|
|
51
61
|
extract_footer?: boolean;
|
|
52
62
|
confidence_scores_granularity?: TSmartAiMistralOcrConfidenceScoresGranularity;
|
|
53
63
|
}
|
|
64
|
+
/** A document (PDF, PPTX, DOCX and other formats) as a URL or a base64 data URL; the other fields are those of an image request. */
|
|
65
|
+
export interface IMistralOcrDocumentRequest extends Omit<IMistralOcrRequest, 'document'> {
|
|
66
|
+
document: {
|
|
67
|
+
type: 'document_url';
|
|
68
|
+
document_url: string;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
54
71
|
export interface ISmartAiMistralOcrTransport {
|
|
55
72
|
process: (request: IMistralOcrRequest) => Promise<IMistralOcrResponse>;
|
|
73
|
+
/** Reads documents. A transport without it reads images only, and `recognizeDocument` refuses documents. */
|
|
74
|
+
processDocument?: (request: IMistralOcrDocumentRequest) => Promise<IMistralOcrResponse>;
|
|
56
75
|
}
|
|
57
76
|
export interface ISmartAiMistralOcrOptions {
|
|
58
77
|
apiKey?: string;
|
|
@@ -72,4 +91,4 @@ export interface ISmartAiMistralOcrRecognizeOptions {
|
|
|
72
91
|
extractFooter?: boolean;
|
|
73
92
|
confidenceScoresGranularity?: TSmartAiMistralOcrConfidenceScoresGranularity;
|
|
74
93
|
}
|
|
75
|
-
export declare const createMistralOcrEngine: (options?: ISmartAiMistralOcrOptions) =>
|
|
94
|
+
export declare const createMistralOcrEngine: (options?: ISmartAiMistralOcrOptions) => ISmartAiMistralOcrEngine;
|
|
@@ -1,32 +1,50 @@
|
|
|
1
1
|
const defaultMistralOcrModel = 'mistral-ocr-latest';
|
|
2
2
|
const defaultMistralOcrEndpointUrl = 'https://api.mistral.ai/v1/ocr';
|
|
3
3
|
const createMistralOcrHttpTransport = (options) => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return (await response.json());
|
|
22
|
-
},
|
|
4
|
+
const post = async (request) => {
|
|
5
|
+
if (!options.apiKey) {
|
|
6
|
+
throw new Error('Mistral OCR requires an apiKey when no custom transport is provided.');
|
|
7
|
+
}
|
|
8
|
+
const response = await fetch(options.endpointUrl ?? defaultMistralOcrEndpointUrl, {
|
|
9
|
+
method: 'POST',
|
|
10
|
+
headers: {
|
|
11
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
12
|
+
'Content-Type': 'application/json',
|
|
13
|
+
},
|
|
14
|
+
body: JSON.stringify(request),
|
|
15
|
+
});
|
|
16
|
+
if (!response.ok) {
|
|
17
|
+
const errorBody = await response.text();
|
|
18
|
+
throw new Error(`Mistral OCR request failed with status ${response.status}: ${errorBody}`);
|
|
19
|
+
}
|
|
20
|
+
return (await response.json());
|
|
23
21
|
};
|
|
22
|
+
return { process: post, processDocument: post };
|
|
24
23
|
};
|
|
25
24
|
const getPageConfidence = (page) => {
|
|
26
25
|
const confidenceScores = page.confidence_scores ?? page.confidenceScores;
|
|
27
26
|
return (confidenceScores?.average_page_confidence_score ??
|
|
28
27
|
confidenceScores?.averagePageConfidenceScore);
|
|
29
28
|
};
|
|
29
|
+
const toOcrResult = (response) => {
|
|
30
|
+
const pages = response.pages.map((page) => ({
|
|
31
|
+
index: page.index,
|
|
32
|
+
text: page.markdown,
|
|
33
|
+
confidence: getPageConfidence(page),
|
|
34
|
+
}));
|
|
35
|
+
const pageConfidences = pages
|
|
36
|
+
.map((page) => page.confidence)
|
|
37
|
+
.filter((confidence) => typeof confidence === 'number');
|
|
38
|
+
const confidence = pageConfidences.length
|
|
39
|
+
? pageConfidences.reduce((sum, value) => sum + value, 0) / pageConfidences.length
|
|
40
|
+
: undefined;
|
|
41
|
+
return {
|
|
42
|
+
text: pages.map((page) => page.text).join('\n\n').trim(),
|
|
43
|
+
confidence,
|
|
44
|
+
pages,
|
|
45
|
+
raw: response,
|
|
46
|
+
};
|
|
47
|
+
};
|
|
30
48
|
export const createMistralOcrEngine = (options = {}) => {
|
|
31
49
|
const transport = options.transport ??
|
|
32
50
|
createMistralOcrHttpTransport({
|
|
@@ -34,6 +52,13 @@ export const createMistralOcrEngine = (options = {}) => {
|
|
|
34
52
|
endpointUrl: options.endpointUrl,
|
|
35
53
|
});
|
|
36
54
|
const model = options.model ?? defaultMistralOcrModel;
|
|
55
|
+
const settingsOf = (recognizeOptions) => ({
|
|
56
|
+
include_image_base64: recognizeOptions.includeImageBase64 ?? options.includeImageBase64 ?? false,
|
|
57
|
+
table_format: recognizeOptions.tableFormat ?? options.tableFormat,
|
|
58
|
+
extract_header: recognizeOptions.extractHeader ?? options.extractHeader,
|
|
59
|
+
extract_footer: recognizeOptions.extractFooter ?? options.extractFooter,
|
|
60
|
+
confidence_scores_granularity: recognizeOptions.confidenceScoresGranularity ?? options.confidenceScoresGranularity,
|
|
61
|
+
});
|
|
37
62
|
return {
|
|
38
63
|
recognizeImage: async (input, recognizeOptions = {}) => {
|
|
39
64
|
if (!input.dataBase64) {
|
|
@@ -42,36 +67,34 @@ export const createMistralOcrEngine = (options = {}) => {
|
|
|
42
67
|
if (!input.mimeType) {
|
|
43
68
|
throw new Error('Mistral OCR image input requires mimeType.');
|
|
44
69
|
}
|
|
45
|
-
|
|
70
|
+
return toOcrResult(await transport.process({
|
|
46
71
|
model,
|
|
47
72
|
document: {
|
|
48
73
|
type: 'image_url',
|
|
49
74
|
image_url: `data:${input.mimeType};base64,${input.dataBase64}`,
|
|
50
75
|
},
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
76
|
+
...settingsOf(recognizeOptions),
|
|
77
|
+
}));
|
|
78
|
+
},
|
|
79
|
+
recognizeDocument: async (input, recognizeOptions = {}) => {
|
|
80
|
+
if (!transport.processDocument) {
|
|
81
|
+
throw new Error('This Mistral OCR transport reads images only: it has no processDocument, so it cannot read documents.');
|
|
82
|
+
}
|
|
83
|
+
if (!input.dataBase64) {
|
|
84
|
+
throw new Error('Mistral OCR document input requires dataBase64.');
|
|
85
|
+
}
|
|
86
|
+
if (!input.mimeType) {
|
|
87
|
+
throw new Error('Mistral OCR document input requires mimeType.');
|
|
88
|
+
}
|
|
89
|
+
return toOcrResult(await transport.processDocument({
|
|
90
|
+
model,
|
|
91
|
+
document: {
|
|
92
|
+
type: 'document_url',
|
|
93
|
+
document_url: `data:${input.mimeType};base64,${input.dataBase64}`,
|
|
94
|
+
},
|
|
95
|
+
...settingsOf(recognizeOptions),
|
|
61
96
|
}));
|
|
62
|
-
const pageConfidences = pages
|
|
63
|
-
.map((page) => page.confidence)
|
|
64
|
-
.filter((confidence) => typeof confidence === 'number');
|
|
65
|
-
const confidence = pageConfidences.length
|
|
66
|
-
? pageConfidences.reduce((sum, value) => sum + value, 0) / pageConfidences.length
|
|
67
|
-
: undefined;
|
|
68
|
-
return {
|
|
69
|
-
text: pages.map((page) => page.text).join('\n\n').trim(),
|
|
70
|
-
confidence,
|
|
71
|
-
pages,
|
|
72
|
-
raw: response,
|
|
73
|
-
};
|
|
74
97
|
},
|
|
75
98
|
};
|
|
76
99
|
};
|
|
77
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
100
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib2NyLm1pc3RyYWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19vY3Ivb2NyLm1pc3RyYWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBOEhBLE1BQU0sc0JBQXNCLEdBQUcsb0JBQW9CLENBQUM7QUFDcEQsTUFBTSw0QkFBNEIsR0FBRywrQkFBK0IsQ0FBQztBQUVyRSxNQUFNLDZCQUE2QixHQUFHLENBQUMsT0FHdEMsRUFBK0IsRUFBRTtJQUNoQyxNQUFNLElBQUksR0FBRyxLQUFLLEVBQUUsT0FBd0QsRUFBZ0MsRUFBRTtRQUM1RyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ3BCLE1BQU0sSUFBSSxLQUFLLENBQUMsc0VBQXNFLENBQUMsQ0FBQztRQUMxRixDQUFDO1FBRUQsTUFBTSxRQUFRLEdBQUcsTUFBTSxLQUFLLENBQUMsT0FBTyxDQUFDLFdBQVcsSUFBSSw0QkFBNEIsRUFBRTtZQUNoRixNQUFNLEVBQUUsTUFBTTtZQUNkLE9BQU8sRUFBRTtnQkFDUCxhQUFhLEVBQUUsVUFBVSxPQUFPLENBQUMsTUFBTSxFQUFFO2dCQUN6QyxjQUFjLEVBQUUsa0JBQWtCO2FBQ25DO1lBQ0QsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDO1NBQzlCLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDakIsTUFBTSxTQUFTLEdBQUcsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDeEMsTUFBTSxJQUFJLEtBQUssQ0FBQywwQ0FBMEMsUUFBUSxDQUFDLE1BQU0sS0FBSyxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBQzdGLENBQUM7UUFFRCxPQUFPLENBQUMsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQXdCLENBQUM7SUFDeEQsQ0FBQyxDQUFDO0lBQ0YsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsZUFBZSxFQUFFLElBQUks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
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"author": "Task Venture Capital GmbH",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"name": "@modelprofile.com/flexharness",
|
|
5
|
-
"version": "10.
|
|
5
|
+
"version": "10.19.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"description": "Managed agent sessions with tools, MCP, chat, OCR, documents and browser control through focused subpath imports.",
|
|
8
8
|
"main": "./dist_ts/index.js",
|
|
@@ -87,8 +87,8 @@
|
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
89
|
"@cfworker/json-schema": "^4.1.1",
|
|
90
|
-
"@modelprofile.com/flexharness-agent": "10.
|
|
91
|
-
"@modelprofile.com/flexharness-models": "10.
|
|
90
|
+
"@modelprofile.com/flexharness-agent": "10.19.0",
|
|
91
|
+
"@modelprofile.com/flexharness-models": "10.19.0",
|
|
92
92
|
"@push.rocks/smartrequest": "^5.5.1",
|
|
93
93
|
"ai": "^7.0.111",
|
|
94
94
|
"zod": "^4.6.5"
|
package/ts/00_commitinfo_data.ts
CHANGED
package/ts_ocr/ocr.mistral.ts
CHANGED
|
@@ -14,6 +14,18 @@ export interface ISmartAiOcrImageInput {
|
|
|
14
14
|
mimeType: TSmartAiOcrImageMimeType;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/** Mistral OCR reads PDF, PPTX, DOCX and other document formats. */
|
|
18
|
+
export type TSmartAiOcrDocumentMimeType =
|
|
19
|
+
| 'application/pdf'
|
|
20
|
+
| 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
|
|
21
|
+
| 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
|
22
|
+
| string;
|
|
23
|
+
|
|
24
|
+
export interface ISmartAiOcrDocumentInput {
|
|
25
|
+
dataBase64: string;
|
|
26
|
+
mimeType: TSmartAiOcrDocumentMimeType;
|
|
27
|
+
}
|
|
28
|
+
|
|
17
29
|
export interface ISmartAiOcrPageResult {
|
|
18
30
|
index: number;
|
|
19
31
|
text: string;
|
|
@@ -34,6 +46,14 @@ export interface ISmartAiOcrEngine {
|
|
|
34
46
|
) => Promise<ISmartAiOcrResult<IMistralOcrResponse>>;
|
|
35
47
|
}
|
|
36
48
|
|
|
49
|
+
/** The Mistral OCR engine also reads whole documents, such as a PDF with all its pages. */
|
|
50
|
+
export interface ISmartAiMistralOcrEngine extends ISmartAiOcrEngine {
|
|
51
|
+
recognizeDocument: (
|
|
52
|
+
input: ISmartAiOcrDocumentInput,
|
|
53
|
+
options?: ISmartAiMistralOcrRecognizeOptions
|
|
54
|
+
) => Promise<ISmartAiOcrResult<IMistralOcrResponse>>;
|
|
55
|
+
}
|
|
56
|
+
|
|
37
57
|
export interface IMistralOcrPageConfidenceScores {
|
|
38
58
|
average_page_confidence_score?: number;
|
|
39
59
|
averagePageConfidenceScore?: number;
|
|
@@ -70,8 +90,18 @@ export interface IMistralOcrRequest {
|
|
|
70
90
|
confidence_scores_granularity?: TSmartAiMistralOcrConfidenceScoresGranularity;
|
|
71
91
|
}
|
|
72
92
|
|
|
93
|
+
/** A document (PDF, PPTX, DOCX and other formats) as a URL or a base64 data URL; the other fields are those of an image request. */
|
|
94
|
+
export interface IMistralOcrDocumentRequest extends Omit<IMistralOcrRequest, 'document'> {
|
|
95
|
+
document: {
|
|
96
|
+
type: 'document_url';
|
|
97
|
+
document_url: string;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
73
101
|
export interface ISmartAiMistralOcrTransport {
|
|
74
102
|
process: (request: IMistralOcrRequest) => Promise<IMistralOcrResponse>;
|
|
103
|
+
/** Reads documents. A transport without it reads images only, and `recognizeDocument` refuses documents. */
|
|
104
|
+
processDocument?: (request: IMistralOcrDocumentRequest) => Promise<IMistralOcrResponse>;
|
|
75
105
|
}
|
|
76
106
|
|
|
77
107
|
export interface ISmartAiMistralOcrOptions {
|
|
@@ -101,29 +131,28 @@ const createMistralOcrHttpTransport = (options: {
|
|
|
101
131
|
apiKey?: string;
|
|
102
132
|
endpointUrl?: string;
|
|
103
133
|
}): ISmartAiMistralOcrTransport => {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
});
|
|
134
|
+
const post = async (request: IMistralOcrRequest | IMistralOcrDocumentRequest): Promise<IMistralOcrResponse> => {
|
|
135
|
+
if (!options.apiKey) {
|
|
136
|
+
throw new Error('Mistral OCR requires an apiKey when no custom transport is provided.');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const response = await fetch(options.endpointUrl ?? defaultMistralOcrEndpointUrl, {
|
|
140
|
+
method: 'POST',
|
|
141
|
+
headers: {
|
|
142
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
143
|
+
'Content-Type': 'application/json',
|
|
144
|
+
},
|
|
145
|
+
body: JSON.stringify(request),
|
|
146
|
+
});
|
|
118
147
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
148
|
+
if (!response.ok) {
|
|
149
|
+
const errorBody = await response.text();
|
|
150
|
+
throw new Error(`Mistral OCR request failed with status ${response.status}: ${errorBody}`);
|
|
151
|
+
}
|
|
123
152
|
|
|
124
|
-
|
|
125
|
-
},
|
|
153
|
+
return (await response.json()) as IMistralOcrResponse;
|
|
126
154
|
};
|
|
155
|
+
return { process: post, processDocument: post };
|
|
127
156
|
};
|
|
128
157
|
|
|
129
158
|
const getPageConfidence = (page: IMistralOcrPageResponse): number | undefined => {
|
|
@@ -134,9 +163,30 @@ const getPageConfidence = (page: IMistralOcrPageResponse): number | undefined =>
|
|
|
134
163
|
);
|
|
135
164
|
};
|
|
136
165
|
|
|
166
|
+
const toOcrResult = (response: IMistralOcrResponse): ISmartAiOcrResult<IMistralOcrResponse> => {
|
|
167
|
+
const pages = response.pages.map((page) => ({
|
|
168
|
+
index: page.index,
|
|
169
|
+
text: page.markdown,
|
|
170
|
+
confidence: getPageConfidence(page),
|
|
171
|
+
}));
|
|
172
|
+
const pageConfidences = pages
|
|
173
|
+
.map((page) => page.confidence)
|
|
174
|
+
.filter((confidence): confidence is number => typeof confidence === 'number');
|
|
175
|
+
const confidence = pageConfidences.length
|
|
176
|
+
? pageConfidences.reduce((sum, value) => sum + value, 0) / pageConfidences.length
|
|
177
|
+
: undefined;
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
text: pages.map((page) => page.text).join('\n\n').trim(),
|
|
181
|
+
confidence,
|
|
182
|
+
pages,
|
|
183
|
+
raw: response,
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
|
|
137
187
|
export const createMistralOcrEngine = (
|
|
138
188
|
options: ISmartAiMistralOcrOptions = {}
|
|
139
|
-
):
|
|
189
|
+
): ISmartAiMistralOcrEngine => {
|
|
140
190
|
const transport =
|
|
141
191
|
options.transport ??
|
|
142
192
|
createMistralOcrHttpTransport({
|
|
@@ -145,6 +195,16 @@ export const createMistralOcrEngine = (
|
|
|
145
195
|
});
|
|
146
196
|
const model = options.model ?? defaultMistralOcrModel;
|
|
147
197
|
|
|
198
|
+
const settingsOf = (recognizeOptions: ISmartAiMistralOcrRecognizeOptions) => ({
|
|
199
|
+
include_image_base64:
|
|
200
|
+
recognizeOptions.includeImageBase64 ?? options.includeImageBase64 ?? false,
|
|
201
|
+
table_format: recognizeOptions.tableFormat ?? options.tableFormat,
|
|
202
|
+
extract_header: recognizeOptions.extractHeader ?? options.extractHeader,
|
|
203
|
+
extract_footer: recognizeOptions.extractFooter ?? options.extractFooter,
|
|
204
|
+
confidence_scores_granularity:
|
|
205
|
+
recognizeOptions.confidenceScoresGranularity ?? options.confidenceScoresGranularity,
|
|
206
|
+
});
|
|
207
|
+
|
|
148
208
|
return {
|
|
149
209
|
recognizeImage: async (input, recognizeOptions = {}) => {
|
|
150
210
|
if (!input.dataBase64) {
|
|
@@ -153,40 +213,33 @@ export const createMistralOcrEngine = (
|
|
|
153
213
|
if (!input.mimeType) {
|
|
154
214
|
throw new Error('Mistral OCR image input requires mimeType.');
|
|
155
215
|
}
|
|
156
|
-
|
|
157
|
-
const response = await transport.process({
|
|
216
|
+
return toOcrResult(await transport.process({
|
|
158
217
|
model,
|
|
159
218
|
document: {
|
|
160
219
|
type: 'image_url',
|
|
161
220
|
image_url: `data:${input.mimeType};base64,${input.dataBase64}`,
|
|
162
221
|
},
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
222
|
+
...settingsOf(recognizeOptions),
|
|
223
|
+
}));
|
|
224
|
+
},
|
|
225
|
+
recognizeDocument: async (input, recognizeOptions = {}) => {
|
|
226
|
+
if (!transport.processDocument) {
|
|
227
|
+
throw new Error('This Mistral OCR transport reads images only: it has no processDocument, so it cannot read documents.');
|
|
228
|
+
}
|
|
229
|
+
if (!input.dataBase64) {
|
|
230
|
+
throw new Error('Mistral OCR document input requires dataBase64.');
|
|
231
|
+
}
|
|
232
|
+
if (!input.mimeType) {
|
|
233
|
+
throw new Error('Mistral OCR document input requires mimeType.');
|
|
234
|
+
}
|
|
235
|
+
return toOcrResult(await transport.processDocument({
|
|
236
|
+
model,
|
|
237
|
+
document: {
|
|
238
|
+
type: 'document_url',
|
|
239
|
+
document_url: `data:${input.mimeType};base64,${input.dataBase64}`,
|
|
240
|
+
},
|
|
241
|
+
...settingsOf(recognizeOptions),
|
|
176
242
|
}));
|
|
177
|
-
const pageConfidences = pages
|
|
178
|
-
.map((page) => page.confidence)
|
|
179
|
-
.filter((confidence): confidence is number => typeof confidence === 'number');
|
|
180
|
-
const confidence = pageConfidences.length
|
|
181
|
-
? pageConfidences.reduce((sum, value) => sum + value, 0) / pageConfidences.length
|
|
182
|
-
: undefined;
|
|
183
|
-
|
|
184
|
-
return {
|
|
185
|
-
text: pages.map((page) => page.text).join('\n\n').trim(),
|
|
186
|
-
confidence,
|
|
187
|
-
pages,
|
|
188
|
-
raw: response,
|
|
189
|
-
};
|
|
190
243
|
},
|
|
191
244
|
};
|
|
192
245
|
};
|
package/ts_ocr/readme.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Image OCR with Mistral or an injected recognition engine. This subpath imports no runtime dependencies and works with Node buffers and browser byte arrays.
|
|
1
|
+
Image OCR with Mistral or an injected recognition engine, and document OCR with Mistral. This subpath imports no runtime dependencies and works with Node buffers and browser byte arrays.
|
|
2
2
|
|
|
3
3
|
Part of the [FlexHarness toolbox](https://code.foss.global/modelprofile.com/flexharness).
|
|
4
4
|
Install the components your project uses. Provider adapters are registered explicitly;
|
|
@@ -20,6 +20,17 @@ console.log(result.text);
|
|
|
20
20
|
|
|
21
21
|
Constructor and call options accept `engine` or `mistralOptions`. A per-call engine takes precedence over the constructor engine. Otherwise Mistral settings merge, with per-call settings taking precedence. `recognizeOptions` controls each request. `recognizeImage` accepts an existing `{ dataBase64, mimeType }` image; `createMistralOcrEngine` remains available for lower-level integrations.
|
|
22
22
|
|
|
23
|
+
`createMistralOcrEngine()` also reads whole documents: `recognizeDocument({ dataBase64, mimeType: 'application/pdf' })` sends the document as a `document_url` data URL, as Mistral's OCR API takes PDF, PPTX, DOCX and other document formats, and returns every page. Mistral accepts documents of up to 50 MB and 1,000 pages.
|
|
24
|
+
|
|
25
|
+
A custom `transport` receives image requests (`IMistralOcrRequest`) through `process`, as before. It reads documents only when it also implements the optional `processDocument`, which receives an `IMistralOcrDocumentRequest`, whose `document` is a `document_url`; for a transport without it, `recognizeDocument` fails with "This Mistral OCR transport reads images only". The built-in transport implements both.
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { createMistralOcrEngine } from '@modelprofile.com/flexharness/ocr';
|
|
29
|
+
|
|
30
|
+
const engine = createMistralOcrEngine({ apiKey: process.env.MISTRAL_API_KEY });
|
|
31
|
+
const { text, pages } = await engine.recognizeDocument({ dataBase64: pdfBase64, mimeType: 'application/pdf' });
|
|
32
|
+
```
|
|
33
|
+
|
|
23
34
|
Model-based PDF text extraction lives in `@modelprofile.com/flexharness/documents`. Native `ocrmypdf` processing remains in `@push.rocks/smartocr`.
|
|
24
35
|
|
|
25
36
|
## Issue Reporting and Security
|