Browse Source

refactor(vapi-webhook): simplify to store raw payload

- Remove all VAPI-specific interfaces and field processing
- Store entire webhook payload as JSON in 'payload' column
- Simplified table schema: id, store_id, created_at, payload
Fszontagh 4 months ago
parent
commit
1ae4c59ed0
1 changed files with 5 additions and 138 deletions
  1. 5 138
      supabase/functions/vapi-webhook/index.ts

+ 5 - 138
supabase/functions/vapi-webhook/index.ts

@@ -11,62 +11,6 @@ const corsHeaders = {
   'Access-Control-Allow-Methods': 'POST, OPTIONS',
   'Access-Control-Allow-Methods': 'POST, OPTIONS',
 }
 }
 
 
-interface VAPIMessage {
-  role: string
-  message?: string
-  content?: string
-  time: number
-  endTime?: number
-  secondsFromStart: number
-  duration?: number
-  source?: string
-  metadata?: any
-  toolCalls?: any[]
-  tool_calls?: any[]
-  toolCallId?: string
-  tool_call_id?: string
-  name?: string
-  result?: string
-}
-
-interface VAPIAnalysis {
-  summary?: string
-  successEvaluation?: string
-}
-
-interface VAPIArtifact {
-  messages: VAPIMessage[]
-  messagesOpenAIFormatted?: VAPIMessage[]
-  transcript?: string
-  recordingUrl?: string
-  stereoRecordingUrl?: string
-  pcapUrl?: string
-  logUrl?: string
-}
-
-interface VAPIWebhookPayload {
-  message: {
-    timestamp: number
-    type: string
-    analysis?: VAPIAnalysis
-    artifact?: VAPIArtifact
-    call?: {
-      id?: string
-      phoneNumberId?: string
-      customerId?: string
-      assistantId?: string
-      cost?: number
-      costBreakdown?: {
-        stt?: number
-        llm?: number
-        tts?: number
-        twilio?: number
-        total?: number
-      }
-    }
-  }
-}
-
 serve(async (req) => {
 serve(async (req) => {
   // Handle CORS preflight
   // Handle CORS preflight
   if (req.method === 'OPTIONS') {
   if (req.method === 'OPTIONS') {
@@ -142,10 +86,10 @@ serve(async (req) => {
     console.log(`Processing VAPI webhook for webshop: ${store.store_name} (${webshopId})`)
     console.log(`Processing VAPI webhook for webshop: ${store.store_name} (${webshopId})`)
 
 
     // Parse the webhook payload
     // Parse the webhook payload
-    const payload: VAPIWebhookPayload = await req.json()
+    const payload = await req.json()
     console.log('Received VAPI webhook:', JSON.stringify(payload, null, 2))
     console.log('Received VAPI webhook:', JSON.stringify(payload, null, 2))
 
 
-    // Validate payload structure
+    // Validate payload structure - only process end-of-call-report
     if (!payload.message || payload.message.type !== 'end-of-call-report') {
     if (!payload.message || payload.message.type !== 'end-of-call-report') {
       console.log('Ignoring non-end-of-call-report webhook:', payload.message?.type)
       console.log('Ignoring non-end-of-call-report webhook:', payload.message?.type)
       return new Response(
       return new Response(
@@ -154,91 +98,14 @@ serve(async (req) => {
       )
       )
     }
     }
 
 
-    const { message } = payload
-    const { timestamp, analysis, artifact, call } = message
-
-    // Extract transcript from messages
-    let transcript = artifact?.transcript || ''
-    if (!transcript && artifact?.messages) {
-      // Build transcript from messages
-      const transcriptParts = artifact.messages
-        .filter(msg => msg.role === 'user' || msg.role === 'bot' || msg.role === 'assistant')
-        .map(msg => {
-          const speaker = msg.role === 'user' ? 'Customer' : 'Assistant'
-          const text = msg.message || msg.content || ''
-          return `[${speaker}]: ${text}`
-        })
-      transcript = transcriptParts.join('\n\n')
-    }
-
-    // Calculate call duration from messages
-    let durationSeconds = 0
-    if (artifact?.messages && artifact.messages.length > 0) {
-      const lastMessage = artifact.messages[artifact.messages.length - 1]
-      durationSeconds = Math.round(lastMessage.secondsFromStart)
-    }
-
-    // Determine call outcome based on analysis
-    let callOutcome = 'pending'
-    if (analysis?.successEvaluation === 'true' || analysis?.successEvaluation === true) {
-      callOutcome = 'resolved'
-    } else if (analysis?.successEvaluation === 'false' || analysis?.successEvaluation === false) {
-      callOutcome = 'not_interested'
-    }
-
-    // Prepare call log data
+    // Prepare simplified call log data
     const callLogData = {
     const callLogData = {
-      // Primary key - generate UUID for the call log
       id: crypto.randomUUID(),
       id: crypto.randomUUID(),
-
-      // Associate with webshop
       store_id: webshopId,
       store_id: webshopId,
-
-      // VAPI-specific fields
-      vapi_call_id: call?.id || crypto.randomUUID(),
-      vapi_timestamp: timestamp,
-      messages: artifact?.messages || [],
-      analysis: analysis || {},
-
-      // Recording URLs
-      recording_url: artifact?.recordingUrl,
-      stereo_recording_url: artifact?.stereoRecordingUrl,
-      pcap_url: artifact?.pcapUrl,
-      log_url: artifact?.logUrl,
-
-      // Call metadata
-      assistant_id: call?.assistantId,
-      phone_number_id: call?.phoneNumberId,
-      customer_number: call?.customerId,
-
-      // Call status and outcome
-      status: 'completed',
-      call_outcome: callOutcome,
-      call_type: 'inbound', // VAPI calls are typically inbound
-
-      // Transcript and summary
-      transcript: transcript,
-      summary: analysis?.summary || '',
-
-      // Timing
-      started_at: new Date(timestamp).toISOString(),
-      ended_at: new Date(timestamp).toISOString(),
-      duration_seconds: durationSeconds,
-
-      // Costs
-      cost_stt: call?.costBreakdown?.stt || 0,
-      cost_llm: call?.costBreakdown?.llm || 0,
-      cost_tts: call?.costBreakdown?.tts || 0,
-      cost_twilio: call?.costBreakdown?.twilio || 0,
-      cost_total: call?.costBreakdown?.total || call?.cost || 0,
-      cost_totals: call?.costBreakdown?.total || call?.cost || 0,
-
-      // Timestamps
-      created_at: new Date().toISOString(),
-      updated_at: new Date().toISOString(),
+      payload: payload,
     }
     }
 
 
-    console.log('Inserting call log:', callLogData)
+    console.log('Inserting call log for store:', webshopId)
 
 
     // Insert call log into database
     // Insert call log into database
     const { data, error } = await supabase
     const { data, error } = await supabase