feat(rooms): add webhook for transcript completion (#578)

* feat(rooms): add webhook notifications for transcript completion

- Add webhook_url and webhook_secret fields to rooms table
- Create Celery task with 24-hour retry window using exponential backoff
- Send transcript metadata, diarized text, topics, and summaries via webhook
- Add HMAC signature verification for webhook security
- Add test endpoint POST /v1/rooms/{room_id}/webhook/test
- Update frontend with webhook configuration UI and test button
- Auto-generate webhook secret if not provided
- Trigger webhook after successful file pipeline processing for room recordings

* style: linting

* fix: remove unwanted files

* fix: update openapi gen

* fix: self-review

* docs: add comprehensive webhook documentation

- Document webhook configuration, events, and payloads
- Include transcript.completed and test event examples
- Add security considerations and best practices
- Provide example webhook receiver implementation
- Document retry policy and signature verification

* fix: remove audio_mp3_url from webhook payload

- Remove audio download URL generation from webhook
- Update documentation to reflect the change
- Keep only frontend_url for accessing transcripts

* docs: remove unwanted section

* fix: correct API method name and type imports for rooms

- Fix v1RoomsRetrieve to v1RoomsGet
- Update Room type to RoomDetails throughout frontend
- Fix type imports in useRoomList, RoomList, RoomTable, and RoomCards

* feat: add show/hide toggle for webhook secret field

- Add eye icon button to reveal/hide webhook secret when editing
- Show password dots when webhook secret is hidden
- Reset visibility state when opening/closing dialog
- Only show toggle button when editing existing room with secret

* fix: resolve event loop conflict in webhook test endpoint

- Extract webhook test logic into shared async function
- Call async function directly from FastAPI endpoint
- Keep Celery task wrapper for background processing
- Fixes RuntimeError: event loop already running

* refactor: remove unnecessary Celery task for webhook testing

- Webhook testing is synchronous and provides immediate feedback
- No need for background processing via Celery
- Keep only the async function called directly from API endpoint

* feat: improve webhook test error messages and display

- Show HTTP status code in error messages
- Parse JSON error responses to extract meaningful messages
- Improved UI layout for webhook test results
- Added colored background for success/error states
- Better text wrapping for long error messages

* docs: adjust doc

* fix: review

* fix: update attempts to match close 24h

* fix: add event_id

* fix: changed to uuid, to have new event_id when reprocess.

* style: linting

* fix: alembic revision
This commit is contained in:
2025-08-29 10:07:49 -06:00
committed by GitHub
parent 6f0c7c1a5e
commit 88ed7cfa78
14 changed files with 1102 additions and 42 deletions

View File

@@ -91,6 +91,14 @@ export const $CreateRoom = {
type: "boolean",
title: "Is Shared",
},
webhook_url: {
type: "string",
title: "Webhook Url",
},
webhook_secret: {
type: "string",
title: "Webhook Secret",
},
},
type: "object",
required: [
@@ -103,6 +111,8 @@ export const $CreateRoom = {
"recording_type",
"recording_trigger",
"is_shared",
"webhook_url",
"webhook_secret",
],
title: "CreateRoom",
} as const;
@@ -809,11 +819,11 @@ export const $Page_GetTranscriptMinimal_ = {
title: "Page[GetTranscriptMinimal]",
} as const;
export const $Page_Room_ = {
export const $Page_RoomDetails_ = {
properties: {
items: {
items: {
$ref: "#/components/schemas/Room",
$ref: "#/components/schemas/RoomDetails",
},
type: "array",
title: "Items",
@@ -869,7 +879,7 @@ export const $Page_Room_ = {
},
type: "object",
required: ["items", "page", "size"],
title: "Page[Room]",
title: "Page[RoomDetails]",
} as const;
export const $Participant = {
@@ -969,6 +979,86 @@ export const $Room = {
title: "Room",
} as const;
export const $RoomDetails = {
properties: {
id: {
type: "string",
title: "Id",
},
name: {
type: "string",
title: "Name",
},
user_id: {
type: "string",
title: "User Id",
},
created_at: {
type: "string",
format: "date-time",
title: "Created At",
},
zulip_auto_post: {
type: "boolean",
title: "Zulip Auto Post",
},
zulip_stream: {
type: "string",
title: "Zulip Stream",
},
zulip_topic: {
type: "string",
title: "Zulip Topic",
},
is_locked: {
type: "boolean",
title: "Is Locked",
},
room_mode: {
type: "string",
title: "Room Mode",
},
recording_type: {
type: "string",
title: "Recording Type",
},
recording_trigger: {
type: "string",
title: "Recording Trigger",
},
is_shared: {
type: "boolean",
title: "Is Shared",
},
webhook_url: {
type: "string",
title: "Webhook Url",
},
webhook_secret: {
type: "string",
title: "Webhook Secret",
},
},
type: "object",
required: [
"id",
"name",
"user_id",
"created_at",
"zulip_auto_post",
"zulip_stream",
"zulip_topic",
"is_locked",
"room_mode",
"recording_type",
"recording_trigger",
"is_shared",
"webhook_url",
"webhook_secret",
],
title: "RoomDetails",
} as const;
export const $RtcOffer = {
properties: {
sdp: {
@@ -1351,6 +1441,14 @@ export const $UpdateRoom = {
type: "boolean",
title: "Is Shared",
},
webhook_url: {
type: "string",
title: "Webhook Url",
},
webhook_secret: {
type: "string",
title: "Webhook Secret",
},
},
type: "object",
required: [
@@ -1363,6 +1461,8 @@ export const $UpdateRoom = {
"recording_type",
"recording_trigger",
"is_shared",
"webhook_url",
"webhook_secret",
],
title: "UpdateRoom",
} as const;
@@ -1541,6 +1641,50 @@ export const $ValidationError = {
title: "ValidationError",
} as const;
export const $WebhookTestResult = {
properties: {
success: {
type: "boolean",
title: "Success",
},
message: {
type: "string",
title: "Message",
default: "",
},
error: {
type: "string",
title: "Error",
default: "",
},
status_code: {
anyOf: [
{
type: "integer",
},
{
type: "null",
},
],
title: "Status Code",
},
response_preview: {
anyOf: [
{
type: "string",
},
{
type: "null",
},
],
title: "Response Preview",
},
},
type: "object",
required: ["success"],
title: "WebhookTestResult",
} as const;
export const $WherebyWebhookEvent = {
properties: {
apiVersion: {