-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathserver.mjs
More file actions
132 lines (117 loc) · 3.97 KB
/
server.mjs
File metadata and controls
132 lines (117 loc) · 3.97 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
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
import { serve } from "@hono/node-server";
import { StreamClient } from "@stream-io/node-sdk";
import { Hono } from "hono";
import { cors } from "hono/cors";
import crypto from 'crypto';
import { config } from 'dotenv';
// load config from dotenv
config();
// Get environment variables
const streamApiKey = process.env.STREAM_API_KEY;
const streamApiSecret = process.env.STREAM_API_SECRET;
const openAiApiKey = process.env.OPENAI_API_KEY;
// Check if all required environment variables are set
if (!streamApiKey || !streamApiSecret || !openAiApiKey) {
console.error("Error: Missing required environment variables, make sure to have a .env file in the project root, check .env.example for reference");
process.exit(1);
}
const app = new Hono();
app.use(cors());
const streamClient = new StreamClient(streamApiKey, streamApiSecret);
/**
* Endpoint to generate credentials for a new video call.
* Creates a unique call ID, generates a token, and returns necessary connection details.
*/
app.get("/credentials", (c) => {
console.log("got a request for credentials");
// Generate a shorter UUID for callId (first 12 chars)
const callId = crypto.randomUUID().replace(/-/g, '').substring(0, 12);
// Generate a shorter UUID for userId (first 8 chars with prefix)
const userId = `user-${crypto.randomUUID().replace(/-/g, '').substring(0, 8)}`;
const callType = "default";
const token = streamClient.generateUserToken({
user_id: userId,
});
return c.json({
apiKey: streamApiKey,
token,
callType,
callId,
userId
});
});
/**
* Endpoint to connect an AI agent to an existing video call.
* Takes call type and ID parameters, connects the OpenAI agent to the call,
* sets up the realtime client with event handlers and tools,
* and returns a success response when complete.
*/
app.post("/:callType/:callId/connect", async (c) => {
console.log("got a request for connect");
const callType = c.req.param("callType");
const callId = c.req.param("callId");
const call = streamClient.video.call(callType, callId);
const realtimeClient = await streamClient.video.connectOpenAi({
call,
openAiApiKey,
agentUserId: "lucy",
});
await setupRealtimeClient(realtimeClient);
console.log("agent is connected now");
return c.json({ ok: true });
});
async function setupRealtimeClient(realtimeClient) {
realtimeClient.on("error", (event) => {
console.error("Error:", event);
});
realtimeClient.on("session.update", (event) => {
console.log("Realtime session update:", event);
});
realtimeClient.updateSession({
instructions: "You are a helpful assistant that can answer questions and help with tasks.",
});
realtimeClient.addTool(
{
name: "get_weather",
description:
"Call this function to retrieve current weather information for a specific location. Provide the city name.",
parameters: {
type: "object",
properties: {
city: {
type: "string",
description: "The name of the city to get weather information for",
},
},
required: ["city"],
},
},
async ({ city, country, units = "metric" }) => {
console.log("get_weather request", { city, country, units });
try {
// This is a placeholder for actual weather API implementation
// In a real implementation, you would call a weather API service here
const weatherData = {
location: country ? `${city}, ${country}` : city,
temperature: 22,
units: units === "imperial" ? "°F" : "°C",
condition: "Partly Cloudy",
humidity: 65,
windSpeed: 10
};
return weatherData;
} catch (error) {
console.error("Error fetching weather data:", error);
return { error: "Failed to retrieve weather information" };
}
},
);
return realtimeClient;
}
// Start the server
serve({
fetch: app.fetch,
hostname: "0.0.0.0",
port: 3000,
});
console.log(`Server started on :3000`);