7

I am trying to programm a litte application for Cortana.

My idea is, that i say: (I enabled the "Hey Cortana" feature)

Hey Cortana, Convert 45 degrees to farenheit

and I get (in the moment) a log in my Output window (Visual Studio). I tried to say exact this sentence and Cortana understood me perfectly, but Cortana opened the browser and entered it into Bing.

Why? What did I do wrong? I don't get any Syntax Error.

This is my Code:

// commands.xml

<?xml version="1.0" encoding="utf-8"?>
<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.1">
  <CommandSet xml:lang="en-us" Name="MyCommands_en-us">
    <CommandPrefix> Convert, </CommandPrefix>
    <Example> Convert 45 degrees to farenheit </Example>

    <Command Name ="farenheitToDegrees">
      <Example> 73 farenheit to degrees</Example>
      <ListenFor> {farenheit} farenheit to degrees </ListenFor>
      <Feedback> {farenheit} are ... in degrees </Feedback>
      <Navigate/>
    </Command>

    <Command Name="degreesToFarenheit">
      <Example> 45 degrees to farenheit </Example>
      <ListenFor> {degrees} degrees to farenheit </ListenFor>
      <Feedback> {degrees} degrees are ... in fareneheit </Feedback>
      <Navigate/>
    </Command>

    <PhraseTopic Label="degrees" Scenario="Dictation">
      <Subject>Temperature</Subject>
    </PhraseTopic>

    <PhraseTopic Label="farenheit" Scenario="Dictation">
      <Subject>Temperature</Subject>
    </PhraseTopic>
  </CommandSet>
</VoiceCommands>

// App.xaml.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

using Windows.ApplicationModel.VoiceCommands;
using Windows.Storage;
using Windows.Media.SpeechRecognition;

namespace HelloWorld
{
    /// <summary>
    /// Provides application-specific behavior to supplement the default  Application class.
    /// </summary>
    sealed partial class App : Application
    {
        /// <summary>
        /// Initializes the singleton application object.  This is the first line of authored code
        /// executed, and as such is the logical equivalent of main() or WinMain().
        /// </summary>
        public App()
        {
            Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync(
            Microsoft.ApplicationInsights.WindowsCollectors.Metadata |
            Microsoft.ApplicationInsights.WindowsCollectors.Session);
            this.InitializeComponent();
            this.Suspending += OnSuspending;
        }

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used such as when the application is launched to open a specific file.
        /// </summary>
        /// <param name="e">Details about the launch request and process.</param>
        protected async override void OnLaunched(LaunchActivatedEventArgs e)
        {

#if DEBUG
            if (System.Diagnostics.Debugger.IsAttached)
            {
                this.DebugSettings.EnableFrameRateCounter = true;
            }
#endif

            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new Frame();

                rootFrame.NavigationFailed += OnNavigationFailed;

                if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    //TODO: Load state from previously suspended application
                }

                // Place the frame in the current Window
                Window.Current.Content = rootFrame;
            }

            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }
            // Ensure the current window is active
            Window.Current.Activate();


            var storageFile =
              await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///commands.xml"));
            await
                Windows.ApplicationModel.VoiceCommands.VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(storageFile);
        }

        protected override void OnActivated(IActivatedEventArgs e)
        {
            // Was the app activated by a voice command?
            if (e.Kind != Windows.ApplicationModel.Activation.ActivationKind.VoiceCommand)
            {
                return;
            }

            var commandArgs = e as Windows.ApplicationModel.Activation.VoiceCommandActivatedEventArgs;

        SpeechRecognitionResult speechRecognitionResult = commandArgs.Result;

        // Get the name of the voice command and the text spoken
        string voiceCommandName = speechRecognitionResult.RulePath[0];
        string textSpoken = speechRecognitionResult.Text;

        switch (voiceCommandName)
        {
            case "farenheitToDegrees":
                string farenheit = speechRecognitionResult.SemanticInterpretation.Properties["farenheit"][0];
                System.Diagnostics.Debug.WriteLine((Convert.ToInt32(farenheit) - 32) / 1.8);
                break;

            case "degreesToFarenheit":
                string degrees = speechRecognitionResult.SemanticInterpretation.Properties["degrees"][0];
                System.Diagnostics.Debug.WriteLine(Convert.ToInt32(degrees) * 1.8 + 32);
                break;

            default:
                System.Diagnostics.Debug.WriteLine("None of my bussiness");
                break;
        }
    }


    /// <summary>
    /// Invoked when Navigation to a certain page fails
    /// </summary>
    /// <param name="sender">The Frame which failed navigation</param>
    /// <param name="e">Details about the navigation failure</param>
    void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
    {
        throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
    }

    /// <summary>
    /// Invoked when application execution is being suspended.  Application state is saved
    /// without knowing whether the application will be terminated or resumed with the contents
    /// of memory still intact.
    /// </summary>
    /// <param name="sender">The source of the suspend request.</param>
    /// <param name="e">Details about the suspend request.</param>
    private void OnSuspending(object sender, SuspendingEventArgs e)
    {
        var deferral = e.SuspendingOperation.GetDeferral();
        //TODO: Save application state and stop any background activity
        deferral.Complete();
    }
}

}

