Skip to content

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