Appearance
Examples
Real-world examples and use cases.
Customer Service Bot
A complete customer service bot with state management and routing:
typescript
import { AiFlowAssistant, BargeInStrategy } from "@sipgate/ai-flow-sdk";
import express from "express";
// Session state management
const sessions = new Map<string, { state: string; data: any }>();
const assistant = AiFlowAssistant.create({
debug: true,
onSessionStart: async (event) => {
// Initialize session state
sessions.set(event.session.id, {
state: "greeting",
data: { attempts: 0 },
});
return {
type: "speak",
session_id: event.session.id,
text: "Welcome to customer support. How can I help you today? You can ask about billing, technical support, or sales.",
barge_in: {
strategy: "minimum_characters",
minimum_characters: 3,
},
};
},
onUserSpeak: async (event) => {
const session = sessions.get(event.session.id);
if (!session) return null;
const text = event.text.toLowerCase();
// Intent routing
if (text.includes("billing") || text.includes("invoice")) {
return {
type: "transfer",
session_id: event.session.id,
target_phone_number: "+1234567890",
caller_id_name: "Billing Department",
caller_id_number: "+1234567890",
};
}
if (text.includes("goodbye") || text.includes("bye")) {
return {
type: "speak",
session_id: event.session.id,
text: "Thank you for calling. Have a great day!",
barge_in: { strategy: "none" }, // Don't allow interruption
};
}
if (text.includes("technical") || text.includes("support")) {
session.state = "technical_support";
return "I'll connect you with our technical support team. Please describe your issue.";
}
// Default response
session.data.attempts++;
if (session.data.attempts > 2) {
return "I'm having trouble understanding. Let me transfer you to a representative.";
}
return "I can help with billing, technical support, or sales. Which would you like?";
},
onUserBargeIn: async (event) => {
console.log(`User interrupted: ${event.text}`);
return "Yes, I'm listening.";
},
onSessionEnd: async (event) => {
// Cleanup session state
sessions.delete(event.session.id);
console.log(`Session ${event.session.id} ended`);
},
});
const app = express();
app.use(express.json());
app.post("/webhook", assistant.express());
app.listen(3000, () => {
console.log("Customer service bot running on port 3000");
});Multi-Language Support
Switch languages based on user preference:
typescript
const sessions = new Map();
const assistant = AiFlowAssistant.create({
onSessionStart: async (event) => {
sessions.set(event.session.id, { language: "en" });
return "Welcome! Say 'deutsch' for German or 'english' for English.";
},
onUserSpeak: async (event) => {
const session = sessions.get(event.session.id);
if (!session) return null;
const text = event.text.toLowerCase();
if (text.includes("deutsch") || text.includes("german")) {
session.language = "de";
return {
type: "speak",
session_id: event.session.id,
text: "Willkommen! Wie kann ich Ihnen helfen?",
tts: {
provider: "azure",
language: "de-DE",
voice: "de-DE-KatjaNeural",
},
};
}
if (text.includes("english") || text.includes("englisch")) {
session.language = "en";
return "Welcome! How can I help you?";
}
// Continue in selected language
if (session.language === "de") {
return {
type: "speak",
session_id: event.session.id,
text: "Wie kann ich Ihnen helfen?",
tts: {
provider: "azure",
language: "de-DE",
voice: "de-DE-KatjaNeural",
},
};
}
return "How can I help you?";
},
});User Input Timeout Handling
Handle scenarios where users don't respond within a specified time period:
typescript
import { AiFlowAssistant } from "@sipgate/ai-flow-sdk";
import express from "express";
// Track timeout counts per session
const timeoutCounts = new Map<string, number>();
const assistant = AiFlowAssistant.create({
debug: true,
onSessionStart: async (event) => {
// Initialize timeout counter
timeoutCounts.set(event.session.id, 0);
return {
type: "speak",
session_id: event.session.id,
text: "Welcome to our automated assistant. What can I help you with today?",
user_input_timeout_seconds: 8 // Wait 8 seconds for initial response
};
},
onUserSpeak: async (event) => {
// Reset timeout counter on successful user input
timeoutCounts.set(event.session.id, 0);
const text = event.text.toLowerCase();
if (text.includes("account") || text.includes("balance")) {
return {
type: "speak",
session_id: event.session.id,
text: "Please tell me your account number.",
user_input_timeout_seconds: 10 // Give more time for account number
};
}
if (text.includes("speak") || text.includes("agent") || text.includes("human")) {
return {
type: "speak",
session_id: event.session.id,
text: "Let me transfer you to a live agent. Please hold."
// Follow with transfer action
};
}
return {
type: "speak",
session_id: event.session.id,
text: "I can help you with account information, billing questions, or connect you to an agent. What would you like?",
user_input_timeout_seconds: 8
};
},
onUserInputTimeout: async (event) => {
const sessionId = event.session.id;
const count = (timeoutCounts.get(sessionId) || 0) + 1;
timeoutCounts.set(sessionId, count);
console.log(`Timeout #${count} for session ${sessionId}`);
// After 3 timeouts, offer to transfer to agent
if (count >= 3) {
return {
type: "speak",
session_id: sessionId,
text: "I'm having trouble hearing you. Let me transfer you to a live agent who can better assist you."
// Could follow with transfer action
};
}
// After 2 timeouts, give clearer instructions
if (count === 2) {
return {
type: "speak",
session_id: sessionId,
text: "I still haven't heard your response. Please speak clearly after the beep. Say 'agent' if you'd like to speak to a person.",
user_input_timeout_seconds: 10 // Give more time
};
}
// First timeout - gentle prompt
return {
type: "speak",
session_id: sessionId,
text: "I didn't catch that. Are you still there? Please let me know how I can help you.",
user_input_timeout_seconds: 8
};
},
onSessionEnd: async (event) => {
// Cleanup timeout counters
timeoutCounts.delete(event.session.id);
console.log(`Session ${event.session.id} ended`);
},
});
const app = express();
app.use(express.json());
app.post("/webhook", assistant.express());
app.listen(3000, () => {
console.log("Timeout-aware assistant running on port 3000");
});Advanced Timeout Strategy
Context-aware timeout handling with different strategies based on the conversation state:
typescript
interface SessionData {
state: "greeting" | "collecting_info" | "confirming" | "completing";
timeouts: number;
data: Record<string, any>;
}
const sessions = new Map<string, SessionData>();
const assistant = AiFlowAssistant.create({
onSessionStart: async (event) => {
sessions.set(event.session.id, {
state: "greeting",
timeouts: 0,
data: {}
});
return {
type: "speak",
session_id: event.session.id,
text: "Hello! To help you with your order, I'll need some information. What's your order number?",
user_input_timeout_seconds: 10
};
},
onUserSpeak: async (event) => {
const session = sessions.get(event.session.id);
if (!session) return null;
// Reset timeout counter on successful input
session.timeouts = 0;
const text = event.text;
if (session.state === "greeting") {
session.data.orderNumber = text;
session.state = "collecting_info";
return {
type: "speak",
session_id: event.session.id,
text: `Thank you. Order number ${text} received. Can you verify your email address?`,
user_input_timeout_seconds: 10
};
}
if (session.state === "collecting_info") {
session.data.email = text;
session.state = "confirming";
return {
type: "speak",
session_id: event.session.id,
text: `Perfect. Let me look up order ${session.data.orderNumber} for ${text}. One moment please.`,
user_input_timeout_seconds: 5 // Shorter timeout for confirmation
};
}
return "How else can I help you?";
},
onUserInputTimeout: async (event) => {
const session = sessions.get(event.session.id);
if (!session) return null;
session.timeouts++;
// Different strategies based on conversation state
switch (session.state) {
case "greeting":
if (session.timeouts >= 2) {
return {
type: "speak",
session_id: event.session.id,
text: "I'm having trouble hearing your order number. Let me transfer you to someone who can help.",
// Follow with transfer
};
}
return {
type: "speak",
session_id: event.session.id,
text: "I didn't hear your order number. Please say or spell it out for me.",
user_input_timeout_seconds: 12 // Give extra time
};
case "collecting_info":
return {
type: "speak",
session_id: event.session.id,
text: "I need your email address to proceed. Please provide it now, or say 'skip' to continue without it.",
user_input_timeout_seconds: 10
};
case "confirming":
// Just continue with the process
session.state = "completing";
return {
type: "speak",
session_id: event.session.id,
text: "I found your order. Your package is scheduled for delivery tomorrow. Is there anything else I can help with?",
user_input_timeout_seconds: 8
};
default:
if (session.timeouts >= 3) {
return {
type: "hangup",
session_id: event.session.id
};
}
return {
type: "speak",
session_id: event.session.id,
text: "Are you still there?",
user_input_timeout_seconds: 5
};
}
},
onSessionEnd: async (event) => {
sessions.delete(event.session.id);
},
});Next Steps
- Integration Guides - Detailed integration guides
- API Reference - Complete API documentation