హెడ్‌లెస్ హుక్

useThunderPhone హుక్ మీకు యూజర్ ఇంటర్‌ఫేస్‌పై పూర్తి నియంత్రణను ఇస్తుంది, అదే సమయంలో ThunderPhone వాయిస్ సెషన్, ఆడియో రూటింగ్ మరియు కనెక్షన్ స్థితిని నిర్వహిస్తుంది. మీ స్వంత బటన్‌లు, లేఅవుట్‌లు, యానిమేషన్‌లు మరియు బ్రాండింగ్‌తో పూర్తిగా అనుకూల UI కావాలనుకున్నప్పుడు దీన్ని ఉపయోగించండి -- అంతర్గతంగా ఉన్న ప్రతిదాన్ని ThunderPhone నిర్వహిస్తుంది.

హెడ్‌లెస్ హుక్‌ను ఎప్పుడు ఉపయోగించాలి

ముందే రూపొందించిన ThunderPhoneWidget కాంపొనెంట్ చాలా వినియోగ సందర్భాలను కవర్ చేస్తుంది, కానీ మీకు కిందివి అవసరమైనప్పుడు హెడ్‌లెస్ హుక్‌ను ఉపయోగించండి:


ఇన్‌స్టాలేషన్

npm install @thunderphone/widget

ప్రాథమిక వినియోగం

import { useThunderPhone } from '@thunderphone/widget'

function CustomCallButton() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })

  const handleClick = () => {
    if (phone.state === 'connected') {
      phone.disconnect()
    } else {
      phone.connect()
    }
  }

  return (
    <>
      <button onClick={handleClick} disabled={phone.state === 'connecting'}>
        {phone.state === 'connecting'
          ? 'Connecting...'
          : phone.state === 'connected'
            ? 'End call'
            : 'Start call'}
      </button>
      {phone.audio}
    </>
  )
}

ఎంపికలు

UseThunderPhoneOptions ద్వారా ఈ ఎంపికలను useThunderPhoneకు పంపండి:

ఎంపికరకంఅవసరండిఫాల్ట్వివరణ
publishableKeystringఅవును--ప్రచురించదగిన API కీ (pk_live_...). కీ యొక్క విడ్జెట్ కాన్ఫిగరేషన్ నుండి ఏజెంట్ స్వయంచాలకంగా నిర్ణయించబడుతుంది.
apiBasestringకాదు'https://api.thunderphone.com/v1'API బేస్ URL ఓవర్‌రైడ్.
languagestringకాదు--ప్రతి సెషన్‌కు భాష ఓవర్‌రైడ్ -- en, es, లేదా fr-FR వంటి భాష కోడ్ లేదా లోకేల్. సెట్ చేయనప్పుడు, ఏజెంట్ కాన్ఫిగర్ చేసిన భాష వర్తిస్తుంది.
voicestringకాదు--ప్రతి సెషన్‌కు వాయిస్ ఓవర్‌రైడ్ -- maria వంటి వాయిస్ పేరు. సెట్ చేయనప్పుడు, ఏజెంట్ కాన్ఫిగర్ చేసిన వాయిస్ వర్తిస్తుంది.
contextstringకాదు--ఏజెంట్‌కు పంపే ప్రతి సెషన్‌కు సంబంధించిన వాస్తవ పేజీ లేదా సైట్ సందర్భం. సర్వర్ వైపున 12,000 అక్షరాలకు కుదించబడుతుంది.
onConnect() => voidకాదు--వాయిస్ సెషన్ కనెక్ట్ అయినప్పుడు కాల్ చేయబడుతుంది.
onDisconnect() => voidకాదు--సెషన్ ముగిసినప్పుడు కాల్ చేయబడుతుంది.
onError(error) => voidకాదు--ఎర్రర్‌లు సంభవించినప్పుడు కాల్ చేయబడుతుంది. ఎర్రర్‌లో error (కోడ్) మరియు message ఫీల్డ్‌లు ఉంటాయి.
ringtoneboolean | stringకాదుfalseకనెక్ట్ అవుతున్నప్పుడు రింగ్‌టోన్ ప్లే చేయండి. డిఫాల్ట్ రింగ్‌టోన్ కోసం true లేదా అనుకూల ఆడియో కోసం URL స్ట్రింగ్‌ను ఉపయోగించండి.

