Hook Isiyo na Kiolesura
Hook ya useThunderPhone hukupa udhibiti kamili wa kiolesura cha mtumiaji huku ThunderPhone ikisimamia kipindi cha sauti, uelekezaji wa sauti na hali ya muunganisho. Itumie unapohitaji UI iliyobinafsishwa kikamilifu -- vitufe, mipangilio, uhuishaji na utambulisho wako wa chapa -- huku ThunderPhone ikishughulikia kila kitu chinichini.
Wakati wa Kutumia Hook Isiyo na Kiolesura
Kijenzi kilichojengwa awali cha ThunderPhoneWidget kinatosheleza hali nyingi za matumizi, lakini tumia hook isiyo na kiolesura unapohitaji:
- UI ya simu iliyobinafsishwa kikamilifu inayolingana na mfumo wa usanifu wa app yako
- Vielelezo vinavyoitikia sauti (mawimbi ya sauti, duara, viashiria vinavyodunda) vinavyoendeshwa na viwango vya sauti vya wakati halisi
- Mitiririko maalum ya simu kama vile fomu za kabla ya simu, tafiti za baada ya simu, au gumzo la ndani sambamba na sauti
- Ujumuishaji katika maktaba ya vijenzi iliyopo (Material UI, Chakra, Radix, n.k.)
Usakinishaji
npm install @thunderphone/widget
Matumizi ya Msingi
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}
</>
)
}
Chaguo
Pitisha chaguo hizi kwa useThunderPhone kupitia UseThunderPhoneOptions:
| Chaguo | Aina | Inahitajika | Chaguomsingi | Maelezo |
|---|---|---|---|---|
publishableKey | string | Ndiyo | -- | Ufunguo wa API unaoweza kuchapishwa (pk_live_...). Ejenti hutambuliwa kiotomatiki kutoka kwenye usanidi wa wijeti wa ufunguo. |
apiBase | string | Hapana | 'https://api.thunderphone.com/v1' | Badilisha URL ya msingi ya API. |
language | string | Hapana | -- | Badilisha lugha kwa kila kipindi -- msimbo wa lugha au eneo kama en, es, au fr-FR. Isipowekwa, lugha iliyosanidiwa ya ejenti hutumika. |
voice | string | Hapana | -- | Badilisha sauti kwa kila kipindi -- jina la sauti kama maria. Isipowekwa, sauti iliyosanidiwa ya ejenti hutumika. |
context | string | Hapana | -- | Muktadha wa ukweli wa ukurasa au tovuti kwa kila kipindi unaopitishwa kwa ejenti. Hukatwa upande wa seva hadi herufi 12,000. |
onConnect | () => void | Hapana | -- | Huitwa kipindi cha sauti kinapounganishwa. |
onDisconnect | () => void | Hapana | -- | Huitwa kipindi kinapoisha. |
onError | (error) => void | Hapana | -- | Huitwa kunapotokea hitilafu. Hitilafu ina sehemu za error (msimbo) na message. |
ringtone | boolean | string | Hapana | false | Cheza mlio wa simu wakati wa kuunganisha. true kwa mlio chaguomsingi wa simu, au mfuatano wa URL kwa sauti maalum. |
Thamani ya Kurejesha
Hook hurejesha objekti ya UseThunderPhoneReturn:
| Sifa | Aina | Maelezo |
|---|---|---|
state | 'idle' | 'connecting' | 'connected' | 'disconnected' | 'error' | Hali ya sasa ya muunganisho. |
connect | () => void | Anzisha kipindi cha sauti. |
disconnect | () => void | Maliza kipindi cha sasa. |
toggleMute | () => void | Washa au zima kunyamazisha maikrofoni. |
isMuted | boolean | Ikiwa maikrofoni imenyamazishwa kwa sasa. |
error | string | undefined | Ujumbe wa hitilafu wakati hali ni 'error'. |
agentName | string | undefined | Jina la kuonyesha la ejenti aliyeunganishwa. |
audioLevel | number | Imeondolewa -- daima 0. Kishikilia nafasi kisichobadilika kinachohifadhiwa kwa uoanifu wa nyuma; hakisasishwi kamwe. Soma audioLevelRef.current badala yake. |
audioLevelRef | React.RefObject<number> | Ref inayoweza kubadilishwa iliyo na kiwango cha sauti cha wakati halisi (0--1) -- kilicho juu zaidi kati ya sauti ya ejenti na maikrofoni ya mgeni -- inayosasishwa katika kila fremu ya uhuishaji, nje ya mzunguko wa render wa React. Soma audioLevelRef.current ndani ya mizunguko ya requestAnimationFrame kwa uhuishaji laini usio na kukwama, au ichukue kwa vipindi unapohitaji thamani katika state ya React. |
audio | ReactNode | Kipengele kisichoonekana kinachoshughulikia muunganisho wa sauti -- lazima kirendwe. |
Kiolesura Kinachoathiriwa na Sauti
ref ya audioLevelRef hukupa viwango vya sauti kwa kasi ya fremu bila kusababisha React kujitoa upya, hivyo ni bora kwa kuendesha vielelezo laini vya muundo wa mawimbi, duara zinazodunda, au uhuishaji wowote unaohusishwa na mazungumzo. Kiwango huonyesha sauti iliyo kubwa zaidi: sauti ya ejenti au maikrofoni ya mgeni.
Mfano wa Muundo wa Mawimbi
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>
)
}
Mfano wa Duara Linalodunda
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>
)
}
Mfano wa Kiashiria cha Kuzungumza
Kwa UI inayotolewa na React ambayo hubadilika kulingana na sauti -- kama beji ya "inayozungumza" inayotegemea kizingiti -- chukua sampuli ya audioLevelRef.current kwa vipindi na uhifadhi matokeo katika state:
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>
)
}
Mashine ya Hali
Sifa ya state hufuata mzunguko huu wa maisha:
idle --> connecting --> connected --> disconnected --> idle (after 1.5s)
\
--> error (stays until connect() is called again)
| Hali | Maelezo |
|---|---|
idle | Hakuna kipindi kinachoendelea. Tayari kuita connect(). |
connecting | Kipindi kinaanzishwa. Zima kitufe cha kupiga simu wakati wa hali hii. |
connected | Kipindi cha sauti kinaendelea. Mtumiaji anazungumza na ejenti. |
disconnected | Kipindi kimeisha vizuri. Hubadilika kurudi kuwa idle kiotomatiki baada ya sekunde 1.5. |
error | Kitu kimeharibika. Angalia phone.error kwa ujumbe. Hali hii haijifuti yenyewe -- kuita connect() tena huanzisha jaribio jipya na kuweka upya hitilafu. |
Mifano
Kwa Udhibiti wa Kunyamazisha
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>
)
}
Kwa Mlio wa Simu
Cheza sauti ya mlio wa simu wakati wa kuunganisha ili kuiga simu:
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}
</>
)
}
Mlio wa simu hurudiwa katika hali ya connecting na hupungua sauti ejenti anapounganishwa. Pitisha true kwa mlio chaguomsingi uliojengewa ndani, au mfuatano wa URL ili kutumia faili yako ya sauti.
Kwa Callback za Matukio
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}
</>
)
}
Kiolesura Maalum Kabisa
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>
)
}
Vidokezo
Render phone.audio kila wakati
Kipengele cha phone.audio hakionekani lakini kinahitajika. Kiweke mahali popote katika JSX yako -- hakirender DOM inayoonekana lakini kinasimamia muunganisho wa sauti wa WebRTC ndani kwa ndani.
Zima kitufe wakati wa kuunganisha
Hali ya connecting inaweza kudumu sekunde 1-3. Zima kitufe cha simu wakati wa hali hii ili kuzuia majaribio ya muunganisho yanayojirudia.
Shughulikia hali ya hitilafu kwa ustadi
Hali inapokuwa error, onyesha phone.error kwa mtumiaji na uache kitufe chako cha simu kikiwa kimewashwa. Hook haitoki kwenye hali ya error yenyewe -- kuita connect() tena huanzisha jaribio jipya na kufuta hitilafu ya awali.
Tumia callbacks kwa athari za kando
Callbacks za onConnect, onDisconnect, na onError zinafaa kwa uchanganuzi, uandishi wa kumbukumbu, au kuanzisha mantiki nyingine ya programu bila kufuatilia hali mara kwa mara.
Soma viwango vya sauti kutoka audioLevelRef
audioLevelRef ndicho chanzo pekee cha viwango vya sauti vya moja kwa moja. Soma audioLevelRef.current ndani ya requestAnimationFrame kwa uhuishaji laini kama maumbo ya mawimbi (kusoma ref hakusababishi render upya), au ichukue sampuli kwa vipindi na uhifadhi matokeo katika state kwa kiolesura kinachorendwa na React. Nambari ya audioLevel imepitwa na wakati na daima ni 0 -- usijenge mantiki juu yake.