@vertesia/workflow 0.80.0 → 0.81.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertesia/workflow",
3
- "version": "0.80.0",
3
+ "version": "0.81.0",
4
4
  "type": "module",
5
5
  "description": "Vertesia workflow DSL",
6
6
  "main": "./lib/esm/index.js",
@@ -44,11 +44,11 @@
44
44
  "tmp": "^0.2.4",
45
45
  "tmp-promise": "^3.0.3",
46
46
  "yaml": "^2.6.0",
47
- "@llumiverse/common": "0.23.0",
48
- "@vertesia/common": "0.80.0",
49
- "@vertesia/client": "0.80.0",
50
- "@vertesia/api-fetch-client": "0.80.0",
51
- "@vertesia/memory": "0.80.0"
47
+ "@llumiverse/common": "0.24.0",
48
+ "@vertesia/common": "0.81.0",
49
+ "@vertesia/client": "0.81.0",
50
+ "@vertesia/api-fetch-client": "0.81.0",
51
+ "@vertesia/memory": "0.81.0"
52
52
  },
53
53
  "ts_dual_module": {
54
54
  "outDir": "lib",
@@ -8,14 +8,17 @@ export { executeInteraction } from "./executeInteraction.js";
8
8
  export { extractDocumentText } from "./extractDocumentText.js";
9
9
  export { generateDocumentProperties } from "./generateDocumentProperties.js";
10
10
  export { generateEmbeddings } from "./generateEmbeddings.js";
11
- export { generateImageRendition } from "./renditions/generateImageRendition.js";
12
- export { generateVideoRendition } from "./renditions/generateVideoRendition.js";
13
11
  export { generateOrAssignContentType } from "./generateOrAssignContentType.js";
14
12
  export { getObjectFromStore } from "./getObjectFromStore.js";
15
13
  export { handleDslError } from "./handleError.js";
14
+ export { prepareVideo } from "./media/prepareVideo.js";
16
15
  export { convertPdfToStructuredText } from "./media/processPdfWithTextract.js";
16
+ export { saveGladiaTranscription } from "./media/saveGladiaTranscription.js";
17
17
  export { transcribeMedia } from "./media/transcribeMediaWithGladia.js";
18
- export { prepareVideo } from "./media/prepareVideo.js";
18
+ export type { TranscriptMediaResult } from "./media/transcribeMediaWithGladia.js";
19
19
  export { notifyWebhook } from "./notifyWebhook.js";
20
- export { setDocumentStatus } from "./setDocumentStatus.js";
21
20
  export { checkRateLimit } from "./rateLimiter.js";
21
+ export { generateImageRendition } from "./renditions/generateImageRendition.js";
22
+ export { generateVideoRendition } from "./renditions/generateVideoRendition.js";
23
+ export { setDocumentStatus } from "./setDocumentStatus.js";
24
+
@@ -0,0 +1,128 @@
1
+ import { log } from "@temporalio/activity";
2
+ import { FetchClient } from "@vertesia/api-fetch-client";
3
+ import { AudioMetadata, DSLActivityExecutionPayload, DSLActivitySpec, GladiaConfiguration, SupportedIntegrations, TranscriptSegment, VideoMetadata } from "@vertesia/common";
4
+ import { setupActivity } from "../../dsl/setup/ActivityContext.js";
5
+ import { TextExtractionResult, TextExtractionStatus } from "../../result-types.js";
6
+
7
+ export interface SaveGladiaTranscriptionParams {
8
+ gladiaTranscriptionId: string;
9
+ }
10
+
11
+ export interface SaveGladiaTranscription extends DSLActivitySpec<SaveGladiaTranscriptionParams> {
12
+ name: 'SaveGladiaTranscription';
13
+ }
14
+
15
+ const GLADIA_URL = "https://api.gladia.io/v2";
16
+
17
+ /**
18
+ * Fetches transcription results from Gladia and saves them to the content object.
19
+ * This activity is called after transcribeMedia completes via webhook callback.
20
+ */
21
+ export async function saveGladiaTranscription(payload: DSLActivityExecutionPayload<SaveGladiaTranscriptionParams>): Promise<TextExtractionResult> {
22
+ const { params, client, objectId } = await setupActivity<SaveGladiaTranscriptionParams>(payload);
23
+
24
+ const gladiaConfig = await client.projects.integrations.retrieve(payload.project_id, SupportedIntegrations.gladia) as GladiaConfiguration | undefined;
25
+ if (!gladiaConfig || !gladiaConfig.enabled) {
26
+ return {
27
+ hasText: false,
28
+ objectId,
29
+ status: TextExtractionStatus.error,
30
+ error: "Gladia integration not enabled",
31
+ };
32
+ }
33
+
34
+ const gladiaClient = new FetchClient(gladiaConfig.url ?? GLADIA_URL);
35
+ gladiaClient.withHeaders({ "x-gladia-key": gladiaConfig.api_key });
36
+
37
+ log.info(`Fetching transcription result from Gladia`, { objectId, transcriptionId: params.gladiaTranscriptionId });
38
+
39
+ const transcriptionResult = await gladiaClient.get(`/transcription/${params.gladiaTranscriptionId}`) as GladiaTranscriptionResult;
40
+
41
+ if (transcriptionResult.status === 'error') {
42
+ log.error(`Gladia transcription failed`, { objectId, error: transcriptionResult });
43
+ return {
44
+ hasText: false,
45
+ objectId,
46
+ status: TextExtractionStatus.error,
47
+ error: "Gladia transcription failed",
48
+ };
49
+ }
50
+
51
+ if (transcriptionResult.status !== 'done') {
52
+ log.warn(`Gladia transcription not ready`, { objectId, status: transcriptionResult.status });
53
+ return {
54
+ hasText: false,
55
+ objectId,
56
+ status: TextExtractionStatus.error,
57
+ error: `Gladia transcription not ready: ${transcriptionResult.status}`,
58
+ };
59
+ }
60
+
61
+ const object = await client.objects.retrieve(objectId, "+text");
62
+
63
+ const segments = processUtterances(transcriptionResult.result.transcription.utterances);
64
+ const fullText = transcriptionResult.result.transcription.full_transcript;
65
+
66
+ await client.objects.update(objectId, {
67
+ text: fullText,
68
+ text_etag: object.content?.etag,
69
+ transcript: {
70
+ segments,
71
+ etag: object.content?.etag
72
+ },
73
+ metadata: {
74
+ ...object.metadata,
75
+ duration: transcriptionResult.result.metadata.audio_duration,
76
+ languages: transcriptionResult.result.transcription.languages
77
+ } as AudioMetadata | VideoMetadata
78
+ });
79
+
80
+ log.info(`Saved transcription for object`, { objectId, textLength: fullText?.length, segmentCount: segments.length });
81
+
82
+ return {
83
+ hasText: (fullText?.length ?? 0) > 0,
84
+ objectId,
85
+ status: TextExtractionStatus.success,
86
+ message: `Transcription saved with ${segments.length} segments`
87
+ };
88
+ }
89
+
90
+ function processUtterances(utterances: GladiaUtterance[]): TranscriptSegment[] {
91
+ return utterances.map(u => ({
92
+ start: u.start,
93
+ end: u.end,
94
+ text: u.text,
95
+ speaker: u.speaker,
96
+ confidence: u.confidence,
97
+ language: u.language
98
+ }));
99
+ }
100
+
101
+ // Gladia API response types
102
+ interface GladiaTranscriptionResult {
103
+ id: string;
104
+ status: 'queued' | 'processing' | 'done' | 'error';
105
+ result: {
106
+ metadata: {
107
+ audio_duration: number;
108
+ number_of_distinct_channels: number;
109
+ billing_time: number;
110
+ transcription_time: number;
111
+ };
112
+ transcription: {
113
+ full_transcript: string;
114
+ languages: string[];
115
+ utterances: GladiaUtterance[];
116
+ };
117
+ };
118
+ }
119
+
120
+ interface GladiaUtterance {
121
+ language: string;
122
+ start: number;
123
+ end: number;
124
+ confidence: number;
125
+ channel: number;
126
+ speaker: number;
127
+ text: string;
128
+ }
@@ -1,6 +1,6 @@
1
- import { DSLActivityExecutionPayload, DSLActivitySpec, GladiaConfiguration, SupportedIntegrations, AUDIO_RENDITION_NAME, VideoMetadata, ContentNature } from "@vertesia/common";
2
1
  import { activityInfo, CompleteAsyncError, log } from "@temporalio/activity";
3
2
  import { FetchClient, RequestError } from "@vertesia/api-fetch-client";
3
+ import { AUDIO_RENDITION_NAME, ContentNature, DSLActivityExecutionPayload, DSLActivitySpec, GladiaConfiguration, SupportedIntegrations, VideoMetadata } from "@vertesia/common";
4
4
  import { setupActivity } from "../../dsl/setup/ActivityContext.js";
5
5
  import { DocumentNotFoundError } from "../../errors.js";
6
6
  import { TextExtractionResult, TextExtractionStatus } from "../../index.js";
@@ -17,6 +17,11 @@ export interface TranscriptMedia extends DSLActivitySpec<TranscriptMediaParams>
17
17
 
18
18
  export interface TranscriptMediaResult extends TextExtractionResult {
19
19
  message?: string;
20
+ /**
21
+ * Gladia transcription ID for fetching results in a follow-up activity.
22
+ * Present when async media transcription completes successfully.
23
+ */
24
+ gladiaTranscriptionId?: string;
20
25
  }
21
26
 
22
27
  const GLADIA_URL = "https://api.gladia.io/v2";
@@ -68,7 +73,7 @@ export async function transcribeMedia(payload: DSLActivityExecutionPayload<Trans
68
73
  log.info(`Using media URL for transcription`, { objectId, mediaUrl: mediaSource });
69
74
 
70
75
  const taskToken = Buffer.from(activityInfo().taskToken).toString('base64url');
71
- const callbackUrl = generateCallbackUrlForGladia(client.store.baseUrl, payload.auth_token, taskToken, objectId);
76
+ const callbackUrl = generateCallbackUrlForGladia(client.store.baseUrl, taskToken, objectId);
72
77
 
73
78
  log.info(`Transcribing media ${mediaUrl} with Gladia`, { objectId, callbackUrl });
74
79
 
@@ -85,10 +90,7 @@ export async function transcribeMedia(payload: DSLActivityExecutionPayload<Trans
85
90
  }
86
91
  }
87
92
  }) as GladiaTranscriptRequestResponse;