రిటర్న్ విలువ

హుక్ ఒక UseThunderPhoneReturn ఆబ్జెక్ట్‌ను రిటర్న్ చేస్తుంది:

ప్రాపర్టీరకంవివరణ
state'idle' | 'connecting' | 'connected' | 'disconnected' | 'error'ప్రస్తుత కనెక్షన్ స్థితి.
connect() => voidవాయిస్ సెషన్‌ను ప్రారంభించండి.
disconnect() => voidప్రస్తుత సెషన్‌ను ముగించండి.
toggleMute() => voidమైక్రోఫోన్ మ్యూట్‌ను ఆన్/ఆఫ్ చేయండి.
isMutedbooleanమైక్రోఫోన్ ప్రస్తుతం మ్యూట్‌లో ఉందా లేదా.
errorstring | undefinedస్థితి 'error'గా ఉన్నప్పుడు ఎర్రర్ సందేశం.
agentNamestring | undefinedకనెక్ట్ అయిన ఏజెంట్ డిస్‌ప్లే పేరు.
audioLevelnumberకాలం చెల్లింది -- ఎల్లప్పుడూ 0. వెనుకబడిన అనుకూలత కోసం ఉంచిన స్థిర ప్లేస్‌హోల్డర్; ఇది ఎప్పుడూ అప్‌డేట్ కాదు. బదులుగా audioLevelRef.current చదవండి.
audioLevelRefReact.RefObject<number>ఏజెంట్ వాయిస్ మరియు సందర్శకుడి మైక్రోఫోన్‌లో ఎక్కువగా ఉన్న రియల్-టైమ్ ఆడియో స్థాయి (0--1)ను కలిగి ఉండే మార్చగల ref -- ఇది ప్రతి యానిమేషన్ ఫ్రేమ్‌లో React రెండర్ సైకిల్ వెలుపల అప్‌డేట్ అవుతుంది. మృదువైన, జాంక్-రహిత యానిమేషన్‌ల కోసం requestAnimationFrame లూప్‌లలో audioLevelRef.current చదవండి లేదా React స్థితిలో విలువ అవసరమైనప్పుడు దానిని విరామ వ్యవధిలో శాంపిల్ చేయండి.
audioReactNodeఆడియో కనెక్షన్‌ను నిర్వహించే అదృశ్య ఎలిమెంట్ -- తప్పనిసరిగా రెండర్ చేయాలి.

ఆడియో-రియాక్టివ్ UI

audioLevelRef ref, React రీ-రెండర్‌లను ట్రిగర్ చేయకుండా ఫ్రేమ్-రేట్ ఆడియో స్థాయిలను అందిస్తుంది. అందువల్ల సున్నితమైన వేవ్‌ఫార్మ్ విజువలైజేషన్‌లు, పల్సింగ్ ఆర్బ్‌లు లేదా సంభాషణకు అనుసంధానమైన ఏదైనా యానిమేషన్‌ను నడపడానికి ఇది అనువైనది. ఏజెంట్ వాయిస్ లేదా సందర్శకుడి మైక్రోఫోన్‌లో ఏది ఎక్కువగా ఉంటే స్థాయి దానినే ప్రతిబింబిస్తుంది.

వేవ్‌ఫార్మ్ ఉదాహరణ

import { useRef, useEffect } from 'react'
import { useThunderPhone } from '@thunderphone/widget'

