ttp-agent-sdk
Version:
Comprehensive Voice Agent SDK for web integration with real-time audio, WebSocket communication, and React components
456 lines (405 loc) âĸ 13.1 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React VoiceSDK Example</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
max-width: 1000px;
margin: 0 auto;
padding: 20px;
background: #F9FAFB;
}
.container {
background: white;
padding: 30px;
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
h1 {
color: #111827;
margin-top: 0;
}
.info {
background: #EFF6FF;
border-left: 4px solid #3B82F6;
padding: 16px;
margin: 20px 0;
border-radius: 4px;
}
.code-block {
background: #1F2937;
color: #F9FAFB;
padding: 20px;
border-radius: 8px;
font-family: 'Monaco', 'Menlo', monospace;
font-size: 14px;
overflow-x: auto;
margin: 20px 0;
}
.note {
background: #FEF3C7;
border-left: 4px solid #F59E0B;
padding: 16px;
margin: 20px 0;
border-radius: 4px;
}
.back-link {
display: inline-block;
background: #4F46E5;
color: white;
padding: 12px 24px;
text-decoration: none;
border-radius: 8px;
font-weight: 600;
margin-bottom: 20px;
}
.back-link:hover {
background: #4338CA;
}
</style>
</head>
<body>
<a href="../index.html" class="back-link">â Back to SDK Home</a>
<div class="container">
<h1>âī¸ React VoiceSDK Example</h1>
<div class="info">
<strong>Note:</strong> This is a code example showing how to integrate the VoiceSDK with React.
To run this example, you'll need a React development environment.
</div>
<h2>Installation</h2>
<div class="code-block">
npm install ttp-agent-sdk react react-dom
</div>
<h2>Basic React Component</h2>
<div class="code-block">
import React, { useState, useEffect, useRef } from 'react';
import { VoiceSDK } from 'ttp-agent-sdk';
function VoiceChat() {
const [isConnected, setIsConnected] = useState(false);
const [isRecording, setIsRecording] = useState(false);
const [messages, setMessages] = useState([]);
const voiceSDKRef = useRef(null);
useEffect(() => {
const voiceSDK = new VoiceSDK({
websocketUrl: 'wss://speech.talktopc.com/ws/conv',
agentId: 'your_agent_id',
appId: 'your_app_id'
});
voiceSDK.on('connected', () => setIsConnected(true));
voiceSDK.on('disconnected', () => setIsConnected(false));
voiceSDK.on('recordingStarted', () => setIsRecording(true));
voiceSDK.on('recordingStopped', () => setIsRecording(false));
voiceSDK.on('message', (message) => {
if (message.type === 'agent_response') {
setMessages(prev => [...prev, { type: 'agent', text: message.agent_response }]);
}
});
voiceSDKRef.current = voiceSDK;
return () => voiceSDK.destroy();
}, []);
const handleConnect = async () => {
await voiceSDKRef.current.connect();
};
const handleToggleRecording = async () => {
if (isRecording) {
await voiceSDKRef.current.stopRecording();
} else {
await voiceSDKRef.current.startRecording();
}
};
return (
<div>
<button onClick={handleConnect} disabled={isConnected}>
Connect
</button>
<button onClick={handleToggleRecording} disabled={!isConnected}>
{isRecording ? 'Stop Recording' : 'Start Recording'}
</button>
<div>
{messages.map((msg, i) => (
<div key={i}>{msg.type}: {msg.text}</div>
))}
</div>
</div>
);
}
export default VoiceChat;
</div>
<h2>Using the VoiceButton Component</h2>
<div class="code-block">
import React from 'react';
import { VoiceButton } from 'ttp-agent-sdk';
function App() {
return (
<VoiceButton
websocketUrl="wss://speech.talktopc.com/ws/conv"
agentId="your_agent_id"
appId="your_app_id"
onConnected={() => console.log('Connected!')}
onRecordingStarted={() => console.log('Recording...')}
onPlaybackStarted={() => console.log('Playing audio...')}
/>
);
}
export default App;
</div>
<h2>Advanced React Integration</h2>
<div class="code-block">
import React, { useState, useEffect, useRef } from 'react';
import { VoiceSDK } from 'ttp-agent-sdk';
function AdvancedVoiceChat() {
const [isConnected, setIsConnected] = useState(false);
const [isRecording, setIsRecording] = useState(false);
const [isPlaying, setIsPlaying] = useState(false);
const [messages, setMessages] = useState([]);
const [connectionStatus, setConnectionStatus] = useState('Disconnected');
const voiceSDKRef = useRef(null);
useEffect(() => {
const voiceSDK = new VoiceSDK({
websocketUrl: 'wss://speech.talktopc.com/ws/conv',
agentId: 'your_agent_id',
appId: 'your_app_id',
voice: 'default',
language: 'en',
autoReconnect: true
});
// Set up comprehensive event handlers
voiceSDK.on('connected', () => {
setIsConnected(true);
setConnectionStatus('Connected');
addMessage('system', 'Connected to voice agent');
});
voiceSDK.on('disconnected', () => {
setIsConnected(false);
setIsRecording(false);
setIsPlaying(false);
setConnectionStatus('Disconnected');
addMessage('system', 'Disconnected from voice agent');
});
voiceSDK.on('recordingStarted', () => {
setIsRecording(true);
addMessage('user', 'đ¤ Recording...');
});
voiceSDK.on('recordingStopped', () => {
setIsRecording(false);
addMessage('user', 'âšī¸ Recording stopped');
});
voiceSDK.on('playbackStarted', () => {
setIsPlaying(true);
addMessage('agent', 'đ Agent is speaking...');
});
voiceSDK.on('playbackStopped', () => {
setIsPlaying(false);
});
voiceSDK.on('message', (message) => {
if (message.type === 'agent_response') {
addMessage('agent', message.agent_response);
} else if (message.type === 'user_transcript') {
addMessage('user', message.user_transcription);
}
});
voiceSDK.on('error', (error) => {
console.error('VoiceSDK Error:', error);
addMessage('error', `Error: ${error.message}`);
});
voiceSDKRef.current = voiceSDK;
return () => {
if (voiceSDKRef.current) {
voiceSDKRef.current.destroy();
}
};
}, []);
const addMessage = (type, text) => {
setMessages(prev => [...prev, { type, text, timestamp: new Date() }]);
};
const handleConnect = async () => {
if (voiceSDKRef.current) {
try {
setConnectionStatus('Connecting...');
await voiceSDKRef.current.connect();
} catch (error) {
console.error('Connection failed:', error);
setConnectionStatus('Connection failed');
}
}
};
const handleDisconnect = () => {
if (voiceSDKRef.current) {
voiceSDKRef.current.disconnect();
}
};
const handleToggleRecording = async () => {
if (voiceSDKRef.current) {
try {
if (isRecording) {
await voiceSDKRef.current.stopRecording();
} else {
await voiceSDKRef.current.startRecording();
}
} catch (error) {
console.error('Recording toggle failed:', error);
}
}
};
return (
<div style={{ maxWidth: '800px', margin: '0 auto', padding: '20px' }}>
<h1>đ¤ Voice Chat App</h1>
<div style={{
padding: '12px',
borderRadius: '8px',
marginBottom: '20px',
backgroundColor: isConnected ? '#D1FAE5' : '#FEE2E2',
color: isConnected ? '#065F46' : '#991B1B',
border: `1px solid ${isConnected ? '#10B981' : '#EF4444'}`
}}>
<strong>Status:</strong> {connectionStatus}
</div>
<div style={{ display: 'flex', gap: '12px', marginBottom: '20px' }}>
<button
onClick={handleConnect}
disabled={isConnected}
style={{
padding: '12px 24px',
backgroundColor: isConnected ? '#9CA3AF' : '#4F46E5',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: isConnected ? 'not-allowed' : 'pointer'
}}
>
Connect
</button>
<button
onClick={handleDisconnect}
disabled={!isConnected}
style={{
padding: '12px 24px',
backgroundColor: !isConnected ? '#9CA3AF' : '#EF4444',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: !isConnected ? 'not-allowed' : 'pointer'
}}
>
Disconnect
</button>
<button
onClick={handleToggleRecording}
disabled={!isConnected}
style={{
padding: '12px 24px',
backgroundColor: !isConnected ? '#9CA3AF' : (isRecording ? '#EF4444' : '#10B981'),
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: !isConnected ? 'not-allowed' : 'pointer'
}}
>
{isRecording ? 'Stop Recording' : 'Start Recording'}
</button>
</div>
<div style={{
border: '1px solid #E5E7EB',
borderRadius: '8px',
height: '400px',
overflowY: 'auto',
padding: '16px',
backgroundColor: '#F9FAFB'
}}>
<h3>Messages:</h3>
{messages.length === 0 ? (
<p style={{ color: '#6B7280', fontStyle: 'italic' }}>
No messages yet. Connect and start recording to begin the conversation.
</p>
) : (
messages.map((message, index) => (
<div
key={index}
style={{
marginBottom: '12px',
padding: '8px 12px',
borderRadius: '6px',
backgroundColor: message.type === 'user' ? '#E5E7EB' :
message.type === 'agent' ? '#F3F4F6' :
message.type === 'error' ? '#FEE2E2' : '#EFF6FF',
color: message.type === 'error' ? '#991B1B' : '#111827',
alignSelf: message.type === 'user' ? 'flex-end' : 'flex-start',
maxWidth: '80%',
marginLeft: message.type === 'user' ? 'auto' : '0',
marginRight: message.type === 'user' ? '0' : 'auto'
}}
>
<div style={{ fontWeight: 'bold', marginBottom: '4px' }}>
{message.type === 'user' ? 'đ¤ You' :
message.type === 'agent' ? 'đ¤ Agent' :
message.type === 'error' ? 'â Error' : 'âšī¸ System'}
</div>
<div>{message.text}</div>
<div style={{
fontSize: '12px',
color: '#6B7280',
marginTop: '4px'
}}>
{message.timestamp.toLocaleTimeString()}
</div>
</div>
))
)}
</div>
<div style={{
display: 'flex',
gap: '20px',
marginTop: '20px',
fontSize: '14px',
color: '#6B7280'
}}>
<div>
<span style={{
display: 'inline-block',
width: '8px',
height: '8px',
borderRadius: '50%',
backgroundColor: isConnected ? '#10B981' : '#EF4444',
marginRight: '8px'
}}></span>
Connection
</div>
<div>
<span style={{
display: 'inline-block',
width: '8px',
height: '8px',
borderRadius: '50%',
backgroundColor: isRecording ? '#EF4444' : '#9CA3AF',
marginRight: '8px'
}}></span>
Recording
</div>
<div>
<span style={{
display: 'inline-block',
width: '8px',
height: '8px',
borderRadius: '50%',
backgroundColor: isPlaying ? '#10B981' : '#9CA3AF',
marginRight: '8px'
}}></span>
Playing
</div>
</div>
</div>
);
}
export default AdvancedVoiceChat;
</div>
<div class="note">
<strong>Note:</strong> This is a comprehensive React example showing how to integrate the VoiceSDK.
Copy this code into your React application and customize the agentId and appId values.
</div>
</div>
</body>
</html>