Initial commit
This commit is contained in:
111
assets/agent-config-schema.json
Normal file
111
assets/agent-config-schema.json
Normal file
@@ -0,0 +1,111 @@
|
||||
{
|
||||
"name": "Support Agent",
|
||||
"conversation_config": {
|
||||
"agent": {
|
||||
"prompt": {
|
||||
"prompt": "You are a helpful customer support agent...",
|
||||
"llm": "gpt-4o-mini",
|
||||
"temperature": 0.7,
|
||||
"max_tokens": 500,
|
||||
"tool_ids": ["tool_123"],
|
||||
"knowledge_base": ["doc_456"],
|
||||
"custom_llm": {
|
||||
"endpoint": "https://api.openai.com/v1/chat/completions",
|
||||
"api_key": "{{secret__openai_api_key}}",
|
||||
"model": "gpt-4"
|
||||
}
|
||||
},
|
||||
"first_message": "Hello! How can I help you today?",
|
||||
"language": "en"
|
||||
},
|
||||
"tts": {
|
||||
"model_id": "eleven_turbo_v2_5",
|
||||
"voice_id": "your_voice_id",
|
||||
"stability": 0.5,
|
||||
"similarity_boost": 0.75,
|
||||
"speed": 1.0,
|
||||
"output_format": "pcm_22050"
|
||||
},
|
||||
"asr": {
|
||||
"quality": "high",
|
||||
"provider": "deepgram",
|
||||
"keywords": ["product_name", "company_name"]
|
||||
},
|
||||
"turn": {
|
||||
"mode": "normal",
|
||||
"turn_timeout": 5000
|
||||
},
|
||||
"conversation": {
|
||||
"max_duration_seconds": 600
|
||||
},
|
||||
"language_presets": [
|
||||
{
|
||||
"language": "en",
|
||||
"voice_id": "en_voice_id",
|
||||
"first_message": "Hello! How can I help you?"
|
||||
},
|
||||
{
|
||||
"language": "es",
|
||||
"voice_id": "es_voice_id",
|
||||
"first_message": "¡Hola! ¿Cómo puedo ayudarte?"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workflow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node_1",
|
||||
"type": "subagent",
|
||||
"config": {
|
||||
"system_prompt": "You are now handling technical support...",
|
||||
"turn_eagerness": "patient",
|
||||
"voice_id": "tech_voice_id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node_2",
|
||||
"type": "tool",
|
||||
"tool_name": "transfer_to_human"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"from": "node_1",
|
||||
"to": "node_2",
|
||||
"condition": "user_requests_escalation"
|
||||
}
|
||||
]
|
||||
},
|
||||
"platform_settings": {
|
||||
"widget": {
|
||||
"theme": {
|
||||
"primaryColor": "#3B82F6",
|
||||
"backgroundColor": "#1F2937",
|
||||
"textColor": "#F9FAFB"
|
||||
},
|
||||
"position": "bottom-right"
|
||||
},
|
||||
"authentication": {
|
||||
"type": "signed_url",
|
||||
"session_duration": 3600
|
||||
},
|
||||
"privacy": {
|
||||
"transcripts": {
|
||||
"retention_days": 730
|
||||
},
|
||||
"audio": {
|
||||
"retention_days": 2190
|
||||
},
|
||||
"zero_retention": false
|
||||
}
|
||||
},
|
||||
"webhooks": {
|
||||
"post_call": {
|
||||
"url": "https://api.example.com/webhook",
|
||||
"headers": {
|
||||
"Authorization": "Bearer {{secret__webhook_auth_token}}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": ["customer-support", "production"]
|
||||
}
|
||||
77
assets/ci-cd-example.yml
Normal file
77
assets/ci-cd-example.yml
Normal file
@@ -0,0 +1,77 @@
|
||||
name: Deploy ElevenLabs Agent
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'agent_configs/**'
|
||||
- 'tool_configs/**'
|
||||
- 'test_configs/**'
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Install ElevenLabs CLI
|
||||
run: npm install -g @elevenlabs/cli
|
||||
|
||||
- name: Dry Run (Preview Changes)
|
||||
run: elevenlabs agents push --env staging --dry-run
|
||||
env:
|
||||
ELEVENLABS_API_KEY: ${{ secrets.ELEVENLABS_API_KEY_STAGING }}
|
||||
|
||||
- name: Push to Staging
|
||||
if: github.event_name == 'pull_request'
|
||||
run: elevenlabs agents push --env staging
|
||||
env:
|
||||
ELEVENLABS_API_KEY: ${{ secrets.ELEVENLABS_API_KEY_STAGING }}
|
||||
|
||||
- name: Run Tests
|
||||
if: github.event_name == 'pull_request'
|
||||
run: |
|
||||
elevenlabs tests push --env staging
|
||||
elevenlabs agents test "Support Agent"
|
||||
env:
|
||||
ELEVENLABS_API_KEY: ${{ secrets.ELEVENLABS_API_KEY_STAGING }}
|
||||
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
needs: test
|
||||
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Install ElevenLabs CLI
|
||||
run: npm install -g @elevenlabs/cli
|
||||
|
||||
- name: Deploy to Production
|
||||
run: elevenlabs agents push --env prod
|
||||
env:
|
||||
ELEVENLABS_API_KEY: ${{ secrets.ELEVENLABS_API_KEY_PROD }}
|
||||
|
||||
- name: Verify Deployment
|
||||
run: elevenlabs agents status
|
||||
env:
|
||||
ELEVENLABS_API_KEY: ${{ secrets.ELEVENLABS_API_KEY_PROD }}
|
||||
|
||||
- name: Notify on Success
|
||||
if: success()
|
||||
run: echo "✅ Agent deployed to production successfully"
|
||||
|
||||
- name: Notify on Failure
|
||||
if: failure()
|
||||
run: echo "❌ Deployment failed"
|
||||
215
assets/javascript-sdk-boilerplate.js
Normal file
215
assets/javascript-sdk-boilerplate.js
Normal file
@@ -0,0 +1,215 @@
|
||||
import { Conversation } from '@elevenlabs/client';
|
||||
|
||||
// Configuration
|
||||
const AGENT_ID = 'your-agent-id';
|
||||
const API_KEY = process.env.ELEVENLABS_API_KEY; // Server-side only, never expose in browser
|
||||
|
||||
// Initialize conversation
|
||||
const conversation = new Conversation({
|
||||
agentId: AGENT_ID,
|
||||
|
||||
// Authentication (choose one)
|
||||
// Option 1: API key (for private agents)
|
||||
apiKey: API_KEY,
|
||||
|
||||
// Option 2: Signed URL (most secure)
|
||||
// signedUrl: 'https://api.elevenlabs.io/v1/convai/auth/...',
|
||||
|
||||
// Client tools (browser-side functions)
|
||||
clientTools: {
|
||||
updateCart: {
|
||||
description: "Update shopping cart",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
item: { type: "string" },
|
||||
quantity: { type: "number" }
|
||||
},
|
||||
required: ["item", "quantity"]
|
||||
},
|
||||
handler: async ({ item, quantity }) => {
|
||||
console.log('Cart updated:', item, quantity);
|
||||
// Your cart logic here
|
||||
return { success: true };
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Event handlers
|
||||
onConnect: () => {
|
||||
console.log('Connected to agent');
|
||||
updateStatus('connected');
|
||||
clearTranscript();
|
||||
},
|
||||
|
||||
onDisconnect: () => {
|
||||
console.log('Disconnected from agent');
|
||||
updateStatus('disconnected');
|
||||
},
|
||||
|
||||
onEvent: (event) => {
|
||||
switch (event.type) {
|
||||
case 'transcript':
|
||||
addToTranscript('user', event.data.text);
|
||||
break;
|
||||
|
||||
case 'agent_response':
|
||||
addToTranscript('agent', event.data.text);
|
||||
break;
|
||||
|
||||
case 'tool_call':
|
||||
console.log('Tool called:', event.data.tool_name);
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
console.error('Agent error:', event.data);
|
||||
showError(event.data.message);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onError: (error) => {
|
||||
console.error('Connection error:', error);
|
||||
showError(error.message);
|
||||
},
|
||||
|
||||
// Regional compliance
|
||||
serverLocation: 'us' // 'us' | 'global' | 'eu-residency' | 'in-residency'
|
||||
});
|
||||
|
||||
// UI Helpers
|
||||
function updateStatus(status) {
|
||||
const statusEl = document.getElementById('status');
|
||||
if (statusEl) {
|
||||
statusEl.textContent = `Status: ${status}`;
|
||||
}
|
||||
}
|
||||
|
||||
function addToTranscript(role, text) {
|
||||
const transcriptEl = document.getElementById('transcript');
|
||||
if (transcriptEl) {
|
||||
const messageEl = document.createElement('div');
|
||||
messageEl.className = `message ${role}`;
|
||||
messageEl.innerHTML = `
|
||||
<strong>${role === 'user' ? 'You' : 'Agent'}:</strong>
|
||||
<p>${text}</p>
|
||||
`;
|
||||
transcriptEl.appendChild(messageEl);
|
||||
transcriptEl.scrollTop = transcriptEl.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
function clearTranscript() {
|
||||
const transcriptEl = document.getElementById('transcript');
|
||||
if (transcriptEl) {
|
||||
transcriptEl.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
function showError(message) {
|
||||
const errorEl = document.getElementById('error');
|
||||
if (errorEl) {
|
||||
errorEl.textContent = `Error: ${message}`;
|
||||
errorEl.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
function hideError() {
|
||||
const errorEl = document.getElementById('error');
|
||||
if (errorEl) {
|
||||
errorEl.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Button event listeners
|
||||
document.getElementById('start-btn')?.addEventListener('click', async () => {
|
||||
try {
|
||||
hideError();
|
||||
await conversation.start();
|
||||
} catch (error) {
|
||||
console.error('Failed to start conversation:', error);
|
||||
showError(error.message);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('stop-btn')?.addEventListener('click', async () => {
|
||||
try {
|
||||
await conversation.stop();
|
||||
} catch (error) {
|
||||
console.error('Failed to stop conversation:', error);
|
||||
showError(error.message);
|
||||
}
|
||||
});
|
||||
|
||||
// HTML Template
|
||||
/*
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ElevenLabs Voice Agent</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 600px;
|
||||
margin: 50px auto;
|
||||
padding: 20px;
|
||||
}
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
margin: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#status {
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
background: #f0f0f0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
#error {
|
||||
display: none;
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
background: #ffebee;
|
||||
color: #c62828;
|
||||
border-radius: 4px;
|
||||
}
|
||||
#transcript {
|
||||
margin-top: 20px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.message {
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.message.user {
|
||||
background: #e3f2fd;
|
||||
}
|
||||
.message.agent {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>ElevenLabs Voice Agent</h1>
|
||||
|
||||
<div>
|
||||
<button id="start-btn">Start Conversation</button>
|
||||
<button id="stop-btn">Stop</button>
|
||||
</div>
|
||||
|
||||
<div id="status">Status: disconnected</div>
|
||||
<div id="error"></div>
|
||||
|
||||
<div id="transcript"></div>
|
||||
|
||||
<script type="module" src="./app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
*/
|
||||
62
assets/react-native-boilerplate.tsx
Normal file
62
assets/react-native-boilerplate.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { useConversation } from '@elevenlabs/react-native';
|
||||
import { View, Button, Text, ScrollView } from 'react-native';
|
||||
import { z } from 'zod';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function VoiceAgent() {
|
||||
const [transcript, setTranscript] = useState<Array<{ role: string; text: string }>>([]);
|
||||
|
||||
const { startConversation, stopConversation, status } = useConversation({
|
||||
agentId: process.env.EXPO_PUBLIC_ELEVENLABS_AGENT_ID!,
|
||||
|
||||
// Use signed URL (most secure)
|
||||
signedUrl: async () => {
|
||||
const response = await fetch('https://your-api.com/elevenlabs/auth');
|
||||
const { signedUrl } = await response.json();
|
||||
return signedUrl;
|
||||
},
|
||||
|
||||
clientTools: {
|
||||
updateProfile: {
|
||||
description: "Update user profile",
|
||||
parameters: z.object({
|
||||
name: z.string()
|
||||
}),
|
||||
handler: async ({ name }) => {
|
||||
console.log('Updating profile:', name);
|
||||
return { success: true };
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onEvent: (event) => {
|
||||
if (event.type === 'transcript') {
|
||||
setTranscript(prev => [...prev, { role: 'user', text: event.data.text }]);
|
||||
} else if (event.type === 'agent_response') {
|
||||
setTranscript(prev => [...prev, { role: 'agent', text: event.data.text }]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={{ padding: 20 }}>
|
||||
<Text style={{ fontSize: 24, fontWeight: 'bold', marginBottom: 20 }}>Voice Agent</Text>
|
||||
|
||||
<View style={{ flexDirection: 'row', gap: 10, marginBottom: 20 }}>
|
||||
<Button title="Start" onPress={startConversation} disabled={status === 'connected'} />
|
||||
<Button title="Stop" onPress={stopConversation} disabled={status !== 'connected'} />
|
||||
</View>
|
||||
|
||||
<Text>Status: {status}</Text>
|
||||
|
||||
<ScrollView style={{ marginTop: 20, maxHeight: 400 }}>
|
||||
{transcript.map((msg, i) => (
|
||||
<View key={i} style={{ padding: 10, marginBottom: 10, backgroundColor: msg.role === 'user' ? '#e3f2fd' : '#f5f5f5' }}>
|
||||
<Text style={{ fontWeight: 'bold' }}>{msg.role === 'user' ? 'You' : 'Agent'}</Text>
|
||||
<Text>{msg.text}</Text>
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
166
assets/react-sdk-boilerplate.tsx
Normal file
166
assets/react-sdk-boilerplate.tsx
Normal file
@@ -0,0 +1,166 @@
|
||||
import { useConversation } from '@elevenlabs/react';
|
||||
import { z } from 'zod';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function VoiceAgent() {
|
||||
const [transcript, setTranscript] = useState<Array<{ role: 'user' | 'agent'; text: string }>>([]);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const {
|
||||
startConversation,
|
||||
stopConversation,
|
||||
status,
|
||||
isSpeaking
|
||||
} = useConversation({
|
||||
// Agent Configuration
|
||||
agentId: process.env.NEXT_PUBLIC_ELEVENLABS_AGENT_ID!,
|
||||
|
||||
// Authentication (choose one)
|
||||
// Option 1: API key (for private agents, less secure)
|
||||
// apiKey: process.env.NEXT_PUBLIC_ELEVENLABS_API_KEY,
|
||||
|
||||
// Option 2: Signed URL (most secure, recommended for production)
|
||||
signedUrl: async () => {
|
||||
const response = await fetch('/api/elevenlabs/auth');
|
||||
const { signedUrl } = await response.json();
|
||||
return signedUrl;
|
||||
},
|
||||
|
||||
// Client-side tools (browser functions)
|
||||
clientTools: {
|
||||
updateCart: {
|
||||
description: "Update the shopping cart with items",
|
||||
parameters: z.object({
|
||||
item: z.string().describe("The item name"),
|
||||
quantity: z.number().describe("Quantity to add"),
|
||||
action: z.enum(['add', 'remove']).describe("Add or remove item")
|
||||
}),
|
||||
handler: async ({ item, quantity, action }) => {
|
||||
console.log(`${action} ${quantity}x ${item}`);
|
||||
// Your cart logic here
|
||||
return { success: true, total: 99.99 };
|
||||
}
|
||||
},
|
||||
|
||||
navigate: {
|
||||
description: "Navigate to a different page",
|
||||
parameters: z.object({
|
||||
url: z.string().url().describe("The URL to navigate to")
|
||||
}),
|
||||
handler: async ({ url }) => {
|
||||
window.location.href = url;
|
||||
return { success: true };
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Event handlers
|
||||
onConnect: () => {
|
||||
console.log('Connected to agent');
|
||||
setTranscript([]);
|
||||
setError(null);
|
||||
},
|
||||
|
||||
onDisconnect: () => {
|
||||
console.log('Disconnected from agent');
|
||||
},
|
||||
|
||||
onEvent: (event) => {
|
||||
switch (event.type) {
|
||||
case 'transcript':
|
||||
setTranscript(prev => [
|
||||
...prev,
|
||||
{ role: 'user', text: event.data.text }
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'agent_response':
|
||||
setTranscript(prev => [
|
||||
...prev,
|
||||
{ role: 'agent', text: event.data.text }
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'tool_call':
|
||||
console.log('Tool called:', event.data.tool_name, event.data.parameters);
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
console.error('Agent error:', event.data);
|
||||
setError(event.data.message);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onError: (error) => {
|
||||
console.error('Connection error:', error);
|
||||
setError(error.message);
|
||||
},
|
||||
|
||||
// Regional compliance (for GDPR)
|
||||
serverLocation: 'us' // 'us' | 'global' | 'eu-residency' | 'in-residency'
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-screen max-w-2xl mx-auto p-4">
|
||||
<h1 className="text-2xl font-bold mb-4">Voice Agent</h1>
|
||||
|
||||
{/* Controls */}
|
||||
<div className="flex gap-2 mb-4">
|
||||
<button
|
||||
onClick={startConversation}
|
||||
disabled={status === 'connected'}
|
||||
className="px-4 py-2 bg-blue-500 text-white rounded disabled:bg-gray-300"
|
||||
>
|
||||
Start Conversation
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={stopConversation}
|
||||
disabled={status !== 'connected'}
|
||||
className="px-4 py-2 bg-red-500 text-white rounded disabled:bg-gray-300"
|
||||
>
|
||||
Stop
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Status */}
|
||||
<div className="mb-4 p-2 bg-gray-100 rounded">
|
||||
<p>Status: <span className="font-semibold">{status}</span></p>
|
||||
{isSpeaking && <p className="text-blue-600">Agent is speaking...</p>}
|
||||
</div>
|
||||
|
||||
{/* Error */}
|
||||
{error && (
|
||||
<div className="mb-4 p-2 bg-red-100 border border-red-400 text-red-700 rounded">
|
||||
Error: {error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Transcript */}
|
||||
<div className="flex-1 overflow-y-auto border rounded p-4 space-y-2">
|
||||
<h2 className="font-semibold mb-2">Transcript</h2>
|
||||
|
||||
{transcript.length === 0 ? (
|
||||
<p className="text-gray-500">No conversation yet. Click "Start Conversation" to begin.</p>
|
||||
) : (
|
||||
transcript.map((message, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className={`p-2 rounded ${
|
||||
message.role === 'user'
|
||||
? 'bg-blue-100 ml-8'
|
||||
: 'bg-gray-100 mr-8'
|
||||
}`}
|
||||
>
|
||||
<p className="text-xs font-semibold mb-1">
|
||||
{message.role === 'user' ? 'You' : 'Agent'}
|
||||
</p>
|
||||
<p>{message.text}</p>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
70
assets/swift-sdk-boilerplate.swift
Normal file
70
assets/swift-sdk-boilerplate.swift
Normal file
@@ -0,0 +1,70 @@
|
||||
import SwiftUI
|
||||
import ElevenLabs
|
||||
|
||||
struct VoiceAgentView: View {
|
||||
@State private var isConnected = false
|
||||
@State private var transcript: [(role: String, text: String)] = []
|
||||
|
||||
private let agentID = "your-agent-id"
|
||||
private let apiKey = "your-api-key" // Use environment variable in production
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("Voice Agent")
|
||||
.font(.largeTitle)
|
||||
.padding()
|
||||
|
||||
HStack {
|
||||
Button("Start Conversation") {
|
||||
startConversation()
|
||||
}
|
||||
.disabled(isConnected)
|
||||
|
||||
Button("Stop") {
|
||||
stopConversation()
|
||||
}
|
||||
.disabled(!isConnected)
|
||||
}
|
||||
.padding()
|
||||
|
||||
Text("Status: \(isConnected ? "Connected" : "Disconnected")")
|
||||
.padding()
|
||||
|
||||
ScrollView {
|
||||
ForEach(transcript.indices, id: \.self) { index in
|
||||
let message = transcript[index]
|
||||
HStack {
|
||||
VStack(alignment: .leading) {
|
||||
Text(message.role == "user" ? "You" : "Agent")
|
||||
.font(.caption)
|
||||
.fontWeight(.bold)
|
||||
Text(message.text)
|
||||
}
|
||||
.padding()
|
||||
.background(message.role == "user" ? Color.blue.opacity(0.1) : Color.gray.opacity(0.1))
|
||||
.cornerRadius(8)
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func startConversation() {
|
||||
// Initialize ElevenLabs conversation
|
||||
// Implementation would use the ElevenLabs Swift SDK
|
||||
isConnected = true
|
||||
}
|
||||
|
||||
private func stopConversation() {
|
||||
isConnected = false
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
VoiceAgentView()
|
||||
}
|
||||
|
||||
// Note: This is a placeholder. Full Swift SDK documentation available at:
|
||||
// https://github.com/elevenlabs/elevenlabs-swift-sdk
|
||||
210
assets/system-prompt-template.md
Normal file
210
assets/system-prompt-template.md
Normal file
@@ -0,0 +1,210 @@
|
||||
# System Prompt Template
|
||||
|
||||
Use this template to create structured, effective agent prompts.
|
||||
|
||||
---
|
||||
|
||||
## Personality
|
||||
```
|
||||
You are [NAME], a [ROLE/PROFESSION] at [COMPANY].
|
||||
You have [YEARS] years of experience [DOING WHAT].
|
||||
Your key traits: [LIST 3-5 PERSONALITY TRAITS].
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```
|
||||
You are Sarah, a patient and knowledgeable technical support specialist at TechCorp.
|
||||
You have 7 years of experience helping customers troubleshoot software issues.
|
||||
Your key traits: patient, empathetic, detail-oriented, solution-focused, friendly.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Environment
|
||||
```
|
||||
You're communicating via [CHANNEL: phone/chat/video].
|
||||
Context: [ENVIRONMENTAL FACTORS].
|
||||
Communication style: [GUIDELINES].
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```
|
||||
You're speaking with customers over the phone.
|
||||
Context: Background noise and poor connections are common.
|
||||
Communication style: Speak clearly, use short sentences, pause occasionally for emphasis.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tone
|
||||
```
|
||||
Formality: [PROFESSIONAL/CASUAL/FORMAL].
|
||||
Language: [CONTRACTIONS/JARGON GUIDELINES].
|
||||
Verbosity: [SENTENCE/RESPONSE LENGTH].
|
||||
Emotional Expression: [HOW TO EXPRESS EMPATHY/ENTHUSIASM].
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```
|
||||
Formality: Professional yet warm and approachable.
|
||||
Language: Use contractions for natural conversation. Avoid jargon unless customer uses it first.
|
||||
Verbosity: 2-3 sentences per response. Ask one question at a time.
|
||||
Emotional Expression: Show empathy with phrases like "I understand how frustrating that must be."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Goal
|
||||
```
|
||||
Primary Goal: [MAIN OBJECTIVE]
|
||||
|
||||
Secondary Goals:
|
||||
- [SUPPORTING OBJECTIVE 1]
|
||||
- [SUPPORTING OBJECTIVE 2]
|
||||
- [SUPPORTING OBJECTIVE 3]
|
||||
|
||||
Success Criteria:
|
||||
- [MEASURABLE OUTCOME 1]
|
||||
- [MEASURABLE OUTCOME 2]
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```
|
||||
Primary Goal: Resolve customer technical issues on the first call.
|
||||
|
||||
Secondary Goals:
|
||||
- Verify customer identity securely
|
||||
- Document issue details accurately
|
||||
- Provide proactive tips to prevent future issues
|
||||
|
||||
Success Criteria:
|
||||
- Customer verbally confirms issue is resolved
|
||||
- Issue documented in CRM
|
||||
- Customer satisfaction ≥ 4/5
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Guardrails
|
||||
```
|
||||
Never:
|
||||
- [PROHIBITED ACTION 1]
|
||||
- [PROHIBITED ACTION 2]
|
||||
- [PROHIBITED ACTION 3]
|
||||
|
||||
Always:
|
||||
- [REQUIRED ACTION 1]
|
||||
- [REQUIRED ACTION 2]
|
||||
|
||||
Escalate When:
|
||||
- [ESCALATION TRIGGER 1]
|
||||
- [ESCALATION TRIGGER 2]
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```
|
||||
Never:
|
||||
- Provide medical, legal, or financial advice
|
||||
- Share confidential company information
|
||||
- Make promises about refunds without verification
|
||||
- Continue if customer becomes abusive
|
||||
|
||||
Always:
|
||||
- Verify customer identity before accessing account details
|
||||
- Document all interactions
|
||||
- Offer alternative solutions if first approach fails
|
||||
|
||||
Escalate When:
|
||||
- Customer requests manager
|
||||
- Issue requires account credit/refund approval
|
||||
- Technical issue beyond knowledge base
|
||||
- Customer exhibits abusive behavior
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tools
|
||||
```
|
||||
Available Tools:
|
||||
|
||||
1. tool_name(param1, param2)
|
||||
Purpose: [WHAT IT DOES]
|
||||
Use When: [TRIGGER CONDITION]
|
||||
Example: [SAMPLE USAGE]
|
||||
|
||||
2. ...
|
||||
|
||||
Guidelines:
|
||||
- Always explain to customer before calling tool
|
||||
- Wait for tool response before continuing
|
||||
- If tool fails, offer alternative
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```
|
||||
Available Tools:
|
||||
|
||||
1. lookup_order(order_id: string)
|
||||
Purpose: Fetch order details from database
|
||||
Use When: Customer mentions order number or asks about order status
|
||||
Example: "Let me look that up for you. [Call lookup_order('ORD-12345')]"
|
||||
|
||||
2. send_password_reset(email: string)
|
||||
Purpose: Trigger password reset email
|
||||
Use When: Customer can't access account and identity verified
|
||||
Example: "I'll send a password reset email. [Call send_password_reset('user@example.com')]"
|
||||
|
||||
3. transfer_to_supervisor()
|
||||
Purpose: Escalate to human agent
|
||||
Use When: Issue requires manager approval or customer explicitly requests
|
||||
Example: "Let me connect you with a supervisor. [Call transfer_to_supervisor()]"
|
||||
|
||||
Guidelines:
|
||||
- Always explain what you're doing before calling tool
|
||||
- Wait for tool response before continuing conversation
|
||||
- If tool fails, acknowledge and offer alternative solution
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Prompt
|
||||
|
||||
Combine all sections into your final system prompt:
|
||||
|
||||
```
|
||||
Personality:
|
||||
You are [NAME], a [ROLE] at [COMPANY]. You have [EXPERIENCE]. Your traits: [TRAITS].
|
||||
|
||||
Environment:
|
||||
You're communicating via [CHANNEL]. [CONTEXT]. [COMMUNICATION STYLE].
|
||||
|
||||
Tone:
|
||||
[FORMALITY]. [LANGUAGE]. [VERBOSITY]. [EMOTIONAL EXPRESSION].
|
||||
|
||||
Goal:
|
||||
Primary: [PRIMARY GOAL]
|
||||
Secondary: [SECONDARY GOALS]
|
||||
Success: [SUCCESS CRITERIA]
|
||||
|
||||
Guardrails:
|
||||
Never: [PROHIBITIONS]
|
||||
Always: [REQUIREMENTS]
|
||||
Escalate: [TRIGGERS]
|
||||
|
||||
Tools:
|
||||
[TOOL DESCRIPTIONS WITH EXAMPLES]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Your Prompt
|
||||
|
||||
1. Create test scenarios covering common use cases
|
||||
2. Run conversations and analyze transcripts
|
||||
3. Check for:
|
||||
- Tone consistency
|
||||
- Goal achievement
|
||||
- Guardrail adherence
|
||||
- Tool usage accuracy
|
||||
4. Iterate based on findings
|
||||
5. Monitor analytics dashboard for real performance
|
||||
78
assets/widget-embed-template.html
Normal file
78
assets/widget-embed-template.html
Normal file
@@ -0,0 +1,78 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ElevenLabs Voice Agent Widget</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to Our Support</h1>
|
||||
<p>Need help? Click the voice assistant button in the bottom-right corner!</p>
|
||||
|
||||
<!-- ElevenLabs Widget -->
|
||||
<script src="https://elevenlabs.io/convai-widget/index.js"></script>
|
||||
<script>
|
||||
ElevenLabsWidget.init({
|
||||
// Required: Your agent ID
|
||||
agentId: 'your-agent-id',
|
||||
|
||||
// Optional: Theming
|
||||
theme: {
|
||||
primaryColor: '#3B82F6', // Blue
|
||||
backgroundColor: '#1F2937', // Dark gray
|
||||
textColor: '#F9FAFB', // Light gray
|
||||
accentColor: '#10B981' // Green
|
||||
},
|
||||
|
||||
// Optional: Position
|
||||
position: 'bottom-right', // or 'bottom-left'
|
||||
|
||||
// Optional: Custom branding
|
||||
branding: {
|
||||
logo: 'https://example.com/logo.png',
|
||||
name: 'Support Assistant',
|
||||
tagline: 'How can I help you today?'
|
||||
},
|
||||
|
||||
// Optional: Customize button
|
||||
button: {
|
||||
size: 'medium', // 'small' | 'medium' | 'large'
|
||||
icon: 'microphone', // 'microphone' | 'chat' | 'phone'
|
||||
text: 'Talk to us' // Optional button label
|
||||
},
|
||||
|
||||
// Optional: Auto-open widget
|
||||
autoOpen: false,
|
||||
autoOpenDelay: 3000, // milliseconds
|
||||
|
||||
// Optional: Welcome message
|
||||
welcomeMessage: {
|
||||
enabled: true,
|
||||
message: "Hi! I'm here to help. Click to start a voice conversation."
|
||||
},
|
||||
|
||||
// Optional: Callbacks
|
||||
onOpen: () => {
|
||||
console.log('Widget opened');
|
||||
},
|
||||
onClose: () => {
|
||||
console.log('Widget closed');
|
||||
},
|
||||
onConversationStart: () => {
|
||||
console.log('Conversation started');
|
||||
},
|
||||
onConversationEnd: () => {
|
||||
console.log('Conversation ended');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Optional: Custom styling -->
|
||||
<style>
|
||||
/* Override widget styles if needed */
|
||||
.elevenlabs-widget {
|
||||
/* Custom styles */
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user