ஹெட்லெஸ் ஹுக்

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-இன் render சுழற்சிக்கு வெளியே, ஒவ்வொரு animation frame-இலும் புதுப்பிக்கப்படும். மென்மையான, தடையற்ற அனிமேஷன்களுக்காக requestAnimationFrame லூப்களுக்குள் audioLevelRef.current ஐப் படியுங்கள் அல்லது React state-இல் மதிப்பு தேவைப்படும்போது இடைவெளியில் அதை மாதிரியாக எடுத்துக்கொள்ளுங்கள்.
audioReactNodeஆடியோ இணைப்பைக் கையாளும் கண்ணுக்குத் தெரியாத உறுப்பு -- கட்டாயமாக render செய்யப்பட வேண்டும்.

ஒலிக்குப் பதிலளிக்கும் 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 ஆகவே இருக்கும் -- அதனை அடிப்படையாகக் கொண்டு தர்க்கத்தை உருவாக்காதீர்கள்.