function WaveformCall() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })
  const canvasRef = useRef<HTMLCanvasElement>(null)

  useEffect(() => {
    if (phone.state !== 'connected') return
    const canvas = canvasRef.current
    if (!canvas) return
    const ctx = canvas.getContext('2d')!

    let animId: number
    const draw = () => {
      const level = phone.audioLevelRef.current ?? 0
      ctx.clearRect(0, 0, canvas.width, canvas.height)

      // Draw bars that react to audio level
      const barCount = 24
      const barWidth = canvas.width / barCount
      for (let i = 0; i < barCount; i++) {
        const distance = Math.abs(i - barCount / 2) / (barCount / 2)
        const height = level * canvas.height * (1 - distance * 0.6)
        const y = (canvas.height - height) / 2
        ctx.fillStyle = '#0ea5e9'
        ctx.fillRect(i * barWidth + 1, y, barWidth - 2, height)
      }

      animId = requestAnimationFrame(draw)
    }
    animId = requestAnimationFrame(draw)
    return () => cancelAnimationFrame(animId)
  }, [phone.state, phone.audioLevelRef])

  return (
    <div>
      {phone.state === 'connected' && (
        <canvas ref={canvasRef} width={240} height={80} />
      )}
      <button
        onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}
        disabled={phone.state === 'connecting'}
      >
        {phone.state === 'connected' ? 'End call' : 'Start call'}
      </button>
      {phone.audio}
    </div>
  )
}

పల్సింగ్ ఆర్బ్ ఉదాహరణ

import { useRef, useEffect } from 'react'
import { useThunderPhone } from '@thunderphone/widget'

function PulsingOrb() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })
  const orbRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (phone.state !== 'connected') return
    let animId: number
    const animate = () => {
      const level = phone.audioLevelRef.current ?? 0
      if (orbRef.current) {
        const scale = 1 + level * 0.5
        orbRef.current.style.transform = `scale(${scale})`
        orbRef.current.style.opacity = `${0.6 + level * 0.4}`
      }
      animId = requestAnimationFrame(animate)
    }
    animId = requestAnimationFrame(animate)
    return () => cancelAnimationFrame(animId)
  }, [phone.state, phone.audioLevelRef])

  return (
    <div style={{ textAlign: 'center' }}>
      <div
        ref={orbRef}
        style={{
          width: 80,
          height: 80,
          borderRadius: '50%',
          background: '#0ea5e9',
          margin: '20px auto',
          transition: 'transform 0.05s ease-out',
        }}
      />
      <button
        onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}
        disabled={phone.state === 'connecting'}
      >
        {phone.state === 'connected' ? 'End call' : 'Call'}
      </button>
      {phone.audio}
    </div>
  )
}

మాట్లాడుతున్న సూచిక ఉదాహరణ

వాల్యూమ్‌కు అనుగుణంగా మారే React-రెండర్ చేసిన UI కోసం -- ఉదాహరణకు థ్రెషోల్డ్ ఆధారిత "మాట్లాడుతున్నారు" బ్యాడ్జ్ -- audioLevelRef.currentను ఒక ఇంటర్వల్‌లో శాంపుల్ చేసి, ఫలితాన్ని స్టేట్‌లో నిల్వ చేయండి:

import { useEffect, useState } from 'react'
import { useThunderPhone } from '@thunderphone/widget'

function SpeakingBadge() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })
  const [speaking, setSpeaking] = useState(false)

  useEffect(() => {
    if (phone.state !== 'connected') {
      setSpeaking(false)
      return
    }
    const interval = setInterval(() => {
      setSpeaking((phone.audioLevelRef.current ?? 0) > 0.1)
    }, 100)
    return () => clearInterval(interval)
  }, [phone.state, phone.audioLevelRef])

  return (
    <div>
      {phone.state === 'connected' && (
        <span>{speaking ? 'Speaking' : 'Listening'}</span>
      )}
      <button onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}>
        {phone.state === 'connected' ? 'End call' : 'Start call'}
      </button>
      {phone.audio}
    </div>
  )
}

స్టేట్ మెషీన్