88
-
89
93
  log.info(`Transcription request sent to Gladia`, { objectId, res });
90
- throw new CompleteAsyncError();
91
-
92
94
  } catch (error: any) {
93
95
  if (error instanceof RequestError && error.status === 422) {
94
96
  return {
@@ -97,15 +99,16 @@ export async function transcribeMedia(payload: DSLActivityExecutionPayload<Trans
97
99
  status: TextExtractionStatus.error,
98
100
  error: `Gladia transcription error: ${error.message}`,
99
101
  }
100
- } else {
101
- log.error(`Error sending transcription request to Gladia for object ${objectId}`, { error });
102
- throw error;
103
102
  }
103
+ log.error(`Error sending transcription request to Gladia for object ${objectId}`, { error });
104
+ throw error;
104
105
  }
106
+
107
+ throw new CompleteAsyncError();
105
108
  }
106
109
 
107
- function generateCallbackUrlForGladia(baseUrl: string, authToken: string, taskToken: string, objectId: string) {
108
- return `${baseUrl}/api/v1/webhooks/gladia/${objectId}?access_token=${authToken}&task_token=${taskToken}`;
110
+ function generateCallbackUrlForGladia(baseUrl: string, taskToken: string, objectId: string) {
111
+ return `${baseUrl}/webhooks/gladia/${objectId}?task_token=${taskToken}`;
109
112
  }
110
113
 
111
114
  interface GladiaTranscriptRequestResponse {