can somebody help me?

4 Answers4

2

The VCD definition file you've listed above doesn't have either a PhraseTopic or PhraseList to define the parts you've got in curly braces:

 <ListenFor> {farenheit} farenheit to degrees </ListenFor>

I'm guessing you probably wanted a PhraseTopic because that allows for an unconstrained dictation suitable for a wide range of numbers, something like this:

<PhraseTopic Label="farenheit" Scenario="Dictation">
   <Subject>Temperature</Subject>
</PhraseTopic>

See the spec for VCD's here on msdn, you might want to play with tweaking the Scenario value. This does mean you'll need to handle the text you get as the farenheit term yourself, of course, but typically dictated text for numbers comes through in textual '1234' form (but not in 100% of cases).

Andrew Pilley
  • 824
  • 6
  • 9
  • Seems to be just a part of the problem. Cortana still does nothing. Maybe I am doing something wrong? To install the features to Cortana I just have to Press the "Local Maschine" button right? –  Aug 15 '15 at 20:21
  • Paul, can you update your question with an updated VCD file? I can drop it into a project here and poke at it. – Andrew Pilley Aug 16 '15 at 02:34
  • Hm, so I'm able to get this to work in my test environment here without any modifications. If you open Cortana, type 'help' into the search box, and use the "Get Help" option that should appear at the top, does your app show at the bottom of the list of things that Cortana can do (you'll probably need to scroll it down) – Andrew Pilley Aug 17 '15 at 00:38
  • no, my app does not display under "help". But i can find it under the installed applications. What did i wrong? –  Aug 17 '15 at 08:46
  • @PaulScharnofske okay, if it's not showing up under help, then the VCD isn't getting installed for some reason, odd. Is your system set for US English? Or are you in another region? – Andrew Pilley Aug 17 '15 at 14:21
  • Including your location? Did you install an en-US version of windows, but set your location to Germany? It's possible Cortana is looking for en-DE (which we don't support to my knowledge), and not falling back to en-US. Is there a particular reason you haven't tried building a de-DE VCD set? – Andrew Pilley Aug 17 '15 at 15:23
  • No. everything englisch. I am pretty sure. The only thing which is german are my keybindings. –  Aug 17 '15 at 15:32
  • Okay, and when you used cortana for the first time, it walked you through the whole "What should I call you?" process? I'm not sure what "Local machine" button you're referring to above, BTW. Can you give me a quick rundown of how you set up your system specifically? – Andrew Pilley Aug 17 '15 at 18:39
  • Also, are you 100% sure that your call to InstallCommandDefinitionsFromStorageFileAsync is actually completing? When you first started this question, your VCD file should have been causing that to throw an exception. I'm wondering if it's just never returning instead. – Andrew Pilley Aug 17 '15 at 21:22
0

check the properties of your VCD file, values shoud be: Buil Action = Content, Copy to Output Directory = Copy always. Anyway, I hope that you registered the vcd file:

VoiceCommandService.InstallCommandSetsFromFileAsync(new Uri("ms-appx:///VCD.xml"));

