Add automatic VoIP call summaries and sync progress checklist.

When a PBX webhook includes recordingUrl or transcript, queue STT and AI to create a call_result note; mark API, bulk SMS, WooCommerce, and VoIP as done and defer online payments.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-27 15:06:41 +03:30
co-authored by Cursor
parent c06c92b333
commit c5c903d4b4
13 changed files with 615 additions and 22 deletions
@@ -96,6 +96,12 @@ export class VoipCallsService {
durationSec: r.durationSec,
startedAt: r.startedAt.toISOString(),
syncedAt: r.syncedAt.toISOString(),
recordingUrl: r.recordingUrl,
transcript: r.transcript,
summary: r.summary,
summaryStatus: r.summaryStatus,
summaryNoteId: r.summaryNoteId,
summaryError: r.summaryError,
}));
}
@@ -133,6 +139,8 @@ export class VoipCallsService {
event.durationSec != null
? Math.max(0, Math.round(Number(event.durationSec)))
: null;
const recordingUrl = String(event.recordingUrl ?? '').trim() || null;
const transcript = String(event.transcript ?? '').trim() || null;
const existing = await this.prisma.voipCallLog.findUnique({
where: {
@@ -158,6 +166,24 @@ export class VoipCallsService {
activityId = createdId || null;
}
const nextRecordingUrl = recordingUrl ?? existing?.recordingUrl ?? null;
const nextTranscript = transcript ?? existing?.transcript ?? null;
const canQueueSummary =
['completed', 'answered'].includes(status) &&
Boolean(nextRecordingUrl || nextTranscript) &&
!['done', 'pending', 'processing'].includes(
existing?.summaryStatus ?? 'none',
);
const summaryPatch: Prisma.VoipCallLogUpdateInput = {};
if (recordingUrl) summaryPatch.recordingUrl = recordingUrl;
if (transcript) summaryPatch.transcript = transcript;
if (canQueueSummary) {
summaryPatch.summaryStatus = 'pending';
summaryPatch.summaryError = null;
summaryPatch.summaryNextAttemptAt = new Date();
}
if (existing) {
await this.prisma.voipCallLog.update({
where: { id: existing.id },
@@ -173,6 +199,7 @@ export class VoipCallsService {
endedAt,
rawPayload: event as unknown as Prisma.InputJsonValue,
syncedAt: new Date(),
...summaryPatch,
},
});
} else {
@@ -191,6 +218,10 @@ export class VoipCallsService {
startedAt,
endedAt,
rawPayload: event as unknown as Prisma.InputJsonValue,
recordingUrl,
transcript,
summaryStatus: canQueueSummary ? 'pending' : 'none',
summaryNextAttemptAt: canQueueSummary ? new Date() : null,
},
});
}