@vertesia/workflow 0.52.0 → 0.55.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/lib/cjs/activities/createDocumentFromOther.js +1 -1
- package/lib/cjs/activities/executeInteraction.js +29 -15
- package/lib/cjs/activities/executeInteraction.js.map +1 -1
- package/lib/cjs/activities/extractDocumentText.js +33 -30
- package/lib/cjs/activities/extractDocumentText.js.map +1 -1
- package/lib/cjs/activities/generateEmbeddings.js +1 -1
- package/lib/cjs/activities/generateEmbeddings.js.map +1 -1
- package/lib/cjs/activities/generateImageRendition.js +31 -11
- package/lib/cjs/activities/generateImageRendition.js.map +1 -1
- package/lib/cjs/activities/generateOrAssignContentType.js +25 -12
- package/lib/cjs/activities/generateOrAssignContentType.js.map +1 -1
- package/lib/cjs/activities/getObjectFromStore.js +1 -1
- package/lib/cjs/activities/handleError.js +22 -0
- package/lib/cjs/activities/handleError.js.map +1 -0
- package/lib/cjs/activities/index-dsl.js +3 -1
- package/lib/cjs/activities/index-dsl.js.map +1 -1
- package/lib/cjs/activities/index.js +0 -1
- package/lib/cjs/activities/index.js.map +1 -1
- package/lib/cjs/activities/media/processPdfWithTextract.js +4 -4
- package/lib/cjs/activities/media/transcribeMediaWithGladia.js +1 -1
- package/lib/cjs/activities/media/transcribeMediaWithGladia.js.map +1 -1
- package/lib/cjs/activities/setDocumentStatus.js +1 -1
- package/lib/cjs/conversion/TextractProcessor.js +9 -9
- package/lib/cjs/conversion/image.js +6 -2
- package/lib/cjs/conversion/image.js.map +1 -1
- package/lib/cjs/conversion/markitdown.js +42 -0
- package/lib/cjs/conversion/markitdown.js.map +1 -0
- package/lib/cjs/conversion/mutool.js +1 -1
- package/lib/cjs/conversion/pandoc.js +9 -9
- package/lib/cjs/conversion/pandoc.js.map +1 -1
- package/lib/cjs/dsl/dsl-workflow.js +59 -11
- package/lib/cjs/dsl/dsl-workflow.js.map +1 -1
- package/lib/cjs/dsl/vars.js +6 -6
- package/lib/cjs/dsl/vars.js.map +1 -1
- package/lib/cjs/index.js +1 -1
- package/lib/cjs/iterative-generation/activities/extractToc.js +1 -1
- package/lib/cjs/iterative-generation/activities/extractToc.js.map +1 -1
- package/lib/cjs/iterative-generation/activities/generatePart.js +2 -2
- package/lib/cjs/iterative-generation/activities/generatePart.js.map +1 -1
- package/lib/cjs/iterative-generation/activities/generateToc.js +1 -1
- package/lib/cjs/iterative-generation/activities/generateToc.js.map +1 -1
- package/lib/cjs/iterative-generation/iterativeGenerationWorkflow.js +1 -1
- package/lib/cjs/iterative-generation/iterativeGenerationWorkflow.js.map +1 -1
- package/lib/cjs/iterative-generation/utils.js +4 -4
- package/lib/cjs/iterative-generation/utils.js.map +1 -1
- package/lib/esm/activities/createDocumentFromOther.js +1 -1
- package/lib/esm/activities/executeInteraction.js +31 -17
- package/lib/esm/activities/executeInteraction.js.map +1 -1
- package/lib/esm/activities/extractDocumentText.js +39 -36
- package/lib/esm/activities/extractDocumentText.js.map +1 -1
- package/lib/esm/activities/generateEmbeddings.js +1 -1
- package/lib/esm/activities/generateEmbeddings.js.map +1 -1
- package/lib/esm/activities/generateImageRendition.js +31 -11
- package/lib/esm/activities/generateImageRendition.js.map +1 -1
- package/lib/esm/activities/generateOrAssignContentType.js +25 -12
- package/lib/esm/activities/generateOrAssignContentType.js.map +1 -1
- package/lib/esm/activities/getObjectFromStore.js +1 -1
- package/lib/esm/activities/handleError.js +19 -0
- package/lib/esm/activities/handleError.js.map +1 -0
- package/lib/esm/activities/index-dsl.js +1 -0
- package/lib/esm/activities/index-dsl.js.map +1 -1
- package/lib/esm/activities/index.js +0 -1
- package/lib/esm/activities/index.js.map +1 -1
- package/lib/esm/activities/media/processPdfWithTextract.js +4 -4
- package/lib/esm/activities/media/transcribeMediaWithGladia.js +1 -1
- package/lib/esm/activities/media/transcribeMediaWithGladia.js.map +1 -1
- package/lib/esm/activities/setDocumentStatus.js +1 -1
- package/lib/esm/conversion/TextractProcessor.js +9 -9
- package/lib/esm/conversion/image.js +6 -2
- package/lib/esm/conversion/image.js.map +1 -1
- package/lib/esm/conversion/markitdown.js +36 -0
- package/lib/esm/conversion/markitdown.js.map +1 -0
- package/lib/esm/conversion/mutool.js +1 -1
- package/lib/esm/conversion/pandoc.js +11 -11
- package/lib/esm/conversion/pandoc.js.map +1 -1
- package/lib/esm/dsl/dsl-workflow.js +60 -12
- package/lib/esm/dsl/dsl-workflow.js.map +1 -1
- package/lib/esm/dsl/vars.js +6 -6
- package/lib/esm/dsl/vars.js.map +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/iterative-generation/activities/extractToc.js +1 -1
- package/lib/esm/iterative-generation/activities/extractToc.js.map +1 -1
- package/lib/esm/iterative-generation/activities/generatePart.js +2 -2
- package/lib/esm/iterative-generation/activities/generatePart.js.map +1 -1
- package/lib/esm/iterative-generation/activities/generateToc.js +1 -1
- package/lib/esm/iterative-generation/activities/generateToc.js.map +1 -1
- package/lib/esm/iterative-generation/iterativeGenerationWorkflow.js +1 -1
- package/lib/esm/iterative-generation/iterativeGenerationWorkflow.js.map +1 -1
- package/lib/esm/iterative-generation/utils.js +4 -4
- package/lib/esm/iterative-generation/utils.js.map +1 -1
- package/lib/types/activities/createDocumentFromOther.d.ts +1 -1
- package/lib/types/activities/executeInteraction.d.ts +4 -4
- package/lib/types/activities/executeInteraction.d.ts.map +1 -1
- package/lib/types/activities/extractDocumentText.d.ts +3 -3
- package/lib/types/activities/extractDocumentText.d.ts.map +1 -1
- package/lib/types/activities/generateImageRendition.d.ts +1 -1
- package/lib/types/activities/generateImageRendition.d.ts.map +1 -1
- package/lib/types/activities/generateOrAssignContentType.d.ts +1 -1
- package/lib/types/activities/generateOrAssignContentType.d.ts.map +1 -1
- package/lib/types/activities/getObjectFromStore.d.ts +1 -1
- package/lib/types/activities/handleError.d.ts +6 -0
- package/lib/types/activities/handleError.d.ts.map +1 -0
- package/lib/types/activities/index-dsl.d.ts +1 -0
- package/lib/types/activities/index-dsl.d.ts.map +1 -1
- package/lib/types/activities/index.d.ts +0 -1
- package/lib/types/activities/index.d.ts.map +1 -1
- package/lib/types/activities/setDocumentStatus.d.ts +1 -1
- package/lib/types/conversion/image.d.ts.map +1 -1
- package/lib/types/conversion/markitdown.d.ts +2 -0
- package/lib/types/conversion/markitdown.d.ts.map +1 -0
- package/lib/types/conversion/mutool.d.ts +1 -1
- package/lib/types/conversion/pandoc.d.ts +1 -1
- package/lib/types/conversion/pandoc.d.ts.map +1 -1
- package/lib/types/dsl/dsl-workflow.d.ts +1 -1
- package/lib/types/dsl/dsl-workflow.d.ts.map +1 -1
- package/lib/types/dsl/vars.d.ts +2 -2
- package/lib/types/index.d.ts +1 -1
- package/lib/types/iterative-generation/types.d.ts +3 -3
- package/lib/types/iterative-generation/types.d.ts.map +1 -1
- package/lib/workflows-bundle.js +396 -94
- package/package.json +5 -4
- package/src/activities/createDocumentFromOther.ts +1 -1
- package/src/activities/executeInteraction.ts +66 -39
- package/src/activities/extractDocumentText.ts +67 -51
- package/src/activities/generateEmbeddings.ts +1 -1
- package/src/activities/generateImageRendition.ts +35 -14
- package/src/activities/generateOrAssignContentType.ts +52 -26
- package/src/activities/getObjectFromStore.ts +1 -1
- package/src/activities/handleError.ts +25 -0
- package/src/activities/index-dsl.ts +1 -0
- package/src/activities/index.ts +0 -1
- package/src/activities/media/processPdfWithTextract.ts +4 -4
- package/src/activities/media/transcribeMediaWithGladia.ts +1 -1
- package/src/activities/setDocumentStatus.ts +1 -1
- package/src/conversion/TextractProcessor.ts +9 -9
- package/src/conversion/image.ts +8 -2
- package/src/conversion/markitdown.ts +41 -0
- package/src/conversion/mutool.ts +1 -1
- package/src/conversion/pandoc.test.ts +2 -2
- package/src/conversion/pandoc.ts +38 -42
- package/src/dsl/dsl-workflow.ts +80 -12
- package/src/dsl/validation.test.ts +2 -2
- package/src/dsl/vars.test.ts +1 -1
- package/src/dsl/vars.ts +6 -6
- package/src/dsl/workflow-exec-child.test.ts +14 -4
- package/src/dsl/workflow-fetch.test.ts +1 -1
- package/src/dsl/workflow-import.test.ts +1 -1
- package/src/dsl/workflow.test.ts +12 -2
- package/src/index.ts +1 -1
- package/src/iterative-generation/activities/extractToc.ts +1 -1
- package/src/iterative-generation/activities/generatePart.ts +2 -2
- package/src/iterative-generation/activities/generateToc.ts +1 -1
- package/src/iterative-generation/iterativeGenerationWorkflow.ts +1 -1
- package/src/iterative-generation/types.ts +4 -4
- package/src/iterative-generation/utils.ts +4 -4
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vertesia/workflow",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.55.0",
|
4
4
|
"type": "module",
|
5
5
|
"description": "Composable prompts workflow dsl",
|
6
6
|
"main": "./lib/esm/index.js",
|
@@ -19,6 +19,7 @@
|
|
19
19
|
"license": "Apache-2.0",
|
20
20
|
"devDependencies": {
|
21
21
|
"@smithy/types": "^3.7.2",
|
22
|
+
"@temporalio/proto": "^1.11.5",
|
22
23
|
"@temporalio/testing": "^1.11.5",
|
23
24
|
"@temporalio/worker": "^1.11.5",
|
24
25
|
"@types/fluent-ffmpeg": "^2.1.27",
|
@@ -50,9 +51,9 @@
|
|
50
51
|
"tmp": "^0.2.3",
|
51
52
|
"tmp-promise": "^3.0.3",
|
52
53
|
"yaml": "^2.6.0",
|
53
|
-
"@
|
54
|
-
"@vertesia/
|
55
|
-
"@
|
54
|
+
"@llumiverse/core": "0.17.0",
|
55
|
+
"@vertesia/common": "0.55.0",
|
56
|
+
"@vertesia/client": "0.55.0"
|
56
57
|
},
|
57
58
|
"ts_dual_module": {
|
58
59
|
"outDir": "lib",
|
@@ -24,7 +24,7 @@ export interface CreatePdfDocumentFromSource extends DSLActivitySpec<CreatePdfDo
|
|
24
24
|
|
25
25
|
|
26
26
|
/**
|
27
|
-
* Create a new PDF by
|
27
|
+
* Create a new PDF by extracting pages from a source PDF
|
28
28
|
* @returns
|
29
29
|
*/
|
30
30
|
export async function createPdfDocumentFromSource(payload: DSLActivityExecutionPayload<CreatePdfDocumentFromSourceParams>) {
|
@@ -1,16 +1,23 @@
|
|
1
1
|
import { ModelOptions } from "@llumiverse/core";
|
2
2
|
import { activityInfo, log } from "@temporalio/activity";
|
3
3
|
import { VertesiaClient } from "@vertesia/client";
|
4
|
-
import {
|
4
|
+
import {
|
5
|
+
DSLActivityExecutionPayload,
|
6
|
+
DSLActivitySpec,
|
7
|
+
ExecutionRun,
|
8
|
+
ExecutionRunStatus,
|
9
|
+
InteractionExecutionConfiguration,
|
10
|
+
RunSearchPayload,
|
11
|
+
} from "@vertesia/common";
|
5
12
|
import { projectResult } from "../dsl/projections.js";
|
6
13
|
import { setupActivity } from "../dsl/setup/ActivityContext.js";
|
7
|
-
import { ActivityParamNotFound } from "../errors.js";
|
14
|
+
import { ActivityParamInvalid, ActivityParamNotFound } from "../errors.js";
|
8
15
|
import { TruncateSpec, truncByMaxTokens } from "../utils/tokens.js";
|
9
16
|
|
10
17
|
//Example:
|
11
18
|
//@ts-ignore
|
12
19
|
const JSON: DSLActivitySpec = {
|
13
|
-
name:
|
20
|
+
name: "executeInteraction",
|
14
21
|
import: ["defaultModel", "guidlineId", "docTypeId"],
|
15
22
|
params: {
|
16
23
|
defaultModel: "${model}",
|
@@ -23,8 +30,8 @@ const JSON: DSLActivitySpec = {
|
|
23
30
|
result_schema: "${docType.object_schema}",
|
24
31
|
prompt_data: {
|
25
32
|
documents: "${documents}",
|
26
|
-
guidline: "${guidline.text}"
|
27
|
-
}
|
33
|
+
guidline: "${guidline.text}",
|
34
|
+
},
|
28
35
|
},
|
29
36
|
fetch: {
|
30
37
|
documents: {
|
@@ -41,7 +48,7 @@ const JSON: DSLActivitySpec = {
|
|
41
48
|
id: "${guidlineId}",
|
42
49
|
},
|
43
50
|
select: "+text",
|
44
|
-
on_not_found: "throw"
|
51
|
+
on_not_found: "throw",
|
45
52
|
},
|
46
53
|
docType: {
|
47
54
|
type: "document_type",
|
@@ -50,19 +57,19 @@ const JSON: DSLActivitySpec = {
|
|
50
57
|
id: "${docTypeId}",
|
51
58
|
},
|
52
59
|
select: "+object_schema",
|
53
|
-
}
|
54
|
-
}
|
55
|
-
}
|
60
|
+
},
|
61
|
+
},
|
62
|
+
};
|
56
63
|
export interface InteractionExecutionParams {
|
57
64
|
/**
|
58
65
|
* The environment to use. If not specified the project default environment will be used.
|
59
|
-
* If the latter is not specified an
|
66
|
+
* If the latter is not specified an exception will be thrown.
|
60
67
|
*/
|
61
68
|
environment?: string;
|
62
69
|
/**
|
63
70
|
* The model to use. If not specified the project default model will be used.
|
64
71
|
* If the latter is not specified the default model of the environment will be used.
|
65
|
-
* If the latter is not specified an
|
72
|
+
* If the latter is not specified an exception will be thrown.
|
66
73
|
*/
|
67
74
|
model?: string;
|
68
75
|
|
@@ -90,7 +97,7 @@ export interface InteractionExecutionParams {
|
|
90
97
|
/**
|
91
98
|
* TODO: must be kept in sync with InteractionAsyncExecutionPayload form @vertesia/common
|
92
99
|
* Also see the executeInteractionAsync endpoint on the server for how the client payload is sent to the workflow.
|
93
|
-
* (interaction is
|
100
|
+
* (interaction is translated to interactionName)
|
94
101
|
*/
|
95
102
|
export interface ExecuteInteractionParams extends InteractionExecutionParams {
|
96
103
|
//TODO rename to interaction as in InteractionAsyncExecutionPayload
|
@@ -106,13 +113,11 @@ export interface ExecuteInteractionParams extends InteractionExecutionParams {
|
|
106
113
|
}
|
107
114
|
|
108
115
|
export interface ExecuteInteraction extends DSLActivitySpec<ExecuteInteractionParams> {
|
109
|
-
name:
|
116
|
+
name: "executeInteraction";
|
110
117
|
}
|
111
118
|
|
112
119
|
export async function executeInteraction(payload: DSLActivityExecutionPayload<ExecuteInteractionParams>) {
|
113
|
-
const {
|
114
|
-
client, params
|
115
|
-
} = await setupActivity<ExecuteInteractionParams>(payload);
|
120
|
+
const { client, params } = await setupActivity<ExecuteInteractionParams>(payload);
|
116
121
|
|
117
122
|
const { interactionName, prompt_data, static_prompt_data: wf_prompt_data } = params;
|
118
123
|
if (wf_prompt_data) {
|
@@ -131,17 +136,37 @@ export async function executeInteraction(payload: DSLActivityExecutionPayload<Ex
|
|
131
136
|
}
|
132
137
|
}
|
133
138
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
139
|
+
try {
|
140
|
+
const res = await executeInteractionFromActivity(
|
141
|
+
client,
|
142
|
+
interactionName,
|
143
|
+
params,
|
144
|
+
prompt_data,
|
145
|
+
payload.debug_mode,
|
146
|
+
);
|
147
|
+
return projectResult(payload, params, res, {
|
148
|
+
runId: res.id,
|
149
|
+
status: res.status,
|
150
|
+
result: res.result,
|
151
|
+
});
|
152
|
+
} catch (error: any) {
|
153
|
+
log.error("Failed to execute interaction", { error });
|
154
|
+
if (error.message.includes("Failed to validate merged prompt schema")) {
|
155
|
+
//issue with the input data, don't retry
|
156
|
+
throw new ActivityParamInvalid("prompt_data", payload.activity, error.message);
|
157
|
+
} else {
|
158
|
+
throw error;
|
159
|
+
}
|
160
|
+
}
|
142
161
|
}
|
143
162
|
|
144
|
-
export async function executeInteractionFromActivity(
|
163
|
+
export async function executeInteractionFromActivity(
|
164
|
+
client: VertesiaClient,
|
165
|
+
interactionName: string,
|
166
|
+
params: InteractionExecutionParams,
|
167
|
+
prompt_data: any,
|
168
|
+
debug?: boolean,
|
169
|
+
) {
|
145
170
|
const userTags = params.tags;
|
146
171
|
const info = activityInfo();
|
147
172
|
const runId = info.workflowExecution.runId;
|
@@ -161,7 +186,7 @@ export async function executeInteractionFromActivity(client: VertesiaClient, int
|
|
161
186
|
};
|
162
187
|
const previousRun = await client.runs.search(payload).then((res) => {
|
163
188
|
log.info("Search results", { results: res });
|
164
|
-
return res ? res[0] ?? undefined : undefined
|
189
|
+
return res ? (res[0] ?? undefined) : undefined;
|
165
190
|
});
|
166
191
|
|
167
192
|
if (previousRun) {
|
@@ -178,26 +203,28 @@ export async function executeInteractionFromActivity(client: VertesiaClient, int
|
|
178
203
|
environment: params.environment,
|
179
204
|
model: params.model,
|
180
205
|
model_options: params.model_options,
|
181
|
-
}
|
206
|
+
};
|
182
207
|
const data = {
|
183
208
|
...prompt_data,
|
184
209
|
previous_error: previousStudioExecutionRun?.error,
|
185
|
-
}
|
210
|
+
};
|
186
211
|
|
187
212
|
const result_schema = params.result_schema;
|
188
213
|
|
189
214
|
log.debug(`About to execute interaction ${interactionName}`, { config, data, result_schema, tags });
|
190
215
|
|
191
|
-
const res = await client.interactions
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
216
|
+
const res = await client.interactions
|
217
|
+
.executeByName(interactionName, {
|
218
|
+
config,
|
219
|
+
data,
|
220
|
+
result_schema,
|
221
|
+
tags,
|
222
|
+
stream: false,
|
223
|
+
})
|
224
|
+
.catch((err) => {
|
225
|
+
log.error(`Error executing interaction ${interactionName}`, { err });
|
226
|
+
throw new Error(`Interaction Execution failed ${interactionName}: ${err.message}`);
|
227
|
+
});
|
201
228
|
|
202
229
|
if (debug) {
|
203
230
|
log.info(`Interaction executed ${interactionName}`, res);
|
@@ -209,4 +236,4 @@ export async function executeInteractionFromActivity(client: VertesiaClient, int
|
|
209
236
|
}
|
210
237
|
|
211
238
|
return res;
|
212
|
-
}
|
239
|
+
}
|
@@ -1,33 +1,41 @@
|
|
1
1
|
import { log } from "@temporalio/activity";
|
2
|
-
import {
|
3
|
-
|
4
|
-
|
2
|
+
import {
|
3
|
+
ContentObject,
|
4
|
+
CreateContentObjectPayload,
|
5
|
+
DSLActivityExecutionPayload,
|
6
|
+
DSLActivitySpec,
|
7
|
+
} from "@vertesia/common";
|
8
|
+
import { mutoolPdfToText } from "../conversion/mutool.js";
|
9
|
+
import { markdownWithPandoc } from "../conversion/pandoc.js";
|
5
10
|
import { setupActivity } from "../dsl/setup/ActivityContext.js";
|
6
|
-
import { NoDocumentFound } from
|
7
|
-
import { TextExtractionResult, TextExtractionStatus } from
|
8
|
-
import { fetchBlobAsBuffer, md5 } from
|
9
|
-
import { countTokens } from
|
11
|
+
import { NoDocumentFound } from "../errors.js";
|
12
|
+
import { TextExtractionResult, TextExtractionStatus } from "../result-types.js";
|
13
|
+
import { fetchBlobAsBuffer, md5 } from "../utils/blobs.js";
|
14
|
+
import { countTokens } from "../utils/tokens.js";
|
15
|
+
import { markdownWithMarkitdown } from "../conversion/markitdown.js";
|
10
16
|
|
11
17
|
//@ts-ignore
|
12
18
|
const JSON: DSLActivitySpec = {
|
13
|
-
name:
|
14
|
-
}
|
19
|
+
name: "extractDocumentText",
|
20
|
+
};
|
15
21
|
|
16
22
|
// doesn't have any own param
|
17
|
-
export interface ExtractDocumentTextParams {
|
23
|
+
export interface ExtractDocumentTextParams {}
|
18
24
|
export interface ExtractDocumentText extends DSLActivitySpec<ExtractDocumentTextParams> {
|
19
|
-
name:
|
25
|
+
name: "extractDocumentText";
|
20
26
|
projection?: never;
|
21
27
|
}
|
22
28
|
|
23
|
-
export async function extractDocumentText(
|
29
|
+
export async function extractDocumentText(
|
30
|
+
payload: DSLActivityExecutionPayload<ExtractDocumentTextParams>,
|
31
|
+
): Promise<TextExtractionResult> {
|
24
32
|
const { client, objectId } = await setupActivity(payload);
|
25
33
|
|
26
34
|
const r = await client.objects.find({
|
27
35
|
query: { _id: objectId },
|
28
36
|
limit: 1,
|
29
|
-
select: "+text"
|
30
|
-
})
|
37
|
+
select: "+text",
|
38
|
+
});
|
31
39
|
const doc = r[0] as ContentObject;
|
32
40
|
if (!doc) {
|
33
41
|
log.error(`Document ${objectId} not found`);
|
@@ -36,7 +44,6 @@ export async function extractDocumentText(payload: DSLActivityExecutionPayload<E
|
|
36
44
|
|
37
45
|
log.info(`Extracting text for object ${doc.id}`);
|
38
46
|
|
39
|
-
|
40
47
|
if (!doc.content?.type || !doc.content?.source) {
|
41
48
|
if (doc.text) {
|
42
49
|
return createResponse(doc, doc.text, TextExtractionStatus.skipped, "Text present and no source or type");
|
@@ -58,74 +65,80 @@ export async function extractDocumentText(payload: DSLActivityExecutionPayload<E
|
|
58
65
|
return createResponse(doc, "", TextExtractionStatus.error, e.message);
|
59
66
|
}
|
60
67
|
|
61
|
-
|
62
68
|
let txt: string;
|
63
69
|
|
64
70
|
switch (doc.content.type) {
|
65
|
-
|
66
|
-
case 'application/pdf':
|
67
|
-
//if pdf is more than 2MB, use mutool
|
71
|
+
case "application/pdf":
|
68
72
|
txt = await mutoolPdfToText(fileBuffer);
|
69
73
|
break;
|
70
74
|
|
71
|
-
case
|
72
|
-
txt = fileBuffer.toString(
|
75
|
+
case "text/plain":
|
76
|
+
txt = fileBuffer.toString("utf8");
|
73
77
|
break;
|
74
78
|
|
75
79
|
//docx
|
76
|
-
case
|
77
|
-
txt = await
|
80
|
+
case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
|
81
|
+
txt = await markdownWithMarkitdown(fileBuffer, "docx");
|
82
|
+
break;
|
83
|
+
|
84
|
+
//pptx
|
85
|
+
case "application/vnd.openxmlformats-officedocument.presentationml.presentation":
|
86
|
+
txt = await markdownWithMarkitdown(fileBuffer, "pptx");
|
78
87
|
break;
|
79
88
|
|
80
89
|
//html
|
81
|
-
case
|
82
|
-
txt = await
|
90
|
+
case "text/html":
|
91
|
+
txt = await markdownWithPandoc(fileBuffer, "html");
|
83
92
|
break;
|
84
93
|
|
85
94
|
//opendocument
|
86
|
-
case
|
87
|
-
txt = await
|
95
|
+
case "application/vnd.oasis.opendocument.text":
|
96
|
+
txt = await markdownWithPandoc(fileBuffer, "odt");
|
88
97
|
break;
|
89
98
|
|
90
99
|
//rtf
|
91
|
-
case
|
92
|
-
txt = await
|
100
|
+
case "application/rtf":
|
101
|
+
txt = await markdownWithPandoc(fileBuffer, "rtf");
|
93
102
|
break;
|
94
103
|
|
95
104
|
//markdown
|
96
|
-
case
|
97
|
-
txt = fileBuffer.toString(
|
105
|
+
case "text/markdown":
|
106
|
+
txt = fileBuffer.toString("utf8");
|
98
107
|
break;
|
99
108
|
|
100
109
|
//csv
|
101
|
-
case
|
102
|
-
txt = fileBuffer.toString(
|
110
|
+
case "text/csv":
|
111
|
+
txt = fileBuffer.toString("utf8");
|
103
112
|
break;
|
104
113
|
|
105
114
|
//typescript
|
106
|
-
case
|
107
|
-
txt = fileBuffer.toString(
|
115
|
+
case "application/typescript":
|
116
|
+
txt = fileBuffer.toString("utf8");
|
108
117
|
break;
|
109
118
|
|
110
119
|
//javascript
|
111
|
-
case
|
112
|
-
txt = fileBuffer.toString(
|
120
|
+
case "application/javascript":
|
121
|
+
txt = fileBuffer.toString("utf8");
|
113
122
|
break;
|
114
123
|
|
115
124
|
//json
|
116
|
-
case
|
117
|
-
txt = fileBuffer.toString(
|
125
|
+
case "application/json":
|
126
|
+
txt = fileBuffer.toString("utf8");
|
118
127
|
break;
|
119
128
|
|
120
129
|
default:
|
121
130
|
if (sniffIfText(fileBuffer)) {
|
122
|
-
txt = fileBuffer.toString(
|
131
|
+
txt = fileBuffer.toString("utf8"); //TODO: add charset detection
|
123
132
|
break;
|
124
133
|
}
|
125
|
-
return createResponse(
|
134
|
+
return createResponse(
|
135
|
+
doc,
|
136
|
+
doc.text ?? "",
|
137
|
+
TextExtractionStatus.skipped,
|
138
|
+
`Unsupported mime type: ${doc.content.type}`,
|
139
|
+
);
|
126
140
|
}
|
127
141
|
|
128
|
-
|
129
142
|
const tokensData = countTokens(txt);
|
130
143
|
const etag = doc.content.etag ?? md5(txt);
|
131
144
|
|
@@ -135,15 +148,20 @@ export async function extractDocumentText(payload: DSLActivityExecutionPayload<E
|
|
135
148
|
tokens: {
|
136
149
|
...tokensData,
|
137
150
|
etag: etag,
|
138
|
-
}
|
139
|
-
}
|
151
|
+
},
|
152
|
+
};
|
140
153
|
|
141
154
|
await client.objects.update(doc.id, updateData);
|
142
155
|
|
143
156
|
return createResponse(doc, txt, TextExtractionStatus.success);
|
144
157
|
}
|
145
158
|
|
146
|
-
function createResponse(
|
159
|
+
function createResponse(
|
160
|
+
doc: ContentObject,
|
161
|
+
text: string,
|
162
|
+
status: TextExtractionStatus,
|
163
|
+
message?: string,
|
164
|
+
): TextExtractionResult {
|
147
165
|
return {
|
148
166
|
status,
|
149
167
|
message,
|
@@ -151,11 +169,9 @@ function createResponse(doc: ContentObject, text: string, status: TextExtraction
|
|
151
169
|
len: text.length,
|
152
170
|
objectId: doc.id,
|
153
171
|
hasText: !!text,
|
154
|
-
}
|
155
|
-
|
172
|
+
};
|
156
173
|
}
|
157
174
|
|
158
|
-
|
159
175
|
function sniffIfText(buf: Buffer) {
|
160
176
|
// If file is too large, don't even try
|
161
177
|
if (buf.length > 500 * 1024) {
|
@@ -181,9 +197,9 @@ function sniffIfText(buf: Buffer) {
|
|
181
197
|
|
182
198
|
// Additional check for valid UTF-8 encoding
|
183
199
|
try {
|
184
|
-
const s = buf.toString(
|
185
|
-
return s.length > 0 && !s.includes(
|
200
|
+
const s = buf.toString("utf8");
|
201
|
+
return s.length > 0 && !s.includes("\uFFFD"); // Replacement character
|
186
202
|
} catch (e) {
|
187
203
|
return false;
|
188
204
|
}
|
189
|
-
}
|
205
|
+
}
|
@@ -214,7 +214,7 @@ async function generateTextEmbeddings({ document, client, type, config }: Execut
|
|
214
214
|
}
|
215
215
|
log.info(`Generated embeddings for part ${i}`, { len: e.values.length, duration: new Date().getTime() - localStart });
|
216
216
|
|
217
|
-
return {
|
217
|
+
return { number: i, result: e }
|
218
218
|
} catch (err: any) {
|
219
219
|
log.info(`Error generating ${type} embeddings for part ${i} of ${document.id}`, { error: err });
|
220
220
|
return { number: i, result: null, message: "error generating embeddings", error: err.message }
|
@@ -1,17 +1,17 @@
|
|
1
1
|
import { log } from "@temporalio/activity";
|
2
2
|
import { NodeStreamSource } from "@vertesia/client/node";
|
3
3
|
import { DSLActivityExecutionPayload, DSLActivitySpec, RenditionProperties } from "@vertesia/common";
|
4
|
-
import fs from 'fs';
|
5
4
|
import ffmpeg from 'fluent-ffmpeg';
|
6
|
-
import
|
5
|
+
import fs from 'fs';
|
7
6
|
import os from 'os';
|
7
|
+
import path from 'path';
|
8
8
|
import { imageResizer } from "../conversion/image.js";
|
9
9
|
import { setupActivity } from "../dsl/setup/ActivityContext.js";
|
10
10
|
import { NoDocumentFound, WorkflowParamNotFound } from "../errors.js";
|
11
11
|
import { saveBlobToTempFile } from "../utils/blobs.js";
|
12
12
|
|
13
13
|
interface GenerateImageRenditionParams {
|
14
|
-
max_hw: number; //maximum size of the
|
14
|
+
max_hw: number; //maximum size of the longest side of the image
|
15
15
|
format: string; //format of the output image
|
16
16
|
}
|
17
17
|
|
@@ -20,11 +20,20 @@ export interface GenerateImageRendition extends DSLActivitySpec<GenerateImageRen
|
|
20
20
|
}
|
21
21
|
|
22
22
|
export async function generateImageRendition(payload: DSLActivityExecutionPayload<GenerateImageRenditionParams>) {
|
23
|
-
const { client, objectId, params } = await setupActivity<GenerateImageRenditionParams>(payload);
|
23
|
+
const { client, objectId, params: originParams } = await setupActivity<GenerateImageRenditionParams>(payload);
|
24
|
+
|
25
|
+
// Fix: Use maxHeightWidth if max_hw is not provided
|
26
|
+
const params = {
|
27
|
+
...originParams,
|
28
|
+
max_hw: originParams.max_hw || (originParams as any).maxHeightWidth || 1024, // Default to 1024 if both are missing
|
29
|
+
format: originParams.format || (originParams as any).format_output || 'png' // Default to png if format is missing
|
30
|
+
};
|
31
|
+
|
32
|
+
log.info(`Generating image rendition for ${objectId}`, { originParams, params });
|
24
33
|
|
25
34
|
const inputObject = await client.objects.retrieve(objectId).catch((err) => {
|
26
|
-
log.error(`Failed to retrieve document ${objectId}`, err);
|
27
|
-
if (err.
|
35
|
+
log.error(`Failed to retrieve document ${objectId}`, { err });
|
36
|
+
if (err.message.includes("not found")) {
|
28
37
|
throw new NoDocumentFound(`Document ${objectId} not found`, [objectId]);
|
29
38
|
}
|
30
39
|
throw err;
|
@@ -124,38 +133,50 @@ export async function generateImageRendition(payload: DSLActivityExecutionPayloa
|
|
124
133
|
let resizedImagePath = null;
|
125
134
|
|
126
135
|
try {
|
136
|
+
log.info(`Resizing image for ${objectId} page ${i}`, { page, params });
|
127
137
|
// Resize the image using ImageMagick
|
128
138
|
resizedImagePath = await imageResizer(page, params.max_hw, params.format);
|
129
139
|
|
130
140
|
// Create a read stream from the resized image file
|
131
141
|
const fileStream = fs.createReadStream(resizedImagePath);
|
132
|
-
|
142
|
+
const format = "image/" + params.format;
|
143
|
+
const fileId = pageId.split("/").pop() ?? "0." + params.format;
|
133
144
|
const source = new NodeStreamSource(
|
134
145
|
fileStream,
|
135
|
-
|
136
|
-
|
146
|
+
fileId,
|
147
|
+
format,
|
137
148
|
pageId,
|
138
149
|
);
|
139
150
|
|
140
151
|
log.info(
|
141
|
-
`Uploading rendition for ${objectId} page ${i} with max_hw: ${params.max_hw} and format: ${params.format}`,
|
152
|
+
`Uploading rendition for ${objectId} page ${i} with max_hw: ${params.max_hw} and format: ${params.format}`, {
|
153
|
+
resizedImagePath,
|
154
|
+
fileId,
|
155
|
+
format,
|
156
|
+
pageId,
|
157
|
+
}
|
142
158
|
);
|
143
159
|
|
144
160
|
const result = await client.objects.upload(source).catch((err) => {
|
145
|
-
log.error(`Failed to upload rendition for ${objectId} page ${i}`, {
|
146
|
-
|
161
|
+
log.error(`Failed to upload rendition for ${objectId} page ${i}`, {
|
162
|
+
error: err,
|
163
|
+
errorMessage: err.message,
|
164
|
+
stack: err.stack
|
165
|
+
});
|
166
|
+
return Promise.reject(`Upload failed: ${err.message}`);
|
147
167
|
});
|
168
|
+
log.info(`Rendition uploaded for ${objectId} page ${i}`, { result });
|
148
169
|
|
149
170
|
return result;
|
150
171
|
} catch (error) {
|
151
172
|
log.error(`Failed to process rendition for ${objectId} page ${i}`, { error });
|
152
|
-
return Promise.
|
173
|
+
return Promise.reject(error instanceof Error ? error.message : null);
|
153
174
|
}
|
154
175
|
});
|
155
176
|
|
156
177
|
const uploaded = await Promise.all(uploads);
|
157
178
|
if (!uploaded || !uploaded.length || !uploaded[0]) {
|
158
|
-
log.error(`Failed to upload rendition for ${objectId}
|
179
|
+
log.error(`Failed to upload rendition for ${objectId}`, { uploaded });
|
159
180
|
throw new Error(`Failed to upload rendition for ${objectId} - upload object is empty`);
|
160
181
|
}
|
161
182
|
|