-
-
Notifications
You must be signed in to change notification settings - Fork 182
Expand file tree
/
Copy pathuse-realtime.ts
More file actions
102 lines (93 loc) · 2.95 KB
/
use-realtime.ts
File metadata and controls
102 lines (93 loc) · 2.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import { createServerFn } from '@tanstack/react-start'
import { realtimeToken } from '@tanstack/ai'
import { useRealtimeChat } from '@tanstack/ai-react'
import { openaiRealtime, openaiRealtimeToken } from '@tanstack/ai-openai'
import {
elevenlabsRealtime,
elevenlabsRealtimeToken,
} from '@tanstack/ai-elevenlabs'
import { geminiRealtime, geminiRealtimeToken } from '@tanstack/ai-gemini'
import { realtimeClientTools } from '@/lib/realtime-tools'
type Provider = 'openai' | 'elevenlabs' | 'gemini'
const getRealtimeTokenFn = createServerFn({ method: 'POST' })
.inputValidator((data: { provider: Provider; agentId?: string }) => {
if (!data.provider) throw new Error('Provider is required')
return data
})
.handler(async ({ data }) => {
if (data.provider === 'openai') {
return realtimeToken({
adapter: openaiRealtimeToken({
model: 'gpt-4o-realtime-preview',
}),
})
}
if (data.provider === 'gemini') {
return realtimeToken({
adapter: geminiRealtimeToken(),
})
}
if (data.provider === 'elevenlabs') {
const agentId = data.agentId || process.env.ELEVENLABS_AGENT_ID
if (!agentId) {
throw new Error(
'ElevenLabs agent ID is required. Set ELEVENLABS_AGENT_ID or pass agentId in request body.',
)
}
return realtimeToken({
adapter: elevenlabsRealtimeToken({ agentId }),
})
}
throw new Error(`Unknown provider: ${data.provider}`)
})
export function useRealtime({
provider,
agentId,
outputModalities,
temperature,
maxOutputTokens,
semanticEagerness,
}: {
provider: Provider
agentId: string
outputModalities?: Array<'audio' | 'text'>
temperature?: number
maxOutputTokens?: number | 'inf'
semanticEagerness?: 'low' | 'medium' | 'high'
}) {
const adapter =
provider === 'openai'
? openaiRealtime()
: provider === 'gemini'
? geminiRealtime()
: elevenlabsRealtime()
return useRealtimeChat({
getToken: () =>
getRealtimeTokenFn({
data: {
provider,
...(provider === 'elevenlabs' && agentId ? { agentId } : {}),
},
}),
adapter,
instructions: `You are a helpful, friendly voice assistant with access to several tools.
You can:
- Tell the user the current time and date (getCurrentTime)
- Get weather information for any location (getWeather)
- Set reminders for the user (setReminder)
- Search a knowledge base for information (searchKnowledge)
Keep your responses concise and conversational since this is a voice interface.
When using tools, briefly explain what you're doing and then share the results naturally.
If the user sends an image, describe what you see and answer any questions about it.
Be friendly and engaging!`,
voice: 'alloy',
tools: realtimeClientTools,
outputModalities,
temperature,
maxOutputTokens,
semanticEagerness,
onError: (err) => {
console.error('Realtime error:', err)
},
})
}