ThunderPhone 2.0 sasa inapatikana.Anza mwenyewe, kuanzia 2¢/dakika.Soma tangazo

Developer cookbook

Usanidi unaobadilika kwa kila simu

Chagua ejenti anayejibu — au andika upya prompt na mipangilio yake — kivyake kwa kila simu inayoingia, kwa kuongozwa na mantiki maalum katika webhook unayoidhibiti.

Kwa chaguomsingi, kila nambari ya simu na ufunguo unaoweza kuchapishwa una ejenti tuli iliyowekwa. Unapohitaji ubinafsishaji wa kila mpigaji au kila mgeni — uelekezaji wa VIP, muktadha wa mtumiaji aliyeingia, majaribio ya prompt ya A/B — badilisha hadi hali ya webhook na uruhusu seva yako iamue.

Jinsi inavyofanya kazi

  1. Jiandikishe kwa tukio la telephony.incoming (simu) au web.incoming (wijeti). Zote ni webhook zinazosubiri: ThunderPhone husubiri hadi sekunde 10 kwa jibu lako kabla ya kuendelea na simu.
  2. ThunderPhone hukutumia {call_id, from_number, to_number} (vipindi vya wijeti hubeba sehemu mahususi za wijeti badala ya nambari — tazama schema ya ombi).
  3. Seva yako hujibu kwa usanidi wa ejenti (prompt, sauti, bidhaa, zana). ThunderPhone hutumia usanidi huo kwa simu.
  4. Ukirejesha {}, ukichelewa kujibu, au hitilafu ikitokea, ejenti iliyowekwa kwa njia tuli hutumika kama mbadala. Chaguo-msingi salama.

1. Sanidi mahali webhook itakapotumwa

Kwa nambari za simu, jiandikishe endpoint yako kwa 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"]
  }'

Jibu linajumuisha secret ya matumizi ya mara moja — ihifadhi; utaitumia kwa uthibitishaji wa sahihi.

Kwa vipindi vya wijeti, unda ufunguo unaoweza kuchapishwa katika mode="webhook" ukiwa na URL ya endpoint yako tayari imejumuishwa:

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"]
  }'

Wijeti itatuma POST kwenye URL hii kila kipindi kinapoanza.

2. Tekeleza kishughulikiaji

Kanuni tatu za kuzingatia:

  • Thibitisha sahihi kwenye kila ombi (tazama Thibitisha sahihi za webhook). Usiruke hatua hii katika dev — ifanye kwa usahihi mara moja na uitumie tena.
  • Jibu haraka. Sekunde kumi ndiyo kikomo cha juu, na kila sekunde ni ukimya kwa mpigaji simu. Fanya utafutaji wa hifadhidata ikihitajika, lakini usipigie LLM za baadaye kwa usawazishaji — ukitaka utengenezaji wa prompt unaobadilika, hesabu mapema na uhifadhi kwenye cache.
  • Rudi kwenye chaguo la msingi kwa usafi. Hali yoyote isiyotarajiwa inapaswa kurejesha {} ili ejenti iliyowekwa kwa uthabiti ishughulikie simu.
FastAPI
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 ...
    pass
Express
import 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. Schema ya jibu

Mwili wa jibu unalingana na schema ya jibu la simu inayoingia haswa. Sehemu zinazotumiwa mara nyingi:

SehemuAinaMaelezo
promptmfuatano wa maandishi (inahitajika)Prompt ya mfumo kwa ejenti
voicemfuatano wa maandishi (inahitajika)Kitambulisho cha sauti kutoka GET /v1/voices
productmfuatano wa maandishiChaguo-msingi ni spark
background_trackmfuatano wa maandishi | nullKitambulisho cha sauti ya mazingira
acknowledgement_prompt_modemfuatano wa maandishiauto au manual (Storm yenye uthibitisho pekee)
acknowledgement_promptmfuatano wa maandishiInahitajika wakati hali ni manual
toolsorodhaSchema za zana za vitendaji za ndani — tazama Zana za Vitendaji

Hifadhi ejenti iliyohifadhiwa na utoe vigeu

Rudisha {"agent_id": 12, "variables": {"name": "Ada"}} ili kutumia ejenti iliyohifadhiwa ya shirika hilo pamoja na data ya kila simu. Prompt yake inaweza kuwa na {{name}} au {{name|Friend}}. Vigeu vya webhook huunganishwa juu ya vigeu vya kiwango cha ombi; null hutumia chaguo-msingi la kishikilia nafasi, au maandishi matupu ikiwa hakuna lililotolewa. Thamani za mwisho na majina ambayo hayajatatuliwa huonekana katika maelezo ya simu na webhook za ukamilishaji. Majibu ya ejenti iliyohifadhiwa hukubali agent_id na variables pekee. Ikiwa prompt ipo, jibu hutumia usanidi wa ndani na hupuuza agent_id (ikiwemo metadata ya null au isiyo namba kamili); prompt ya ndani lazima bado iwe halali. Majibu ya usanidi wa ndani yanaweza pia kujumuisha variables. Majibu ya ejenti iliyohifadhiwa hutumia mgawanyo wa A/B uliotumwa wa ejenti kwenye simu za simu na wijeti, kisha hutoa vigeu. Tazama vigeu vya simu kwa vikwazo na usaidizi wa API ya kipindi. Usanidi wa kuzuia hutoka kwenye URL ya zamani ya namba ya simu/shirika au ufunguo wa wijeti wa hali ya webhook; matukio ya endpoint-system yanayoingia ni arifa pekee.

Mifumo

Muktadha wa mtumiaji aliyeingia

Katika wijeti za hali ya webhook, ukurasa wa mgeni tayari unajua yeye ni nani. Piga webhook yako kwa kigezo cha mfuatano wa hoja ambacho SDK ya wijeti hupitisha (?customer_id=123) na umtafute mteja upande wa seva.

Utoaji wa prompt wa A/B

Kabla ya kutekeleza hili mwenyewe, fahamu kwamba ThunderPhone ina kipengele cha ndani cha Majaribio (/dashboard/experiments na kichupo cha A/B cha kiunda ejenti) kinachofafanua vibadala, kugawanya trafiki, na kulinganisha matokeo kwa kila kibadala — hakuna webhook inayohitajika.

Ikiwa bado unahitaji udhibiti upande wa webhook: fanya hesabu ya mseto wa call_id → kikundi; toa prompt A kwa 0..49 na prompt B kwa 50..99. Rekodi kikundi ulichochagua katika DB yako mwenyewe na baadaye ukihusianishe na alama ya simu iliyokamilika.

Uelekezaji kulingana na muda

Saa za kazi → ejenti wa "usaidizi wa moja kwa moja"; baada ya saa za kazi → ejenti wa "chukua ujumbe". Badilisha moja kwa moja kwa kutumia new Date().getUTCHours() katika kishughulikiaji chako.


Hatua zinazofuata