Open in
Dinamiska konfigurācija katram zvanam
Katram ienākošajam zvanam atsevišķi izvēlieties atbildētāju balss aģentu vai pārrakstiet tā uzvedni un iestatījumus, izmantojot pielāgotu loģiku jūsu kontrolētā tīmekļa aizķerē.
Pēc noklusējuma katram tālruņa numuram un publicējamajai atslēgai ir piešķirts statisks aģents. Ja nepieciešama katram zvanītājam vai katram apmeklētājam pielāgota konfigurācija — VIP maršrutēšana, pieteikta lietotāja konteksts, A/B uzvedņu testi — pārslēdzieties uz tīmekļa aizķeres režīmu un ļaujiet serverim pieņemt lēmumu.
Kā tas darbojas
- Jūs abonējat
telephony.incoming(tālrunis) vaiweb.incoming(logrīks) notikumu. Abi ir bloķējoši webhooki: ThunderPhone gaida jūsu atbildi, pirms turpināt zvanu — līdz 13 sekundēm tālruņa zvanam (ieskaitot vienu atkārtotu mēģinājumu) un 10 sekundēm logrīka sesijai. - ThunderPhone nosūta jums
{call_id, from_number, to_number}(logrīka sesijās numuru vietā tiek izmantoti logrīkam specifiski lauki — skatiet pieprasījuma shēmu). - Jūsu serveris atbild ar balss aģenta konfigurāciju (uzvedne, balss, produkts, rīki). ThunderPhone izmanto šo konfigurāciju zvanam.
- Nav rezerves balss aģenta. Ja atgriežat
{}vai nederīgu konfigurāciju vai pieprasījums joprojām neizdodas pēc atkārtota mēģinājuma, tālruņa zvans tiek nekavējoties pārtraukts un reģistrēts arend_reasoninbound_config_webhook_failed; logrīka sesijas pieprasījums neizdodas.
1. Konfigurējiet tīmekļa aizķeres galamērķi
Tālruņa numuriem abonējiet savu galapunktu notikumam telephony.incoming:
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"label": "Prod call-incoming",
"url": "https://example.com/thunderphone/incoming",
"events": ["telephony.incoming"]
}'Atbildē ir vienreiz lietojams secret — saglabājiet to; tas būs nepieciešams
paraksta verifikācijai.
Logrīka sesijām izveidojiet publicējamu atslēgu ar mode="webhook",
kurā ir iekļauts jūsu galapunkta URL:
curl -X POST https://api.thunderphone.com/v1/publishable-key \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Dynamic widget",
"mode": "webhook",
"webhook_url": "https://example.com/thunderphone/widget-incoming",
"allowed_domains": ["example.com"]
}'Logrīks katras sesijas sākumā veiks POST pieprasījumu uz šo URL.
2. Ieviesiet apstrādātāju
Trīs pamatprincipi:
- Pārbaudiet parakstu katram pieprasījumam (skatiet Tīmekļa aizķeru parakstu pārbaude). Neizlaidiet to izstrādes vidē — ieviesiet pareizi vienreiz un izmantojiet atkārtoti.
- Atbildiet ātri. Tālruņa zvana pirmais mēģinājums tiek pārtraukts pēc 10 sekundēm, bet visa apmaiņa — pēc 13 sekundēm, un katra sekunde zvanītājam ir klusums. Ja nepieciešams, veiciet datubāzes uzmeklēšanu, bet nesauciet pakārtotos LLM sinhroni — ja vēlaties dinamisku uzvednes ģenerēšanu, iepriekš aprēķiniet un kešojiet.
- Korekti izmantojiet rezerves variantu. Jebkuram neparedzētam stāvoklim atbildiet ar
noklusējuma
promptunvoice(vai saglabātuagent_id). Atgriežot{}vai kļūdas statusu, zvans tiek pārtraukts.
import hashlib
import hmac
import json
import os
from fastapi import FastAPI, HTTPException, Request
app = FastAPI()
SECRET = os.environ["THUNDERPHONE_WEBHOOK_SECRET"]
def verify(body: bytes, sig: str) -> bool:
expected = hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, sig or "")
@app.post("/thunderphone/incoming")
async def incoming(request: Request):
body = await request.body()
if not verify(body, request.headers.get("X-ThunderPhone-Signature", "")):
raise HTTPException(401)
event = json.loads(body)
if event["type"] not in ("telephony.incoming", "web.incoming"):
return {} # fall back to default
caller = event["data"]["from_number"]
# Cheap DB lookup: is this a known VIP?
customer = lookup_customer(caller)
if customer and customer.tier == "vip":
return {
"prompt": f"You are a VIP concierge for {customer.name}. Be proactive…",
"voice": "john",
"product": "storm-base",
}
return {} # default agent handles non-VIPs
def lookup_customer(phone: str):
# ... your CRM integration ...
passimport crypto from "node:crypto";
import express from "express";
const app = express();
const SECRET = process.env.THUNDERPHONE_WEBHOOK_SECRET;
function verify(body, sig) {
const expected = crypto.createHmac("sha256", SECRET).update(body).digest("hex");
return sig &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}
app.post(
"/thunderphone/incoming",
express.raw({ type: "application/json" }),
async (req, res) => {
if (!verify(req.body, req.header("X-ThunderPhone-Signature"))) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString("utf8"));
const IMPORTANT_TYPES = new Set([
"telephony.incoming",
"web.incoming",
]);
if (!IMPORTANT_TYPES.has(event.type)) return res.json({});
const customer = await lookupCustomer(event.data.from_number);
if (customer?.tier === "vip") {
return res.json({
prompt: `You are a VIP concierge for ${customer.name}. Be proactive…`,
voice: "john",
product: "storm-base",
});
}
res.json({}); // fall back to default agent
},
);3. Atbildes shēma
Atbildes pamatteksts precīzi atbilst ienākošā zvana atbildes shēmai. Bieži izmantotie lauki:
| Lauks | Tips | Apraksts |
|---|---|---|
prompt | virkne (obligāts) | Balss aģenta sistēmas uzvedne |
voice | virkne (obligāts) | Balss ID no GET /v1/voices |
product | virkne | Pēc noklusējuma ir spark. Eksperimentālie produkti ir pieejami tikai organizācijām atļauju sarakstā. |
background_track | virkne | null | Fona audio ID |
acknowledgement_prompt_mode | virkne | auto vai manual (tikai Storm ar apstiprinājumu) |
acknowledgement_prompt | virkne | Obligāts, ja režīms ir manual |
language_switching | virkne | Daudzvalodu balss aģentiem: ask_first vai follow_caller |
tools | masīvs | Iekļautās funkciju rīku shēmas — skatiet Funkciju rīki |
Saglabājiet balss aģentu un nododiet mainīgos
Atgrieziet {"agent_id": 12, "variables": {"name": "Ada"}}, lai izmantotu šīs organizācijas
saglabāto balss aģentu ar katra izsaukuma datiem. Tā uzvednē var būt {{name}} vai
{{name|Friend}}. Tīmekļa aizķeres mainīgie tiek apvienoti ar pieprasījuma līmeņa mainīgajiem; null
izmanto viettura noklusējuma vērtību vai tukšu tekstu, ja tāda nav norādīta. Galīgās
vērtības un neatrisinātie nosaukumi tiek parādīti izsaukuma detalizētajā informācijā un pabeigšanas tīmekļa aizķerēs.
Saglabātā balss aģenta atbildes pieņem tikai agent_id, variables un timezone. Ja ir
norādīts prompt, atbilde izmanto iekļauto konfigurāciju un ignorē agent_id (tostarp
null vai neveselu skaitļu metadatus); iekļautajai uzvednei joprojām jābūt derīgai. Iekļautās
konfigurācijas atbildēs var būt arī variables. Saglabātā balss aģenta atbildes izmanto
aģenta izvietoto A/B sadalījumu gan tālruņa, gan logrīka izsaukumiem un pēc tam atveido mainīgos. Skatiet izsaukuma mainīgos,
lai uzzinātu par ierobežojumiem un sesijas API atbalstu. Bloķējošā konfigurācija tiek iegūta no mantotā
tālruņa numura/organizācijas URL vai tīmekļa aizķeres režīma logrīka atslēgas; galapunktu sistēmā
ienākošie notikumi ir tikai paziņojumi.
Iestatiet laika joslu katram zvanam
Viens balss aģents var atbildēt kontaktpersonām dažādās laika joslās. Pievienojiet timezone — IANA nosaukumu — saglabātā aģenta vai iekļautajai atbildei, un aģents šim zvanam norādīs datumu un laiku, kā arī piedāvās laikus šajā joslā, nevis aģenta paša laika joslā:
{"agent_id": 12, "timezone": "America/Chicago", "variables": {"name": "Ada"}}Sūtiet joslu, nevis laikspiedolu laukā variables: aģenta pulkstenis zvana laikā turpina darboties, un jūsu nodotais laiks noveco. Vērtība, kas nav IANA josla, tiek ignorēta, un zvans tiek savienots aģenta laika joslā.
Modeļi
Pieteikušās personas konteksts
Webhook režīma logrīkos apmeklētāja lapa jau zina, kas viņš ir.
Izsauciet savu webhook ar vaicājuma virknes parametru, ko logrīka SDK
pārsūta (?customer_id=123), un atrodiet klientu servera pusē.
A/B uzvedņu ieviešana
Pirms veidojat to manuāli, ņemiet vērā, ka ThunderPhone ir vietējā
Eksperimentu funkcija
(/dashboard/experiments un balss aģenta veidotāja cilne A/B), kas
definē variantus, sadala datplūsmu un salīdzina rezultātus katram variantam —
webhook nav nepieciešams.
Ja tomēr nepieciešama vadība webhook pusē: jauciet call_id → segments;
apkalpojiet uzvedni A vērtībām 0..49 un uzvedni B vērtībām 50..99. Saglabājiet,
kuru segmentu izvēlējāties, savā datubāzē un vēlāk sasaistiet to ar
pabeigtā zvana vērtējumu.
Maršrutēšana pēc laika
Darba laikā → balss aģents “tiešais atbalsts”; ārpus darba laika → balss aģents “ziņas pieņemšana”.
Vienkārša pārslēgšana uz new Date().getUTCHours() jūsu apstrādātājā.
Nākamie soļi
Precīzas pieprasījuma un atbildes shēmas, tostarp katra konfigurācijas atslēga.
Vienreiz pareizi iestatiet HMAC; izmantojiet to atkārtoti visur.
Apvienojiet dinamisko maršrutēšanu ar balss aģentu rīkiem.
Atkārtoti mēģinājumi, secība, taimauti.