ہیڈلیس ہک
useThunderPhone ہک آپ کو یوزر انٹرفیس پر مکمل کنٹرول دیتا ہے، جبکہ ThunderPhone وائس سیشن، آڈیو روٹنگ، اور کنکشن کی حالت کو منظم کرتا ہے۔ جب آپ مکمل طور پر حسبِ ضرورت UI چاہتے ہوں — اپنے بٹن، لے آؤٹس، اینیمیشنز، اور برانڈنگ — جبکہ ThunderPhone پسِ پردہ ہر چیز سنبھالے، تو اسے استعمال کریں۔
ہیڈلیس ہک کب استعمال کریں
پہلے سے تیار ThunderPhoneWidget کمپوننٹ زیادہ تر استعمال کے معاملات کو پورا کرتا ہے، لیکن جب آپ کو درج ذیل کی ضرورت ہو تو ہیڈلیس ہک استعمال کریں:
- مکمل طور پر حسبِ ضرورت کال UI جو آپ کی ایپ کے ڈیزائن سسٹم سے مطابقت رکھتا ہو
- حقیقی وقت کے آڈیو لیولز سے چلنے والی آڈیو-ردعملی ویژولائزیشنز (ویوفارمز، آربز، دھڑکتے اشارے)
- حسبِ ضرورت کال فلو، جیسے کال سے پہلے کے فارمز، کال کے بعد کے سرویز، یا وائس کے ساتھ اِن لائن چیٹ
- کسی موجودہ کمپوننٹ لائبریری میں انضمام (Material UI، Chakra، Radix، وغیرہ)
انسٹالیشن
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 کو دیں:
| اختیار | قسم | ضروری | ڈیفالٹ | تفصیل |
|---|---|---|---|---|
publishableKey | string | ہاں | -- | پبلش ایبل API کلید (pk_live_...)۔ ایجنٹ کلید کی widget کنفیگریشن سے خودکار طور پر متعین ہوتا ہے۔ |
apiBase | string | نہیں | 'https://api.thunderphone.com/v1' | API بیس URL کا اووررائیڈ۔ |
language | string | نہیں | -- | فی سیشن زبان کا اووررائیڈ — زبان کا کوڈ یا لوکیل، جیسے en، es، یا fr-FR۔ جب یہ متعین نہ ہو، تو ایجنٹ کی کنفیگر کردہ زبان لاگو ہوتی ہے۔ |
voice | string | نہیں | -- | فی سیشن آواز کا اووررائیڈ — آواز کا نام، جیسے maria۔ جب یہ متعین نہ ہو، تو ایجنٹ کی کنفیگر کردہ آواز لاگو ہوتی ہے۔ |
context | string | نہیں | -- | ایجنٹ کو دیا جانے والا فی سیشن حقائق پر مبنی صفحہ یا سائٹ کا سیاق۔ سرور کی طرف سے 12,000 حروف تک محدود کیا جاتا ہے۔ |
onConnect | () => void | نہیں | -- | وائس سیشن کے کنیکٹ ہونے پر کال کیا جاتا ہے۔ |
onDisconnect | () => void | نہیں | -- | سیشن ختم ہونے پر کال کیا جاتا ہے۔ |
onError | (error) => void | نہیں | -- | خرابیوں پر کال کیا جاتا ہے۔ خرابی میں error (کوڈ) اور message فیلڈز ہوتے ہیں۔ |
ringtone | boolean | string | نہیں | false | کنیکٹ ہونے کے دوران رنگ ٹون چلائیں۔ ڈیفالٹ رنگ ٹون کے لیے true، یا حسبِ ضرورت آڈیو کے لیے URL اسٹرنگ استعمال کریں۔ |
واپسی کی قدر
ہک ایک UseThunderPhoneReturn آبجیکٹ واپس کرتا ہے:
| پراپرٹی | قسم | وضاحت |
|---|---|---|
state | 'idle' | 'connecting' | 'connected' | 'disconnected' | 'error' | موجودہ کنکشن کی حالت۔ |
connect | () => void | وائس سیشن شروع کریں۔ |
disconnect | () => void | موجودہ سیشن ختم کریں۔ |
toggleMute | () => void | مائیکروفون میوٹ کو آن یا آف کریں۔ |
isMuted | boolean | آیا مائیکروفون اس وقت میوٹ ہے۔ |
error | string | undefined | جب حالت 'error' ہو تو خرابی کا پیغام۔ |
agentName | string | undefined | منسلک ایجنٹ کا ڈسپلے نام۔ |
audioLevel | number | متروک -- ہمیشہ 0۔ پسماندہ مطابقت کے لیے برقرار رکھا گیا ایک جامد پلیس ہولڈر؛ یہ کبھی اپ ڈیٹ نہیں ہوتا۔ اس کے بجائے audioLevelRef.current پڑھیں۔ |
audioLevelRef | React.RefObject<number> | ایک قابلِ تبدیلی ref جس میں حقیقی وقت کا آڈیو لیول (0 سے 1) موجود ہوتا ہے -- ایجنٹ کی آواز اور وزیٹر کے مائیکروفون میں سے جو زیادہ بلند ہو -- جو React کے رینڈر سائیکل سے باہر، ہر اینیمیشن فریم پر اپ ڈیٹ ہوتا ہے۔ ہموار، جھٹکوں سے پاک اینیمیشنز کے لیے requestAnimationFrame لوپس کے اندر audioLevelRef.current پڑھیں، یا جب React state میں قدر درکار ہو تو اسے کسی وقفے پر سیمپل کریں۔ |
audio | ReactNode | غیر مرئی عنصر جو آڈیو کنکشن سنبھالتا ہے -- اسے رینڈر کرنا لازمی ہے۔ |
آڈیو پر ردعمل دینے والا 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 کا نمونہ لیں اور نتیجہ 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>
)
}
اسٹیٹ مشین
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 دکھائیں اور اپنا کال بٹن فعال رکھیں۔ hook خود سے error حالت سے باہر نہیں آتا -- connect() کو دوبارہ کال کرنے سے ایک نئی کوشش شروع ہوتی ہے اور پچھلی خرابی صاف ہو جاتی ہے۔
ضمنی اثرات کے لیے callbacks استعمال کریں
onConnect، onDisconnect، اور onError callbacks اسٹیٹ کو poll کیے بغیر analytics، logging، یا دیگر ایپلیکیشن منطق کو trigger کرنے کے لیے موزوں ہیں۔
audioLevelRef سے آڈیو لیولز پڑھیں
audioLevelRef واحد لائیو آڈیو-لیول سورس ہے۔ waveform جیسی ہموار animations کے لیے requestAnimationFrame کے اندر audioLevelRef.current پڑھیں (ref پڑھنے سے دوبارہ رینڈر نہیں ہوتے)، یا اسے کسی interval پر sample کریں اور نتیجہ React سے رینڈر ہونے والے UI کے لیے state میں محفوظ کریں۔ audioLevel نمبر متروک ہے اور ہمیشہ 0 ہوتا ہے -- اس پر منطق نہ بنائیں۔