2

我正在试验 Twilio Flex。我们正在尝试构建的是集成了两个或三个参与者的聊天(机器人)应用程序(用户 + cc 人工代理 + chabotuser + cc 人工代理)。

我能够加入 Twilio 聊天频道(两者都来自基于 Node.js 的 Web 应用程序启动应用程序https://www.twilio.com/docs/chat/javascript/quickstart和我们使用 npm 包 twilio-chat 的服务器端代码)。然后我使用以下代码创建 Flex Task:

let task = await twilioClient.taskrouter.workspaces(TWILIO_FLEX_WORKSPACE)
  .tasks.create({attributes: JSON.stringify({
    type: 'support',
    message: 'some message from chat here'
  }),
  workflowSid: TWILIO_FLEX_CHAT_WORKFLOW,
  taskChannel: 'chat'
})

任务已成功创建并在 Twilio Flex 代理仪表板中弹出,但是当我接受它时:

  1. 聊天选项卡完全为空

  2. INFO 选项卡仅包含一般信息,例如:

    TASK CONTEXT
    Task type
    chat
    
    Task created on
    Wed Jan 23 2019 16:01:36 GMT+0100 (Central Europe Standard Time)
    
    Task priority
    0
    
    Task queue
    Everyone
    
    CUSTOMER CONTEXT
    Customer name / phone number
    Anonymous
    
    Country
    ADDONS
    No add-ons enabled. To expand your experience, visit Twilio Marketplace
    

我的自定义属性(类型/消息)根本不包括在内

我无法在 twilio 聊天中找到任何使用 flex 的复杂示例,这里只是非常通用(而不是过度解释)的高级概述:https ://www.twilio.com/docs/taskrouter/contact-center-blueprint/聊天任务路由器

有人有将聊天(不一定是 Twilio Chat)与 Twilio Flex 集成的经验吗?

  1. 如何正确创建Task Rotuer任务,以便在聊天中显示消息并在INFO选项卡上显示自定义属性?
  2. 如何实现该代理在 Flex 聊天窗口中的响应将路由回现有聊天?
  3. 如何实现后续用户消息将被路由到现有的 Flex 任务而不是创建新任务?换句话说,如何跟踪聊天和 Flex 之间的对话?

  4. 有人有代码片段显示原始“ Flex Create Chat ”Twilio 功能在从 Twilio 控制台中删除并替换为 Twilio 代理服务集成之前的样子吗?

4

1 回答 1

2

我正在尝试做类似的事情(可编程聊天,Twilio Flex),这就是让我进入工作状态的原因:

  1. 我没有手动创建任务,而是选择了在初始化 Flex 时获得的默认 Studio 流程。我从这个文档开始,但它只给出了理论上的理解。我通过使用Twilio Flex 示例 Web 应用程序并跟踪它创建的通道找出了实际的 webhook 。
  2. 每当网络/移动客户端想要聊天时,我都会调用我的自定义端点来执行所需的设置。
// After creating a Twilio Programmable Chat Channel set up a Studio webhook 

app.post("/create-task", function(request, response) {
  // see full code below

  chatService.channels
    .create({
      // See full code below
    })
    .then(channel => {
      const webhookUrl = channel.links.webhooks;

      const options = {
        url: webhookUrl,
        method: "POST",
        auth: {
          user: accountSid,
          pass: authToken
        },
        form: {
          Type: "studio",
          "Configuration.FlowSid": twilioFlowSid
        }
      };

      return new Promise((resolve, reject) => {
        requestLibrary.post(options, function(error, response, body) {
          if (!error) {
            resolve(channel);
          } else {
            reject(error);
          }
        });
      });
    });
  // see full code below
});
  1. 那只会让你成功一半。现在,您应该会在 Flex 中看到一个任务弹出,但如果 Agent 接受它,他将无法回复消息,也看不到来自客户端的消息。我认为当您从 Twilio Widget 执行此操作时会涉及到一些魔法。

我能够弄清楚,对于我手动创建的频道,当我接受作为代理的任务时,代理不会加入频道。所以参与者的数量是 1 而不是 2。

这意味着 Agent 基本上看不到 Channel 数据并向其发送消息。也许我的频道在属性中缺少一些元数据,但我还无法弄清楚。

我所做的是我使用了一个回调,当任务状态发生变化时,你会得到一个回调,特别是,我使用reservation.accepted事件手动将代理添加为通道的成员。您可以在底部的 TaskRouter 设置下添加回调。

app.post("/accept-task-callback", function(request, response) {
  const { TaskAttributes, WorkerSid, WorkerName, EventType } = request.body;
  const { channelSid } = JSON.parse(TaskAttributes);

  console.log("received event", EventType);

  if (EventType !== "reservation.accepted") {
    response.send("OK");
    return;
  }

  console.log("Adding member", WorkerSid, WorkerName, "on event", EventType);

  chatService
    .channels(channelSid)
    .members.create({ identity: WorkerName })
    .then(member => {
      response.send({
        instruction: "accept"
      });
    })
    .catch(error => {
      console.error(error);
      response.send({
        instruction: "reject"
      });
    });
});

这是完整的代码

// This is Express App

app.post("/create-task", function(request, response) {
  const accountSid = process.env.TWILIO_ACCOUNT_SID;
  const authToken = process.env.TWILIO_AUTH_TOKEN;
  const workspaceSid = process.env.TWILIO_WORKSPACE_SID;
  const workflowSid = process.env.TWILIO_WORKFLOW_SID;
  const twilioFlowSid = "FW..."

  // Identity of the Twilio Programmable Chat user who initiates a dialog. You get it from you signin or whatever
  const username = request.body || "Nancy Drew Support";

  chatService.channels
    .create({
      type: "private",
      friendlyName: username,
      attributes: JSON.stringify({
        status: "ACTIVE",
        from: username,
        channel_type: "web"
      })
    })
    .then(channel => {
      const webhookUrl = channel.links.webhooks;

      const options = {
        url: webhookUrl,
        method: "POST",
        auth: {
          user: accountSid,
          pass: authToken
        },
        form: {
          Type: "studio",
          "Configuration.FlowSid": twilioFlowSid
        }
      };

      return new Promise((resolve, reject) => {
        requestLibrary.post(options, function(error, response, body) {
          if (!error) {
            resolve(channel);
          } else 
            reject(error);
          }
        });
      });
    })
    .then(async channel => {
        // Join as a Customer requesting Support
      return chatService
        .channels(channel.sid)
        .members.create({ identity: username });
    })
    .then(member => {
        // return back channel sid we created
      response.send({ channelSid: member.channelSid });
    })
    .catch(error => {
      console.log(error);
      response.fail(error);
    });
});

app.post("/accept-task-callback", function(request, response) {
  const { TaskAttributes, WorkerSid, WorkerName, EventType } = request.body;
  const { channelSid } = JSON.parse(TaskAttributes);

  console.log("received event", EventType);

  if (EventType !== "reservation.accepted") {
    response.send("OK");
    return;
  }

  console.log("Adding member", WorkerSid, WorkerName, "on event", EventType);

  chatService
    .channels(channelSid)
    .members.create({ identity: WorkerName })
    .then(member => {
      response.send({
        instruction: "accept"
      });
    })
    .catch(error => {
      console.error(error);
      response.send({
        instruction: "reject"
      });
    });
});

我还有很多事情要弄清楚。不幸的是,Flex 文档在这一点上并不是很好,并且错过了一些非常基本的教程,例如“从头开始使用 Flex 配置 Twilio 可编程聊天”。这种教程将帮助每个人了解所有 Twilio API 如何在像 Flex 这样强大的工具中组合在一起。

无论如何,希望我的回答有帮助。如果您有问题,我可以尝试进一步详细说明。

于 2019-03-12T18:59:46.390 回答