70 lines
2.0 KiB
Python
70 lines
2.0 KiB
Python
"""Build durable webhook events in the same transaction as domain updates."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime
|
|
import uuid
|
|
from typing import Any
|
|
|
|
from db.models import ConversationSession, SiteSetting, WebhookDelivery
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
|
|
ANALYSIS_WEBHOOK_KEY = "analysis_webhook"
|
|
ANALYSIS_COMPLETED_EVENT = "call.analysis.completed"
|
|
|
|
|
|
def analysis_completed_payload(
|
|
conversation: ConversationSession,
|
|
result: dict[str, Any],
|
|
*,
|
|
event_id: str,
|
|
timestamp: datetime,
|
|
) -> dict[str, Any]:
|
|
return {
|
|
"id": event_id,
|
|
"event": ANALYSIS_COMPLETED_EVENT,
|
|
"timestamp": timestamp.isoformat(),
|
|
"data": {
|
|
"conversationId": conversation.id,
|
|
"assistantId": conversation.assistant_id,
|
|
"assistantName": conversation.assistant_name,
|
|
"analysis": result,
|
|
},
|
|
}
|
|
|
|
|
|
async def enqueue_analysis_completed(
|
|
session: AsyncSession,
|
|
conversation: ConversationSession,
|
|
result: dict[str, Any],
|
|
) -> WebhookDelivery | None:
|
|
setting = await session.get(SiteSetting, ANALYSIS_WEBHOOK_KEY)
|
|
values = dict(setting.value or {}) if setting else {}
|
|
secrets = dict(setting.secrets or {}) if setting else {}
|
|
url = str(values.get("url") or "")
|
|
secret = str(secrets.get("secret") or "")
|
|
if not values.get("enabled") or not url or not secret:
|
|
return None
|
|
|
|
event_id = f"evt_{uuid.uuid4().hex}"
|
|
now = datetime.now(UTC)
|
|
delivery = WebhookDelivery(
|
|
id=f"dlv_{uuid.uuid4().hex}",
|
|
event_id=event_id,
|
|
event_type=ANALYSIS_COMPLETED_EVENT,
|
|
conversation_id=conversation.id,
|
|
payload=analysis_completed_payload(
|
|
conversation,
|
|
result,
|
|
event_id=event_id,
|
|
timestamp=now,
|
|
),
|
|
url=url,
|
|
secrets={"secret": secret},
|
|
status="pending",
|
|
next_attempt_at=now,
|
|
)
|
|
session.add(delivery)
|
|
return delivery
|