@vertesia/workflow 1.0.0-dev.20260128.144200 → 1.0.0-dev.20260225.024852Z
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/advanced/createOrUpdateDocumentFromInteractionRun.js +1 -1
- package/lib/cjs/activities/advanced/createOrUpdateDocumentFromInteractionRun.js.map +1 -1
- package/lib/cjs/activities/chunkDocument.js +3 -1
- package/lib/cjs/activities/chunkDocument.js.map +1 -1
- package/lib/cjs/activities/extractDocumentText.js +56 -16
- package/lib/cjs/activities/extractDocumentText.js.map +1 -1
- package/lib/cjs/activities/generateDocumentProperties.js +4 -2
- package/lib/cjs/activities/generateDocumentProperties.js.map +1 -1
- package/lib/cjs/activities/generateEmbeddings.js +20 -10
- package/lib/cjs/activities/generateEmbeddings.js.map +1 -1
- package/lib/cjs/activities/generateOrAssignContentType.js +2 -2
- package/lib/cjs/activities/generateOrAssignContentType.js.map +1 -1
- package/lib/cjs/activities/index-dsl.js +7 -7
- package/lib/cjs/activities/index-dsl.js.map +1 -1
- package/lib/cjs/activities/media/saveGladiaTranscription.js +38 -24
- package/lib/cjs/activities/media/saveGladiaTranscription.js.map +1 -1
- package/lib/cjs/activities/media/transcribeMediaWithGladia.js +41 -24
- package/lib/cjs/activities/media/transcribeMediaWithGladia.js.map +1 -1
- package/lib/cjs/activities/notifyWebhook.js +11 -2
- package/lib/cjs/activities/notifyWebhook.js.map +1 -1
- package/lib/cjs/activities/renditions/generateImageRendition.js +2 -2
- package/lib/cjs/activities/renditions/generateImageRendition.js.map +1 -1
- package/lib/cjs/activities/setDocumentStatus.js +13 -2
- package/lib/cjs/activities/setDocumentStatus.js.map +1 -1
- package/lib/cjs/conversion/image.js +10 -10
- package/lib/cjs/conversion/image.js.map +1 -1
- package/lib/cjs/dsl/dsl-workflow.js +44 -7
- package/lib/cjs/dsl/dsl-workflow.js.map +1 -1
- package/lib/cjs/dsl/setup/ActivityContext.js +56 -0
- package/lib/cjs/dsl/setup/ActivityContext.js.map +1 -1
- package/lib/cjs/errors.js +11 -1
- package/lib/cjs/errors.js.map +1 -1
- package/lib/cjs/index.js +6 -5
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/result-types.js.map +1 -1
- package/lib/cjs/utils/renditions.js +9 -5
- package/lib/cjs/utils/renditions.js.map +1 -1
- package/lib/cjs/utils/text-preview-utils.js +43 -0
- package/lib/cjs/utils/text-preview-utils.js.map +1 -0
- package/lib/esm/activities/advanced/createOrUpdateDocumentFromInteractionRun.js +1 -1
- package/lib/esm/activities/advanced/createOrUpdateDocumentFromInteractionRun.js.map +1 -1
- package/lib/esm/activities/chunkDocument.js +3 -1
- package/lib/esm/activities/chunkDocument.js.map +1 -1
- package/lib/esm/activities/extractDocumentText.js +56 -16
- package/lib/esm/activities/extractDocumentText.js.map +1 -1
- package/lib/esm/activities/generateDocumentProperties.js +4 -2
- package/lib/esm/activities/generateDocumentProperties.js.map +1 -1
- package/lib/esm/activities/generateEmbeddings.js +20 -10
- package/lib/esm/activities/generateEmbeddings.js.map +1 -1
- package/lib/esm/activities/generateOrAssignContentType.js +2 -2
- package/lib/esm/activities/generateOrAssignContentType.js.map +1 -1
- package/lib/esm/activities/index-dsl.js +3 -3
- package/lib/esm/activities/index-dsl.js.map +1 -1
- package/lib/esm/activities/media/saveGladiaTranscription.js +38 -24
- package/lib/esm/activities/media/saveGladiaTranscription.js.map +1 -1
- package/lib/esm/activities/media/transcribeMediaWithGladia.js +41 -24
- package/lib/esm/activities/media/transcribeMediaWithGladia.js.map +1 -1
- package/lib/esm/activities/notifyWebhook.js +11 -2
- package/lib/esm/activities/notifyWebhook.js.map +1 -1
- package/lib/esm/activities/renditions/generateImageRendition.js +2 -2
- package/lib/esm/activities/renditions/generateImageRendition.js.map +1 -1
- package/lib/esm/activities/setDocumentStatus.js +13 -2
- package/lib/esm/activities/setDocumentStatus.js.map +1 -1
- package/lib/esm/conversion/image.js +10 -10
- package/lib/esm/conversion/image.js.map +1 -1
- package/lib/esm/dsl/dsl-workflow.js +44 -7
- package/lib/esm/dsl/dsl-workflow.js.map +1 -1
- package/lib/esm/dsl/setup/ActivityContext.js +57 -1
- package/lib/esm/dsl/setup/ActivityContext.js.map +1 -1
- package/lib/esm/errors.js +9 -0
- package/lib/esm/errors.js.map +1 -1
- package/lib/esm/index.js +6 -5
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/result-types.js.map +1 -1
- package/lib/esm/utils/renditions.js +9 -5
- package/lib/esm/utils/renditions.js.map +1 -1
- package/lib/esm/utils/text-preview-utils.js +38 -0
- package/lib/esm/utils/text-preview-utils.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types/activities/chunkDocument.d.ts.map +1 -1
- package/lib/types/activities/extractDocumentText.d.ts +1 -0
- package/lib/types/activities/extractDocumentText.d.ts.map +1 -1
- package/lib/types/activities/generateDocumentProperties.d.ts.map +1 -1
- package/lib/types/activities/generateEmbeddings.d.ts.map +1 -1
- package/lib/types/activities/index-dsl.d.ts +3 -3
- package/lib/types/activities/index-dsl.d.ts.map +1 -1
- package/lib/types/activities/media/saveGladiaTranscription.d.ts +1 -0
- package/lib/types/activities/media/saveGladiaTranscription.d.ts.map +1 -1
- package/lib/types/activities/media/transcribeMediaWithGladia.d.ts +1 -0
- package/lib/types/activities/media/transcribeMediaWithGladia.d.ts.map +1 -1
- package/lib/types/activities/setDocumentStatus.d.ts +1 -1
- package/lib/types/activities/setDocumentStatus.d.ts.map +1 -1
- package/lib/types/dsl/dsl-workflow.d.ts.map +1 -1
- package/lib/types/dsl/setup/ActivityContext.d.ts +32 -2
- package/lib/types/dsl/setup/ActivityContext.d.ts.map +1 -1
- package/lib/types/errors.d.ts +4 -0
- package/lib/types/errors.d.ts.map +1 -1
- package/lib/types/index.d.ts +6 -5
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/result-types.d.ts +5 -1
- package/lib/types/result-types.d.ts.map +1 -1
- package/lib/types/utils/renditions.d.ts +2 -0
- package/lib/types/utils/renditions.d.ts.map +1 -1
- package/lib/types/utils/text-preview-utils.d.ts +15 -0
- package/lib/types/utils/text-preview-utils.d.ts.map +1 -0
- package/lib/workflows-bundle.js +11747 -11141
- package/package.json +6 -7
- package/src/activities/advanced/createOrUpdateDocumentFromInteractionRun.ts +1 -1
- package/src/activities/chunkDocument.ts +3 -1
- package/src/activities/extractDocumentText.ts +85 -26
- package/src/activities/generateDocumentProperties.ts +4 -2
- package/src/activities/generateEmbeddings.ts +22 -14
- package/src/activities/generateOrAssignContentType.ts +2 -2
- package/src/activities/index-dsl.ts +4 -3
- package/src/activities/media/saveGladiaTranscription.test.ts +406 -0
- package/src/activities/media/saveGladiaTranscription.ts +41 -26
- package/src/activities/media/transcribeMediaWithGladia.test.ts +583 -0
- package/src/activities/media/transcribeMediaWithGladia.ts +46 -25
- package/src/activities/notifyWebhook.test.ts +121 -8
- package/src/activities/notifyWebhook.ts +10 -2
- package/src/activities/renditions/generateImageRendition.ts +2 -2
- package/src/activities/setDocumentStatus.ts +12 -4
- package/src/conversion/image.test.ts +1 -0
- package/src/conversion/image.ts +10 -10
- package/src/dsl/dsl-workflow.ts +57 -9
- package/src/dsl/setup/ActivityContext.ts +73 -0
- package/src/dsl.ts +1 -0
- package/src/errors.ts +15 -0
- package/src/index.ts +6 -5
- package/src/result-types.ts +5 -1
- package/src/utils/renditions.ts +11 -5
- package/src/utils/text-preview-utils.ts +62 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { MockActivityEnvironment } from "@temporalio/testing";
|
|
2
|
+
import { ContentEventName, DSLActivityExecutionPayload } from "@vertesia/common";
|
|
3
|
+
import type { VertesiaClient } from "@vertesia/client";
|
|
4
|
+
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import type { ActivityContext, TextExtractionResult } from "@vertesia/workflow";
|
|
6
|
+
import { TextExtractionStatus } from "../../result-types.js";
|
|
7
|
+
import { saveGladiaTranscription, SaveGladiaTranscriptionParams } from "./saveGladiaTranscription.js";
|
|
8
|
+
|
|
9
|
+
// Mock setupActivity from the relative path used by the activity
|
|
10
|
+
vi.mock("../../dsl/setup/ActivityContext.js", async (importOriginal) => {
|
|
11
|
+
const actual = await importOriginal<typeof import("../../dsl/setup/ActivityContext.js")>();
|
|
12
|
+
return {
|
|
13
|
+
...actual,
|
|
14
|
+
setupActivity: vi.fn(),
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Mock FetchClient as a constructor
|
|
19
|
+
vi.mock("@vertesia/api-fetch-client", async (importOriginal) => {
|
|
20
|
+
const actual = await importOriginal<typeof import("@vertesia/api-fetch-client")>();
|
|
21
|
+
return {
|
|
22
|
+
...actual,
|
|
23
|
+
FetchClient: vi.fn(),
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
let testEnv: MockActivityEnvironment;
|
|
28
|
+
|
|
29
|
+
beforeAll(async () => {
|
|
30
|
+
testEnv = new MockActivityEnvironment();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
vi.clearAllMocks();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Helper function to create test payload
|
|
38
|
+
const createTestPayload = (
|
|
39
|
+
params: SaveGladiaTranscriptionParams,
|
|
40
|
+
objectId?: string,
|
|
41
|
+
fileInput?: { url: string; mimetype: string }
|
|
42
|
+
): DSLActivityExecutionPayload<SaveGladiaTranscriptionParams> => {
|
|
43
|
+
return {
|
|
44
|
+
auth_token: process.env.VERTESIA_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vbW9jay10b2tlbi1zZXJ2ZXIiLCJzdWIiOiJ0ZXN0In0.signature",
|
|
45
|
+
account_id: "test-account",
|
|
46
|
+
project_id: "test-project",
|
|
47
|
+
params,
|
|
48
|
+
config: {
|
|
49
|
+
studio_url: "http://mock-studio",
|
|
50
|
+
store_url: "http://mock-store",
|
|
51
|
+
},
|
|
52
|
+
workflow_name: "test-workflow",
|
|
53
|
+
event: ContentEventName.create,
|
|
54
|
+
objectIds: objectId ? [objectId] : [],
|
|
55
|
+
input: fileInput
|
|
56
|
+
? { inputType: 'files' as const, files: [fileInput] }
|
|
57
|
+
: objectId
|
|
58
|
+
? { inputType: 'objectIds' as const, objectIds: [objectId] }
|
|
59
|
+
: undefined,
|
|
60
|
+
vars: {},
|
|
61
|
+
activity: { name: "SaveGladiaTranscription", params }
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Mock Gladia transcription response
|
|
66
|
+
const mockGladiaTranscriptionResult = {
|
|
67
|
+
id: "test-transcription-id",
|
|
68
|
+
status: "done" as const,
|
|
69
|
+
result: {
|
|
70
|
+
metadata: {
|
|
71
|
+
audio_duration: 120.5,
|
|
72
|
+
number_of_distinct_channels: 1,
|
|
73
|
+
billing_time: 120,
|
|
74
|
+
transcription_time: 30,
|
|
75
|
+
},
|
|
76
|
+
transcription: {
|
|
77
|
+
full_transcript: "Hello world, this is a test transcription.",
|
|
78
|
+
languages: ["en"],
|
|
79
|
+
utterances: [
|
|
80
|
+
{
|
|
81
|
+
language: "en",
|
|
82
|
+
start: 0,
|
|
83
|
+
end: 2.5,
|
|
84
|
+
confidence: 0.95,
|
|
85
|
+
channel: 0,
|
|
86
|
+
speaker: 0,
|
|
87
|
+
text: "Hello world,"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
language: "en",
|
|
91
|
+
start: 2.5,
|
|
92
|
+
end: 5.0,
|
|
93
|
+
confidence: 0.97,
|
|
94
|
+
channel: 0,
|
|
95
|
+
speaker: 0,
|
|
96
|
+
text: "this is a test transcription."
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
describe("SaveGladiaTranscription", () => {
|
|
104
|
+
it("should save transcription in object mode", async () => {
|
|
105
|
+
const { setupActivity } = await import("../../dsl/setup/ActivityContext.js");
|
|
106
|
+
const { FetchClient } = await import("@vertesia/api-fetch-client");
|
|
107
|
+
|
|
108
|
+
// Mock FetchClient instance
|
|
109
|
+
const mockFetchClient = {
|
|
110
|
+
withHeaders: vi.fn().mockReturnThis(),
|
|
111
|
+
get: vi.fn().mockResolvedValue(mockGladiaTranscriptionResult),
|
|
112
|
+
};
|
|
113
|
+
vi.mocked(FetchClient).mockImplementation(function(this: any) {
|
|
114
|
+
return mockFetchClient as any;
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Mock client
|
|
118
|
+
const mockClient = {
|
|
119
|
+
projects: {
|
|
120
|
+
integrations: {
|
|
121
|
+
retrieve: vi.fn().mockResolvedValue({
|
|
122
|
+
enabled: true,
|
|
123
|
+
api_key: "test-api-key",
|
|
124
|
+
url: "https://api.gladia.io/v2",
|
|
125
|
+
}),
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
objects: {
|
|
129
|
+
retrieve: vi.fn().mockResolvedValue({
|
|
130
|
+
content: { etag: "test-etag" },
|
|
131
|
+
}),
|
|
132
|
+
update: vi.fn().mockResolvedValue({}),
|
|
133
|
+
},
|
|
134
|
+
} as unknown as VertesiaClient;
|
|
135
|
+
|
|
136
|
+
const params: SaveGladiaTranscriptionParams = {
|
|
137
|
+
gladiaTranscriptionId: "test-transcription-id",
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// Mock setupActivity
|
|
141
|
+
vi.mocked(setupActivity).mockResolvedValue({
|
|
142
|
+
client: mockClient,
|
|
143
|
+
objectId: "test-object-id",
|
|
144
|
+
inputType: 'objectIds',
|
|
145
|
+
params,
|
|
146
|
+
} as unknown as ActivityContext<SaveGladiaTranscriptionParams>);
|
|
147
|
+
|
|
148
|
+
const payload = createTestPayload(params, "test-object-id");
|
|
149
|
+
const result: TextExtractionResult = await testEnv.run(saveGladiaTranscription, payload);
|
|
150
|
+
|
|
151
|
+
expect(result).toMatchObject({
|
|
152
|
+
hasText: true,
|
|
153
|
+
objectId: "test-object-id",
|
|
154
|
+
status: TextExtractionStatus.success,
|
|
155
|
+
});
|
|
156
|
+
expect(result.message).toContain("saved with 2 segments");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("should handle transcription in file mode", async () => {
|
|
160
|
+
const { setupActivity } = await import("../../dsl/setup/ActivityContext.js");
|
|
161
|
+
const { FetchClient } = await import("@vertesia/api-fetch-client");
|
|
162
|
+
|
|
163
|
+
const mockFetchClient = {
|
|
164
|
+
withHeaders: vi.fn().mockReturnThis(),
|
|
165
|
+
get: vi.fn().mockResolvedValue(mockGladiaTranscriptionResult),
|
|
166
|
+
};
|
|
167
|
+
vi.mocked(FetchClient).mockImplementation(function(this: any) {
|
|
168
|
+
return mockFetchClient as any;
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const mockClient = {
|
|
172
|
+
projects: {
|
|
173
|
+
integrations: {
|
|
174
|
+
retrieve: vi.fn().mockResolvedValue({
|
|
175
|
+
enabled: true,
|
|
176
|
+
api_key: "test-api-key",
|
|
177
|
+
url: "https://api.gladia.io/v2",
|
|
178
|
+
}),
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
files: {
|
|
182
|
+
uploadText: vi.fn().mockResolvedValue({}),
|
|
183
|
+
},
|
|
184
|
+
} as unknown as VertesiaClient;
|
|
185
|
+
|
|
186
|
+
const params: SaveGladiaTranscriptionParams = {
|
|
187
|
+
gladiaTranscriptionId: "test-transcription-id",
|
|
188
|
+
output_storage_path: "test-storage-path",
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
vi.mocked(setupActivity).mockResolvedValue({
|
|
192
|
+
client: mockClient,
|
|
193
|
+
file: { url: "gs://test-bucket/audio.mp3", mimetype: "audio/mpeg" },
|
|
194
|
+
inputType: 'files',
|
|
195
|
+
params,
|
|
196
|
+
} as unknown as ActivityContext<SaveGladiaTranscriptionParams>);
|
|
197
|
+
|
|
198
|
+
const payload = createTestPayload(
|
|
199
|
+
params,
|
|
200
|
+
undefined,
|
|
201
|
+
{ url: "gs://test-bucket/audio.mp3", mimetype: "audio/mpeg" }
|
|
202
|
+
);
|
|
203
|
+
const result: TextExtractionResult = await testEnv.run(saveGladiaTranscription, payload);
|
|
204
|
+
|
|
205
|
+
expect(result).toMatchObject({
|
|
206
|
+
hasText: true,
|
|
207
|
+
objectId: "test-storage-path",
|
|
208
|
+
status: TextExtractionStatus.success,
|
|
209
|
+
});
|
|
210
|
+
expect(result.message).toContain("completed with 2 segments");
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("should handle Gladia integration not enabled", async () => {
|
|
214
|
+
const { setupActivity } = await import("../../dsl/setup/ActivityContext.js");
|
|
215
|
+
|
|
216
|
+
const mockClient = {
|
|
217
|
+
projects: {
|
|
218
|
+
integrations: {
|
|
219
|
+
retrieve: vi.fn().mockResolvedValue({
|
|
220
|
+
enabled: false,
|
|
221
|
+
}),
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
} as unknown as VertesiaClient;
|
|
225
|
+
|
|
226
|
+
const params: SaveGladiaTranscriptionParams = {
|
|
227
|
+
gladiaTranscriptionId: "test-transcription-id",
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
vi.mocked(setupActivity).mockResolvedValue({
|
|
231
|
+
client: mockClient,
|
|
232
|
+
objectId: "test-object-id",
|
|
233
|
+
inputType: 'objectIds',
|
|
234
|
+
params,
|
|
235
|
+
} as unknown as ActivityContext<SaveGladiaTranscriptionParams>);
|
|
236
|
+
|
|
237
|
+
const payload = createTestPayload(params, "test-object-id");
|
|
238
|
+
const result: TextExtractionResult = await testEnv.run(saveGladiaTranscription, payload);
|
|
239
|
+
|
|
240
|
+
expect(result).toMatchObject({
|
|
241
|
+
hasText: false,
|
|
242
|
+
objectId: "test-object-id",
|
|
243
|
+
status: TextExtractionStatus.error,
|
|
244
|
+
error: "Gladia integration not enabled",
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("should handle Gladia transcription error status", async () => {
|
|
249
|
+
const { setupActivity } = await import("../../dsl/setup/ActivityContext.js");
|
|
250
|
+
const { FetchClient } = await import("@vertesia/api-fetch-client");
|
|
251
|
+
|
|
252
|
+
const mockFetchClient = {
|
|
253
|
+
withHeaders: vi.fn().mockReturnThis(),
|
|
254
|
+
get: vi.fn().mockResolvedValue({
|
|
255
|
+
id: "test-transcription-id",
|
|
256
|
+
status: "error",
|
|
257
|
+
}),
|
|
258
|
+
};
|
|
259
|
+
vi.mocked(FetchClient).mockImplementation(function(this: any) {
|
|
260
|
+
return mockFetchClient as any;
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
const mockClient = {
|
|
264
|
+
projects: {
|
|
265
|
+
integrations: {
|
|
266
|
+
retrieve: vi.fn().mockResolvedValue({
|
|
267
|
+
enabled: true,
|
|
268
|
+
api_key: "test-api-key",
|
|
269
|
+
url: "https://api.gladia.io/v2",
|
|
270
|
+
}),
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
} as unknown as VertesiaClient;
|
|
274
|
+
|
|
275
|
+
const params: SaveGladiaTranscriptionParams = {
|
|
276
|
+
gladiaTranscriptionId: "test-transcription-id",
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
vi.mocked(setupActivity).mockResolvedValue({
|
|
280
|
+
client: mockClient,
|
|
281
|
+
objectId: "test-object-id",
|
|
282
|
+
inputType: 'objectIds',
|
|
283
|
+
params,
|
|
284
|
+
} as unknown as ActivityContext<SaveGladiaTranscriptionParams>);
|
|
285
|
+
|
|
286
|
+
const payload = createTestPayload(params, "test-object-id");
|
|
287
|
+
const result: TextExtractionResult = await testEnv.run(saveGladiaTranscription, payload);
|
|
288
|
+
|
|
289
|
+
expect(result).toMatchObject({
|
|
290
|
+
hasText: false,
|
|
291
|
+
objectId: "test-object-id",
|
|
292
|
+
status: TextExtractionStatus.error,
|
|
293
|
+
error: "Gladia transcription failed",
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it("should handle Gladia transcription not ready", async () => {
|
|
298
|
+
const { setupActivity } = await import("../../dsl/setup/ActivityContext.js");
|
|
299
|
+
const { FetchClient } = await import("@vertesia/api-fetch-client");
|
|
300
|
+
|
|
301
|
+
const mockFetchClient = {
|
|
302
|
+
withHeaders: vi.fn().mockReturnThis(),
|
|
303
|
+
get: vi.fn().mockResolvedValue({
|
|
304
|
+
id: "test-transcription-id",
|
|
305
|
+
status: "processing",
|
|
306
|
+
}),
|
|
307
|
+
};
|
|
308
|
+
vi.mocked(FetchClient).mockImplementation(function(this: any) {
|
|
309
|
+
return mockFetchClient as any;
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
const mockClient = {
|
|
313
|
+
projects: {
|
|
314
|
+
integrations: {
|
|
315
|
+
retrieve: vi.fn().mockResolvedValue({
|
|
316
|
+
enabled: true,
|
|
317
|
+
api_key: "test-api-key",
|
|
318
|
+
url: "https://api.gladia.io/v2",
|
|
319
|
+
}),
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
} as unknown as VertesiaClient;
|
|
323
|
+
|
|
324
|
+
const params: SaveGladiaTranscriptionParams = {
|
|
325
|
+
gladiaTranscriptionId: "test-transcription-id",
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
vi.mocked(setupActivity).mockResolvedValue({
|
|
329
|
+
client: mockClient,
|
|
330
|
+
objectId: "test-object-id",
|
|
331
|
+
inputType: 'objectIds',
|
|
332
|
+
params,
|
|
333
|
+
} as unknown as ActivityContext<SaveGladiaTranscriptionParams>);
|
|
334
|
+
|
|
335
|
+
const payload = createTestPayload(params, "test-object-id");
|
|
336
|
+
const result: TextExtractionResult = await testEnv.run(saveGladiaTranscription, payload);
|
|
337
|
+
|
|
338
|
+
expect(result).toMatchObject({
|
|
339
|
+
hasText: false,
|
|
340
|
+
objectId: "test-object-id",
|
|
341
|
+
status: TextExtractionStatus.error,
|
|
342
|
+
});
|
|
343
|
+
expect(result.error).toContain("not ready: processing");
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it("should handle empty transcript", async () => {
|
|
347
|
+
const { setupActivity } = await import("../../dsl/setup/ActivityContext.js");
|
|
348
|
+
const { FetchClient } = await import("@vertesia/api-fetch-client");
|
|
349
|
+
|
|
350
|
+
const mockFetchClient = {
|
|
351
|
+
withHeaders: vi.fn().mockReturnThis(),
|
|
352
|
+
get: vi.fn().mockResolvedValue({
|
|
353
|
+
...mockGladiaTranscriptionResult,
|
|
354
|
+
result: {
|
|
355
|
+
...mockGladiaTranscriptionResult.result,
|
|
356
|
+
transcription: {
|
|
357
|
+
full_transcript: "",
|
|
358
|
+
languages: [],
|
|
359
|
+
utterances: [],
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
}),
|
|
363
|
+
};
|
|
364
|
+
vi.mocked(FetchClient).mockImplementation(function(this: any) {
|
|
365
|
+
return mockFetchClient as any;
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
const mockClient = {
|
|
369
|
+
projects: {
|
|
370
|
+
integrations: {
|
|
371
|
+
retrieve: vi.fn().mockResolvedValue({
|
|
372
|
+
enabled: true,
|
|
373
|
+
api_key: "test-api-key",
|
|
374
|
+
url: "https://api.gladia.io/v2",
|
|
375
|
+
}),
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
objects: {
|
|
379
|
+
retrieve: vi.fn().mockResolvedValue({
|
|
380
|
+
content: { etag: "test-etag" },
|
|
381
|
+
}),
|
|
382
|
+
update: vi.fn().mockResolvedValue({}),
|
|
383
|
+
},
|
|
384
|
+
} as unknown as VertesiaClient;
|
|
385
|
+
|
|
386
|
+
const params: SaveGladiaTranscriptionParams = {
|
|
387
|
+
gladiaTranscriptionId: "test-transcription-id",
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
vi.mocked(setupActivity).mockResolvedValue({
|
|
391
|
+
client: mockClient,
|
|
392
|
+
objectId: "test-object-id",
|
|
393
|
+
inputType: 'objectIds',
|
|
394
|
+
params,
|
|
395
|
+
} as unknown as ActivityContext<SaveGladiaTranscriptionParams>);
|
|
396
|
+
|
|
397
|
+
const payload = createTestPayload(params, "test-object-id");
|
|
398
|
+
const result: TextExtractionResult = await testEnv.run(saveGladiaTranscription, payload);
|
|
399
|
+
|
|
400
|
+
expect(result).toMatchObject({
|
|
401
|
+
hasText: false,
|
|
402
|
+
objectId: "test-object-id",
|
|
403
|
+
status: TextExtractionStatus.success,
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
});
|
|
@@ -6,6 +6,7 @@ import { TextExtractionResult, TextExtractionStatus } from "../../result-types.j
|
|
|
6
6
|
|
|
7
7
|
export interface SaveGladiaTranscriptionParams {
|
|
8
8
|
gladiaTranscriptionId: string;
|
|
9
|
+
output_storage_path?: string;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export interface SaveGladiaTranscription extends DSLActivitySpec<SaveGladiaTranscriptionParams> {
|
|
@@ -19,13 +20,14 @@ const GLADIA_URL = "https://api.gladia.io/v2";
|
|
|
19
20
|
* This activity is called after transcribeMedia completes via webhook callback.
|
|
20
21
|
*/
|
|
21
22
|
export async function saveGladiaTranscription(payload: DSLActivityExecutionPayload<SaveGladiaTranscriptionParams>): Promise<TextExtractionResult> {
|
|
22
|
-
const
|
|
23
|
+
const context = await setupActivity<SaveGladiaTranscriptionParams>(payload);
|
|
24
|
+
const { params, client, inputType } = context;
|
|
23
25
|
|
|
24
26
|
const gladiaConfig = await client.projects.integrations.retrieve(payload.project_id, SupportedIntegrations.gladia) as GladiaConfiguration | undefined;
|
|
25
27
|
if (!gladiaConfig || !gladiaConfig.enabled) {
|
|
26
28
|
return {
|
|
27
29
|
hasText: false,
|
|
28
|
-
objectId,
|
|
30
|
+
objectId: inputType === 'objectIds' ? context.objectId : undefined,
|
|
29
31
|
status: TextExtractionStatus.error,
|
|
30
32
|
error: "Gladia integration not enabled",
|
|
31
33
|
};
|
|
@@ -34,56 +36,69 @@ export async function saveGladiaTranscription(payload: DSLActivityExecutionPaylo
|
|
|
34
36
|
const gladiaClient = new FetchClient(gladiaConfig.url ?? GLADIA_URL);
|
|
35
37
|
gladiaClient.withHeaders({ "x-gladia-key": gladiaConfig.api_key });
|
|
36
38
|
|
|
37
|
-
log.info(`Fetching transcription result from Gladia`, {
|
|
39
|
+
log.info(`Fetching transcription result from Gladia`, { transcriptionId: params.gladiaTranscriptionId });
|
|
38
40
|
|
|
39
41
|
const transcriptionResult = await gladiaClient.get(`/transcription/${params.gladiaTranscriptionId}`) as GladiaTranscriptionResult;
|
|
40
42
|
|
|
43
|
+
// Determine storage identifier based on input type
|
|
44
|
+
const storageId = inputType === 'objectIds' ? context.objectId : params.output_storage_path;
|
|
45
|
+
|
|
41
46
|
if (transcriptionResult.status === 'error') {
|
|
42
|
-
log.error(`Gladia transcription failed`, {
|
|
47
|
+
log.error(`Gladia transcription failed`, { error: transcriptionResult });
|
|
43
48
|
return {
|
|
44
49
|
hasText: false,
|
|
45
|
-
objectId,
|
|
50
|
+
objectId: inputType === 'objectIds' ? context.objectId : undefined,
|
|
51
|
+
file: inputType === 'files' ? {
|
|
52
|
+
source_url: context.file.url,
|
|
53
|
+
} : undefined,
|
|
46
54
|
status: TextExtractionStatus.error,
|
|
47
55
|
error: "Gladia transcription failed",
|
|
48
56
|
};
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
if (transcriptionResult.status !== 'done') {
|
|
52
|
-
log.warn(`Gladia transcription not ready`, {
|
|
60
|
+
log.warn(`Gladia transcription not ready`, { storageId, status: transcriptionResult.status });
|
|
53
61
|
return {
|
|
54
62
|
hasText: false,
|
|
55
|
-
objectId,
|
|
63
|
+
objectId: storageId,
|
|
56
64
|
status: TextExtractionStatus.error,
|
|
57
65
|
error: `Gladia transcription not ready: ${transcriptionResult.status}`,
|
|
58
66
|
};
|
|
59
67
|
}
|
|
60
68
|
|
|
61
|
-
const object = await client.objects.retrieve(objectId, "+text");
|
|
62
|
-
|
|
63
69
|
const segments = processUtterances(transcriptionResult.result.transcription.utterances);
|
|
64
70
|
const fullText = transcriptionResult.result.transcription.full_transcript;
|
|
65
71
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
72
|
+
if (inputType === 'objectIds') {
|
|
73
|
+
// Object mode: save to object store
|
|
74
|
+
const objectId = context.objectId;
|
|
75
|
+
const object = await client.objects.retrieve(objectId, "+text");
|
|
76
|
+
|
|
77
|
+
await client.objects.update(objectId, {
|
|
78
|
+
text: fullText,
|
|
79
|
+
text_etag: object.content?.etag,
|
|
80
|
+
transcript: {
|
|
81
|
+
segments,
|
|
82
|
+
etag: object.content?.etag
|
|
83
|
+
},
|
|
84
|
+
metadata: {
|
|
85
|
+
...object.metadata,
|
|
86
|
+
duration: transcriptionResult.result.metadata.audio_duration,
|
|
87
|
+
languages: transcriptionResult.result.transcription.languages
|
|
88
|
+
} as AudioMetadata | VideoMetadata
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
log.info(`Saved transcription for object`, { objectId, textLength: fullText?.length, segmentCount: segments.length });
|
|
92
|
+
} else {
|
|
93
|
+
// File mode: don't save to object, just log
|
|
94
|
+
log.info(`Transcription completed (file mode, not saved to object)`, { storageId, textLength: fullText?.length, segmentCount: segments.length });
|
|
95
|
+
}
|
|
81
96
|
|
|
82
97
|
return {
|
|
83
98
|
hasText: (fullText?.length ?? 0) > 0,
|
|
84
|
-
objectId,
|
|
99
|
+
objectId: storageId,
|
|
85
100
|
status: TextExtractionStatus.success,
|
|
86
|
-
message: `Transcription saved with ${segments.length} segments`
|
|
101
|
+
message: `Transcription ${inputType === 'objectIds' ? 'saved' : 'completed'} with ${segments.length} segments`
|
|
87
102
|
};
|
|
88
103
|
}
|
|
89
104
|
|