forked from craigsdennis/talk-to-javascript-openai-workers
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscript.js
158 lines (146 loc) · 4.24 KB
/
script.js
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
const hand = new Hand();
function talkToTheHand() {
hand
.connect()
.then(() => console.log('Hand is ready'))
.catch((err) => console.error(err));
}
const fns = {
getPageHTML: () => {
return { success: true, html: document.documentElement.outerHTML };
},
changeBackgroundColor: ({ color }) => {
document.body.style.backgroundColor = color;
return { success: true, color };
},
changeTextColor: ({ color }) => {
document.body.style.color = color;
return { success: true, color };
},
showFingers: async ({ numberOfFingers }) => {
await hand.sendCommand(numberOfFingers);
return { success: true, numberOfFingers };
},
};
// Create a WebRTC Agent
const peerConnection = new RTCPeerConnection();
// On inbound audio add to page
peerConnection.ontrack = (event) => {
const el = document.createElement('audio');
el.srcObject = event.streams[0];
el.autoplay = el.controls = true;
document.body.appendChild(el);
};
const dataChannel = peerConnection.createDataChannel('response');
function configureData() {
console.log('Configuring data channel');
const event = {
type: 'session.update',
session: {
modalities: ['text', 'audio'],
// Provide the tools. Note they match the keys in the `fns` object above
tools: [
{
type: 'function',
name: 'changeBackgroundColor',
description: 'Changes the background color of a web page',
parameters: {
type: 'object',
properties: {
color: { type: 'string', description: 'A hex value of the color' },
},
},
},
{
type: 'function',
name: 'changeTextColor',
description: 'Changes the text color of a web page',
parameters: {
type: 'object',
properties: {
color: { type: 'string', description: 'A hex value of the color' },
},
},
},
{
type: 'function',
name: 'showFingers',
description: 'Controls a robot hand to show a specific number of fingers',
parameters: {
type: 'object',
properties: {
numberOfFingers: { type: 'string', description: 'Values 1 through 5 of the number of fingers to hold up' },
},
},
},
{
type: 'function',
name: 'getPageHTML',
description: 'Gets the HTML for the current page',
},
],
},
};
dataChannel.send(JSON.stringify(event));
}
dataChannel.addEventListener('open', (ev) => {
console.log('Opening data channel', ev);
configureData();
});
// {
// "type": "response.function_call_arguments.done",
// "event_id": "event_Ad2gt864G595umbCs2aF9",
// "response_id": "resp_Ad2griUWUjsyeLyAVtTtt",
// "item_id": "item_Ad2gsxA84w9GgEvFwW1Ex",
// "output_index": 1,
// "call_id": "call_PG12S5ER7l7HrvZz",
// "name": "get_weather",
// "arguments": "{\"location\":\"Portland, Oregon\"}"
// }
dataChannel.addEventListener('message', async (ev) => {
const msg = JSON.parse(ev.data);
// Handle function calls
if (msg.type === 'response.function_call_arguments.done') {
const fn = fns[msg.name];
if (fn !== undefined) {
console.log(`Calling local function ${msg.name} with ${msg.arguments}`);
const args = JSON.parse(msg.arguments);
const result = await fn(args);
console.log('result', result);
// Let OpenAI know that the function has been called and share it's output
const event = {
type: 'conversation.item.create',
item: {
type: 'function_call_output',
call_id: msg.call_id, // call_id from the function_call message
output: JSON.stringify(result), // result of the function
},
};
dataChannel.send(JSON.stringify(event));
}
}
});
// Capture microphone
navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
// Add microphone to PeerConnection
stream.getTracks().forEach((track) => peerConnection.addTransceiver(track, { direction: 'sendrecv' }));
peerConnection.createOffer().then((offer) => {
peerConnection.setLocalDescription(offer);
// Send WebRTC Offer to Workers Realtime WebRTC API Relay
fetch('/rtc-connect', {
method: 'POST',
body: offer.sdp,
headers: {
'Content-Type': 'application/sdp',
},
})
.then((r) => r.text())
.then((answer) => {
// Accept answer from Realtime WebRTC API
peerConnection.setRemoteDescription({
sdp: answer,
type: 'answer',
});
});
});
});