state ప్రాపర్టీ ఈ లైఫ్‌సైకిల్‌ను అనుసరిస్తుంది:

idle --> connecting --> connected --> disconnected --> idle (after 1.5s)
                  \
                   --> error (stays until connect() is called again)
స్థితివివరణ
idleసక్రియ సెషన్ లేదు. connect() కాల్ చేయడానికి సిద్ధంగా ఉంది.
connectingసెషన్ ఏర్పాటు అవుతోంది. ఈ స్థితిలో కాల్ బటన్‌ను డిసేబుల్ చేయండి.
connectedవాయిస్ సెషన్ సక్రియంగా ఉంది. వినియోగదారు ఏజెంట్‌తో మాట్లాడుతున్నారు.
disconnectedసెషన్ సక్రమంగా ముగిసింది. 1.5 సెకన్ల తర్వాత స్వయంచాలకంగా తిరిగి idleకి మారుతుంది.
errorఏదో తప్పు జరిగింది. సందేశం కోసం phone.errorను తనిఖీ చేయండి. ఈ స్థితి స్వయంగా క్లియర్ కాదు -- మళ్లీ connect() కాల్ చేస్తే కొత్త ప్రయత్నం ప్రారంభమై ఎర్రర్ రీసెట్ అవుతుంది.

ఉదాహరణలు

మ్యూట్ నియంత్రణతో

import { useThunderPhone } from '@thunderphone/widget'

function CallWithMute() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })

  return (
    <div>
      {phone.state === 'connected' && (
        <div>
          <p>Talking to {phone.agentName ?? 'Agent'}</p>
          <button onClick={phone.toggleMute}>
            {phone.isMuted ? 'Unmute' : 'Mute'}
          </button>
          <button onClick={phone.disconnect}>End call</button>
        </div>
      )}

      {phone.state !== 'connected' && (
        <button
          onClick={phone.connect}
          disabled={phone.state === 'connecting'}
        >
          {phone.state === 'connecting' ? 'Connecting...' : 'Call support'}
        </button>
      )}

      {phone.state === 'error' && (
        <p style={{ color: 'red' }}>{phone.error}</p>
      )}

      {phone.audio}
    </div>
  )
}

రింగ్‌టోన్‌తో

ఫోన్ కాల్‌ను అనుకరించడానికి కనెక్ట్ అవుతున్నప్పుడు రింగ్ అయ్యే శబ్దాన్ని ప్లే చేయండి:

import { useThunderPhone } from '@thunderphone/widget'

function PhoneCallButton() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
    ringtone: true, // or a custom URL: 'https://example.com/ringtone.mp3'
  })

  return (
    <>
      <button
        onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}
        disabled={phone.state === 'connecting'}
      >
        {phone.state === 'connecting'
          ? 'Ringing...'
          : phone.state === 'connected'
            ? 'Hang up'
            : 'Call'}
      </button>
      {phone.audio}
    </>
  )
}

connecting స్థితిలో రింగ్‌టోన్ నిరంతరం ప్లే అవుతుంది మరియు ఏజెంట్ కనెక్ట్ అయినప్పుడు క్రమంగా తగ్గిపోతుంది. అంతర్నిర్మిత డిఫాల్ట్ రింగ్‌టోన్ కోసం trueని లేదా మీ స్వంత ఆడియో ఫైల్‌ను ఉపయోగించడానికి URL స్ట్రింగ్‌ను అందించండి.

ఈవెంట్ కాల్‌బ్యాక్‌లతో

import { useThunderPhone } from '@thunderphone/widget'

function TrackedCallButton() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
    onConnect: () => {
      analytics.track('call_started')
    },
    onDisconnect: () => {
      analytics.track('call_ended')
    },
    onError: (error) => {
      analytics.track('call_error', { code: error.error, message: error.message })
    },
  })

  return (
    <>
      <button
        onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}
        disabled={phone.state === 'connecting'}
      >
        {phone.state === 'connected' ? 'Hang up' : 'Talk to AI'}
      </button>
      {phone.audio}
    </>
  )
}

