Este artigo foi traduzido por máquina.

O trabalho programador

Fale comigo, Parte 3: Conheça o terapeuta

Ted Neward

 

Ted NewardNa primeira parte desta série (msdn.microsoft.com/magazine/hh781028), criei um simple sistema de entrada de voz pelo telefone usando o sistema de nuvem hospedado voz/SMS Tropo. Não era muito complicado, mas ele mostrou como usar o Tropo scripting API, hospedado nos servidores Tropo, para receber chamadas telefônicas, apresentam um menu, coletar entrada de resposta e assim por diante.

Na segunda coluna (msdn.microsoft.com/magazine/hh852597), dei um passo para o lado e falou sobre Feliza, um "bate-papo-bot" no espírito do programa "ELIZA" original, projetado para ter texto de usuário de entrada e responde a ele em uma maneira similar a que nós pode ouvir enquanto deitado no sofá do psicólogo. Novamente, "ela" não era tão sofisticada, mas Feliza tem o ponto em toda e mais importante, demonstrou como o sistema poderia ser facilmente estendido para aproximar-se muito para passar o teste de Turing.

Parece natural, em seguida, tomar estas duas peças e solda-los juntos: Deixe Tropo reunir a voz ou SMS de entrada do usuário, alimentá-lo para Feliza, deixe seu calcular uma resposta profunda, pensativa, enviá-lo para Tropo e ter Tropo em transformar alimentos ele volta para o usuário. Infelizmente, uma desconexão significativa impede de ser tão fácil como parece. Porque estamos usando a API de Scripting Tropo, nosso aplicativo Tropo é hospedado em seus servidores e Tropo não está abrindo os seus servidores para hospedar um ASP.NET app, muito menos nossos binários personalizados Feliza (que, como da última coluna, são apenas um conjunto de Microsoft.NET Framework DLLs).

Felizmente, Tropo percebeu que a possibilidade de fazer voz e SMS por si só não estava indo realmente cortá-lo entre a multidão de desenvolvedor de negócios experientes, e oferece o mesmo tipo de acesso de voz/SMS, mas sobre HTTP/resto-como canais. Em outras palavras, Tropo terá a voz recebida ou SMS de entrada, passá-lo para um URL de sua escolha, em seguida, capturar a resposta e … bem, fazer tudo o que a resposta diz-lhe para (ver Figura 1).

Tropo-Hosted API Call Flow
Figura 1 fluxo de chamadas de API Tropo-hospedado

Verdadeiro, isto adiciona outra camada de comunicação em rede para todo o sistema, com todas as preocupações de failover e desempenho outra ida e volta de rede implica. Mas isso também significa que podemos capturar a entrada e armazená-lo em qualquer servidor de nossa escolha, que poderia muito bem ser uma preocupação significativa para certas aplicações — segurança, acessar banco de dados e assim por diante.

Então, vamos dar mais um passo para o lado e descobrir como Tropo faz esta pequena dança HTTP.

Olá, Tropo … do meu domínio

O lugar para começar é com um simple "Hello world"-acesso de estilo. Tropo, como muitas APIs da Internet, usa HTTP como o canal de comunicação e JSON como formato serializado dos dados sendo enviados. Então o mais fácil coisa fazer é construir um JSON simple, estático objeto Tropo solicitar quando um número de telefone é chamado, dizendo "Olá" para o chamador. O JSON para fazer que tem esta aparência:

{
  "tropo": [
    {
      "say": {
        "value":"Hello, Tropo, from my host!"
      }
    }
  ]
}

Na superfície, a estrutura é bastante simple.O objeto JSON é um objeto de campo único, o campo "tropo" armazenar uma matriz de objetos que cada um dizer Tropo que fazer; Neste caso, é um "dizer" comando único, usando o mecanismo de reconhecimento de voz do Tropo para dizer, "Olá, Tropo, de meu host!" Mas Tropo precisa saber como encontrar este objeto JSON, que significa que temos de criar e configurar um novo aplicativo de Tropo, e precisamos de um servidor que Tropo pode encontrar (significado provavelmente não pode ser um laptop de desenvolvedor escondido atrás de um firewall).O segundo ponto é facilmente corrigido através de uma rápida visita ao seu favorito ASP.NET provedor de hospedagem (eu usei WinHost — seu plano básico é perfeito para isso).A primeira requer uma viagem de volta para o painel de controle do Tropo.

Desta vez, ao criar um novo aplicativo, escolha "Tropo WebAPI" em vez de "Tropo Scripting" (ver Figura 2) e dar-lhe a URL pela qual localizar esse arquivo em particular JSON; no meu caso, eu criei feliza.org (em antecipação dos passos após isso) e deixou-a cair fora da raiz do site.Totalmente configurado, ele se parece com Figura 3.

