Skip to content

Commit f3e40b4

Browse files
committed
realtime function call
1 parent 199adf2 commit f3e40b4

File tree

3 files changed

+82
-4
lines changed

3 files changed

+82
-4
lines changed

src/lib/services/api-endpoints.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export const endpoints = {
4646

4747
// agent realtime interaction
4848
agentInitRealtimeSessionUrl: `${host}/agent/{agentId}/realtime/session`,
49+
agentFunctionCallUrl: `${host}/agent/{agentId}/function/{functionName}/execute`,
4950

5051
// router
5152
routerSettingUrl: `${host}/router/settings`,

src/lib/services/llm-realtime-service.js

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import { endpoints } from '$lib/services/api-endpoints.js';
22
import { replaceUrl } from '$lib/helpers/http';
33
import axios from 'axios';
4+
import { json } from '@sveltejs/kit';
45

56
export const llmRealtime = {
67
/** @type {RTCPeerConnection} */
78
pc: new RTCPeerConnection(),
8-
/** @param {string} agentId */
9-
async start(agentId) {
9+
/**
10+
* @param {string} agentId
11+
* @param {function} onMessageReceived
12+
*/
13+
async start(agentId, onMessageReceived) {
1014
const session = await initRealtimeSession(agentId);
1115
const EPHEMERAL_KEY = session.client_secret.value;
1216

@@ -25,10 +29,13 @@ export const llmRealtime = {
2529

2630
// Set up data channel for sending and receiving events
2731
const dc = this.pc.createDataChannel("oai-events");
28-
dc.addEventListener("message", (e) => {
32+
dc.addEventListener("message", async (e) => {
2933
// Realtime server events appear here!
3034
var data = JSON.parse(e.data);
3135
console.log(data);
36+
if (data.type === "response.done" && data.response.status == "completed") {
37+
await handleServerEvents(agentId, data, dc);
38+
}
3239
});
3340

3441
// Start the session using the Session Description Protocol (SDP)
@@ -51,6 +58,20 @@ export const llmRealtime = {
5158
sdp: await sdpResponse.text(),
5259
};
5360
await this.pc.setRemoteDescription(answer);
61+
62+
// send on data channel connect is open
63+
dc.onopen = () => {
64+
console.log("Data channel is open");
65+
/*const responseCreate = {
66+
type: "response.create",
67+
response: {
68+
modalities: ["audio", "text"],
69+
instructions: "Write a haiku about code",
70+
},
71+
};
72+
dc.send(JSON.stringify(responseCreate));*/
73+
};
74+
5475
},
5576

5677
stop() {
@@ -68,4 +89,58 @@ export async function initRealtimeSession(agentId) {
6889
let url = replaceUrl(endpoints.agentInitRealtimeSessionUrl, {agentId: agentId});
6990
var response = await axios.get(url);
7091
return response.data;
92+
}
93+
94+
/**
95+
* Handle server events
96+
* @param {string} agentId
97+
* @param {Object} data
98+
* @param {RTCDataChannel} dc
99+
*/
100+
async function handleServerEvents(agentId, data, dc) {
101+
// for each response.output, do something with it
102+
data.response.output.forEach(async completion => {
103+
if (completion.type === "function_call") {
104+
const result = await callFunction(agentId, completion.name, completion.arguments);
105+
console.log(result);
106+
107+
// send the result back to the model
108+
const conversationItemCreation = {
109+
"type": "conversation.item.create",
110+
"item": {
111+
"call_id": completion.call_id,
112+
"type": "function_call_output",
113+
"output": result
114+
}
115+
};
116+
dc.send(JSON.stringify(conversationItemCreation));
117+
118+
/*const conversationItemResponse = {
119+
"type": "response.create",
120+
"response": {
121+
"modalities": ["text", "audio"],
122+
"instructions": "Please continue the conversation based on the function output.",
123+
}
124+
};
125+
dc.send(JSON.stringify(conversationItemResponse));*/
126+
}
127+
});
128+
}
129+
130+
/**
131+
* Execute agent function call
132+
* @param {string} agentId
133+
* @param {string} functionName
134+
* @param {string} args
135+
* @returns {Promise<string>}
136+
*/
137+
async function callFunction(agentId, functionName, args) {
138+
let url = replaceUrl(endpoints.agentFunctionCallUrl, {
139+
agentId: agentId,
140+
functionName: functionName
141+
});
142+
143+
const functionArgs = JSON.parse(args);
144+
var response = await axios.post(url, functionArgs);
145+
return JSON.stringify(response.data);
71146
}

src/routes/chat/[agentId]/[conversationId]/chat-box.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,9 @@
659659
if (disableSpeech) return;
660660
661661
if (!isListening) {
662-
llmRealtime.start(params.agentId);
662+
llmRealtime.start(params.agentId, message => {
663+
console.log(message);
664+
});
663665
isListening = true;
664666
microphoneIcon = "microphone";
665667
} else {

0 commit comments

Comments
 (0)