పూర్తి కస్టమ్ UI

import { useThunderPhone } from '@thunderphone/widget'

function FullCustomUI() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })

  return (
    <div className="call-panel">
      <div className="call-status">
        {phone.state === 'idle' && <span>Ready</span>}
        {phone.state === 'connecting' && <span className="pulse">Connecting...</span>}
        {phone.state === 'connected' && (
          <span>On call with {phone.agentName}</span>
        )}
        {phone.state === 'error' && <span className="error">{phone.error}</span>}
      </div>

      <div className="call-controls">
        {phone.state === 'connected' ? (
          <>
            <button className="mute-btn" onClick={phone.toggleMute}>
              {phone.isMuted ? 'Unmute' : 'Mute'}
            </button>
            <button className="end-btn" onClick={phone.disconnect}>
              End
            </button>
          </>
        ) : (
          <button
            className="start-btn"
            onClick={phone.connect}
            disabled={phone.state === 'connecting'}
          >
            Start call
          </button>
        )}
      </div>

      {/* Required -- handles audio under the hood */}
      {phone.audio}
    </div>
  )
}

చిట్కాలు

ఎల్లప్పుడూ phone.audioను రెండర్ చేయండి

phone.audio ఎలిమెంట్ కనిపించదు, కానీ అవసరం. దీన్ని మీ JSXలో ఎక్కడైనా ఉంచండి -- ఇది కనిపించే DOMను రెండర్ చేయదు, కానీ WebRTC ఆడియో కనెక్షన్‌ను అంతర్గతంగా నిర్వహిస్తుంది.

కనెక్ట్ అవుతున్నప్పుడు బటన్‌ను నిలిపివేయండి

connecting స్థితి 1-3 సెకన్ల వరకు ఉండవచ్చు. డూప్లికేట్ కనెక్షన్ ప్రయత్నాలను నివారించడానికి ఈ స్థితిలో కాల్ బటన్‌ను నిలిపివేయండి.

లోపం స్థితిని సజావుగా నిర్వహించండి

స్థితి errorగా ఉన్నప్పుడు, వినియోగదారికి phone.errorను చూపించి, మీ కాల్ బటన్‌ను ఎనేబుల్‌లో ఉంచండి. హుక్ తనంతట తాను error స్థితిని విడిచిపెట్టదు -- మళ్లీ connect()ను కాల్ చేయడం కొత్త ప్రయత్నాన్ని ప్రారంభించి, మునుపటి లోపాన్ని క్లియర్ చేస్తుంది.

సైడ్ ఎఫెక్ట్‌ల కోసం కాల్‌బ్యాక్‌లను ఉపయోగించండి

స్థితిని పోలింగ్ చేయకుండా అనలిటిక్స్, లాగింగ్ లేదా ఇతర అప్లికేషన్ లాజిక్‌ను ట్రిగ్గర్ చేయడానికి onConnect, onDisconnect, మరియు onError కాల్‌బ్యాక్‌లు అనువైనవి.

audioLevelRef నుండి ఆడియో స్థాయిలను చదవండి

audioLevelRef మాత్రమే లైవ్ ఆడియో-స్థాయి సోర్స్. వేవ్‌ఫారమ్‌ల వంటి స్మూత్ యానిమేషన్‌ల కోసం requestAnimationFrameలో audioLevelRef.currentను చదవండి (refను చదవడం వల్ల రీ-రెండర్‌లు జరగవు), లేదా విరామాల ప్రకారం దీనిని శాంపిల్ చేసి, React-రెండర్ చేసిన UI కోసం ఫలితాన్ని స్టేట్‌లో నిల్వ చేయండి. audioLevel సంఖ్య డిప్రికేట్ చేయబడింది మరియు ఎల్లప్పుడూ 0గా ఉంటుంది -- దానిపై లాజిక్‌ను నిర్మించవద్దు.