fireflies-api 0.5.1 → 0.6.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/cli/index.cjs +1435 -217
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +1436 -222
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +1372 -392
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +462 -3
- package/dist/index.d.ts +462 -3
- package/dist/index.js +1357 -393
- package/dist/index.js.map +1 -1
- package/dist/middleware/express.cjs +459 -16
- package/dist/middleware/express.cjs.map +1 -1
- package/dist/middleware/express.d.cts +2 -2
- package/dist/middleware/express.d.ts +2 -2
- package/dist/middleware/express.js +459 -16
- package/dist/middleware/express.js.map +1 -1
- package/dist/middleware/fastify.cjs +459 -16
- package/dist/middleware/fastify.cjs.map +1 -1
- package/dist/middleware/fastify.d.cts +2 -2
- package/dist/middleware/fastify.d.ts +2 -2
- package/dist/middleware/fastify.js +459 -16
- package/dist/middleware/fastify.js.map +1 -1
- package/dist/middleware/hono.cjs +459 -16
- package/dist/middleware/hono.cjs.map +1 -1
- package/dist/middleware/hono.d.cts +2 -2
- package/dist/middleware/hono.d.ts +2 -2
- package/dist/middleware/hono.js +459 -16
- package/dist/middleware/hono.js.map +1 -1
- package/dist/templates/digest/compact.md +8 -0
- package/dist/templates/digest/default.md +44 -0
- package/dist/templates/digest/executive.md +22 -0
- package/dist/{types-CaHcwnKw.d.ts → types-BMzVSd6w.d.ts} +1 -1
- package/dist/{types-BX-3JcRI.d.cts → types-BeXRmVD7.d.cts} +1 -1
- package/dist/{types-DIPZmUl3.d.ts → types-D2XsCR5R.d.ts} +120 -1
- package/dist/{types-C_XxdRd1.d.cts → types-zVGqyFzP.d.cts} +120 -1
- package/package.json +6 -1
|
@@ -291,8 +291,8 @@ async function retry(fn, options) {
|
|
|
291
291
|
if (attempt >= maxRetries || !shouldRetry(error, attempt)) {
|
|
292
292
|
throw error;
|
|
293
293
|
}
|
|
294
|
-
const
|
|
295
|
-
await sleep(
|
|
294
|
+
const delay2 = calculateDelay(error, attempt, baseDelay, maxDelay);
|
|
295
|
+
await sleep(delay2);
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
298
|
throw lastError;
|
|
@@ -441,9 +441,9 @@ var GraphQLClient = class {
|
|
|
441
441
|
if (!this.rateLimitTracker || !this.rateLimitConfig?.throttle) {
|
|
442
442
|
return;
|
|
443
443
|
}
|
|
444
|
-
const
|
|
445
|
-
if (
|
|
446
|
-
await sleep2(
|
|
444
|
+
const delay2 = this.rateLimitTracker.getThrottleDelay(this.rateLimitConfig.throttle);
|
|
445
|
+
if (delay2 > 0) {
|
|
446
|
+
await sleep2(delay2);
|
|
447
447
|
}
|
|
448
448
|
}
|
|
449
449
|
/**
|
|
@@ -1097,6 +1097,46 @@ function buildAggregatedResult(items, transcriptsProcessed, transcriptsWithItems
|
|
|
1097
1097
|
};
|
|
1098
1098
|
}
|
|
1099
1099
|
|
|
1100
|
+
// src/helpers/batch.ts
|
|
1101
|
+
async function* batch(items, processor, options = {}) {
|
|
1102
|
+
const { delayMs = 100, handleRateLimit = true, maxRateLimitRetries = 3 } = options;
|
|
1103
|
+
let isFirst = true;
|
|
1104
|
+
for await (const item of items) {
|
|
1105
|
+
if (!isFirst && delayMs > 0) {
|
|
1106
|
+
await delay(delayMs);
|
|
1107
|
+
}
|
|
1108
|
+
isFirst = false;
|
|
1109
|
+
yield await processWithRetry(item, processor, {
|
|
1110
|
+
handleRateLimit,
|
|
1111
|
+
maxRateLimitRetries
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
async function processWithRetry(item, processor, options) {
|
|
1116
|
+
const { handleRateLimit, maxRateLimitRetries } = options;
|
|
1117
|
+
let retries = 0;
|
|
1118
|
+
while (true) {
|
|
1119
|
+
try {
|
|
1120
|
+
const result = await processor(item);
|
|
1121
|
+
return { item, result };
|
|
1122
|
+
} catch (err) {
|
|
1123
|
+
if (handleRateLimit && err instanceof RateLimitError && retries < maxRateLimitRetries) {
|
|
1124
|
+
const waitTime = err.retryAfter ?? 1e3;
|
|
1125
|
+
await delay(waitTime);
|
|
1126
|
+
retries++;
|
|
1127
|
+
continue;
|
|
1128
|
+
}
|
|
1129
|
+
return {
|
|
1130
|
+
item,
|
|
1131
|
+
error: err instanceof Error ? err : new Error(String(err))
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
function delay(ms) {
|
|
1137
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1100
1140
|
// src/helpers/domain-utils.ts
|
|
1101
1141
|
function extractDomain(email) {
|
|
1102
1142
|
const atIndex = email.indexOf("@");
|
|
@@ -1112,6 +1152,332 @@ function hasExternalParticipants(participants, internalDomain) {
|
|
|
1112
1152
|
});
|
|
1113
1153
|
}
|
|
1114
1154
|
|
|
1155
|
+
// src/helpers/markdown.ts
|
|
1156
|
+
var DEFAULT_OPTIONS2 = {
|
|
1157
|
+
includeMetadata: true,
|
|
1158
|
+
includeSummary: true,
|
|
1159
|
+
includeActionItems: true,
|
|
1160
|
+
actionItemFormat: "checkbox",
|
|
1161
|
+
includeTimestamps: false,
|
|
1162
|
+
speakerFormat: "bold",
|
|
1163
|
+
groupBySpeaker: true
|
|
1164
|
+
};
|
|
1165
|
+
async function transcriptToMarkdown(transcript, options = {}) {
|
|
1166
|
+
const opts = { ...DEFAULT_OPTIONS2, ...options };
|
|
1167
|
+
const sections = [];
|
|
1168
|
+
if (opts.includeMetadata) {
|
|
1169
|
+
sections.push(formatMetadata(transcript));
|
|
1170
|
+
}
|
|
1171
|
+
if (opts.includeSummary && transcript.summary) {
|
|
1172
|
+
sections.push(formatSummary(transcript.summary, opts));
|
|
1173
|
+
}
|
|
1174
|
+
if (transcript.sentences && transcript.sentences.length > 0) {
|
|
1175
|
+
sections.push(formatTranscript(transcript.sentences, opts));
|
|
1176
|
+
}
|
|
1177
|
+
const content = sections.join("\n\n---\n\n");
|
|
1178
|
+
await writeIfOutputPath(content, options.outputPath);
|
|
1179
|
+
return content;
|
|
1180
|
+
}
|
|
1181
|
+
function formatMetadata(transcript) {
|
|
1182
|
+
const lines = [`# ${transcript.title || "Untitled Meeting"}`];
|
|
1183
|
+
if (transcript.dateString) {
|
|
1184
|
+
lines.push(`
|
|
1185
|
+
**Date:** ${formatDate(transcript.dateString)}`);
|
|
1186
|
+
}
|
|
1187
|
+
const duration = calculateDuration(transcript);
|
|
1188
|
+
if (duration > 0) {
|
|
1189
|
+
lines.push(`**Duration:** ${formatDuration(duration)}`);
|
|
1190
|
+
}
|
|
1191
|
+
const participants = getParticipantNames(transcript);
|
|
1192
|
+
if (participants.length > 0) {
|
|
1193
|
+
lines.push(`**Participants:** ${participants.join(", ")}`);
|
|
1194
|
+
}
|
|
1195
|
+
return lines.join("\n");
|
|
1196
|
+
}
|
|
1197
|
+
function calculateDuration(transcript) {
|
|
1198
|
+
if (transcript.sentences && transcript.sentences.length > 0) {
|
|
1199
|
+
const lastSentence = transcript.sentences[transcript.sentences.length - 1];
|
|
1200
|
+
if (lastSentence) {
|
|
1201
|
+
return parseFloat(lastSentence.end_time);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
return transcript.duration || 0;
|
|
1205
|
+
}
|
|
1206
|
+
function formatSummary(summary, opts) {
|
|
1207
|
+
const sections = ["## Summary"];
|
|
1208
|
+
if (summary.gist) {
|
|
1209
|
+
sections.push("", summary.gist);
|
|
1210
|
+
}
|
|
1211
|
+
if (summary.bullet_gist) {
|
|
1212
|
+
const bullets = parseMultilineField(summary.bullet_gist);
|
|
1213
|
+
if (bullets.length > 0) {
|
|
1214
|
+
sections.push("", "### Key Points");
|
|
1215
|
+
sections.push(bullets.map((p) => `- ${p}`).join("\n"));
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
if (opts.includeActionItems && summary.action_items) {
|
|
1219
|
+
const items = parseMultilineField(summary.action_items);
|
|
1220
|
+
if (items.length > 0) {
|
|
1221
|
+
sections.push("", "### Action Items");
|
|
1222
|
+
const prefix = opts.actionItemFormat === "checkbox" ? "- [ ] " : "- ";
|
|
1223
|
+
sections.push(items.map((a) => `${prefix}${a}`).join("\n"));
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
return sections.join("\n");
|
|
1227
|
+
}
|
|
1228
|
+
function formatTranscript(sentences, opts) {
|
|
1229
|
+
const lines = ["## Transcript"];
|
|
1230
|
+
if (opts.groupBySpeaker) {
|
|
1231
|
+
const groups = groupSentencesBySpeaker(sentences);
|
|
1232
|
+
for (const group of groups) {
|
|
1233
|
+
lines.push("", formatSpeakerGroup(group, opts));
|
|
1234
|
+
}
|
|
1235
|
+
} else {
|
|
1236
|
+
for (const sentence of sentences) {
|
|
1237
|
+
lines.push("", formatSentence(sentence, opts));
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
return lines.join("\n");
|
|
1241
|
+
}
|
|
1242
|
+
function groupSentencesBySpeaker(sentences) {
|
|
1243
|
+
const groups = [];
|
|
1244
|
+
let current = null;
|
|
1245
|
+
for (const sentence of sentences) {
|
|
1246
|
+
if (!current || current.speakerName !== sentence.speaker_name) {
|
|
1247
|
+
current = { speakerName: sentence.speaker_name, sentences: [] };
|
|
1248
|
+
groups.push(current);
|
|
1249
|
+
}
|
|
1250
|
+
current.sentences.push(sentence);
|
|
1251
|
+
}
|
|
1252
|
+
return groups;
|
|
1253
|
+
}
|
|
1254
|
+
function formatSpeakerGroup(group, opts) {
|
|
1255
|
+
const speaker = formatSpeakerName(group.speakerName, opts.speakerFormat);
|
|
1256
|
+
const text = group.sentences.map((s) => s.text).join(" ");
|
|
1257
|
+
const firstSentence = group.sentences[0];
|
|
1258
|
+
if (opts.includeTimestamps && firstSentence) {
|
|
1259
|
+
const timestamp = formatTimestamp(firstSentence.start_time);
|
|
1260
|
+
return `${timestamp} ${speaker} ${text}`;
|
|
1261
|
+
}
|
|
1262
|
+
return `${speaker} ${text}`;
|
|
1263
|
+
}
|
|
1264
|
+
function formatSentence(sentence, opts) {
|
|
1265
|
+
const speaker = formatSpeakerName(sentence.speaker_name, opts.speakerFormat);
|
|
1266
|
+
if (opts.includeTimestamps) {
|
|
1267
|
+
const timestamp = formatTimestamp(sentence.start_time);
|
|
1268
|
+
return `${timestamp} ${speaker} ${sentence.text}`;
|
|
1269
|
+
}
|
|
1270
|
+
return `${speaker} ${sentence.text}`;
|
|
1271
|
+
}
|
|
1272
|
+
function formatSpeakerName(name, format) {
|
|
1273
|
+
switch (format) {
|
|
1274
|
+
case "bold":
|
|
1275
|
+
return `**${name}:**`;
|
|
1276
|
+
case "plain":
|
|
1277
|
+
return `${name}:`;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
function formatTimestamp(startTime) {
|
|
1281
|
+
const seconds = parseFloat(startTime);
|
|
1282
|
+
const mins = Math.floor(seconds / 60);
|
|
1283
|
+
const secs = Math.floor(seconds % 60);
|
|
1284
|
+
return `[${mins}:${secs.toString().padStart(2, "0")}]`;
|
|
1285
|
+
}
|
|
1286
|
+
function formatDuration(seconds) {
|
|
1287
|
+
const hours = Math.floor(seconds / 3600);
|
|
1288
|
+
const mins = Math.floor(seconds % 3600 / 60);
|
|
1289
|
+
if (hours > 0) {
|
|
1290
|
+
return `${hours}h ${mins}m`;
|
|
1291
|
+
}
|
|
1292
|
+
return `${mins} minutes`;
|
|
1293
|
+
}
|
|
1294
|
+
function formatDate(isoString) {
|
|
1295
|
+
return new Date(isoString).toLocaleDateString("en-US", {
|
|
1296
|
+
weekday: "long",
|
|
1297
|
+
year: "numeric",
|
|
1298
|
+
month: "long",
|
|
1299
|
+
day: "numeric"
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
function getParticipantNames(transcript) {
|
|
1303
|
+
if (transcript.meeting_attendees?.length) {
|
|
1304
|
+
return transcript.meeting_attendees.map((a) => a.displayName || a.name || a.email).filter(Boolean);
|
|
1305
|
+
}
|
|
1306
|
+
return transcript.speakers?.map((s) => s.name) || [];
|
|
1307
|
+
}
|
|
1308
|
+
function parseMultilineField(value) {
|
|
1309
|
+
return value.split(/\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
1310
|
+
}
|
|
1311
|
+
async function writeIfOutputPath(content, outputPath) {
|
|
1312
|
+
if (outputPath) {
|
|
1313
|
+
const { writeFile } = await import('fs/promises');
|
|
1314
|
+
await writeFile(outputPath, content, "utf-8");
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
// src/helpers/export-formats.ts
|
|
1319
|
+
var DEFAULT_TEXT_OPTIONS = {
|
|
1320
|
+
includeTimestamps: false,
|
|
1321
|
+
includeMetadata: true
|
|
1322
|
+
};
|
|
1323
|
+
var DEFAULT_CSV_OPTIONS = {
|
|
1324
|
+
includeHeader: true,
|
|
1325
|
+
delimiter: ","
|
|
1326
|
+
};
|
|
1327
|
+
function transcriptToText(transcript, options = {}) {
|
|
1328
|
+
const opts = { ...DEFAULT_TEXT_OPTIONS, ...options };
|
|
1329
|
+
const sections = [];
|
|
1330
|
+
if (opts.includeMetadata) {
|
|
1331
|
+
sections.push(formatTextMetadata(transcript));
|
|
1332
|
+
}
|
|
1333
|
+
if (transcript.sentences && transcript.sentences.length > 0) {
|
|
1334
|
+
sections.push(formatTextTranscript(transcript.sentences, opts));
|
|
1335
|
+
}
|
|
1336
|
+
return sections.join("\n\n");
|
|
1337
|
+
}
|
|
1338
|
+
function transcriptToCsv(transcript, options = {}) {
|
|
1339
|
+
const opts = { ...DEFAULT_CSV_OPTIONS, ...options };
|
|
1340
|
+
const d = opts.delimiter;
|
|
1341
|
+
const lines = [];
|
|
1342
|
+
if (opts.includeHeader) {
|
|
1343
|
+
lines.push(`timestamp${d}speaker${d}text${d}is_question${d}is_task`);
|
|
1344
|
+
}
|
|
1345
|
+
for (const sentence of transcript.sentences) {
|
|
1346
|
+
const isQuestion = Boolean(sentence.ai_filters?.question);
|
|
1347
|
+
const isTask = Boolean(sentence.ai_filters?.task);
|
|
1348
|
+
const row = [
|
|
1349
|
+
sentence.start_time,
|
|
1350
|
+
escapeCsvField(sentence.speaker_name, d),
|
|
1351
|
+
escapeCsvField(sentence.text, d),
|
|
1352
|
+
String(isQuestion),
|
|
1353
|
+
String(isTask)
|
|
1354
|
+
];
|
|
1355
|
+
lines.push(row.join(d));
|
|
1356
|
+
}
|
|
1357
|
+
return lines.join("\n");
|
|
1358
|
+
}
|
|
1359
|
+
function sanitizeFilename(title) {
|
|
1360
|
+
if (!title.trim()) {
|
|
1361
|
+
return "untitled";
|
|
1362
|
+
}
|
|
1363
|
+
return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 100);
|
|
1364
|
+
}
|
|
1365
|
+
function generateExportFilename(transcript, extension) {
|
|
1366
|
+
const sanitizedTitle = sanitizeFilename(transcript.title);
|
|
1367
|
+
let datePrefix = "";
|
|
1368
|
+
if (transcript.dateString) {
|
|
1369
|
+
try {
|
|
1370
|
+
const date = new Date(transcript.dateString);
|
|
1371
|
+
if (!Number.isNaN(date.getTime())) {
|
|
1372
|
+
datePrefix = `${date.toISOString().slice(0, 10)}-`;
|
|
1373
|
+
}
|
|
1374
|
+
} catch {
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
return `${datePrefix}${sanitizedTitle}.${extension}`;
|
|
1378
|
+
}
|
|
1379
|
+
async function exportTranscript(transcript, format) {
|
|
1380
|
+
switch (format) {
|
|
1381
|
+
case "markdown":
|
|
1382
|
+
return transcriptToMarkdown(transcript);
|
|
1383
|
+
case "json":
|
|
1384
|
+
return JSON.stringify(transcript, null, 2);
|
|
1385
|
+
case "txt":
|
|
1386
|
+
return transcriptToText(transcript);
|
|
1387
|
+
case "csv":
|
|
1388
|
+
return transcriptToCsv(transcript);
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
async function createZipArchive(files) {
|
|
1392
|
+
const archiver = await import('archiver');
|
|
1393
|
+
const { Writable } = await import('stream');
|
|
1394
|
+
return new Promise((resolve, reject) => {
|
|
1395
|
+
const chunks = [];
|
|
1396
|
+
const archive = archiver.default("zip", { zlib: { level: 9 } });
|
|
1397
|
+
const writable = new Writable({
|
|
1398
|
+
write(chunk, _encoding, callback) {
|
|
1399
|
+
chunks.push(chunk);
|
|
1400
|
+
callback();
|
|
1401
|
+
}
|
|
1402
|
+
});
|
|
1403
|
+
writable.on("finish", () => {
|
|
1404
|
+
resolve(Buffer.concat(chunks));
|
|
1405
|
+
});
|
|
1406
|
+
archive.on("error", reject);
|
|
1407
|
+
archive.pipe(writable);
|
|
1408
|
+
for (const file of files) {
|
|
1409
|
+
archive.append(file.content, { name: file.filename });
|
|
1410
|
+
}
|
|
1411
|
+
archive.finalize();
|
|
1412
|
+
});
|
|
1413
|
+
}
|
|
1414
|
+
function formatTextMetadata(transcript) {
|
|
1415
|
+
const lines = [];
|
|
1416
|
+
lines.push(transcript.title || "Untitled Meeting");
|
|
1417
|
+
if (transcript.dateString) {
|
|
1418
|
+
lines.push(`Date: ${formatDate2(transcript.dateString)}`);
|
|
1419
|
+
}
|
|
1420
|
+
const participants = getParticipantNames2(transcript);
|
|
1421
|
+
if (participants.length > 0) {
|
|
1422
|
+
lines.push(`Participants: ${participants.join(", ")}`);
|
|
1423
|
+
}
|
|
1424
|
+
return lines.join("\n");
|
|
1425
|
+
}
|
|
1426
|
+
function formatTextTranscript(sentences, opts) {
|
|
1427
|
+
const groups = groupSentencesBySpeaker2(sentences);
|
|
1428
|
+
const lines = [];
|
|
1429
|
+
for (const group of groups) {
|
|
1430
|
+
const text = group.sentences.map((s) => s.text).join(" ");
|
|
1431
|
+
const speaker = group.speakerName || "Unknown";
|
|
1432
|
+
const firstSentence = group.sentences[0];
|
|
1433
|
+
if (opts.includeTimestamps && firstSentence) {
|
|
1434
|
+
const timestamp = formatTimestamp2(firstSentence.start_time);
|
|
1435
|
+
lines.push(`${timestamp} ${speaker}: ${text}`);
|
|
1436
|
+
} else {
|
|
1437
|
+
lines.push(`${speaker}: ${text}`);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
return lines.join("\n");
|
|
1441
|
+
}
|
|
1442
|
+
function groupSentencesBySpeaker2(sentences) {
|
|
1443
|
+
const groups = [];
|
|
1444
|
+
let current = null;
|
|
1445
|
+
for (const sentence of sentences) {
|
|
1446
|
+
if (!current || current.speakerName !== sentence.speaker_name) {
|
|
1447
|
+
current = { speakerName: sentence.speaker_name, sentences: [] };
|
|
1448
|
+
groups.push(current);
|
|
1449
|
+
}
|
|
1450
|
+
current.sentences.push(sentence);
|
|
1451
|
+
}
|
|
1452
|
+
return groups;
|
|
1453
|
+
}
|
|
1454
|
+
function formatTimestamp2(startTime) {
|
|
1455
|
+
const seconds = parseFloat(startTime);
|
|
1456
|
+
const mins = Math.floor(seconds / 60);
|
|
1457
|
+
const secs = Math.floor(seconds % 60);
|
|
1458
|
+
return `[${mins}:${secs.toString().padStart(2, "0")}]`;
|
|
1459
|
+
}
|
|
1460
|
+
function formatDate2(isoString) {
|
|
1461
|
+
return new Date(isoString).toLocaleDateString("en-US", {
|
|
1462
|
+
weekday: "long",
|
|
1463
|
+
year: "numeric",
|
|
1464
|
+
month: "long",
|
|
1465
|
+
day: "numeric"
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
function getParticipantNames2(transcript) {
|
|
1469
|
+
if (transcript.meeting_attendees?.length) {
|
|
1470
|
+
return transcript.meeting_attendees.map((a) => a.displayName || a.name || a.email).filter(Boolean);
|
|
1471
|
+
}
|
|
1472
|
+
return transcript.speakers?.map((s) => s.name) || [];
|
|
1473
|
+
}
|
|
1474
|
+
function escapeCsvField(field, delimiter) {
|
|
1475
|
+
if (field.includes('"') || field.includes(delimiter) || field.includes("\n")) {
|
|
1476
|
+
return `"${field.replace(/"/g, '""')}"`;
|
|
1477
|
+
}
|
|
1478
|
+
return field;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1115
1481
|
// src/helpers/meeting-insights.ts
|
|
1116
1482
|
function analyzeMeetings(transcripts, options = {}) {
|
|
1117
1483
|
const { speakers, groupBy, topSpeakersCount = 10, topParticipantsCount = 10 } = options;
|
|
@@ -1585,6 +1951,21 @@ var TRANSCRIPT_LIST_FIELDS = `
|
|
|
1585
1951
|
summary_status
|
|
1586
1952
|
}
|
|
1587
1953
|
`;
|
|
1954
|
+
function buildListFields(params) {
|
|
1955
|
+
const includeSentences = params?.includeSentences === true;
|
|
1956
|
+
const includeSummary = params?.includeSummary === true;
|
|
1957
|
+
if (!includeSentences && !includeSummary) {
|
|
1958
|
+
return TRANSCRIPT_LIST_FIELDS;
|
|
1959
|
+
}
|
|
1960
|
+
let fields = TRANSCRIPT_BASE_FIELDS;
|
|
1961
|
+
if (includeSentences) {
|
|
1962
|
+
fields += SENTENCES_FIELDS;
|
|
1963
|
+
}
|
|
1964
|
+
if (includeSummary) {
|
|
1965
|
+
fields += SUMMARY_FIELDS;
|
|
1966
|
+
}
|
|
1967
|
+
return fields;
|
|
1968
|
+
}
|
|
1588
1969
|
function createTranscriptsAPI(client) {
|
|
1589
1970
|
return {
|
|
1590
1971
|
async get(id, params) {
|
|
@@ -1600,6 +1981,7 @@ function createTranscriptsAPI(client) {
|
|
|
1600
1981
|
return normalizeTranscript(data.transcript);
|
|
1601
1982
|
},
|
|
1602
1983
|
async list(params) {
|
|
1984
|
+
const fields = buildListFields(params);
|
|
1603
1985
|
const query = `
|
|
1604
1986
|
query ListTranscripts(
|
|
1605
1987
|
$keyword: String
|
|
@@ -1637,13 +2019,23 @@ function createTranscriptsAPI(client) {
|
|
|
1637
2019
|
participant_email: $participant_email
|
|
1638
2020
|
date: $date
|
|
1639
2021
|
) {
|
|
1640
|
-
${
|
|
2022
|
+
${fields}
|
|
1641
2023
|
}
|
|
1642
2024
|
}
|
|
1643
2025
|
`;
|
|
2026
|
+
let internalDomain;
|
|
2027
|
+
if (params?.external) {
|
|
2028
|
+
const userQuery = "query { user { email } }";
|
|
2029
|
+
const userData = await client.execute(userQuery);
|
|
2030
|
+
internalDomain = extractDomain(userData.user.email);
|
|
2031
|
+
}
|
|
1644
2032
|
const variables = buildListVariables(params);
|
|
1645
2033
|
const data = await client.execute(query, variables);
|
|
1646
|
-
|
|
2034
|
+
let results = data.transcripts.map(normalizeTranscript);
|
|
2035
|
+
if (internalDomain) {
|
|
2036
|
+
results = results.filter((t) => hasExternalParticipants(t.participants, internalDomain));
|
|
2037
|
+
}
|
|
2038
|
+
return results;
|
|
1647
2039
|
},
|
|
1648
2040
|
async getSummary(id) {
|
|
1649
2041
|
const query = `
|
|
@@ -1690,9 +2082,10 @@ function createTranscriptsAPI(client) {
|
|
|
1690
2082
|
} = params;
|
|
1691
2083
|
const transcripts = [];
|
|
1692
2084
|
for await (const t of this.listAll({
|
|
2085
|
+
...listParams,
|
|
1693
2086
|
keyword: query,
|
|
1694
2087
|
scope,
|
|
1695
|
-
|
|
2088
|
+
includeSentences: true
|
|
1696
2089
|
})) {
|
|
1697
2090
|
transcripts.push(t);
|
|
1698
2091
|
if (limit && transcripts.length >= limit) break;
|
|
@@ -1700,8 +2093,7 @@ function createTranscriptsAPI(client) {
|
|
|
1700
2093
|
const allMatches = [];
|
|
1701
2094
|
let transcriptsWithMatches = 0;
|
|
1702
2095
|
for (const t of transcripts) {
|
|
1703
|
-
const
|
|
1704
|
-
const matches = searchTranscript(full, {
|
|
2096
|
+
const matches = searchTranscript(t, {
|
|
1705
2097
|
query,
|
|
1706
2098
|
caseSensitive,
|
|
1707
2099
|
speakers,
|
|
@@ -1753,13 +2145,13 @@ function createTranscriptsAPI(client) {
|
|
|
1753
2145
|
organizers,
|
|
1754
2146
|
participants,
|
|
1755
2147
|
user_id,
|
|
1756
|
-
channel_id
|
|
2148
|
+
channel_id,
|
|
2149
|
+
includeSentences: true
|
|
1757
2150
|
})) {
|
|
1758
2151
|
if (internalDomain && !hasExternalParticipants(t.participants, internalDomain)) {
|
|
1759
2152
|
continue;
|
|
1760
2153
|
}
|
|
1761
|
-
|
|
1762
|
-
transcripts.push(full);
|
|
2154
|
+
transcripts.push(t);
|
|
1763
2155
|
if (limit && transcripts.length >= limit) break;
|
|
1764
2156
|
}
|
|
1765
2157
|
return analyzeMeetings(transcripts, {
|
|
@@ -1777,13 +2169,20 @@ function createTranscriptsAPI(client) {
|
|
|
1777
2169
|
toDate,
|
|
1778
2170
|
mine,
|
|
1779
2171
|
organizers,
|
|
1780
|
-
participants
|
|
2172
|
+
participants,
|
|
2173
|
+
includeSummary: true
|
|
1781
2174
|
})) {
|
|
1782
|
-
|
|
1783
|
-
transcripts.push(full);
|
|
2175
|
+
transcripts.push(t);
|
|
1784
2176
|
if (limit && transcripts.length >= limit) break;
|
|
1785
2177
|
}
|
|
1786
2178
|
return aggregateActionItems(transcripts, {}, filterOptions);
|
|
2179
|
+
},
|
|
2180
|
+
async bulkExport(params = {}) {
|
|
2181
|
+
const { format = "markdown", asZip = false, onProgress } = params;
|
|
2182
|
+
const transcriptIds = await collectTranscriptIds(client, this, params);
|
|
2183
|
+
const files = await convertTranscripts(this, transcriptIds, format, onProgress);
|
|
2184
|
+
const zip = asZip ? await createZipArchive(files) : void 0;
|
|
2185
|
+
return { files, zip, format, totalExported: files.length };
|
|
1787
2186
|
}
|
|
1788
2187
|
};
|
|
1789
2188
|
}
|
|
@@ -1862,6 +2261,50 @@ function buildListVariables(params) {
|
|
|
1862
2261
|
date: params.date
|
|
1863
2262
|
};
|
|
1864
2263
|
}
|
|
2264
|
+
async function collectTranscriptIds(client, api, params) {
|
|
2265
|
+
const { ids, fromDate, toDate, mine, organizers, participants, external, limit } = params;
|
|
2266
|
+
if (ids?.length) {
|
|
2267
|
+
return ids;
|
|
2268
|
+
}
|
|
2269
|
+
let internalDomain;
|
|
2270
|
+
if (external) {
|
|
2271
|
+
const userQuery = "query { user { email } }";
|
|
2272
|
+
const userData = await client.execute(userQuery);
|
|
2273
|
+
internalDomain = extractDomain(userData.user.email);
|
|
2274
|
+
}
|
|
2275
|
+
const result = [];
|
|
2276
|
+
for await (const t of api.listAll({ fromDate, toDate, mine, organizers, participants })) {
|
|
2277
|
+
if (internalDomain && !hasExternalParticipants(t.participants, internalDomain)) {
|
|
2278
|
+
continue;
|
|
2279
|
+
}
|
|
2280
|
+
result.push(t.id);
|
|
2281
|
+
if (limit && result.length >= limit) break;
|
|
2282
|
+
}
|
|
2283
|
+
return result;
|
|
2284
|
+
}
|
|
2285
|
+
async function convertTranscripts(api, transcriptIds, format, onProgress) {
|
|
2286
|
+
const files = [];
|
|
2287
|
+
const extension = format === "markdown" ? "md" : format;
|
|
2288
|
+
let completed = 0;
|
|
2289
|
+
const total = transcriptIds.length;
|
|
2290
|
+
for await (const result of batch(
|
|
2291
|
+
transcriptIds,
|
|
2292
|
+
async (id) => {
|
|
2293
|
+
const transcript = await api.get(id);
|
|
2294
|
+
const content = await exportTranscript(transcript, format);
|
|
2295
|
+
const filename = generateExportFilename(transcript, extension);
|
|
2296
|
+
return { id, title: transcript.title, filename, content };
|
|
2297
|
+
},
|
|
2298
|
+
{ delayMs: 100 }
|
|
2299
|
+
)) {
|
|
2300
|
+
if (!result.error) {
|
|
2301
|
+
files.push(result.result);
|
|
2302
|
+
}
|
|
2303
|
+
completed++;
|
|
2304
|
+
onProgress?.(completed, total);
|
|
2305
|
+
}
|
|
2306
|
+
return files;
|
|
2307
|
+
}
|
|
1865
2308
|
|
|
1866
2309
|
// src/graphql/queries/users.ts
|
|
1867
2310
|
var USER_FIELDS = `
|