Check this MVA video about Cortana: https://www.microsoftvirtualacademy.com/en-US/training-courses/universal-windows-app-development-with-cortana-and-the-speech-sdk-8487

  • I'm using it in Windows Phone 8.1 Silverlight app. using Windows.Phone.Speech.VoiceCommands; – Szabolcs Tóth Aug 17 '15 at 09:04
  • Another source from microsoft: https://msdn.microsoft.com/en-us/library/windows/apps/jj206959(v=vs.105).aspx#BKMK_CreatingaVCDfile – Szabolcs Tóth Aug 17 '15 at 09:07
  • OH! I tried to write this code for Windows 10 (PC) not for the phone. What do i have to change? –  Aug 17 '15 at 09:13
  • Sory, you are right, here is the namespace for Windows 10: https://msdn.microsoft.com/en-us/library/windows/apps/xaml/windows.applicationmodel.voicecommands.aspx – Szabolcs Tóth Aug 17 '15 at 09:41
  • This is it: https://msdn.microsoft.com/en-us/library/windows/apps/xaml/dn630430.aspx#install_the_vcd_commands – Szabolcs Tóth Aug 17 '15 at 09:46
  • so that means, this: `var storageFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///commands.xml")); await Windows.ApplicationModel.VoiceCommands.VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(storageFile); ` should work? –  Aug 17 '15 at 10:35
  • Let me know if it work. I think If you have done all related steps, then it should work. – Szabolcs Tóth Aug 17 '15 at 11:50
0

Well... Seems that you have understood all the steps but still something is missing...

Here's an example that I have made regarding Cortana's foreground functionality:

Here's the VCD...

    <?xml version="1.0" encoding="utf-8" ?>
    <VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.2">
      <CommandSet xml:lang="en-us" Name="HomeControlCommandSet_en-us">
        <CommandPrefix>HomeControl</CommandPrefix>
        <Example>Control alarm, temperature, light and others</Example>

        <Command Name="Activate_Alarm">
          <Example>Activate alarm</Example>
          <ListenFor>[Would] [you] [please] activate [the] alarm [please]</ListenFor>
          <ListenFor RequireAppName="BeforeOrAfterPhrase">Activate alarm</ListenFor>
          <ListenFor RequireAppName="ExplicitlySpecified">Activate {builtin:AppName} alarm</ListenFor>
          <Feedback>Activating alarm</Feedback>
          <Navigate />
        </Command>

After create this definitions, you need to registry it at App Startup:

    protected async override void OnLaunched(LaunchActivatedEventArgs e)
    {
        ...
        // Install the VCD
        try
        {
            StorageFile vcdStorageFile = await Package.Current.InstalledLocation.GetFileAsync(@"HomeControlCommands.xml");
            await VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(vcdStorageFile);
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine("There was an error registering the Voice Command Definitions", ex);
        }
    }

An then override App.OnActivated method to handle when the events are triggered:

    protected override void OnActivated(IActivatedEventArgs e)
    {
        // Handle when app is launched by Cortana
        if (e.Kind == ActivationKind.VoiceCommand)
        {
            VoiceCommandActivatedEventArgs commandArgs = e as VoiceCommandActivatedEventArgs;
            SpeechRecognitionResult speechRecognitionResult = commandArgs.Result;

            string voiceCommandName = speechRecognitionResult.RulePath[0];
            string textSpoken = speechRecognitionResult.Text;
            IReadOnlyList<string> recognizedVoiceCommandPhrases;

            System.Diagnostics.Debug.WriteLine("voiceCommandName: " + voiceCommandName);
            System.Diagnostics.Debug.WriteLine("textSpoken: " + textSpoken);

            switch (voiceCommandName)
            {
                case "Activate_Alarm":
                    System.Diagnostics.Debug.WriteLine("Activate_Alarm command");
                    break;

To see the complete tutorial, please visit this link and a working project is here. Also, if you interested in respond to the user through Cortana window, check this post regarding Cortana in background

talkitbr
  • 1,112
  • 9
  • 12
0

I think you are missing a part of the command.

You're asking for Cortana to convert degrees to Fahrenheit, and the program is confused because you're not being specific enough.

If you want Cortana to covert from degrees Celsius to degrees Fahrenheit, you have to tell it specifically Celsius to Fahrenheit.

rrauenza
  • 6,285
  • 4
  • 32
  • 57