HoloLens (1.ª generación) y Azure 312: Integración de bots
Nota:
Los tutoriales de Mixed Reality Academy se han diseñado teniendo en cuenta HoloLens (1.ª generación) y los cascos envolventes de realidad mixta. Por lo tanto, creemos que es importante conservar estos tutoriales para los desarrolladores que sigan buscando instrucciones sobre el desarrollo para esos dispositivos. Estos tutoriales no se actualizarán con los conjuntos de herramientas o las interacciones más recientes que se usan para HoloLens 2. Se mantendrán para que sigan funcionando en los dispositivos compatibles. Habrá una nueva serie de tutoriales que se publicarán en el futuro que demostrarán cómo desarrollar para HoloLens 2. Este aviso se actualizará con un vínculo a esos tutoriales cuando se publiquen.
En este curso, aprenderá a crear e implementar un bot mediante Microsoft Bot Framework V4 y a comunicarse con él a través de una aplicación de Windows Mixed Reality.
Microsoft Bot Framework V4 es un conjunto de API diseñadas para proporcionar a los desarrolladores las herramientas para crear una aplicación de bot extensible y escalable. Para obtener más información, visite la página microsoft Bot Framework o el repositorio de Git V4.
Después de completar este curso, habrá creado una aplicación de Windows Mixed Reality, que podrá hacer lo siguiente:
- Use un gesto de pulsación para iniciar el bot escuchando la voz de los usuarios.
- Cuando el usuario haya dicho algo, el bot intentará proporcionar una respuesta.
- Muestra la respuesta de los bots como texto, situado cerca del bot, en la escena de Unity.
En la aplicación, es el momento de integrar los resultados con el diseño. Este curso está diseñado para enseñar a integrar un servicio de Azure con el proyecto de Unity. Es su trabajo usar el conocimiento que obtiene de este curso para mejorar la aplicación de realidad mixta.
Compatibilidad con dispositivos
Curso | HoloLens | Cascos envolventes |
---|---|---|
MR y Azure 312: integración de bots | ✔️ | ✔️ |
Nota:
Aunque este curso se centra principalmente en HoloLens, también puede aplicar lo que aprende en este curso a cascos envolventes de Windows Mixed Reality (VR). Dado que los cascos envolventes (VR) no tienen cámaras accesibles, necesitará una cámara externa conectada a su PC. A medida que siga con el curso, verá notas sobre los cambios que podría necesitar para admitir cascos envolventes (VR).
Requisitos previos
Nota:
Este tutorial está diseñado para desarrolladores que tienen experiencia básica con Unity y C#. Tenga en cuenta también que los requisitos previos y las instrucciones escritas de este documento representan lo que se ha probado y comprobado en el momento de redactarlo (julio de 2018). Puede usar el software más reciente, como se muestra en el artículo de instalación de las herramientas , aunque no debe asumirse que la información de este curso coincidirá perfectamente con lo que encontrará en el software más reciente que lo que se muestra a continuación.
Se recomienda el siguiente hardware y software para este curso:
- Un equipo de desarrollo, compatible con Windows Mixed Reality para el desarrollo de cascos envolventes (VR)
- Windows 10 Fall Creators Update (o posterior) con el modo desarrollador habilitado
- El SDK de Windows 10 más reciente
- Unity 2017.4
- Visual Studio 2017
- Casco envolvente (VR) de Windows Mixed Reality o Microsoft HoloLens con el modo desarrollador habilitado
- Acceso a Internet para Azure y para la recuperación de Azure Bot. Para obtener más información, siga este vínculo.
Antes de comenzar
- Para evitar encontrar problemas al compilar este proyecto, se recomienda encarecidamente crear el proyecto mencionado en este tutorial en una carpeta raíz o casi raíz (las rutas de acceso de carpeta largas pueden causar problemas en tiempo de compilación).
- Configure y pruebe holoLens. Si necesita compatibilidad con la configuración de HoloLens, asegúrese de visitar el artículo configuración de HoloLens.
- Es una buena idea realizar la calibración y la optimización del sensor al empezar a desarrollar una nueva aplicación de HoloLens (a veces puede ayudar a realizar esas tareas para cada usuario).
Para obtener ayuda sobre calibración, siga este vínculo al artículo Calibración de HoloLens.
Para obtener ayuda sobre la optimización del sensor, siga este vínculo al artículo Optimización de sensores de HoloLens.
Capítulo 1: Creación de la aplicación bot
El primer paso es crear el bot como una aplicación web local ASP.Net Core. Una vez que haya terminado y probado, lo publicará en Azure Portal.
Abra Visual Studio. Cree un nuevo proyecto, seleccione Aplicación web de ASP NET Core como el tipo de proyecto (lo encontrará en la subsección .NET Core) y llámelo MyBot. Haga clic en OK.
En la ventana que aparecerá, seleccione Vacío. Asegúrese también de que el destino esté establecido en ASP NET Core 2.0 y la autenticación esté establecida en Sin autenticación. Haga clic en OK.
Ahora se abrirá la solución. Haga clic con el botón derecho en Solución Mybot en el Explorador de soluciones y haga clic en Administrar paquetes NuGet para la solución.
En la pestaña Examinar , busque Microsoft.Bot.Builder.Integration.AspNet.Core (asegúrese de que ha activado Incluir versión preliminar). Seleccione la versión 4.0.1-preview del paquete y marque las casillas del proyecto. A continuación, haga clic en Instalar. Ahora ha instalado las bibliotecas necesarias para Bot Framework v4. Cierre la página NuGet.
Haga clic con el botón derecho en el proyecto, MyBot, en el Explorador de soluciones y haga clic en Agregar | clase.
Asigne un nombre a la clase MyBot y haga clic en Agregar.
Repita el punto anterior para crear otra clase denominada ConversationContext.
Haga clic con el botón derecho en wwwroot en el Explorador de soluciones y haga clic en Agregar | nuevo elemento. Seleccione Página HTML (la encontrará en la subsección Web). Asigne al archivo el nombre default.html. Haga clic en Agregar.
La lista de clases o objetos de la Explorador de soluciones debe tener un aspecto similar a la imagen siguiente.
Haga doble clic en la clase ConversationContext . Esta clase es responsable de contener las variables usadas por el bot para mantener el contexto de la conversación. Estos valores de contexto de conversación se mantienen en una instancia de esta clase, ya que cualquier instancia de la clase MyBot se actualizará cada vez que se reciba una actividad. Agregue el siguiente código a la clase :
namespace MyBot { public static class ConversationContext { internal static string userName; internal static string userMsg; } }
Haga doble clic en la clase MyBot . Esta clase hospedará los controladores llamados por cualquier actividad entrante del cliente. En esta clase, agregará el código usado para compilar la conversación entre el bot y el cliente. Como se mencionó anteriormente, se inicializa una instancia de esta clase cada vez que se recibe una actividad. Agregue el código siguiente a esta clase:
using Microsoft.Bot; using Microsoft.Bot.Builder; using Microsoft.Bot.Schema; using System.Threading.Tasks; namespace MyBot { public class MyBot : IBot { public async Task OnTurn(ITurnContext context) { ConversationContext.userMsg = context.Activity.Text; if (context.Activity.Type is ActivityTypes.Message) { if (string.IsNullOrEmpty(ConversationContext.userName)) { ConversationContext.userName = ConversationContext.userMsg; await context.SendActivity($"Hello {ConversationContext.userName}. Looks like today it is going to rain. \nLuckily I have umbrellas and waterproof jackets to sell!"); } else { if (ConversationContext.userMsg.Contains("how much")) { if (ConversationContext.userMsg.Contains("umbrella")) await context.SendActivity($"Umbrellas are $13."); else if (ConversationContext.userMsg.Contains("jacket")) await context.SendActivity($"Waterproof jackets are $30."); else await context.SendActivity($"Umbrellas are $13. \nWaterproof jackets are $30."); } else if (ConversationContext.userMsg.Contains("color") || ConversationContext.userMsg.Contains("colour")) { await context.SendActivity($"Umbrellas are black. \nWaterproof jackets are yellow."); } else { await context.SendActivity($"Sorry {ConversationContext.userName}. I did not understand the question"); } } } else { ConversationContext.userMsg = string.Empty; ConversationContext.userName = string.Empty; await context.SendActivity($"Welcome! \nI am the Weather Shop Bot \nWhat is your name?"); } } } }
Haga doble clic en la clase Startup . Esta clase inicializará el bot. Agregue el siguiente código a la clase :
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Bot.Builder.BotFramework; using Microsoft.Bot.Builder.Integration.AspNet.Core; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace MyBot { public class Startup { public IConfiguration Configuration { get; } public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); Configuration = builder.Build(); } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddSingleton(_ => Configuration); services.AddBot<MyBot>(options => { options.CredentialProvider = new ConfigurationCredentialProvider(Configuration); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseDefaultFiles(); app.UseStaticFiles(); app.UseBotFramework(); } } }
Abra el archivo de clase Program y compruebe que el código en él es el mismo que el siguiente:
using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; namespace MyBot { public class Program { public static void Main(string[] args) { BuildWebHost(args).Run(); } public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .Build(); } }
Recuerde guardar los cambios para hacerlo, vaya a Guardar>todo en la barra de herramientas de la parte superior de Visual Studio.
Capítulo 2: Creación de Azure Bot Service
Ahora que ha creado el código para el bot, debe publicarlo en una instancia de Web App Bot Service, en Azure Portal. En este capítulo se muestra cómo crear y configurar Bot Service en Azure y, a continuación, publicar el código en él.
En primer lugar, inicie sesión en Azure Portal (https://portal.azure.com).
- Si aún no tiene una cuenta de Azure, deberá crear una. Si sigue este tutorial en una situación de clase o laboratorio, pida a su instructor o a uno de los proctores que le ayuden a configurar la nueva cuenta.
Una vez que haya iniciado sesión, haga clic en Crear un recurso en la esquina superior izquierda y busque Bot de aplicación web y haga clic en Entrar.
La nueva página proporcionará una descripción de Web App Bot Service. En la parte inferior izquierda de esta página, seleccione el botón Crear para crear una asociación con este servicio.
Una vez que haya hecho clic en Crear:
Inserte el nombre deseado para esta instancia de servicio.
Seleccione una opción en Suscripción.
Elija un grupo de recursos o cree uno nuevo. Un grupo de recursos proporciona una manera de supervisar, controlar el acceso, aprovisionar y administrar la facturación de una colección de recursos de Azure. Se recomienda mantener todos los servicios de Azure asociados a un único proyecto (por ejemplo, estos cursos) en un grupo de recursos común).
Si desea obtener más información sobre los grupos de recursos de Azure, siga este vínculo.
Determine la ubicación del grupo de recursos (si va a crear un nuevo grupo de recursos). Idealmente, la ubicación estaría en la región donde se ejecutaría la aplicación. Algunos recursos de Azure solo están disponibles en determinadas regiones.
Seleccione el plan de tarifa adecuado para usted, si es la primera vez que se crea un servicio bot de aplicación web, un nivel gratuito (denominado F0) debe estar disponible para usted.
El nombre de la aplicación puede dejarse igual que el nombre del bot.
Deje la plantilla bot como Básica (C#).
El plan o la ubicación de App Service deben haberse rellenado automáticamente para su cuenta.
Establezca Azure Storage que desea usar para hospedar el bot. Si aún no tiene una, puede crearla aquí.
También deberá confirmar que ha comprendido los Términos y Condiciones aplicados a este Servicio.
Haga clic en Crear.
Una vez que haya hecho clic en Crear, tendrá que esperar a que se cree el servicio, esto puede tardar un minuto.
Aparecerá una notificación en el portal una vez creada la instancia de servicio.
Haga clic en la notificación para explorar la nueva instancia de servicio.
Haga clic en el botón Ir al recurso de la notificación para explorar la nueva instancia de servicio. Se le llevará a la nueva instancia del servicio de Azure.
En este momento, debe configurar una característica denominada Direct Line para permitir que la aplicación cliente se comunique con este Bot Service. Haga clic en Canales y, a continuación, en la sección Agregar un canal destacado, haga clic en Configurar canal de Direct Line.
En esta página encontrará las claves secretas que permitirán que la aplicación cliente se autentique con el bot. Haga clic en el botón Mostrar y realice una copia de una de las claves mostradas, ya que lo necesitará más adelante en el proyecto.
Capítulo 3: Publicación del bot en Azure Web App Bot Service
Ahora que el servicio está listo, debe publicar el código del bot, que creó anteriormente, en la instancia de Web App Bot Service recién creada.
Nota:
Tendrá que publicar el bot en el servicio de Azure cada vez que realice cambios en la solución o el código del bot.
Vuelva a la solución de Visual Studio que creó anteriormente.
Haga clic con el botón derecho en el proyecto MyBot, en el Explorador de soluciones y, a continuación, haga clic en Publicar.
En la página Elegir un destino de publicación, haga clic en App Service y, a continuación, seleccione Existente y, por último, haga clic en Crear perfil (es posible que tenga que hacer clic en la flecha desplegable junto al botón Publicar, si no está visible).
Si aún no ha iniciado sesión en su cuenta Microsoft, debe hacerlo aquí.
En la página Publicar , encontrará que tiene que establecer la misma suscripción que usó para la creación de Web App Bot Service. A continuación, establezca la vista como grupo de recursos y, en la estructura de carpetas desplegables, seleccione el grupo de recursos que ha creado anteriormente. Haga clic en OK.
Ahora haga clic en el botón Publicar y espere a que se publique el bot (puede tardar unos minutos).
Capítulo 4: Configuración del proyecto de Unity
A continuación se muestra una configuración típica para desarrollar con realidad mixta y, como tal, es una buena plantilla para otros proyectos.
Abra Unity y haga clic en Nuevo.
Ahora deberá proporcionar un nombre de proyecto de Unity. Inserte HoloLens Bot. Asegúrese de que la plantilla de proyecto esté establecida en 3D. Establezca la ubicación en algún lugar adecuado para usted (recuerde que más cerca de los directorios raíz es mejor). A continuación, haga clic en Crear proyecto.
Con Unity abierto, vale la pena comprobar que el Editor de scripts predeterminado está establecido en Visual Studio. Vaya a Editar > preferencias y, a continuación, en la nueva ventana, vaya a Herramientas externas. Cambie el Editor de scripts externos a Visual Studio 2017. Cierre la ventana Preferencias.
A continuación, vaya a Configuración > de compilación de archivos y seleccione Plataforma universal de Windows y haga clic en el botón Cambiar plataforma para aplicar la selección.
Mientras sigue en Configuración de compilación de archivos > y asegúrese de que:
El dispositivo de destino está establecido en HoloLens
Para los cascos envolventes, establezca Dispositivo de destino en Cualquier dispositivo.
Tipo de compilación se establece en D3D
El SDK se establece en Latest installed (Versión más reciente instalada)
La versión de Visual Studio se establece en Latest installed (Versión más reciente instalada)
Build and Run (Compilar y ejecutar ) está establecido en Equipo local
Guarde la escena y agréguela a la compilación.
Para ello, seleccione Agregar escenas abiertas. Aparecerá una ventana de guardado.
Cree una nueva carpeta para esto y cualquier escena futura y, a continuación, seleccione el botón Nueva carpeta para crear una nueva carpeta, asígnela el nombre Scenes.
Abra la carpeta Escenas recién creada y, a continuación, en el campo Nombre de archivo: texto, escriba BotScene y, a continuación, haga clic en Guardar.
La configuración restante, en Configuración de compilación, debe dejarse como predeterminada por ahora.
En la ventana Configuración de compilación, haga clic en el botón Configuración del reproductor; se abrirá el panel relacionado en el espacio donde se encuentra el Inspector.
En este panel, es necesario comprobar algunos valores:
En la pestaña Otros valores :
La versión del entorno de ejecución de scripting debe ser experimental (EQUIVALENTE de NET 4.6). Si cambia esto, será necesario reiniciar el editor.
El back-end de scripting debe ser .NET
El nivel de compatibilidad de API debe ser .NET 4.6
En la pestaña Configuración de publicación, en Funcionalidades, active:
InternetClient
Microphone
Más abajo en el panel, en Configuración de XR (que se encuentra a continuación de Configuración de publicación), marque Virtual Reality Supported (Compatible con la realidad virtual), asegúrese de que se agrega el SDK de Windows Mixed Reality.
De nuevo en Configuración de compilación, los proyectos de Unity de C# ya no están atenuados; marque la casilla situada junto a esto.
Cierre la ventana Build Settings (Configuración de compilación).
Guarde la escena y el proyecto (FILE > SAVE SCENE/FILE > SAVE PROJECT).
Capítulo 5: Configuración de la cámara
Importante
Si desea omitir el componente Configuración de Unity de este curso y continuar directamente en el código, no dude en descargar este paquete Azure-MR-312-Package.unitypackage, impórtelo en el proyecto como paquete personalizado y, a continuación, continúe desde el capítulo 7.
En el panel Jerarquía, seleccione la cámara principal.
Una vez seleccionado, podrá ver todos los componentes de la cámara principal en el panel Inspector.
- El objeto Camera debe denominarse Cámara principal (tenga en cuenta la ortografía)
- La etiqueta de cámara principal debe establecerse en MainCamera (tenga en cuenta la ortografía).
- Asegúrese de que la posición de transformación está establecida en 0, 0, 0
- Establezca Borrar marcas en Color sólido.
- Establezca el color de fondo del componente cámara en Negro, Alfa 0 (código hexadecimal: #000000000)
Capítulo 6: Importación de la biblioteca Newtonsoft
Para ayudarle a deserializar y serializar objetos recibidos y enviados a Bot Service, debe descargar la biblioteca Newtonsoft . Encontrará una versión compatible ya organizada con la estructura de carpetas de Unity correcta aquí.
Para importar la biblioteca Newtonsoft en el proyecto, use el paquete de Unity que se incluye en este curso.
Agregue el archivo .unitypackage a Unity mediante la opción de >menú Importar paquete personalizado de paquetes>de activos.
En el cuadro Importar paquete de Unity que aparece, asegúrese de que está seleccionado todo en complementos (e incluidos).
Haga clic en el botón Importar para agregar los elementos al proyecto.
Vaya a la carpeta Newtonsoft en Complementos en la vista del proyecto y seleccione el complemento Newtonsoft.
Con el complemento Newtonsoft seleccionado, asegúrese de que Cualquier plataforma está desactivada y, a continuación, asegúrese de que WSAPlayer también esté desactivado y, a continuación, haga clic en Aplicar. Esto es solo para confirmar que los archivos están configurados correctamente.
Nota:
Marcar estos complementos los configura para que solo se usen en el Editor de Unity. Hay un conjunto diferente de ellos en la carpeta WSA que se usará después de exportar el proyecto desde Unity.
A continuación, debe abrir la carpeta WSA , dentro de la carpeta Newtonsoft . Verá una copia del mismo archivo que acaba de configurar. Seleccione el archivo y, a continuación, en el inspector, asegúrese de que
- Cualquier plataforma está desactivada
- solo se comprueba WSAPlayer
- No se comprueba el proceso de dont
Capítulo 7: Creación de BotTag
Cree un nuevo objeto Tag denominado BotTag. Seleccione la Cámara principal en la escena. Haga clic en el menú desplegable Etiqueta del panel Inspector. Haga clic en Agregar etiqueta.
Haga clic en el + símbolo. Asigne un nombre a la nueva etiqueta como BotTag, Guardar.
Advertencia
No aplique botTag a la cámara principal. Si lo has hecho accidentalmente, asegúrate de cambiar la etiqueta Cámara principal de nuevo a MainCamera.
Capítulo 8: Creación de la clase BotObjects
El primer script que necesita crear es la clase BotObjects , que es una clase vacía creada para que una serie de otros objetos de clase se puedan almacenar dentro del mismo script y acceder a ellos otros scripts de la escena.
La creación de esta clase es puramente una opción arquitectónica, estos objetos podrían hospedarse en el script bot que creará más adelante en este curso.
Para crear esta clase:
Haga clic con el botón derecho en el panel Proyecto y, a continuación , en Crear > carpeta. Asigne un nombre a la carpeta Scripts.
Haga doble clic en la carpeta Scripts para abrirla. A continuación, en esa carpeta, haga clic con el botón derecho y seleccione Crear > script de C#. Asigne al script el nombre BotObjects.
Haga doble clic en el nuevo script BotObjects para abrirlo con Visual Studio.
Elimine el contenido del script y reemplácelo por el código siguiente:
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class BotObjects : MonoBehaviour{} /// <summary> /// Object received when first opening a conversation /// </summary> [Serializable] public class ConversationObject { public string ConversationId; public string token; public string expires_in; public string streamUrl; public string referenceGrammarId; } /// <summary> /// Object including all Activities /// </summary> [Serializable] public class ActivitiesRootObject { public List<Activity> activities { get; set; } public string watermark { get; set; } } [Serializable] public class Conversation { public string id { get; set; } } [Serializable] public class From { public string id { get; set; } public string name { get; set; } } [Serializable] public class Activity { public string type { get; set; } public string channelId { get; set; } public Conversation conversation { get; set; } public string id { get; set; } public From from { get; set; } public string text { get; set; } public string textFormat { get; set; } public DateTime timestamp { get; set; } public string serviceUrl { get; set; } }
Asegúrese de guardar los cambios en Visual Studio antes de volver a Unity.
Capítulo 9: Crear la clase GazeInput
La siguiente clase que va a crear es la clase GazeInput . Esta clase es responsable de:
- Crear un cursor que represente la mirada del jugador.
- Detectar objetos alcanzados por la mirada del jugador y mantener una referencia a los objetos detectados.
Para crear esta clase:
Vaya a la carpeta Scripts que creó anteriormente.
Haga clic con el botón derecho en la carpeta Create C# Script (Crear > script de C#). Llame al script GazeInput.
Haga doble clic en el nuevo script GazeInput para abrirlo con Visual Studio.
Inserte la siguiente línea justo en la parte superior del nombre de clase:
/// <summary> /// Class responsible for the User's gaze interactions /// </summary> [System.Serializable] public class GazeInput : MonoBehaviour
A continuación, agregue las siguientes variables dentro de la clase GazeInput, encima del método Start():
[Tooltip("Used to compare whether an object is to be interacted with.")] internal string InteractibleTag = "BotTag"; /// <summary> /// Length of the gaze /// </summary> internal float GazeMaxDistance = 300; /// <summary> /// Object currently gazed /// </summary> internal GameObject FocusedObject { get; private set; } internal GameObject _oldFocusedObject { get; private set; } internal RaycastHit HitInfo { get; private set; } /// <summary> /// Cursor object visible in the scene /// </summary> internal GameObject Cursor { get; private set; } internal bool Hit { get; private set; } internal Vector3 Position { get; private set; } internal Vector3 Normal { get; private set; } private Vector3 _gazeOrigin; private Vector3 _gazeDirection;
Se debe agregar código para el método Start(). Se llamará cuando se inicialice la clase:
/// <summary> /// Start method used upon initialization. /// </summary> internal virtual void Start() { FocusedObject = null; Cursor = CreateCursor(); }
Implemente un método que cree una instancia y configure el cursor de mirada:
/// <summary> /// Method to create a cursor object. /// </summary> internal GameObject CreateCursor() { GameObject newCursor = GameObject.CreatePrimitive(PrimitiveType.Sphere); newCursor.SetActive(false); // Remove the collider, so it does not block Raycast. Destroy(newCursor.GetComponent<SphereCollider>()); newCursor.transform.localScale = new Vector3(0.05f, 0.05f, 0.05f); Material mat = new Material(Shader.Find("Diffuse")); newCursor.GetComponent<MeshRenderer>().material = mat; mat.color = Color.HSVToRGB(0.0223f, 0.7922f, 1.000f); newCursor.SetActive(true); return newCursor; }
Implemente los métodos que configurarán Raycast desde la cámara principal y realizará un seguimiento del objeto centrado actual.
/// <summary> /// Called every frame /// </summary> internal virtual void Update() { _gazeOrigin = Camera.main.transform.position; _gazeDirection = Camera.main.transform.forward; UpdateRaycast(); } /// <summary> /// Reset the old focused object, stop the gaze timer, and send data if it /// is greater than one. /// </summary> private void ResetFocusedObject() { // Ensure the old focused object is not null. if (_oldFocusedObject != null) { if (_oldFocusedObject.CompareTag(InteractibleTag)) { // Provide the OnGazeExited event. _oldFocusedObject.SendMessage("OnGazeExited", SendMessageOptions.DontRequireReceiver); } } } private void UpdateRaycast() { // Set the old focused gameobject. _oldFocusedObject = FocusedObject; RaycastHit hitInfo; // Initialize Raycasting. Hit = Physics.Raycast(_gazeOrigin, _gazeDirection, out hitInfo, GazeMaxDistance); HitInfo = hitInfo; // Check whether raycast has hit. if (Hit == true) { Position = hitInfo.point; Normal = hitInfo.normal; // Check whether the hit has a collider. if (hitInfo.collider != null) { // Set the focused object with what the user just looked at. FocusedObject = hitInfo.collider.gameObject; } else { // Object looked on is not valid, set focused gameobject to null. FocusedObject = null; } } else { // No object looked upon, set focused gameobject to null. FocusedObject = null; // Provide default position for cursor. Position = _gazeOrigin + (_gazeDirection * GazeMaxDistance); // Provide a default normal. Normal = _gazeDirection; } // Lerp the cursor to the given position, which helps to stabilize the gaze. Cursor.transform.position = Vector3.Lerp(Cursor.transform.position, Position, 0.6f); // Check whether the previous focused object is this same. If so, reset the focused object. if (FocusedObject != _oldFocusedObject) { ResetFocusedObject(); if (FocusedObject != null) { if (FocusedObject.CompareTag(InteractibleTag)) { // Provide the OnGazeEntered event. FocusedObject.SendMessage("OnGazeEntered", SendMessageOptions.DontRequireReceiver); } } } }
Asegúrese de guardar los cambios en Visual Studio antes de volver a Unity.
Capítulo 10: Creación de la clase Bot
El script que va a crear ahora se denomina Bot. Esta es la clase principal de la aplicación, almacena:
- Credenciales del bot de aplicación web
- Método que recopila los comandos de voz del usuario
- El método necesario para iniciar conversaciones con el bot de aplicación web
- Método necesario para enviar mensajes al bot de aplicación web
Para enviar mensajes a Bot Service, la corrutina SendMessageToBot() creará una actividad, que es un objeto reconocido por Bot Framework como datos enviados por el usuario.
Para crear esta clase:
Haga doble clic en la carpeta Scripts para abrirlo.
Haga clic con el botón derecho en la carpeta Scripts y haga clic en Crear > script de C#. Asigne un nombre al bot de script.
Haga doble clic en el nuevo script para abrirlo con Visual Studio.
Actualice los espacios de nombres para que sean los mismos que los siguientes, en la parte superior de la clase Bot :
using Newtonsoft.Json; using System.Collections; using System.Text; using UnityEngine; using UnityEngine.Networking; using UnityEngine.Windows.Speech;
Dentro de la clase Bot , agregue las siguientes variables:
/// <summary> /// Static instance of this class /// </summary> public static Bot Instance; /// <summary> /// Material of the sphere representing the Bot in the scene /// </summary> internal Material botMaterial; /// <summary> /// Speech recognizer class reference, which will convert speech to text. /// </summary> private DictationRecognizer dictationRecognizer; /// <summary> /// Use this variable to identify the Bot Id /// Can be any value /// </summary> private string botId = "MRBotId"; /// <summary> /// Use this variable to identify the Bot Name /// Can be any value /// </summary> private string botName = "MRBotName"; /// <summary> /// The Bot Secret key found on the Web App Bot Service on the Azure Portal /// </summary> private string botSecret = "-- Add your Secret Key here --"; /// <summary> /// Bot Endpoint, v4 Framework uses v3 endpoint at this point in time /// </summary> private string botEndpoint = "https://directline.botframework.com/v3/directline"; /// <summary> /// The conversation object reference /// </summary> private ConversationObject conversation; /// <summary> /// Bot states to regulate the application flow /// </summary> internal enum BotState {ReadyToListen, Listening, Processing} /// <summary> /// Flag for the Bot state /// </summary> internal BotState botState; /// <summary> /// Flag for the conversation status /// </summary> internal bool conversationStarted = false;
Nota:
Asegúrese de insertar la clave secreta del bot en la variable botSecret . Habrá anotado la clave secreta del bot al principio de este curso, en el capítulo 2, paso 10.
Ahora es necesario agregar código para Awake() y Start().
/// <summary> /// Called on Initialization /// </summary> void Awake() { Instance = this; } /// <summary> /// Called immediately after Awake method /// </summary> void Start() { botState = BotState.ReadyToListen; }
Agregue los dos controladores a los que llaman las bibliotecas de voz cuando comienza y finaliza la captura de voz. DictationRecognizer dejará de capturar automáticamente la voz del usuario cuando el usuario deje de hablar.
/// <summary> /// Start microphone capture. /// </summary> public void StartCapturingAudio() { botState = BotState.Listening; botMaterial.color = Color.red; // Start dictation dictationRecognizer = new DictationRecognizer(); dictationRecognizer.DictationResult += DictationRecognizer_DictationResult; dictationRecognizer.Start(); } /// <summary> /// Stop microphone capture. /// </summary> public void StopCapturingAudio() { botState = BotState.Processing; dictationRecognizer.Stop(); }
El siguiente controlador recopila el resultado de la entrada de voz del usuario y llama a la corrutina responsable de enviar el mensaje a Web App Bot Service.
/// <summary> /// This handler is called every time the Dictation detects a pause in the speech. /// </summary> private void DictationRecognizer_DictationResult(string text, ConfidenceLevel confidence) { // Update UI with dictation captured Debug.Log($"User just said: {text}"); // Send dictation to Bot StartCoroutine(SendMessageToBot(text, botId, botName, "message")); StopCapturingAudio(); }
Se llama a la siguiente corrutina para iniciar una conversación con el bot. Observará que una vez completada la llamada de conversación, llamará a SendMessageToCoroutine() pasando una serie de parámetros que establecerán la actividad que se enviará a Bot Service como un mensaje vacío. Esto se hace para pedir a Bot Service que inicie el diálogo.
/// <summary> /// Request a conversation with the Bot Service /// </summary> internal IEnumerator StartConversation() { string conversationEndpoint = string.Format("{0}/conversations", botEndpoint); WWWForm webForm = new WWWForm(); using (UnityWebRequest unityWebRequest = UnityWebRequest.Post(conversationEndpoint, webForm)) { unityWebRequest.SetRequestHeader("Authorization", "Bearer " + botSecret); unityWebRequest.downloadHandler = new DownloadHandlerBuffer(); yield return unityWebRequest.SendWebRequest(); string jsonResponse = unityWebRequest.downloadHandler.text; conversation = new ConversationObject(); conversation = JsonConvert.DeserializeObject<ConversationObject>(jsonResponse); Debug.Log($"Start Conversation - Id: {conversation.ConversationId}"); conversationStarted = true; } // The following call is necessary to create and inject an activity of type //"conversationUpdate" to request a first "introduction" from the Bot Service. StartCoroutine(SendMessageToBot("", botId, botName, "conversationUpdate")); }
Se llama a la siguiente corrutina para compilar la actividad que se enviará a Bot Service.
/// <summary> /// Send the user message to the Bot Service in form of activity /// and call for a response /// </summary> private IEnumerator SendMessageToBot(string message, string fromId, string fromName, string activityType) { Debug.Log($"SendMessageCoroutine: {conversation.ConversationId}, message: {message} from Id: {fromId} from name: {fromName}"); // Create a new activity here Activity activity = new Activity(); activity.from = new From(); activity.conversation = new Conversation(); activity.from.id = fromId; activity.from.name = fromName; activity.text = message; activity.type = activityType; activity.channelId = "DirectLineChannelId"; activity.conversation.id = conversation.ConversationId; // Serialize the activity string json = JsonConvert.SerializeObject(activity); string sendActivityEndpoint = string.Format("{0}/conversations/{1}/activities", botEndpoint, conversation.ConversationId); // Send the activity to the Bot using (UnityWebRequest www = new UnityWebRequest(sendActivityEndpoint, "POST")) { www.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(json)); www.downloadHandler = new DownloadHandlerBuffer(); www.SetRequestHeader("Authorization", "Bearer " + botSecret); www.SetRequestHeader("Content-Type", "application/json"); yield return www.SendWebRequest(); // extrapolate the response Id used to keep track of the conversation string jsonResponse = www.downloadHandler.text; string cleanedJsonResponse = jsonResponse.Replace("\r\n", string.Empty); string responseConvId = cleanedJsonResponse.Substring(10, 30); // Request a response from the Bot Service StartCoroutine(GetResponseFromBot(activity)); } }
Se llama a la siguiente corrutina para solicitar una respuesta después de enviar una actividad a Bot Service.
/// <summary> /// Request a response from the Bot by using a previously sent activity /// </summary> private IEnumerator GetResponseFromBot(Activity activity) { string getActivityEndpoint = string.Format("{0}/conversations/{1}/activities", botEndpoint, conversation.ConversationId); using (UnityWebRequest unityWebRequest1 = UnityWebRequest.Get(getActivityEndpoint)) { unityWebRequest1.downloadHandler = new DownloadHandlerBuffer(); unityWebRequest1.SetRequestHeader("Authorization", "Bearer " + botSecret); yield return unityWebRequest1.SendWebRequest(); string jsonResponse = unityWebRequest1.downloadHandler.text; ActivitiesRootObject root = new ActivitiesRootObject(); root = JsonConvert.DeserializeObject<ActivitiesRootObject>(jsonResponse); foreach (var act in root.activities) { Debug.Log($"Bot Response: {act.text}"); SetBotResponseText(act.text); } botState = BotState.ReadyToListen; botMaterial.color = Color.blue; } }
El último método que se va a agregar a esta clase es necesario para mostrar el mensaje en la escena:
/// <summary> /// Set the UI Response Text of the bot /// </summary> internal void SetBotResponseText(string responseString) { SceneOrganiser.Instance.botResponseText.text = responseString; }
Nota:
Es posible que vea un error en la consola del editor de Unity, sobre la falta de la clase SceneOrganiser . Ignore este mensaje, ya que creará esta clase más adelante en el tutorial.
Asegúrese de guardar los cambios en Visual Studio antes de volver a Unity.
Capítulo 11: Crear la clase Interactions
La clase que va a crear ahora se denomina Interacciones. Esta clase se usa para detectar la entrada de pulsación de HoloLens del usuario.
Si el usuario pulsa mientras examina el objeto Bot en la escena y el bot está listo para escuchar las entradas de voz, el objeto Bot cambiará de color a rojo y comenzará a escuchar las entradas de voz.
Esta clase hereda de la clase GazeInput y, por tanto, puede hacer referencia al método Start() y las variables de esa clase, indicadas por el uso de base.
Para crear esta clase:
Haga doble clic en la carpeta Scripts para abrirlo.
Haga clic con el botón derecho en la carpeta Scripts y haga clic en Crear > script de C#. Asigne un nombre a las interacciones del script.
Haga doble clic en el nuevo script para abrirlo con Visual Studio.
Actualice los espacios de nombres y la herencia de clases para que sean los mismos que los siguientes, en la parte superior de la clase Interactions :
using UnityEngine.XR.WSA.Input; public class Interactions : GazeInput {
Dentro de la clase Interactions , agregue la siguiente variable:
/// <summary> /// Allows input recognition with the HoloLens /// </summary> private GestureRecognizer _gestureRecognizer;
A continuación, agregue el método Start():
/// <summary> /// Called on initialization, after Awake /// </summary> internal override void Start() { base.Start(); //Register the application to recognize HoloLens user inputs _gestureRecognizer = new GestureRecognizer(); _gestureRecognizer.SetRecognizableGestures(GestureSettings.Tap); _gestureRecognizer.Tapped += GestureRecognizer_Tapped; _gestureRecognizer.StartCapturingGestures(); }
Agregue el controlador que se desencadenará cuando el usuario realice el gesto de pulsación delante de la cámara holoLens.
/// <summary> /// Detects the User Tap Input /// </summary> private void GestureRecognizer_Tapped(TappedEventArgs obj) { // Ensure the bot is being gazed upon. if(base.FocusedObject != null) { // If the user is tapping on Bot and the Bot is ready to listen if (base.FocusedObject.name == "Bot" && Bot.Instance.botState == Bot.BotState.ReadyToListen) { // If a conversation has not started yet, request one if(Bot.Instance.conversationStarted) { Bot.Instance.SetBotResponseText("Listening..."); Bot.Instance.StartCapturingAudio(); } else { Bot.Instance.SetBotResponseText("Requesting Conversation..."); StartCoroutine(Bot.Instance.StartConversation()); } } } }
Asegúrese de guardar los cambios en Visual Studio antes de volver a Unity.
Capítulo 12: Creación de la clase SceneOrganiser
La última clase necesaria en este laboratorio se denomina SceneOrganiser. Esta clase configurará la escena mediante programación, agregando componentes y scripts a la cámara principal y creando los objetos adecuados en la escena.
Para crear esta clase:
Haga doble clic en la carpeta Scripts para abrirlo.
Haga clic con el botón derecho en la carpeta Scripts y haga clic en Crear > script de C#. Asigne al script el nombre SceneOrganiser.
Haga doble clic en el nuevo script para abrirlo con Visual Studio.
Dentro de la clase SceneOrganiser , agregue las siguientes variables:
/// <summary> /// Static instance of this class /// </summary> public static SceneOrganiser Instance; /// <summary> /// The 3D text representing the Bot response /// </summary> internal TextMesh botResponseText;
A continuación, agregue los métodos Awake() y Start():
/// <summary> /// Called on Initialization /// </summary> private void Awake() { Instance = this; } /// <summary> /// Called immediately after Awake method /// </summary> void Start () { // Add the GazeInput class to this object gameObject.AddComponent<GazeInput>(); // Add the Interactions class to this object gameObject.AddComponent<Interactions>(); // Create the Bot in the scene CreateBotInScene(); }
Agregue el método siguiente, responsable de crear el objeto Bot en la escena y configurar los parámetros y componentes:
/// <summary> /// Create the Sign In button object in the scene /// and sets its properties /// </summary> private void CreateBotInScene() { GameObject botObjInScene = GameObject.CreatePrimitive(PrimitiveType.Sphere); botObjInScene.name = "Bot"; // Add the Bot class to the Bot GameObject botObjInScene.AddComponent<Bot>(); // Create the Bot UI botResponseText = CreateBotResponseText(); // Set properties of Bot GameObject Bot.Instance.botMaterial = new Material(Shader.Find("Diffuse")); botObjInScene.GetComponent<Renderer>().material = Bot.Instance.botMaterial; Bot.Instance.botMaterial.color = Color.blue; botObjInScene.transform.position = new Vector3(0f, 2f, 10f); botObjInScene.tag = "BotTag"; }
Agregue el método siguiente, responsable de crear el objeto de interfaz de usuario en la escena, que representa las respuestas del bot:
/// <summary> /// Spawns cursor for the Main Camera /// </summary> private TextMesh CreateBotResponseText() { // Create a sphere as new cursor GameObject textObject = new GameObject(); textObject.transform.parent = Bot.Instance.transform; textObject.transform.localPosition = new Vector3(0,1,0); // Resize the new cursor textObject.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f); // Creating the text of the Label TextMesh textMesh = textObject.AddComponent<TextMesh>(); textMesh.anchor = TextAnchor.MiddleCenter; textMesh.alignment = TextAlignment.Center; textMesh.fontSize = 50; textMesh.text = "Hi there, tap on me and I will start listening."; return textMesh; }
Asegúrese de guardar los cambios en Visual Studio antes de volver a Unity.
En el Editor de Unity, arrastre el script SceneOrganiser desde la carpeta Scripts a la cámara principal. El componente Organizador de escena debería aparecer ahora en el objeto Cámara principal, como se muestra en la imagen siguiente.
Capítulo 13: Antes de la construcción
Para realizar una prueba exhaustiva de la aplicación, deberá transferirla localmente a HoloLens. Antes de hacerlo, asegúrese de que:
- Todas las configuraciones mencionadas en el capítulo 4 se establecen correctamente.
- El script SceneOrganiser está asociado al objeto Main Camera .
- En la clase Bot , asegúrese de que ha insertado la clave secreta del bot en la variable botSecret .
Capítulo 14: Compilación y transferencia local a HoloLens
Todo lo necesario para la sección Unity de este proyecto ya se ha completado, por lo que es el momento de compilarlo desde Unity.
Vaya a Configuración de compilación, Configuración de compilación de archivos > ....
En la ventana Configuración de compilación, haga clic en Compilar.
Si aún no es así, marque Proyectos de C# de Unity.
Haga clic en Generar. Unity iniciará una ventana de Explorador de archivos, donde debe crear y, a continuación, seleccionará una carpeta para compilar la aplicación. Cree esa carpeta ahora y asígnela el nombre App. A continuación, con la carpeta Aplicación seleccionada, haga clic en Seleccionar carpeta.
Unity comenzará a compilar el proyecto en la carpeta Aplicación .
Una vez que Unity haya terminado de compilar (puede tardar algún tiempo), se abrirá una ventana de Explorador de archivos en la ubicación de la compilación (compruebe la barra de tareas, ya que puede que no siempre aparezca encima de las ventanas, pero le notificará la adición de una nueva ventana).
Capítulo 15: Implementación en HoloLens
Para realizar la implementación en HoloLens:
Necesitará la dirección IP de HoloLens (para la implementación remota) y para asegurarse de que HoloLens está en modo de desarrollador. Para ello, siga estos pasos:
- Mientras llevas tu HoloLens, abre la configuración.
- Vaya a Opciones avanzadas de Red e Internet > Wi-Fi >
- Anote la dirección IPv4 .
- A continuación, vuelva a Configuración y, a continuación, a Actualizar y seguridad > para desarrolladores.
- Establezca el modo de desarrollador activado.
Vaya a la nueva compilación de Unity (la carpeta Aplicación ) y abra el archivo de solución con Visual Studio.
En Configuración de la solución, seleccione Depurar.
En la Plataforma de soluciones, seleccione x86, Máquina remota.
Vaya al menú Compilar y haga clic en Implementar solución para transferir localmente la aplicación a HoloLens.
La aplicación debería aparecer ahora en la lista de aplicaciones instaladas en HoloLens, lista para iniciarse.
Nota:
Para realizar la implementación en cascos envolventes, establezca la Plataforma de soluciones en Máquina local y establezca la configuración en Depurar, con x86 como plataforma. A continuación, implemente en el equipo local mediante el menú Compilar y seleccione Implementar solución.
Capítulo 16: Uso de la aplicación en HoloLens
Una vez que haya iniciado la aplicación, verá el bot como una esfera azul delante de usted.
Usa el gesto de pulsar mientras estás mirando en la esfera para iniciar una conversación.
Espere a que se inicie la conversación (la interfaz de usuario mostrará un mensaje cuando se produzca). Una vez que reciba el mensaje introductorio del bot, vuelva a pulsar en el bot para que se active en rojo y empiece a escuchar la voz.
Una vez que deje de hablar, la aplicación enviará el mensaje al bot y recibirá rápidamente una respuesta que se mostrará en la interfaz de usuario.
Repita el proceso para enviar más mensajes al bot (tendrá que pulsar cada vez que desee ver un mensaje).
En esta conversación se muestra cómo el bot puede conservar la información (su nombre), mientras que también proporciona información conocida (por ejemplo, los elementos que están almacenados).
Algunas preguntas para hacer el bot:
what do you sell?
how much are umbrellas?
how much are raincoats?
Aplicación de bot de aplicación web (v4) finalizada
Enhorabuena, ha creado una aplicación de realidad mixta que aprovecha Azure Web App Bot, Microsoft Bot Framework v4.
Ejercicios extra
Ejercicio 1
La estructura de conversación de este laboratorio es muy básica. Use Microsoft LUIS para proporcionar funcionalidades de comprensión del lenguaje natural del bot.
Ejercicio 2
En este ejemplo no se incluye la terminación de una conversación y el reinicio de uno nuevo. Para completar la característica Bot, intente implementar el cierre en la conversación.