The Application WizardFigura 2 O Assistente de aplicativo

The Configured ApplicationFigura 3 aplicativo configurado

Embora Tropo foi feliz ligar um número Skype e Session Initiation Protocol (SIP) para nós, ainda temos de ligar manualmente um número de telefone padrão.Eu fiz isso enquanto você não estava olhando, e que o número é 425-247-3096, caso você queira tome um momento e estabelecer ligação com o servidor.

E é isso!Tipo de.

Se tenho vindo a construir seu próprio serviço de Tropo ao lado de mim, você não está recebendo qualquer tipo de resposta do telefone quando efectuar a marcação.Quando este for o caso, Tropo fornece um depurador de aplicativo para ser capaz de ver os logs do seu app Tropo.(Procure na barra azul na parte superior da página). Ao analisar o log, vemos algo como o seguinte: "Recebido o código de status de não-2XX em Tropo-Thread-8d60bf40bc3409843b52f30f929f641c [url=http://www.feliza.org/helloworld.json, código = 405]."

Sim, o Tropo tem um erro HTTP.Especificamente, ele tem um erro de "405", que (para quem não tiver memorizado a especificação HTTP ainda) se traduz como "Método não suportado."

Para ser honesto, chamando Tropo um serviço REST é algo de um misnomer, porque ele realmente não segue uma das regras cardeais de descanso: o verbo HTTP descreve a ação no recurso.Tropo realmente não se preocupam com o verbo; Ele apenas envia tudo.E é por isso que o host está respondendo (corretamente) o pedido de HTTP POST, porque uma página estática não POSTable.Oy.

Felizmente, nós sabemos que uma tecnologia que repara que muito facilmente.Neste ponto, podemos criar um ASP.NET app (um vazio é bom) e dê a ele um roteamento que leva "/ helloworld.json" e mapeia para um controlador simple, conforme mostrado no código a seguir (com muito código não-relevante omitido):

namespace TropoApp
{
  public class MvcApplication : System.Web.HttpApplication
  {
    public static void RegisterRoutes(RouteCollection routes)
    {
      routes.MapRoute("HelloWorld", "helloworld.json",
        new { controller = "HelloWorld", action = "Index" });
    }
  }
}

… que, por sua vez apenas retorna o JSON estático para nosso HelloWorld, conforme mostrado aqui (com muito código não-relevante omitido):

namespace TropoApp.Controllers
  {
    public class HelloWorldController : Controller
    {
      public const string helloworldJSON =
        "{ \"tropo\":[{\"say\":{\"value\":\"Hello, Tropo," +
        " from my host!
\"}}]}";
      [AcceptVerbs("GET", "POST")]
      public string Index() {
        return helloworldJSON;
      }
    }
  }

Empurrar isso para o servidor, e nós estamos dourados.

Dizer, dizer, dizer...

Se o "dizer" no JSON tickles sua memória um pouco, é porque nós funcionamos em-lo durante a exploração anterior do Tropo Scripting API. Naquela época, era um método são chamados, passando de uma série de nome/valor pares (na verdade JavaScript moda) dos parâmetros que descrevem como personalizar a saída falada. Aqui, porque não temos a capacidade de chamar APIs no servidor — Lembre-se, este arquivo JSON é hospedado no meu servidor, não a nuvem Tropo — temos de descrevê-lo em uma forma estrutural em vez disso. Assim, se queremos uma voz diferente, conversando com o usuário, precisamos especificar que um campo no objeto "dizer":

{
  "tropo":[
    {
      "say":
      {
        "value":"Hello, Tropo, from my host!",
        "voice":"Grace"
      }
    }
  ]
}

Agora, Grace (que é descrito como "Inglês australiano") nos será apresentada em nome do Tropo. Todos os detalhes do "dizer" é descritos nos docs API Tropo em seu Web site, como são todos o JSON objetos sendo passados para a frente e para trás.

Aqui é onde usando ASP.NET realmente brilha: Ao invés de tentar construir essas seqüências de caracteres de JSON no código, podemos usar os vínculos de objeto para JSON implícitos no ASP.NET para tornar mais fácil bater fora esses objetos JSON (ver Figura 4).

Figura 4 usando.NET Framework objeto para JSON Bindings

public static object helloworld =
  new { tropo =
    new[] {
      new {
        say = new {
          value = "Hello, Tropo, from my host!",
          voice = "Grace"
        }
      }
    }
  };
[AcceptVerbs("POST")]
public JsonResult Index()
{
  return Json(helloworld);
}

