telephony.incoming / web.incoming

Kui sissetulev telefonikõne jõuab numbrile ilma määratud häälagendita või veebividina seanss käivitub avalikul võtmel režiimis mode="webhook", saadab ThunderPhone sinu pärand-webhooki URL-ile blokeeriva päringu telephony.incoming / web.incoming ja ootab konfiguratsioonivastust kuni 10 sekundit. Kasuta seda vahetust, et valida iga kõne jaoks dünaamiliselt viip, hääl ja tööriistad — täieliku mustri leiad dünaamilise kõnekonfiguratsiooni juhendist.

Blokeerival vahetusel puudub varuvariant: kui sinu töötleja tagastab muu kui 2xx olekukoodi, aegub või tagastab valideerimist mitte läbiva konfiguratsiooni, lükatakse kõne tagasi (telefonikõne ei ühendata; vidina seansipäring nurjub koodiga 502/422). Vasta kiiresti — helistaja kuuleb samal ajal kutsungitooni.

Päringu sisu

Telefonikõnede puhul (telephony.incoming):

{
  "type": "telephony.incoming",
  "data": {
    "call_id":     987654321,
    "from_number": "+14155550199",
    "to_number":   "+15551234567"
  }
}
VäliTüüpKirjeldus
call_idintegerKõne ID — püsib sama kõigi selle kõne sündmuste puhul
from_numberstringHelistaja E.164 number
to_numberstringE.164 sihtnumber (üks sinu ThunderPhone'i numbritest)

Veebividina seansside puhul (web.incoming) tuvastab data telefoninumbrite asemel vidinat manustava lehe:

{
  "type": "web.incoming",
  "data": {
    "call_id": 987654322,
    "origin_domain": "https://example.com",
    "publishable_key_prefix": "pk_live_a1b2"
  }
}
VäliTüüpKirjeldus
call_idintegerKõne ID
origin_domainstringVidinat majutava lehe päritolu
publishable_key_prefixstringSeansi avanud avaliku võtme esimesed märgid
language, primary_languagestringOlemas, kui veebiseanss taotles keele ülekirjutamist
voicestringOlemas, kui veebiseanss taotles hääle ülekirjutamist
website_contextstringOlemas, kui vidin edastas seansipõhise lehekonteksti

Vastuse skeem

Tagasta JSON-objekt, mis kirjeldab selle kõne häälagendi konfiguratsiooni. prompt ja voice on kohustuslikud; kõik muu on valikuline.

{
  "prompt":  "You are a helpful booking assistant for Acme Restaurant.",
  "voice":   "john",
  "product": "spark",
  "background_track": null,
  "tools":   []
}
VäliTüüpKohustuslikKirjeldus
promptstringjahHäälagenti juhtiv süsteemiprompt
voicestringjahHääle ID asukohast GET /v1/voices, nt john. Aliaseks aktsepteeritakse voice_name. Tundmatud hääled ei läbi valideerimist ja kõne lükatakse tagasi
productstringeiVaikeväärtus on spark. Lubatud: spark, bolt, storm-base, storm-base-with-ack, storm-extra, storm-extra-with-ack
thinking_levelstringeiminimal, base (vaikeväärtus) või extra. Stormi toodete puhul kirjutatakse üle: storm-extra* sunnib kasutama extra, muud storm-* sunnivad kasutama base
audio_context_modestringeifull (vaikeväärtus) või reduced
watchdog_enabledbooleaneiLuba selle kõne järelevalve. Vaikeväärtus on false
storm_feedback_modestringeinone, acknowledgement (vaikeväärtus) või tick
languagestringeiLühivorm väärtusele primary_language
primary_languagestringeiKeelekood, normaliseeritud (vaikeväärtus en). Lahendamatud koodid lükkavad kõne tagasi
has_additional_languagesbooleaneiVaikeväärtus on false
additional_languagesarray of stringeiLisakeeled, millele häälagent võib ümber lülituda
background_trackstring | nulleiTaustaheli ID või null
acknowledgement_prompt_modestringeiauto (vaikeväärtus) või manual (Storm-with-ack toodetele)
acknowledgement_promptstringeiKasutatakse, kui acknowledgement_prompt_mode="manual"
silence_interval_secondsinteger | nullei5–120. Helistaja vaikuse sekundid enne kontrollpäringut
silence_max_checkinsinteger | nullei1–10
silence_checkins_enabledbooleaneiVaikeväärtus on true
connect_tone_enabledbooleaneiVaikeväärtus on false
voicemail_actionstringeiprompt (vaikeväärtus), hangup või message
voicemail_messagestringeiKasutatakse, kui voicemail_action="message"
agent_namestringeiKuvanimi, mis edastatakse töölaudadele ja vidinale
org_namestringeiOrganisatsiooni kuvanimi häälagendi persoona jaoks
toolsarrayeiSisemised funktsioonitööriistade skeemid (vt Funktsioonitööriistad)
call_idintegereiPäringu kõne ID valikuline kaja; eiratakse

Kuna prompt ja voice on kohustuslikud, lükkab {} või mis tahes valideerimist mitteläbiv vastus kõne tagasi koodiga 422 — sellel teel ei ole staatilise häälagendi varuvarianti (veebikonksu režiimis oleval numbril või võtmel pole määratud häälagenti).


Vastuse suuruse piirang


Näidiskäitleja

import hashlib
import hmac
import json
import os

from fastapi import FastAPI, HTTPException, Request

app = FastAPI()
WEBHOOK_SECRET = os.environ["THUNDERPHONE_WEBHOOK_SECRET"]

def verify(body: bytes, signature: str) -> bool:
    expected = hmac.new(WEBHOOK_SECRET.encode(), body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature or "")

@app.post("/thunderphone-webhook")
async def webhook(request: Request):
    body = await request.body()
    if not verify(body, request.headers.get("X-ThunderPhone-Signature", "")):
        raise HTTPException(status_code=401)

    event = json.loads(body)
    if event["type"] == "telephony.incoming":
        caller = event["data"]["from_number"]
        prompt = (
            "Greet the caller as a San Francisco local…"
            if caller.startswith("+1415")
            else "You are a friendly customer support agent…"
        )
        return {
            "prompt": prompt,
            "voice": "john",
            "product": "spark",
        }
    if event["type"] == "web.incoming":
        return {
            "prompt": "You are the website's helpful voice assistant…",
            "voice": "john",
            "product": "spark",
        }
    return {}
import crypto from "node:crypto";
import express from "express";

const app = express();
const SECRET = process.env.THUNDERPHONE_WEBHOOK_SECRET;

function verify(body, signature) {
  const expected = crypto
    .createHmac("sha256", SECRET)
    .update(body)
    .digest("hex");
  return signature &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

app.post(
  "/thunderphone-webhook",
  express.raw({ type: "application/json" }),
  (req, res) => {
    if (!verify(req.body, req.header("X-ThunderPhone-Signature"))) {
      return res.sendStatus(401);
    }
    const event = JSON.parse(req.body.toString("utf8"));

    if (event.type === "telephony.incoming" || event.type === "web.incoming") {
      const caller = event.data.from_number || "web";
      const prompt = caller.startsWith("+1415")
        ? "Greet the caller as a San Francisco local…"
        : "You are a friendly customer support agent…";
      return res.json({
        prompt,
        voice: "john",
        product: "spark",
      });
    }
    res.json({});
  },
);

Vastus funktsioonitööriistadega

Lisa tööriistad, et AI saaks vestluse ajal sinu API-sid kutsuda:

{
  "prompt":  "You are a booking assistant. Use the available tools to help customers schedule appointments.",
  "voice":   "john",
  "product": "spark",
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "search_appointments",
        "description": "Find available appointment slots",
        "parameters": {
          "type": "object",
          "properties": {
            "date": { "type": "string", "description": "YYYY-MM-DD" },
            "service": { "type": "string" }
          },
          "required": ["date"]
        }
      },
      "endpoint": {
        "url": "https://api.example.com/appointments/search",
        "method": "POST",
        "headers": {
          "X-Api-Key": "your-key"
        }
      }
    }
  ]
}

Tootetasemete spikker

ToodeViiteaegArutlusvõimeKinnitussõnum
sparkMadalaimPõhiline
boltMadalTäiustatud
storm-baseKeskmineTugev
storm-base-with-ackKeskmineTugevAutomaatne täitetekst mõtlemise ajal
storm-extraKõrgemSügav
storm-extra-with-ackKõrgemSügavAutomaatne täitetekst mõtlemise ajal

Seotud