-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
105 lines (89 loc) · 3.64 KB
/
Copy pathserver.js
File metadata and controls
105 lines (89 loc) · 3.64 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
require("dotenv").config();
const express = require("express");
const app = express();
const PORT = 3000;
// ── API keys ──
const RETELL_API_KEY = process.env.RETELL_API_KEY || "";
const GEMINI_API_KEY = process.env.GEMINI_API_KEY || "";
app.use(express.json());
app.use(express.static(__dirname)); // serves index.html, styles.css, main.js
// Endpoint that main.js calls to get an access token
app.post("/api/create-web-call", async (req, res) => {
try {
const response = await fetch("https://api.retellai.com/v2/create-web-call", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${RETELL_API_KEY}`,
},
body: JSON.stringify({
agent_id: req.body.agent_id,
}),
});
if (!response.ok) {
const text = await response.text();
console.error("Retell API error:", response.status, text);
return res.status(response.status).json({ error: text });
}
const data = await response.json();
res.json({ access_token: data.access_token });
} catch (err) {
console.error("Server error:", err);
res.status(500).json({ error: "Failed to create web call" });
}
});
// Chat endpoint using Gemini API
app.post("/api/chat", async (req, res) => {
const { message, history } = req.body;
if (!message) {
return res.status(400).json({ error: "Message is required" });
}
const systemInstruction = `You are Sarah, a friendly and knowledgeable AI assistant for Tertiary Infotech Academy, a Singapore-based training provider offering SkillsFuture and WSQ accredited IT courses for working adults.
Key information you should know:
- Courses offered: Cybersecurity Fundamentals (40hrs), Cloud Computing & AWS (36hrs), Data Analytics with Python (32hrs), AI & Machine Learning (44hrs), Full-Stack Web Development (48hrs), Digital Marketing & SEO (28hrs)
- All courses come with certificates
- Funding: SkillsFuture Credit, subsidies, and absentee payroll support available
- Instructors are industry practitioners with real-world experience
- Flexible scheduling: weekday, evening, and weekend classes
- Over 2,500 graduates, 50+ courses, 95% satisfaction rate, 10+ years experience
Keep responses concise (2-3 sentences max), friendly, and helpful. If asked about something outside the academy's scope, politely redirect to relevant academy topics.`;
const contents = [];
if (history && Array.isArray(history)) {
for (const entry of history) {
contents.push({
role: entry.role === "user" ? "user" : "model",
parts: [{ text: entry.text }],
});
}
}
contents.push({ role: "user", parts: [{ text: message }] });
try {
const response = await fetch(
`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${GEMINI_API_KEY}`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
system_instruction: { parts: [{ text: systemInstruction }] },
contents,
}),
}
);
if (!response.ok) {
const text = await response.text();
console.error("Gemini API error:", response.status, text);
return res.status(response.status).json({ error: text });
}
const data = await response.json();
const reply =
data.candidates?.[0]?.content?.parts?.[0]?.text ||
"Sorry, I couldn't generate a response. Please try again.";
res.json({ reply });
} catch (err) {
console.error("Gemini error:", err);
res.status(500).json({ error: "Failed to get response" });
}
});
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});