O JSON enviado deve ter seus campos e valores citados usando as aspas duplas, ao contrário do JavaScript normal "pode ser tanto" aspas simples ou aspas duplas. Usar as ligações de objeto para JSON faz tudo isso totalmente irrelevante para o desenvolvedor do aplicativo. Agradável. (Nota: Tropo também fornece uma biblioteca cliente para c# que abstrai muito afastado das coisas JSON, mas estou focando resto chamadas "manualmente" porque isso também ajuda a mostrar como fazer o mesmo tipo de coisa com o ASP.NET MVC em geral — ver bit.ly/bMMJDv para obter detalhes.)

Ouvir o som …

O ponto de Feliza não é apenas vomitar bits aleatórios cookie-cortador de tripas psicológica, embora. Ela precisa de ouvir a entrada do usuário falada, analisar que e depois vomitar bits aleatórios cookie-cortador de tripas psicológica. Para isso, temos de ser capazes de processar o entrada objeto Postado JSON que Tropo nos enviará. Ao fazê-lo é relativamente fácil, já que é um objeto JSON (e descrito no bit.ly/yV5ect relativas à estrutura "perguntar", que vai dizer alguma coisa, então pause e aguarde a entrada) e o ASP.NET MVC tem algumas ligações de auto JSON para objeto agradáveis para fazer isso. Assim, por exemplo, para enviar uma pergunta para o usuário e ter ele conduzir a um resultado diferente de JSON, queremos uma "perguntar" como que em Figura 5 (como visto nos docs Tropo).

Figura 5 um "pedir" exemplo

public static object helloworld =   new { tropo =
    new[] {
      new {
        say = new {
          value = "Hello, Tropo, from my host!",
          voice = "Grace"
        }
      }
    }
};
[AcceptVerbs("POST")]
public JsonResult Index()
{
  return Json(helloworld);
}
{
  "tropo": [
    {
      "ask": {
        "say": [
          {
            "value": "Please say your account number"  
          }
        ],
        "required": true,
        "timeout": 30,
        "name": "acctNum",
        "choices": {
          "value": "[5 DIGITS]"
        } 
      } 
    },
    {
      "on":{
        "next":"/accountDescribe.json",
        "event":"continue"
      }
    },
    {
      "on":{
        "next":"/accountIncomplete.json",
        "event":"incomplete"
      }
    }
  ] 
}

Como os parâmetros implicam, isso "pedir" irá expirar em 30 segundos e, em seguida, vincular os resultados (que devem ter cinco dígitos) em um parâmetro chamado "acctNum" na resposta JSON subseqüente POSTed volta, que será enviado para o ponto de extremidade de "accountDescribe.json". Se o número da conta é incompleto, Tropo postar para "accountIncomplete.json" e assim por diante.

Há apenas um problema com o sistema como está escrito no momento: Se podemos alterar o tipo de entrada (no campo "opções") de "[5 dígitos]" para "[ANY]" (que é o que quer Feliza, afinal — ela quer que os usuários para ser capaz de dizer qualquer coisa que eles querem), Tropo nos diz na documentação para "pedir" que tentando capturar "[qualquer]" tipos de entrada pelo canal de voz não é permitida. Isso coloca o kibosh usando a voz para falar com Feliza. Em quase qualquer outro cenário de aplicativo, isto não seria um problema. Geralmente entrada de voz terá de ser restrito a um pequeno conjunto de factores de produção, ou então vamos precisar uma quantidade tremenda de precisão em transformar o discurso ao texto. Tropo pode gravar o canal de voz e armazená-lo como um arquivo MP3 para análise off-line, mas Tropo nos oferece outra alternativa para entrada de texto aberto.

ASP.NET falar com F #

Nós já conectados Tropo até ao nosso Web site, mas Feliza ainda se senta em seu F # DLLs, sem ligação. Podemos agora começar a conectar os binários Feliza F # contra a entrada de entrada, mas que vai exigir o ASP.NET falar com F #, um exercício que é relativamente simples, mas não sempre óbvia. O ASP.NET site também vai precisar emitir respostas personalizadas JSON volta, então ao invés de deixar o trabalho concluída pela metade, vou terminar Feliza próxima vez — e olhar algumas maneiras potencialmente alargar ainda mais o sistema.

Codificação feliz!

Ted Neward é um consultor de arquitetura com LLC de Neudesic. Ele escreveu mais de 100 artigos, é um MVP c# e INETA orador e tem o autor e co-autor de uma dúzia de livros, incluindo o recém-lançado "profissional F # 2.0" (Wrox, 2010). Ele consulta, mentores regularmente. Contatá-lo em ted@tedneward.com se você estiver interessado em ter-lhe vir trabalhar com sua equipe ou ler seu blog em blogs.tedneward.com.

Agradecemos ao seguinte especialista técnico pela revisão deste artigo: Adam Kalsey