Windows 10 — программирование Кортаны

Я пытаюсь запрограммировать небольшое приложение для Cortana.

Моя идея в том, что я говорю: (я включил функцию «Привет, Кортана»)

Hey Cortana, Convert 45 degrees to farenheit

и я получаю (на данный момент) журнал в своем окне вывода (Visual Studio). Я попытался точно сказать это предложение, и Кортана прекрасно меня поняла, но Кортана открыла браузер и ввела его в Bing.

Почему? Что я сделал не так? Я не получаю синтаксическую ошибку.

Это мой код:

// 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();
    }
}

}

кто-нибудь может мне помочь?


person Community    schedule 15.08.2015    source источник
comment
Для префикса команды есть после конвертации это специально? Я не уверен, что Кортана распознает , когда он произносится…   -  person Mark3308    schedule 16.08.2015
comment
Также я думаю, что вы используете неправильную версию файла определения голосовой команды. Попробуйте следующее schemas.microsoft.com/voicecommands/1.2.   -  person Mark3308    schedule 16.08.2015
comment
@Mark3308 ссылка устарела   -  person Nicolas Manzini    schedule 31.08.2015


Ответы (4)


Файл определения VCD, который вы указали выше, не имеет ни PhraseTopic, ни PhraseList для определения частей, которые у вас есть в фигурных скобках:

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

Я предполагаю, что вы, вероятно, хотели PhraseTopic, потому что это позволяет неограниченную диктовку, подходящую для широкого диапазона чисел, что-то вроде этого:

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

См. спецификацию VCD здесь на msdn, возможно, вы захотите поиграть с настройка значения сценария. Это означает, что вам, конечно, нужно будет обрабатывать текст, который вы получаете как термин фаренгейта, самостоятельно, но обычно диктуемый текст для чисел передается в текстовой форме «1234» (но не в 100% случаев).

person Andrew Pilley    schedule 15.08.2015
comment
Кажется, это только часть проблемы. Кортана по-прежнему ничего не делает. Может я что-то не так делаю? Чтобы установить функции в Cortana, мне просто нужно нажать кнопку Local Maschine, верно? - person ; 15.08.2015
comment
Пол, вы можете дополнить свой вопрос обновленным файлом VCD? Я могу закинуть его в проект здесь и ткнуть в него. - person Andrew Pilley; 16.08.2015
comment
Хм, так что я могу заставить это работать в моей тестовой среде без каких-либо модификаций. Если вы откроете Кортану, наберете «помощь» в поле поиска и воспользуетесь опцией «Получить справку», которая должна появиться вверху, отображается ли ваше приложение в нижней части списка функций, которые может делать Кортана (вам, вероятно, потребуется прокрутите вниз) - person Andrew Pilley; 17.08.2015
comment
нет, мое приложение не отображается под справкой. Но я могу найти его в установленных приложениях. Что я сделал не так? - person ; 17.08.2015
comment
@PaulScharnofske хорошо, если он не отображается в разделе справки, значит, VCD по какой-то причине не устанавливается, странно. Ваша система настроена на американский английский? Или вы в другом регионе? - person Andrew Pilley; 17.08.2015
comment
Включая ваше местоположение? Вы установили версию Windows для США, но указали свое местоположение в Германии? Возможно, Кортана ищет en-DE (что, насколько мне известно, мы не поддерживаем) и не возвращается к en-US. Есть ли какая-то конкретная причина, по которой вы не пытались собрать набор VCD de-DE? - person Andrew Pilley; 17.08.2015
comment
Нет, все по-английски. Я весьма уверен. Единственное, что является немецким, это мои привязки клавиш. - person ; 17.08.2015
comment
Хорошо, а когда вы впервые воспользовались Кортаной, она провела вас через все этапы Как мне вас называть? процесс? Я не уверен, о какой кнопке локального компьютера вы говорите выше, кстати. Можете ли вы дать мне краткое изложение того, как вы конкретно настроили свою систему? - person Andrew Pilley; 17.08.2015
comment
Кроме того, вы на 100% уверены, что ваш вызов InstallCommandDefinitionsFromStorageFileAsync действительно завершается? Когда вы впервые задали этот вопрос, ваш файл VCD должен был вызвать исключение. Мне интересно, если он просто никогда не возвращается вместо этого. - person Andrew Pilley; 18.08.2015

проверьте свойства вашего VCD-файла, значения должны быть такими: Действие сборки = Контент, Копировать в выходной каталог = Всегда копировать. В любом случае, я надеюсь, что вы зарегистрировали файл vcd:

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

Посмотрите это видео MVA о Cortana: https://www.microsoftvirtualacademy.com/en-US/training-courses/universal-windows-app-development-with-cortana-and-the-speech-sdk-8487

person Szabolcs Tóth    schedule 17.08.2015
comment
Я использую его в приложении Windows Phone 8.1 Silverlight. с помощью Windows.Phone.Speech.VoiceCommands; - person Szabolcs Tóth; 17.08.2015
comment
Другой источник от Microsoft: msdn.microsoft.com/en-us/library/windows/apps/ - person Szabolcs Tóth; 17.08.2015
comment
ОЙ! Я пытался написать этот код для Windows 10 (ПК), а не для телефона. Что мне нужно изменить? - person ; 17.08.2015
comment
Извините, вы правы, вот пространство имен для Windows 10: msdn.microsoft.com/en-us/library/windows/apps/xaml/ - person Szabolcs Tóth; 17.08.2015
comment
Вот оно: msdn.microsoft.com/ en-us/library/windows/apps/xaml/ - person Szabolcs Tóth; 17.08.2015
comment
значит, вот это: var storageFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///commands.xml")); await Windows.ApplicationModel.VoiceCommands.VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(storageFile); должно работать? - person ; 17.08.2015
comment
Дайте мне знать, если это сработает. Я думаю, что если вы сделали все соответствующие шаги, то это должно сработать. - person Szabolcs Tóth; 17.08.2015

Что ж... Кажется, вы поняли все шаги, но все же чего-то не хватает...

Вот пример, который я сделал в отношении функциональности переднего плана Cortana:

Вот ВСД...

    <?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>

После создания этих определений вам необходимо зарегистрировать их при запуске приложения:

    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);
        }
    }

Затем переопределите метод App.OnActivated для обработки запуска событий:

    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;

Чтобы просмотреть полное руководство, посетите этот ссылка, а рабочий проект здесь. Кроме того, если вы хотите ответить пользователю через окно Cortana, проверьте это пост о Кортане в фоновом режиме

person talkitbr    schedule 18.08.2015

Я думаю, что вам не хватает части команды.

Вы просите Кортану преобразовать градусы в градусы Фаренгейта, а программа запуталась, потому что вы недостаточно конкретны.

Если вы хотите, чтобы Кортана преобразовала градусы Цельсия в градусы Фаренгейта, вы должны конкретно указать градусы Цельсия в градусы Фаренгейта.

person John Haines    schedule 21.06.2016