cleaned adatum + initial commit for alpine contoso fabrikam woodgrove
|
@ -188,7 +188,6 @@
|
|||
<Content Include="Images\intro-bg.jpg" />
|
||||
<Content Include="Images\ipad.png" />
|
||||
<Content Include="Images\mouse.jpg" />
|
||||
<Content Include="readme.txt" />
|
||||
<Content Include="Scripts\AdatumTaxCorp.Main.js" />
|
||||
<Content Include="Scripts\bootstrap.bundle.js" />
|
||||
<Content Include="Scripts\bootstrap.bundle.min.js" />
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26730.16
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntelligentKioskSample", "IntelligentKioskSample.csproj", "{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceHelpers", "ServiceHelpers\ServiceHelpers.csproj", "{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmotionAPI_Test", "EmotionAPI_Test\EmotionAPI_Test.csproj", "{688FD938-16ED-4EBB-A0E3-0801D9461823}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
CNDebug|Any CPU = CNDebug|Any CPU
|
||||
CNDebug|ARM = CNDebug|ARM
|
||||
CNDebug|x64 = CNDebug|x64
|
||||
CNDebug|x86 = CNDebug|x86
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM = Release|ARM
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.CNDebug|Any CPU.ActiveCfg = Release|x64
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.CNDebug|Any CPU.Build.0 = Release|x64
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.CNDebug|Any CPU.Deploy.0 = Release|x64
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.CNDebug|ARM.ActiveCfg = Debug|ARM
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.CNDebug|ARM.Build.0 = Debug|ARM
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.CNDebug|ARM.Deploy.0 = Debug|ARM
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.CNDebug|x64.ActiveCfg = Debug|x64
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.CNDebug|x64.Build.0 = Debug|x64
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.CNDebug|x64.Deploy.0 = Debug|x64
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.CNDebug|x86.ActiveCfg = Debug|x86
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.CNDebug|x86.Build.0 = Debug|x86
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.CNDebug|x86.Deploy.0 = Debug|x86
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Debug|Any CPU.Build.0 = Debug|x86
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Debug|Any CPU.Deploy.0 = Debug|x86
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Debug|ARM.ActiveCfg = Debug|ARM
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Debug|ARM.Build.0 = Debug|ARM
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Debug|ARM.Deploy.0 = Debug|ARM
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Debug|x64.Build.0 = Debug|x64
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Debug|x86.Build.0 = Debug|x86
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Release|ARM.ActiveCfg = Release|ARM
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Release|ARM.Build.0 = Release|ARM
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Release|ARM.Deploy.0 = Release|ARM
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Release|x64.ActiveCfg = Release|x64
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Release|x64.Build.0 = Release|x64
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Release|x64.Deploy.0 = Release|x64
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Release|x86.ActiveCfg = Release|x86
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Release|x86.Build.0 = Release|x86
|
||||
{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}.Release|x86.Deploy.0 = Release|x86
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.CNDebug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.CNDebug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.CNDebug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.CNDebug|ARM.Build.0 = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.CNDebug|x64.ActiveCfg = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.CNDebug|x64.Build.0 = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.CNDebug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.CNDebug|x86.Build.0 = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Release|x64.Build.0 = Release|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}.Release|x86.Build.0 = Release|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.CNDebug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.CNDebug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.CNDebug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.CNDebug|ARM.Build.0 = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.CNDebug|x64.ActiveCfg = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.CNDebug|x64.Build.0 = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.CNDebug|x86.ActiveCfg = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.CNDebug|x86.Build.0 = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Release|x64.Build.0 = Release|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{688FD938-16ED-4EBB-A0E3-0801D9461823}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0D40B7A4-F52A-4794-A524-0C30F838E002}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,23 @@
|
|||
<Application
|
||||
x:Class="IntelligentKioskSample.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:c="using:IntelligentKioskSample.Common"
|
||||
RequestedTheme="Dark"
|
||||
xmlns:local="using:IntelligentKioskSample">
|
||||
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Styles/Styles.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<SolidColorBrush x:Key="StatusTextBrush" Color="LightYellow"/>
|
||||
<x:String x:Key="TextStatus_Hi">Hi, how are you doing?</x:String>
|
||||
<x:String x:Key="TextStatus_Still">Please stand still...</x:String>
|
||||
<x:String x:Key="TextStatus_Thanks">Thanks!</x:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
|
||||
</Application>
|
|
@ -0,0 +1,185 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
// The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=402347&clcid=0x409
|
||||
|
||||
namespace IntelligentKioskSample
|
||||
{
|
||||
using ServiceHelpers;
|
||||
using System.Diagnostics;
|
||||
using Views;
|
||||
using Windows.Data.Xml.Dom;
|
||||
using Windows.UI.Notifications;
|
||||
/// <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()
|
||||
{
|
||||
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 override void OnLaunched(LaunchActivatedEventArgs e)
|
||||
{
|
||||
#if DEBUG
|
||||
if (System.Diagnostics.Debugger.IsAttached)
|
||||
{
|
||||
// This just gets in the way.
|
||||
//this.DebugSettings.EnableFrameRateCounter = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
AppShell shell = Window.Current.Content as AppShell;
|
||||
|
||||
// Do not repeat app initialization when the Window already has content,
|
||||
// just ensure that the window is active
|
||||
if (shell == null)
|
||||
{
|
||||
// propogate settings to the core library
|
||||
SettingsHelper.Instance.SettingsChanged += (target, args) =>
|
||||
{
|
||||
EmotionServiceHelper.ApiKey = SettingsHelper.Instance.EmotionApiKey;
|
||||
CoreUtil.MinDetectableFaceCoveragePercentage = SettingsHelper.Instance.MinDetectableFaceCoveragePercentage;
|
||||
};
|
||||
|
||||
// callbacks for core library
|
||||
EmotionServiceHelper.Throttled = () => ShowThrottlingToast("Emotion");
|
||||
ErrorTrackingHelper.TrackException = (ex, msg) => LogException(ex, msg);
|
||||
ErrorTrackingHelper.GenericApiCallExceptionHandler = Util.GenericApiCallExceptionHandler;
|
||||
|
||||
SettingsHelper.Instance.Initialize();
|
||||
|
||||
// Create a AppShell to act as the navigation context and navigate to the first page
|
||||
shell = new AppShell();
|
||||
|
||||
// Set the default language
|
||||
shell.Language = Windows.Globalization.ApplicationLanguages.Languages[0];
|
||||
|
||||
shell.AppFrame.NavigationFailed += OnNavigationFailed;
|
||||
|
||||
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
|
||||
{
|
||||
//TODO: Load state from previously suspended application
|
||||
}
|
||||
|
||||
// Set the TitleBar to Dark Theme
|
||||
var appView = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView();
|
||||
var titleBar = appView.TitleBar;
|
||||
titleBar.BackgroundColor = Windows.UI.Colors.Black;
|
||||
titleBar.ForegroundColor = Windows.UI.Colors.White;
|
||||
titleBar.ButtonBackgroundColor = Windows.UI.Colors.Black;
|
||||
titleBar.ButtonForegroundColor = Windows.UI.Colors.White;
|
||||
}
|
||||
|
||||
// Place our app shell in the current Window
|
||||
Window.Current.Content = shell;
|
||||
|
||||
if (shell.AppFrame.Content == null)
|
||||
{
|
||||
// When the navigation stack isn't restored, navigate to the first page
|
||||
// suppressing the initial entrance animation.
|
||||
shell.AppFrame.Navigate(typeof(EmotionRecognitionPage), e.Arguments, new Windows.UI.Xaml.Media.Animation.SuppressNavigationTransitionInfo());
|
||||
}
|
||||
|
||||
// Ensure the current window is active
|
||||
Window.Current.Activate();
|
||||
}
|
||||
|
||||
private static void ShowThrottlingToast(string api)
|
||||
{
|
||||
ToastTemplateType toastTemplate = ToastTemplateType.ToastText02;
|
||||
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
|
||||
XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");
|
||||
|
||||
toastTextElements[0].AppendChild(toastXml.CreateTextNode("Alpine Ski House Happiness Meter"));
|
||||
toastTextElements[1].AppendChild(toastXml.CreateTextNode("The " + api + " API is throttling your requests. Consider upgrading to a Premium Key."));
|
||||
|
||||
ToastNotification toast = new ToastNotification(toastXml);
|
||||
ToastNotificationManager.CreateToastNotifier().Show(toast);
|
||||
}
|
||||
|
||||
private static void LogException(Exception ex, string message)
|
||||
{
|
||||
Debug.WriteLine("Error detected! Exception: \"{0}\", More info: \"{1}\".", ex.Message, message);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
private 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 async void OnSuspending(object sender, SuspendingEventArgs e)
|
||||
{
|
||||
var deferral = e.SuspendingOperation.GetDeferral();
|
||||
|
||||
//Save application state and stop any background activity
|
||||
//var currentView = (Window.Current.Content as AppShell)?.AppFrame?.Content;
|
||||
|
||||
//if (currentView != null && currentView.GetType() == typeof(RealTimeDemo))
|
||||
//{
|
||||
// await (currentView as RealTimeDemo).HandleApplicationShutdownAsync();
|
||||
//}
|
||||
|
||||
deferral.Complete();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
<Page x:Name="Root"
|
||||
x:Class="IntelligentKioskSample.AppShell"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:IntelligentKioskSample"
|
||||
xmlns:controls="using:IntelligentKioskSample.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||
KeyDown="AppShell_KeyDown"
|
||||
TabNavigation="Cycle"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<!-- Using a Page as the root for the app provides a design time experience as well as ensures that
|
||||
when it runs on Mobile the app content won't appear under the system's StatusBar which is visible
|
||||
by default with a transparent background. It will also take into account the presence of software
|
||||
navigation buttons if they appear on a device. An app can opt-out by switching to UseCoreWindow.
|
||||
-->
|
||||
|
||||
<Page.Resources>
|
||||
<DataTemplate x:Key="NavMenuItemTemplate" x:DataType="local:NavMenuItem">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="48" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- Showing a ToolTip and the Label is redundant. We put the ToolTip on the icon.
|
||||
It appears when the user hovers over the icon, but not the label which provides
|
||||
value when the SplitView is 'Compact' while reducing the likelihood of showing
|
||||
redundant information when the label is shown.-->
|
||||
<FontIcon x:Name="Glyph" FontSize="16" Glyph="{x:Bind SymbolAsChar}" VerticalAlignment="Center" HorizontalAlignment="Center" ToolTipService.ToolTip="{x:Bind Label}"/>
|
||||
<TextBlock x:Name="Text" Grid.Column="1" Text="{x:Bind Label}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</Page.Resources>
|
||||
|
||||
<Grid>
|
||||
<!-- Adaptive triggers -->
|
||||
<!--<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup>
|
||||
<VisualState>
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="720" />
|
||||
</VisualState.StateTriggers>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="RootSplitView.DisplayMode" Value="CompactInline"/>
|
||||
<Setter Target="RootSplitView.IsPaneOpen" Value="True"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState>
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="0" />
|
||||
</VisualState.StateTriggers>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="RootSplitView.DisplayMode" Value="Overlay"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>-->
|
||||
|
||||
<!-- Top-level navigation menu + app content -->
|
||||
<SplitView x:Name="RootSplitView"
|
||||
DisplayMode="Overlay"
|
||||
OpenPaneLength="256"
|
||||
IsTabStop="False">
|
||||
<SplitView.Pane>
|
||||
<!-- A custom ListView to display the items in the pane. The automation Name is set in the ContainerContentChanging event. -->
|
||||
<controls:NavMenuListView x:Name="NavMenuList"
|
||||
TabIndex="3"
|
||||
Margin="0,48,0,0"
|
||||
ContainerContentChanging="NavMenuItemContainerContentChanging"
|
||||
ItemContainerStyle="{StaticResource NavMenuItemContainerStyle}"
|
||||
ItemTemplate="{StaticResource NavMenuItemTemplate}"
|
||||
ItemInvoked="NavMenuList_ItemInvoked">
|
||||
<controls:NavMenuListView.Header>
|
||||
<!-- Using this custom back navigation button until the system-provided back button is enabled. -->
|
||||
<Button x:Name="BackButton"
|
||||
TabIndex="2"
|
||||
Style="{StaticResource NavigationBackButtonStyle}"
|
||||
IsEnabled="{Binding AppFrame.CanGoBack, ElementName=Root}"
|
||||
Width="{Binding ItemsPanelRoot.Width, ElementName=NavMenuList}"
|
||||
HorizontalAlignment="{Binding ItemsPanelRoot.HorizontalAlignment, ElementName=NavMenuList}"
|
||||
Click="BackButton_Click"/>
|
||||
</controls:NavMenuListView.Header>
|
||||
</controls:NavMenuListView>
|
||||
</SplitView.Pane>
|
||||
|
||||
<!-- OnNavigatingToPage we synchronize the selected item in the nav menu with the current page.
|
||||
OnNavigatedToPage we move keyboard focus to the first item on the page after it's loaded. -->
|
||||
<Frame x:Name="frame"
|
||||
Navigating="OnNavigatingToPage"
|
||||
Navigated="OnNavigatedToPage">
|
||||
<Frame.ContentTransitions>
|
||||
<TransitionCollection>
|
||||
<NavigationThemeTransition>
|
||||
<NavigationThemeTransition.DefaultNavigationTransitionInfo>
|
||||
<EntranceNavigationTransitionInfo/>
|
||||
</NavigationThemeTransition.DefaultNavigationTransitionInfo>
|
||||
</NavigationThemeTransition>
|
||||
</TransitionCollection>
|
||||
</Frame.ContentTransitions>
|
||||
</Frame>
|
||||
</SplitView>
|
||||
|
||||
<!-- Declared last to have it rendered above everything else, but it needs to be the first item in the tab sequence. -->
|
||||
<ToggleButton x:Name="TogglePaneButton"
|
||||
TabIndex="1"
|
||||
Style="{StaticResource SplitViewTogglePaneButtonStyle}"
|
||||
Tapped="TogglePaneButton_Tapped"
|
||||
Unchecked="TogglePaneButton_Checked"
|
||||
AutomationProperties.Name="Menu"
|
||||
ToolTipService.ToolTip="Menu" />
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,362 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using IntelligentKioskSample.Controls;
|
||||
using IntelligentKioskSample.Views;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Windows.Devices.Input;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Metadata;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Automation;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
namespace IntelligentKioskSample
|
||||
{
|
||||
/// <summary>
|
||||
/// The "chrome" layer of the app that provides top-level navigation with
|
||||
/// proper keyboarding navigation.
|
||||
/// </summary>
|
||||
public sealed partial class AppShell : Page
|
||||
{
|
||||
// Declare the top level nav items
|
||||
private List<NavMenuItem> navlist = new List<NavMenuItem>(
|
||||
new NavMenuItem[]
|
||||
{
|
||||
new NavMenuItem()
|
||||
{
|
||||
Symbol = Symbol.Favorite,
|
||||
Label = "Emotion",
|
||||
DestPage = typeof(EmotionRecognitionPage)
|
||||
},
|
||||
|
||||
new NavMenuItem()
|
||||
{
|
||||
Symbol = Symbol.Setting,
|
||||
Label = "Settings",
|
||||
DestPage = typeof(SettingsPage)
|
||||
}
|
||||
});
|
||||
|
||||
public static AppShell Current = null;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the AppShell, sets the static 'Current' reference,
|
||||
/// adds callbacks for Back requests and changes in the SplitView's DisplayMode, and
|
||||
/// provide the nav menu list with the data to display.
|
||||
/// </summary>
|
||||
public AppShell()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
this.Loaded += (sender, args) =>
|
||||
{
|
||||
Current = this;
|
||||
|
||||
this.TogglePaneButton.Focus(FocusState.Programmatic);
|
||||
|
||||
this.NavigateToStartingPage();
|
||||
};
|
||||
|
||||
this.RootSplitView.RegisterPropertyChangedCallback(
|
||||
SplitView.DisplayModeProperty,
|
||||
(s, a) =>
|
||||
{
|
||||
// Ensure that we update the reported size of the TogglePaneButton when the SplitView's
|
||||
// DisplayMode changes.
|
||||
this.CheckTogglePaneButtonSizeChanged();
|
||||
});
|
||||
|
||||
SystemNavigationManager.GetForCurrentView().BackRequested += SystemNavigationManager_BackRequested;
|
||||
|
||||
// If on a phone device that has hardware buttons then we hide the app's back button.
|
||||
if (ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
|
||||
{
|
||||
this.BackButton.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
NavMenuList.ItemsSource = navlist;
|
||||
}
|
||||
|
||||
public void NavigateToStartingPage()
|
||||
{
|
||||
NavigateToPage(typeof(EmotionRecognitionPage));
|
||||
}
|
||||
|
||||
public void NavigateToPage(Type destPage)
|
||||
{
|
||||
if (this.AppFrame.CurrentSourcePageType != destPage)
|
||||
{
|
||||
AppFrame.Navigate(destPage, string.Empty, new Windows.UI.Xaml.Media.Animation.SuppressNavigationTransitionInfo());
|
||||
}
|
||||
}
|
||||
|
||||
public Frame AppFrame { get { return this.frame; } }
|
||||
|
||||
/// <summary>
|
||||
/// Default keyboard focus movement for any unhandled keyboarding
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void AppShell_KeyDown(object sender, KeyRoutedEventArgs e)
|
||||
{
|
||||
FocusNavigationDirection direction = FocusNavigationDirection.None;
|
||||
switch (e.Key)
|
||||
{
|
||||
case Windows.System.VirtualKey.Left:
|
||||
case Windows.System.VirtualKey.GamepadDPadLeft:
|
||||
case Windows.System.VirtualKey.GamepadLeftThumbstickLeft:
|
||||
case Windows.System.VirtualKey.NavigationLeft:
|
||||
direction = FocusNavigationDirection.Left;
|
||||
break;
|
||||
case Windows.System.VirtualKey.Right:
|
||||
case Windows.System.VirtualKey.GamepadDPadRight:
|
||||
case Windows.System.VirtualKey.GamepadLeftThumbstickRight:
|
||||
case Windows.System.VirtualKey.NavigationRight:
|
||||
direction = FocusNavigationDirection.Right;
|
||||
break;
|
||||
|
||||
case Windows.System.VirtualKey.Up:
|
||||
case Windows.System.VirtualKey.GamepadDPadUp:
|
||||
case Windows.System.VirtualKey.GamepadLeftThumbstickUp:
|
||||
case Windows.System.VirtualKey.NavigationUp:
|
||||
direction = FocusNavigationDirection.Up;
|
||||
break;
|
||||
|
||||
case Windows.System.VirtualKey.Down:
|
||||
case Windows.System.VirtualKey.GamepadDPadDown:
|
||||
case Windows.System.VirtualKey.GamepadLeftThumbstickDown:
|
||||
case Windows.System.VirtualKey.NavigationDown:
|
||||
direction = FocusNavigationDirection.Down;
|
||||
break;
|
||||
}
|
||||
|
||||
if (direction != FocusNavigationDirection.None)
|
||||
{
|
||||
var control = FocusManager.FindNextFocusableElement(direction) as Control;
|
||||
if (control != null)
|
||||
{
|
||||
control.Focus(FocusState.Programmatic);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region BackRequested Handlers
|
||||
|
||||
private void SystemNavigationManager_BackRequested(object sender, BackRequestedEventArgs e)
|
||||
{
|
||||
bool handled = e.Handled;
|
||||
this.BackRequested(ref handled);
|
||||
e.Handled = handled;
|
||||
}
|
||||
|
||||
private void BackButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
bool ignored = false;
|
||||
this.BackRequested(ref ignored);
|
||||
}
|
||||
|
||||
private void BackRequested(ref bool handled)
|
||||
{
|
||||
// Get a hold of the current frame so that we can inspect the app back stack.
|
||||
|
||||
if (this.AppFrame == null)
|
||||
return;
|
||||
|
||||
// Check to see if this is the top-most page on the app back stack.
|
||||
if (this.AppFrame.CanGoBack && !handled)
|
||||
{
|
||||
// If not, set the event to handled and go back to the previous page in the app.
|
||||
handled = true;
|
||||
this.AppFrame.GoBack();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Navigation
|
||||
|
||||
/// <summary>
|
||||
/// Navigate to the Page for the selected <paramref name="listViewItem"/>.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="listViewItem"></param>
|
||||
private void NavMenuList_ItemInvoked(object sender, ListViewItem listViewItem)
|
||||
{
|
||||
var item = (NavMenuItem)((NavMenuListView)sender).ItemFromContainer(listViewItem);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
if (item.DestPage != null &&
|
||||
item.DestPage != this.AppFrame.CurrentSourcePageType)
|
||||
{
|
||||
this.AppFrame.Navigate(item.DestPage, item.Arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures the nav menu reflects reality when navigation is triggered outside of
|
||||
/// the nav menu buttons.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void OnNavigatingToPage(object sender, NavigatingCancelEventArgs e)
|
||||
{
|
||||
if (e.NavigationMode == NavigationMode.Back)
|
||||
{
|
||||
var item = (from p in this.navlist where p.DestPage == e.SourcePageType select p).SingleOrDefault();
|
||||
if (item == null && this.AppFrame.BackStackDepth > 0)
|
||||
{
|
||||
// In cases where a page drills into sub-pages then we'll highlight the most recent
|
||||
// navigation menu item that appears in the BackStack
|
||||
foreach (var entry in this.AppFrame.BackStack.Reverse())
|
||||
{
|
||||
item = (from p in this.navlist where p.DestPage == entry.SourcePageType select p).SingleOrDefault();
|
||||
if (item != null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var container = (ListViewItem)NavMenuList.ContainerFromItem(item);
|
||||
|
||||
// While updating the selection state of the item prevent it from taking keyboard focus. If a
|
||||
// user is invoking the back button via the keyboard causing the selected nav menu item to change
|
||||
// then focus will remain on the back button.
|
||||
if (container != null) container.IsTabStop = false;
|
||||
NavMenuList.SetSelectedItem(container);
|
||||
if (container != null) container.IsTabStop = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNavigatedToPage(object sender, NavigationEventArgs e)
|
||||
{
|
||||
// After a successful navigation set keyboard focus to the loaded page
|
||||
if (e.Content is Page && e.Content != null)
|
||||
{
|
||||
var control = (Page)e.Content;
|
||||
control.Loaded += Page_Loaded;
|
||||
}
|
||||
}
|
||||
|
||||
private void Page_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((Page)sender).Focus(FocusState.Programmatic);
|
||||
((Page)sender).Loaded -= Page_Loaded;
|
||||
this.CheckTogglePaneButtonSizeChanged();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public Rect TogglePaneButtonRect
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An event to notify listeners when the hamburger button may occlude other content in the app.
|
||||
/// The custom "PageHeader" user control is using this.
|
||||
/// </summary>
|
||||
public event TypedEventHandler<AppShell, Rect> TogglePaneButtonRectChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Callback when the SplitView's Pane is toggled open or close. When the Pane is not visible
|
||||
/// then the floating hamburger may be occluding other content in the app unless it is aware.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void TogglePaneButton_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.CheckTogglePaneButtonSizeChanged();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Check for the conditions where the navigation pane does not occupy the space under the floating
|
||||
/// hamburger button and trigger the event.
|
||||
/// </summary>
|
||||
private void CheckTogglePaneButtonSizeChanged()
|
||||
{
|
||||
if (this.RootSplitView.DisplayMode == SplitViewDisplayMode.Inline ||
|
||||
this.RootSplitView.DisplayMode == SplitViewDisplayMode.Overlay)
|
||||
{
|
||||
var transform = this.TogglePaneButton.TransformToVisual(this);
|
||||
var rect = transform.TransformBounds(new Rect(0, 0, this.TogglePaneButton.ActualWidth, this.TogglePaneButton.ActualHeight));
|
||||
this.TogglePaneButtonRect = rect;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.TogglePaneButtonRect = new Rect();
|
||||
}
|
||||
|
||||
var handler = this.TogglePaneButtonRectChanged;
|
||||
if (handler != null)
|
||||
{
|
||||
// handler(this, this.TogglePaneButtonRect);
|
||||
handler.DynamicInvoke(this, this.TogglePaneButtonRect);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable accessibility on each nav menu item by setting the AutomationProperties.Name on each container
|
||||
/// using the associated Label of each item.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="args"></param>
|
||||
private void NavMenuItemContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
|
||||
{
|
||||
if (!args.InRecycleQueue && args.Item != null && args.Item is NavMenuItem)
|
||||
{
|
||||
args.ItemContainer.SetValue(AutomationProperties.NameProperty, ((NavMenuItem)args.Item).Label);
|
||||
}
|
||||
else
|
||||
{
|
||||
args.ItemContainer.ClearValue(AutomationProperties.NameProperty);
|
||||
}
|
||||
}
|
||||
|
||||
private void TogglePaneButton_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
{
|
||||
RootSplitView.IsPaneOpen = !RootSplitView.IsPaneOpen;
|
||||
TogglePaneButton.IsChecked = !TogglePaneButton.IsChecked;
|
||||
}
|
||||
}
|
||||
}
|
После Ширина: | Высота: | Размер: 1.1 MiB |
После Ширина: | Высота: | Размер: 234 KiB |
После Ширина: | Высота: | Размер: 8.0 KiB |
После Ширина: | Высота: | Размер: 333 KiB |
После Ширина: | Высота: | Размер: 351 KiB |
После Ширина: | Высота: | Размер: 12 KiB |
После Ширина: | Высота: | Размер: 16 KiB |
После Ширина: | Высота: | Размер: 903 KiB |
После Ширина: | Высота: | Размер: 14 KiB |
После Ширина: | Высота: | Размер: 14 KiB |
После Ширина: | Высота: | Размер: 11 KiB |
После Ширина: | Высота: | Размер: 1.0 KiB |
После Ширина: | Высота: | Размер: 429 B |
После Ширина: | Высота: | Размер: 304 KiB |
После Ширина: | Высота: | Размер: 3.9 KiB |
После Ширина: | Высота: | Размер: 1.3 KiB |
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 1.4 KiB |
После Ширина: | Высота: | Размер: 6.4 KiB |
После Ширина: | Высота: | Размер: 11 KiB |
После Ширина: | Высота: | Размер: 481 KiB |
После Ширина: | Высота: | Размер: 363 B |
После Ширина: | Высота: | Размер: 12 KiB |
После Ширина: | Высота: | Размер: 9.5 KiB |
После Ширина: | Высота: | Размер: 11 KiB |
После Ширина: | Высота: | Размер: 1.0 KiB |
После Ширина: | Высота: | Размер: 1.0 KiB |
|
@ -0,0 +1,25 @@
|
|||
<UserControl
|
||||
x:Class="IntelligentKioskSample.Controls.CameraControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:IntelligentKioskSample.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
x:Name="cameraControl"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400"
|
||||
FlowDirection="RightToLeft">
|
||||
|
||||
<Grid FlowDirection="LeftToRight">
|
||||
<CaptureElement x:Name="webCamCaptureElement" FlowDirection="{Binding ElementName=cameraControl, Path=FlowDirection}" />
|
||||
<Canvas x:Name="FaceTrackingVisualizationCanvas" FlowDirection="{Binding ElementName=cameraControl, Path=FlowDirection}" />
|
||||
|
||||
<Grid x:Name="commandBar" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2" >
|
||||
<Button Opacity="0.8" HorizontalAlignment="Right" VerticalAlignment="Bottom" Background="#FF222222" BorderBrush="Transparent" Click="CameraControlButtonClick" >
|
||||
<SymbolIcon x:Name="cameraControlSymbol" Margin="6" Symbol="Camera"></SymbolIcon>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
|
@ -0,0 +1,563 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using Microsoft.ProjectOxford.Common.Contract;
|
||||
using Microsoft.ProjectOxford.Face.Contract;
|
||||
using ServiceHelpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Devices.Enumeration;
|
||||
using Windows.Graphics.Imaging;
|
||||
using Windows.Media;
|
||||
using Windows.Media.Capture;
|
||||
using Windows.Media.Devices;
|
||||
using Windows.Media.FaceAnalysis;
|
||||
using Windows.Media.MediaProperties;
|
||||
using Windows.System.Threading;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace IntelligentKioskSample.Controls
|
||||
{
|
||||
public enum AutoCaptureState
|
||||
{
|
||||
WaitingForFaces,
|
||||
WaitingForStillFaces,
|
||||
ShowingCountdownForCapture,
|
||||
ShowingCapturedPhoto
|
||||
}
|
||||
|
||||
public interface IRealTimeDataProvider
|
||||
{
|
||||
EmotionScores GetLastEmotionForFace(BitmapBounds faceBox);
|
||||
Face GetLastFaceAttributesForFace(BitmapBounds faceBox);
|
||||
}
|
||||
|
||||
public sealed partial class CameraControl : UserControl
|
||||
{
|
||||
public event EventHandler<ImageAnalyzer> ImageCaptured;
|
||||
public event EventHandler<AutoCaptureState> AutoCaptureStateChanged;
|
||||
public event EventHandler CameraRestarted;
|
||||
public event EventHandler CameraAspectRatioChanged;
|
||||
|
||||
public static readonly DependencyProperty ShowDialogOnApiErrorsProperty =
|
||||
DependencyProperty.Register(
|
||||
"ShowDialogOnApiErrors",
|
||||
typeof(bool),
|
||||
typeof(CameraControl),
|
||||
new PropertyMetadata(true)
|
||||
);
|
||||
|
||||
public bool ShowDialogOnApiErrors
|
||||
{
|
||||
get { return (bool)GetValue(ShowDialogOnApiErrorsProperty); }
|
||||
set { SetValue(ShowDialogOnApiErrorsProperty, (bool)value); }
|
||||
}
|
||||
|
||||
public bool FilterOutSmallFaces
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private bool enableAutoCaptureMode;
|
||||
public bool EnableAutoCaptureMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return enableAutoCaptureMode;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.enableAutoCaptureMode = value;
|
||||
this.commandBar.Visibility = this.enableAutoCaptureMode ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
public double CameraAspectRatio { get; set; }
|
||||
public int CameraResolutionWidth { get; private set; }
|
||||
public int CameraResolutionHeight { get; private set; }
|
||||
|
||||
public int NumFacesOnLastFrame { get; set; }
|
||||
|
||||
public CameraStreamState CameraStreamState { get { return captureManager != null ? captureManager.CameraStreamState : CameraStreamState.NotStreaming; } }
|
||||
|
||||
private MediaCapture captureManager;
|
||||
private VideoEncodingProperties videoProperties;
|
||||
private FaceTracker faceTracker;
|
||||
private ThreadPoolTimer frameProcessingTimer;
|
||||
private SemaphoreSlim frameProcessingSemaphore = new SemaphoreSlim(1);
|
||||
private AutoCaptureState autoCaptureState;
|
||||
private IEnumerable<DetectedFace> detectedFacesFromPreviousFrame;
|
||||
private DateTime timeSinceWaitingForStill;
|
||||
private DateTime lastTimeWhenAFaceWasDetected;
|
||||
|
||||
private IRealTimeDataProvider realTimeDataProvider;
|
||||
|
||||
public CameraControl()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
#region Camera stream processing
|
||||
|
||||
public async Task StartStreamAsync(bool isForRealTimeProcessing = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (captureManager == null ||
|
||||
captureManager.CameraStreamState == CameraStreamState.Shutdown ||
|
||||
captureManager.CameraStreamState == CameraStreamState.NotStreaming)
|
||||
{
|
||||
if (captureManager != null)
|
||||
{
|
||||
captureManager.Dispose();
|
||||
}
|
||||
|
||||
captureManager = new MediaCapture();
|
||||
|
||||
MediaCaptureInitializationSettings settings = new MediaCaptureInitializationSettings();
|
||||
var allCameras = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
|
||||
var selectedCamera = allCameras.FirstOrDefault(c => c.Name == SettingsHelper.Instance.CameraName);
|
||||
if (selectedCamera != null)
|
||||
{
|
||||
settings.VideoDeviceId = selectedCamera.Id;
|
||||
}
|
||||
|
||||
await captureManager.InitializeAsync(settings);
|
||||
await SetVideoEncodingToHighestResolution(isForRealTimeProcessing);
|
||||
|
||||
this.webCamCaptureElement.Source = captureManager;
|
||||
}
|
||||
|
||||
if (captureManager.CameraStreamState == CameraStreamState.NotStreaming)
|
||||
{
|
||||
if (this.faceTracker == null)
|
||||
{
|
||||
this.faceTracker = await FaceTracker.CreateAsync();
|
||||
}
|
||||
|
||||
this.videoProperties = this.captureManager.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview) as VideoEncodingProperties;
|
||||
|
||||
await captureManager.StartPreviewAsync();
|
||||
|
||||
if (this.frameProcessingTimer != null)
|
||||
{
|
||||
this.frameProcessingTimer.Cancel();
|
||||
frameProcessingSemaphore.Release();
|
||||
}
|
||||
TimeSpan timerInterval = TimeSpan.FromMilliseconds(66); //15fps
|
||||
this.frameProcessingTimer = ThreadPoolTimer.CreatePeriodicTimer(new TimerElapsedHandler(ProcessCurrentVideoFrame), timerInterval);
|
||||
|
||||
this.cameraControlSymbol.Symbol = Symbol.Camera;
|
||||
this.webCamCaptureElement.Visibility = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Util.GenericApiCallExceptionHandler(ex, "Error starting the camera.");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetVideoEncodingToHighestResolution(bool isForRealTimeProcessing = false)
|
||||
{
|
||||
VideoEncodingProperties highestVideoEncodingSetting;
|
||||
|
||||
// Sort the available resolutions from highest to lowest
|
||||
var availableResolutions = this.captureManager.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.VideoPreview).Cast<VideoEncodingProperties>().OrderByDescending(v => v.Width * v.Height * (v.FrameRate.Numerator / v.FrameRate.Denominator));
|
||||
|
||||
if (isForRealTimeProcessing)
|
||||
{
|
||||
uint maxHeightForRealTime = 720;
|
||||
// Find the highest resolution that is 720p or lower
|
||||
highestVideoEncodingSetting = availableResolutions.FirstOrDefault(v => v.Height <= maxHeightForRealTime);
|
||||
if (highestVideoEncodingSetting == null)
|
||||
{
|
||||
// Since we didn't find 720p or lower, look for the first up from there
|
||||
highestVideoEncodingSetting = availableResolutions.LastOrDefault();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the highest resolution
|
||||
highestVideoEncodingSetting = availableResolutions.FirstOrDefault();
|
||||
}
|
||||
|
||||
if (highestVideoEncodingSetting != null)
|
||||
{
|
||||
this.CameraAspectRatio = (double)highestVideoEncodingSetting.Width / (double)highestVideoEncodingSetting.Height;
|
||||
this.CameraResolutionHeight = (int)highestVideoEncodingSetting.Height;
|
||||
this.CameraResolutionWidth = (int)highestVideoEncodingSetting.Width;
|
||||
|
||||
await this.captureManager.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, highestVideoEncodingSetting);
|
||||
|
||||
if (this.CameraAspectRatioChanged != null)
|
||||
{
|
||||
this.CameraAspectRatioChanged(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void ProcessCurrentVideoFrame(ThreadPoolTimer timer)
|
||||
{
|
||||
if (captureManager.CameraStreamState != Windows.Media.Devices.CameraStreamState.Streaming
|
||||
|| !frameProcessingSemaphore.Wait(0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IEnumerable<DetectedFace> faces = null;
|
||||
|
||||
// Create a VideoFrame object specifying the pixel format we want our capture image to be (NV12 bitmap in this case).
|
||||
// GetPreviewFrame will convert the native webcam frame into this format.
|
||||
const BitmapPixelFormat InputPixelFormat = BitmapPixelFormat.Nv12;
|
||||
using (VideoFrame previewFrame = new VideoFrame(InputPixelFormat, (int)this.videoProperties.Width, (int)this.videoProperties.Height))
|
||||
{
|
||||
await this.captureManager.GetPreviewFrameAsync(previewFrame);
|
||||
|
||||
// The returned VideoFrame should be in the supported NV12 format but we need to verify this.
|
||||
if (FaceDetector.IsBitmapPixelFormatSupported(previewFrame.SoftwareBitmap.BitmapPixelFormat))
|
||||
{
|
||||
faces = await this.faceTracker.ProcessNextFrameAsync(previewFrame);
|
||||
|
||||
if (this.FilterOutSmallFaces)
|
||||
{
|
||||
// We filter out small faces here.
|
||||
faces = faces.Where(f => CoreUtil.IsFaceBigEnoughForDetection((int)f.FaceBox.Height, (int)this.videoProperties.Height));
|
||||
}
|
||||
|
||||
this.NumFacesOnLastFrame = faces.Count();
|
||||
|
||||
if (this.EnableAutoCaptureMode)
|
||||
{
|
||||
this.UpdateAutoCaptureState(faces);
|
||||
}
|
||||
|
||||
// Create our visualization using the frame dimensions and face results but run it on the UI thread.
|
||||
var previewFrameSize = new Windows.Foundation.Size(previewFrame.SoftwareBitmap.PixelWidth, previewFrame.SoftwareBitmap.PixelHeight);
|
||||
var ignored = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
this.ShowFaceTrackingVisualization(previewFrameSize, faces);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
frameProcessingSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowFaceTrackingVisualization(Windows.Foundation.Size framePixelSize, IEnumerable<DetectedFace> detectedFaces)
|
||||
{
|
||||
this.FaceTrackingVisualizationCanvas.Children.Clear();
|
||||
|
||||
double actualWidth = this.FaceTrackingVisualizationCanvas.ActualWidth;
|
||||
double actualHeight = this.FaceTrackingVisualizationCanvas.ActualHeight;
|
||||
|
||||
if (captureManager.CameraStreamState == Windows.Media.Devices.CameraStreamState.Streaming &&
|
||||
detectedFaces != null && actualWidth != 0 && actualHeight != 0)
|
||||
{
|
||||
double widthScale = framePixelSize.Width / actualWidth;
|
||||
double heightScale = framePixelSize.Height / actualHeight;
|
||||
|
||||
foreach (DetectedFace face in detectedFaces)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("ShowFaceTrackingVisualization(...) FACE DETECTED!!!");
|
||||
|
||||
RealTimeFaceIdentificationBorder faceBorder = new RealTimeFaceIdentificationBorder();
|
||||
this.FaceTrackingVisualizationCanvas.Children.Add(faceBorder);
|
||||
|
||||
faceBorder.ShowFaceRectangle((uint)(face.FaceBox.X / widthScale), (uint)(face.FaceBox.Y / heightScale), (uint)(face.FaceBox.Width / widthScale), (uint)(face.FaceBox.Height / heightScale));
|
||||
|
||||
if (this.realTimeDataProvider != null)
|
||||
{
|
||||
EmotionScores lastEmotion = this.realTimeDataProvider.GetLastEmotionForFace(face.FaceBox);
|
||||
if (lastEmotion != null)
|
||||
{
|
||||
faceBorder.ShowRealTimeEmotionData(lastEmotion);
|
||||
}
|
||||
}
|
||||
|
||||
if (SettingsHelper.Instance.ShowDebugInfo)
|
||||
{
|
||||
this.FaceTrackingVisualizationCanvas.Children.Add(new TextBlock
|
||||
{
|
||||
Text = string.Format("Coverage: {0:0}%", 100 * ((double)face.FaceBox.Height / this.videoProperties.Height)),
|
||||
Margin = new Thickness((uint)(face.FaceBox.X / widthScale), (uint)(face.FaceBox.Y / heightScale), 0, 0)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void UpdateAutoCaptureState(IEnumerable<DetectedFace> detectedFaces)
|
||||
{
|
||||
const int IntervalBeforeCheckingForStill = 500;
|
||||
const int IntervalWithoutFacesBeforeRevertingToWaitingForFaces = 3;
|
||||
|
||||
if (!detectedFaces.Any())
|
||||
{
|
||||
if (this.autoCaptureState == AutoCaptureState.WaitingForStillFaces &&
|
||||
(DateTime.Now - this.lastTimeWhenAFaceWasDetected).TotalSeconds > IntervalWithoutFacesBeforeRevertingToWaitingForFaces)
|
||||
{
|
||||
this.autoCaptureState = AutoCaptureState.WaitingForFaces;
|
||||
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
this.OnAutoCaptureStateChanged(this.autoCaptureState);
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.lastTimeWhenAFaceWasDetected = DateTime.Now;
|
||||
|
||||
switch (this.autoCaptureState)
|
||||
{
|
||||
case AutoCaptureState.WaitingForFaces:
|
||||
// We were waiting for faces and got some... go to the "waiting for still" state
|
||||
this.detectedFacesFromPreviousFrame = detectedFaces;
|
||||
this.timeSinceWaitingForStill = DateTime.Now;
|
||||
this.autoCaptureState = AutoCaptureState.WaitingForStillFaces;
|
||||
|
||||
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
this.OnAutoCaptureStateChanged(this.autoCaptureState);
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
case AutoCaptureState.WaitingForStillFaces:
|
||||
// See if we have been waiting for still faces long enough
|
||||
if ((DateTime.Now - this.timeSinceWaitingForStill).TotalMilliseconds >= IntervalBeforeCheckingForStill)
|
||||
{
|
||||
// See if the faces are still enough
|
||||
if (this.AreFacesStill(this.detectedFacesFromPreviousFrame, detectedFaces))
|
||||
{
|
||||
this.autoCaptureState = AutoCaptureState.ShowingCountdownForCapture;
|
||||
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
this.OnAutoCaptureStateChanged(this.autoCaptureState);
|
||||
|
||||
// CAPTURE THE PHOTO DUDE!!!!
|
||||
//this.TakeAutoCapturePhoto();
|
||||
this.CameraControlButtonClick(this, new RoutedEventArgs());
|
||||
|
||||
//// AFTER 10s RESET
|
||||
//var delay = Task.Delay(10000).ContinueWith(async _ =>
|
||||
//{
|
||||
// await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
||||
// {
|
||||
// this.CameraControlButtonClick(this, new RoutedEventArgs());
|
||||
|
||||
// this.RestartAutoCaptureCycle();
|
||||
// });
|
||||
//});
|
||||
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Faces moved too much, update the baseline and keep waiting
|
||||
this.timeSinceWaitingForStill = DateTime.Now;
|
||||
this.detectedFacesFromPreviousFrame = detectedFaces;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AutoCaptureState.ShowingCountdownForCapture:
|
||||
break;
|
||||
|
||||
case AutoCaptureState.ShowingCapturedPhoto:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void RestartAutoCaptureCycle()
|
||||
{
|
||||
CameraControlButtonClick(this, new RoutedEventArgs());
|
||||
this.autoCaptureState = AutoCaptureState.WaitingForFaces;
|
||||
this.OnAutoCaptureStateChanged(this.autoCaptureState);
|
||||
}
|
||||
|
||||
private bool AreFacesStill(IEnumerable<DetectedFace> detectedFacesFromPreviousFrame, IEnumerable<DetectedFace> detectedFacesFromCurrentFrame)
|
||||
{
|
||||
int horizontalMovementThreshold = (int)(videoProperties.Width * 0.02);
|
||||
int verticalMovementThreshold = (int)(videoProperties.Height * 0.02);
|
||||
|
||||
int numStillFaces = 0;
|
||||
int totalFacesInPreviousFrame = detectedFacesFromPreviousFrame.Count();
|
||||
|
||||
foreach (DetectedFace faceInPreviousFrame in detectedFacesFromPreviousFrame)
|
||||
{
|
||||
if (numStillFaces > 0 && numStillFaces >= totalFacesInPreviousFrame / 2)
|
||||
{
|
||||
// If half or more of the faces in the previous frame are considered still we can stop. It is still enough.
|
||||
break;
|
||||
}
|
||||
|
||||
// If there is a face in the current frame that is located close enough to this one in the previous frame, we
|
||||
// assume it is the same face and count it as a still face.
|
||||
if (detectedFacesFromCurrentFrame.Any(f => Math.Abs((int)faceInPreviousFrame.FaceBox.X - (int)f.FaceBox.X) <= horizontalMovementThreshold &&
|
||||
Math.Abs((int)faceInPreviousFrame.FaceBox.Y - (int)f.FaceBox.Y) <= verticalMovementThreshold))
|
||||
{
|
||||
numStillFaces++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numStillFaces > 0 && numStillFaces >= totalFacesInPreviousFrame / 2)
|
||||
{
|
||||
// If half or more of the faces in the previous frame are considered still we consider the group as still
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task StopStreamAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.frameProcessingTimer != null)
|
||||
{
|
||||
this.frameProcessingTimer.Cancel();
|
||||
}
|
||||
|
||||
if (captureManager != null && captureManager.CameraStreamState != Windows.Media.Devices.CameraStreamState.Shutdown)
|
||||
{
|
||||
this.FaceTrackingVisualizationCanvas.Children.Clear();
|
||||
await this.captureManager.StopPreviewAsync();
|
||||
|
||||
this.FaceTrackingVisualizationCanvas.Children.Clear();
|
||||
this.webCamCaptureElement.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//await Util.GenericApiCallExceptionHandler(ex, "Error stopping the camera.");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ImageAnalyzer> CaptureFrameAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!(await this.frameProcessingSemaphore.WaitAsync(250)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Capture a frame from the preview stream
|
||||
var videoFrame = new VideoFrame(BitmapPixelFormat.Bgra8, CameraResolutionWidth, CameraResolutionHeight);
|
||||
using (var currentFrame = await captureManager.GetPreviewFrameAsync(videoFrame))
|
||||
{
|
||||
using (SoftwareBitmap previewFrame = currentFrame.SoftwareBitmap)
|
||||
{
|
||||
ImageAnalyzer imageWithFace = new ImageAnalyzer(await Util.GetPixelBytesFromSoftwareBitmapAsync(previewFrame));
|
||||
|
||||
imageWithFace.ShowDialogOnFaceApiErrors = this.ShowDialogOnApiErrors;
|
||||
imageWithFace.FilterOutSmallFaces = this.FilterOutSmallFaces;
|
||||
imageWithFace.UpdateDecodedImageSize(this.CameraResolutionHeight, this.CameraResolutionWidth);
|
||||
|
||||
return imageWithFace;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (this.ShowDialogOnApiErrors)
|
||||
{
|
||||
await Util.GenericApiCallExceptionHandler(ex, "Error capturing photo.");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.frameProcessingSemaphore.Release();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void OnImageCaptured(ImageAnalyzer imageWithFace)
|
||||
{
|
||||
if (this.ImageCaptured != null)
|
||||
{
|
||||
this.ImageCaptured(this, imageWithFace);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAutoCaptureStateChanged(AutoCaptureState state)
|
||||
{
|
||||
if (this.AutoCaptureStateChanged != null)
|
||||
{
|
||||
this.AutoCaptureStateChanged(this, state);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private async void CameraControlButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (this.cameraControlSymbol.Symbol == Symbol.Camera)
|
||||
{
|
||||
var img = await CaptureFrameAsync();
|
||||
if (img != null)
|
||||
{
|
||||
this.cameraControlSymbol.Symbol = Symbol.Refresh;
|
||||
this.OnImageCaptured(img);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.cameraControlSymbol.Symbol = Symbol.Camera;
|
||||
|
||||
await StartStreamAsync();
|
||||
|
||||
this.CameraRestarted?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<UserControl x:Class="IntelligentKioskSample.Controls.EmotionEmojiControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
>
|
||||
<Grid Background="#FF1F1F1F" HorizontalAlignment="Left" VerticalAlignment="Top" MinWidth="60" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock x:Name="emotionEmoji" FontSize="17" FontFamily="Segoe UI Emoji" HorizontalAlignment="Center" VerticalAlignment="Center">😄</TextBlock>
|
||||
<TextBlock x:Name="emotionText" Margin="2,0,2,3" Grid.Row="1" Style="{StaticResource CaptionTextBlockStyle}" Foreground="LightGray" Opacity="0.5" FontFamily="Segoe UI Semilight" HorizontalAlignment="Center" VerticalAlignment="Top">Happy</TextBlock>
|
||||
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
|
@ -0,0 +1,98 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using Microsoft.ProjectOxford.Common.Contract;
|
||||
using ServiceHelpers;
|
||||
using System.Linq;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace IntelligentKioskSample.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for EmotionEmojiControl.xaml
|
||||
/// </summary>
|
||||
public partial class EmotionEmojiControl : UserControl
|
||||
{
|
||||
public EmotionEmojiControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void UpdateEmotion(EmotionScores scores)
|
||||
{
|
||||
EmotionData topEmotion = EmotionServiceHelper.ScoresToEmotionData(scores).OrderByDescending(d => d.EmotionScore).First();
|
||||
string label = "", emoji = "";
|
||||
|
||||
switch (topEmotion.EmotionName)
|
||||
{
|
||||
case "Anger":
|
||||
label = "Angry";
|
||||
emoji = "\U0001f620";
|
||||
break;
|
||||
case "Contempt":
|
||||
label = "Contemptuous";
|
||||
emoji = "\U0001f612";
|
||||
break;
|
||||
case "Disgust":
|
||||
label = "Disgusted";
|
||||
emoji = "\U0001f627";
|
||||
break;
|
||||
case "Fear":
|
||||
label = "Afraid";
|
||||
emoji = "\U0001f628";
|
||||
break;
|
||||
case "Happiness":
|
||||
label = "Happy";
|
||||
emoji = "\U0001f60a";
|
||||
break;
|
||||
case "Neutral":
|
||||
label = "Neutral";
|
||||
emoji = "\U0001f614";
|
||||
break;
|
||||
case "Sadness":
|
||||
label = "Sad";
|
||||
emoji = "\U0001f622";
|
||||
break;
|
||||
case "Surprise":
|
||||
label = "Surprised";
|
||||
emoji = "\U0001f632";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this.emotionEmoji.Text = emoji;
|
||||
this.emotionText.Text = label;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<UserControl
|
||||
x:Class="IntelligentKioskSample.Controls.EmotionMeterControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:IntelligentKioskSample.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400"
|
||||
VerticalAlignment="Center"
|
||||
x:Name="userControl">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Width="60" Foreground="{Binding ElementName=userControl, Path=MeterForeground}" FontFamily="Segoe UI Semilight" Text="{Binding ElementName=userControl, Path=EmotionName}" HorizontalAlignment="Left" Style="{StaticResource CaptionTextBlockStyle}"/>
|
||||
<ProgressBar Grid.Column="1" Foreground="{Binding ElementName=userControl, Path=MeterForeground}" Height="5" Value="{Binding ElementName=userControl, Path=EmotionValue}" Minimum="0" Maximum="1" Width="60" HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,108 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using Microsoft.ProjectOxford.Emotion.Contract;
|
||||
using Microsoft.ProjectOxford.Face.Contract;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.Storage;
|
||||
using Windows.UI;
|
||||
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.UI.Xaml.Shapes;
|
||||
|
||||
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace IntelligentKioskSample.Controls
|
||||
{
|
||||
public sealed partial class EmotionMeterControl : UserControl
|
||||
{
|
||||
public EmotionMeterControl()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
//this.DataContext = this;
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty EmotionNameProperty =
|
||||
DependencyProperty.Register(
|
||||
"EmotionName",
|
||||
typeof(string),
|
||||
typeof(EmotionMeterControl),
|
||||
new PropertyMetadata("")
|
||||
);
|
||||
|
||||
public static readonly DependencyProperty EmotionValueProperty =
|
||||
DependencyProperty.Register(
|
||||
"EmotionValue",
|
||||
typeof(float),
|
||||
typeof(EmotionMeterControl),
|
||||
new PropertyMetadata(0)
|
||||
);
|
||||
|
||||
public static readonly DependencyProperty MeterForegroundProperty =
|
||||
DependencyProperty.Register(
|
||||
"MeterForeground",
|
||||
typeof(SolidColorBrush),
|
||||
typeof(EmotionMeterControl),
|
||||
new PropertyMetadata(new SolidColorBrush(Colors.White))
|
||||
);
|
||||
|
||||
public SolidColorBrush MeterForeground
|
||||
{
|
||||
get { return (SolidColorBrush)GetValue(MeterForegroundProperty); }
|
||||
set { SetValue(MeterForegroundProperty, (SolidColorBrush)value); }
|
||||
}
|
||||
|
||||
public string EmotionName
|
||||
{
|
||||
get { return (string)GetValue(EmotionNameProperty); }
|
||||
set { SetValue(EmotionNameProperty, (string)value); }
|
||||
}
|
||||
public float EmotionValue
|
||||
{
|
||||
get { return (float)GetValue(EmotionValueProperty); }
|
||||
set { SetValue(EmotionValueProperty, (float)value); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
<UserControl
|
||||
x:Class="IntelligentKioskSample.Controls.FaceIdentificationBorder"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:IntelligentKioskSample.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
x:Name="userControl"
|
||||
>
|
||||
|
||||
<Grid x:Name="hostGrid" >
|
||||
<Rectangle x:Name="faceRectangle" Stroke="White" Visibility="Visible" HorizontalAlignment="Left" VerticalAlignment="Top" />
|
||||
|
||||
<Grid FlowDirection="LeftToRight" VerticalAlignment="Top" x:Name="captionCanvas" Visibility="Collapsed" HorizontalAlignment="Left" SizeChanged="OnCaptionSizeChanged" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid x:Name="genderAgeGrid" Height="43" MinWidth="50" Background="{Binding BalloonBackground}" VerticalAlignment="Top" HorizontalAlignment="Center" Opacity="0.8" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image x:Name="genderIcon" Margin="5,3,3,3"/>
|
||||
<Viewbox Grid.Column="1" >
|
||||
<TextBlock Foreground="{Binding BalloonForeground}" Margin="3,2,3,2" VerticalAlignment="Center"
|
||||
Text="{Binding CaptionText}"
|
||||
FontFamily="Segoe UI Semilight"/>
|
||||
</Viewbox>
|
||||
</Grid>
|
||||
|
||||
<Grid x:Name="emotionGrid" Visibility="Collapsed" MinWidth="50" VerticalAlignment="Top" HorizontalAlignment="Center" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid x:Name="emotionGridBackground" Opacity="0.8" Background="{Binding BalloonBackground}" Grid.RowSpan="2"/>
|
||||
|
||||
<Grid Height="120" Width="120" Margin="0,2,0,0" Visibility="Collapsed" x:Name="emotionFeedbackGrid">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="0.2*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Image x:Name="emotionFeedbackImage" Grid.RowSpan="2">
|
||||
<Image.Source>
|
||||
<BitmapImage x:Name="emotionFeedbackBitmap" />
|
||||
</Image.Source>
|
||||
</Image>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Grid x:Name="emotionFeedbackTextBackground" Background="White" Opacity="0.4"/>
|
||||
<Viewbox>
|
||||
<TextBlock x:Name="emotionFeedbackText" Margin="4,0,4,0" Foreground="{Binding BalloonForeground}" FontFamily="Segoe UI Semilight" HorizontalAlignment="Center"/>
|
||||
</Viewbox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!--The grid below used to be a ListView with an ItemsSource bound to a collection plus a template, but a bug in Windows would make it crash during layout
|
||||
when executed outside the debugger. -->
|
||||
<Grid Grid.Row="1" Margin="2" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<local:EmotionMeterControl EmotionName="{Binding EmotionData[0].EmotionName}" EmotionValue="{Binding EmotionData[0].EmotionScore}" MeterForeground="{Binding BalloonForeground}" />
|
||||
<local:EmotionMeterControl Grid.Row="1" EmotionName="{Binding EmotionData[1].EmotionName}" EmotionValue="{Binding EmotionData[1].EmotionScore}" MeterForeground="{Binding BalloonForeground}"/>
|
||||
<local:EmotionMeterControl Grid.Row="2" EmotionName="{Binding EmotionData[2].EmotionName}" EmotionValue="{Binding EmotionData[2].EmotionScore}" MeterForeground="{Binding BalloonForeground}"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Polyline x:Name="emotionPolyline" StrokeThickness="0" Grid.Row="1" Opacity="0.8"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Center"
|
||||
Points="0,0,10,10,20,0" Fill="{Binding BalloonBackground}" />
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
|
@ -0,0 +1,125 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using ServiceHelpers;
|
||||
using Microsoft.ProjectOxford.Emotion.Contract;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.Storage;
|
||||
using Windows.UI;
|
||||
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.Media.Imaging;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Windows.UI.Xaml.Shapes;
|
||||
using Microsoft.ProjectOxford.Face.Contract;
|
||||
|
||||
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace IntelligentKioskSample.Controls
|
||||
{
|
||||
public sealed partial class FaceIdentificationBorder : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty BalloonBackgroundProperty =
|
||||
DependencyProperty.Register(
|
||||
"BalloonBackground",
|
||||
typeof(SolidColorBrush),
|
||||
typeof(FaceIdentificationBorder),
|
||||
new PropertyMetadata(null)
|
||||
);
|
||||
|
||||
public SolidColorBrush BalloonBackground
|
||||
{
|
||||
get { return (SolidColorBrush)GetValue(BalloonBackgroundProperty); }
|
||||
set { SetValue(BalloonBackgroundProperty, (SolidColorBrush)value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BalloonForegroundProperty =
|
||||
DependencyProperty.Register(
|
||||
"BalloonForeground",
|
||||
typeof(SolidColorBrush),
|
||||
typeof(FaceIdentificationBorder),
|
||||
new PropertyMetadata(null)
|
||||
);
|
||||
|
||||
public SolidColorBrush BalloonForeground
|
||||
{
|
||||
get { return (SolidColorBrush)GetValue(BalloonForegroundProperty); }
|
||||
set { SetValue(BalloonForegroundProperty, (SolidColorBrush)value); }
|
||||
}
|
||||
|
||||
public string CaptionText { get; set; }
|
||||
|
||||
public EmotionData[] EmotionData { get; set; }
|
||||
|
||||
public FaceIdentificationBorder()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
public void ShowFaceRectangle(double width, double height)
|
||||
{
|
||||
this.faceRectangle.Width = width;
|
||||
this.faceRectangle.Height = height;
|
||||
|
||||
this.faceRectangle.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
public void ShowEmotionData(Emotion emotion)
|
||||
{
|
||||
this.EmotionData = EmotionServiceHelper.ScoresToEmotionData(emotion.Scores).OrderByDescending(e => e.EmotionScore).ToArray();
|
||||
|
||||
this.DataContext = this;
|
||||
|
||||
this.genderAgeGrid.Visibility = Visibility.Collapsed;
|
||||
this.emotionGrid.Visibility = Visibility.Visible;
|
||||
this.captionCanvas.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
private void OnCaptionSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
this.captionCanvas.Margin = new Thickness(this.faceRectangle.Margin.Left - (this.captionCanvas.ActualWidth - this.faceRectangle.ActualWidth) / 2,
|
||||
-this.captionCanvas.ActualHeight, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<UserControl
|
||||
x:Class="IntelligentKioskSample.Controls.ImageWithFaceBorderUserControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:IntelligentKioskSample.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400"
|
||||
DataContextChanged="OnDataContextChanged"
|
||||
x:Name="userControl">
|
||||
|
||||
<Grid>
|
||||
<Grid x:Name="hostGrid" SizeChanged="OnImageSizeChanged" >
|
||||
<Image x:Name="imageControl" SizeChanged="OnImageSizeChanged" FlowDirection="{Binding FlowDirection, ElementName=userControl}" >
|
||||
<Image.Source>
|
||||
<BitmapImage x:Name="bitmapImage" ImageOpened="OnBitmapImageOpened" ></BitmapImage>
|
||||
</Image.Source>
|
||||
</Image>
|
||||
</Grid>
|
||||
|
||||
<local:EmotionEmojiControl x:Name="emotionEmojiControl" VerticalAlignment="Top" />
|
||||
<!--<ProgressRing x:Name="progressIndicator" />-->
|
||||
<ProgressBar x:Name="progressIndicator" IsIndeterminate="False" Visibility="Collapsed" Height="32" ></ProgressBar>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,332 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using Microsoft.ProjectOxford.Emotion.Contract;
|
||||
using Microsoft.ProjectOxford.Face.Contract;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using ServiceHelpers;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace IntelligentKioskSample.Controls
|
||||
{
|
||||
public sealed partial class ImageWithFaceBorderUserControl : UserControl
|
||||
{
|
||||
private ImageAnalyzer currentImage;
|
||||
|
||||
public event EventHandler EmotionDetecting;
|
||||
public event EventHandler EmotionDetected;
|
||||
|
||||
public ImageWithFaceBorderUserControl()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DetectFacesOnLoadProperty =
|
||||
DependencyProperty.Register(
|
||||
"DetectFacesOnLoad",
|
||||
typeof(bool),
|
||||
typeof(ImageWithFaceBorderUserControl),
|
||||
new PropertyMetadata(false)
|
||||
);
|
||||
|
||||
public static readonly DependencyProperty ShowMultipleFacesProperty =
|
||||
DependencyProperty.Register(
|
||||
"ShowMultipleFaces",
|
||||
typeof(bool),
|
||||
typeof(ImageWithFaceBorderUserControl),
|
||||
new PropertyMetadata(false)
|
||||
);
|
||||
|
||||
public static readonly DependencyProperty PerformRecognitionProperty =
|
||||
DependencyProperty.Register(
|
||||
"PerformRecognition",
|
||||
typeof(bool),
|
||||
typeof(ImageWithFaceBorderUserControl),
|
||||
new PropertyMetadata(false)
|
||||
);
|
||||
|
||||
public static readonly DependencyProperty ShowRecognitionResultsProperty =
|
||||
DependencyProperty.Register(
|
||||
"ShowRecognitionResults",
|
||||
typeof(bool),
|
||||
typeof(ImageWithFaceBorderUserControl),
|
||||
new PropertyMetadata(false)
|
||||
);
|
||||
|
||||
public static readonly DependencyProperty ShowDialogOnApiErrorsProperty =
|
||||
DependencyProperty.Register(
|
||||
"ShowDialogOnApiErrors",
|
||||
typeof(bool),
|
||||
typeof(ImageWithFaceBorderUserControl),
|
||||
new PropertyMetadata(false)
|
||||
);
|
||||
|
||||
public static readonly DependencyProperty ShowEmotionRecognitionProperty =
|
||||
DependencyProperty.Register(
|
||||
"ShowEmotionRecognition",
|
||||
typeof(bool),
|
||||
typeof(ImageWithFaceBorderUserControl),
|
||||
new PropertyMetadata(false)
|
||||
);
|
||||
|
||||
public static readonly DependencyProperty BalloonBackgroundProperty =
|
||||
DependencyProperty.Register(
|
||||
"BalloonBackground",
|
||||
typeof(SolidColorBrush),
|
||||
typeof(ImageWithFaceBorderUserControl),
|
||||
new PropertyMetadata(null)
|
||||
);
|
||||
|
||||
public static readonly DependencyProperty BalloonForegroundProperty =
|
||||
DependencyProperty.Register(
|
||||
"BalloonForeground",
|
||||
typeof(SolidColorBrush),
|
||||
typeof(ImageWithFaceBorderUserControl),
|
||||
new PropertyMetadata(null)
|
||||
);
|
||||
|
||||
public static readonly DependencyProperty DetectFaceLandmarksProperty =
|
||||
DependencyProperty.Register(
|
||||
"DetectFaceLandmarks",
|
||||
typeof(bool),
|
||||
typeof(ImageWithFaceBorderUserControl),
|
||||
new PropertyMetadata(false)
|
||||
);
|
||||
|
||||
public SolidColorBrush BalloonBackground
|
||||
{
|
||||
get { return (SolidColorBrush)GetValue(BalloonBackgroundProperty); }
|
||||
set { SetValue(BalloonBackgroundProperty, (SolidColorBrush)value); }
|
||||
}
|
||||
|
||||
public SolidColorBrush BalloonForeground
|
||||
{
|
||||
get { return (SolidColorBrush)GetValue(BalloonForegroundProperty); }
|
||||
set { SetValue(BalloonForegroundProperty, (SolidColorBrush)value); }
|
||||
}
|
||||
|
||||
public bool ShowEmotionRecognition
|
||||
{
|
||||
get { return (bool)GetValue(ShowEmotionRecognitionProperty); }
|
||||
set { SetValue(ShowEmotionRecognitionProperty, (bool)value); }
|
||||
}
|
||||
|
||||
public bool ShowMultipleFaces
|
||||
{
|
||||
get { return (bool)GetValue(ShowMultipleFacesProperty); }
|
||||
set { SetValue(ShowMultipleFacesProperty, (bool)value); }
|
||||
}
|
||||
|
||||
public bool DetectFacesOnLoad
|
||||
{
|
||||
get { return (bool)GetValue(DetectFacesOnLoadProperty); }
|
||||
set { SetValue(DetectFacesOnLoadProperty, (bool)value); }
|
||||
}
|
||||
|
||||
public bool PerformRecognition
|
||||
{
|
||||
get { return (bool)GetValue(PerformRecognitionProperty); }
|
||||
set { SetValue(PerformRecognitionProperty, (bool)value); }
|
||||
}
|
||||
|
||||
public bool ShowRecognitionResults
|
||||
{
|
||||
get { return (bool)GetValue(ShowRecognitionResultsProperty); }
|
||||
set { SetValue(ShowRecognitionResultsProperty, (bool)value); }
|
||||
}
|
||||
|
||||
public bool ShowDialogOnApiErrors
|
||||
{
|
||||
get { return (bool)GetValue(ShowDialogOnApiErrorsProperty); }
|
||||
set { SetValue(ShowDialogOnApiErrorsProperty, (bool)value); }
|
||||
}
|
||||
|
||||
public bool DetectFaceLandmarks
|
||||
{
|
||||
get { return (bool)GetValue(DetectFaceLandmarksProperty); }
|
||||
set { SetValue(DetectFaceLandmarksProperty, (bool)value); }
|
||||
}
|
||||
|
||||
private async void OnDataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
ImageAnalyzer dataContext = this.DataContext as ImageAnalyzer;
|
||||
|
||||
if (this.currentImage != dataContext)
|
||||
{
|
||||
this.currentImage = dataContext;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Windows sometimes fires multiple DataContextChanged events.
|
||||
// If we are here that is one of those cases, and since we already set
|
||||
// the data context to this value we can ignore it
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var child in this.hostGrid.Children.Where(c => !(c is Image)).ToArray())
|
||||
{
|
||||
this.hostGrid.Children.Remove(child);
|
||||
}
|
||||
|
||||
// remove the current source
|
||||
this.bitmapImage.UriSource = null;
|
||||
|
||||
if (dataContext != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (dataContext.ImageUrl != null)
|
||||
{
|
||||
this.bitmapImage.UriSource = new Uri(dataContext.ImageUrl);
|
||||
}
|
||||
else if (dataContext.GetImageStreamCallback != null)
|
||||
{
|
||||
await this.bitmapImage.SetSourceAsync((await dataContext.GetImageStreamCallback()).AsRandomAccessStream());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// If we fail to load the image we will just not display it
|
||||
this.bitmapImage.UriSource = null;
|
||||
if (this.ShowDialogOnApiErrors)
|
||||
{
|
||||
await Util.GenericApiCallExceptionHandler(ex, "Error loading captured image.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HideProgressBar()
|
||||
{
|
||||
this.progressIndicator.Visibility = Visibility.Collapsed;
|
||||
this.progressIndicator.IsIndeterminate = false;
|
||||
}
|
||||
|
||||
private void ShowProgressBar()
|
||||
{
|
||||
this.progressIndicator.Visibility = Visibility.Visible;
|
||||
this.progressIndicator.IsIndeterminate = true;
|
||||
}
|
||||
|
||||
private async Task DetectAndShowEmotion()
|
||||
{
|
||||
ShowProgressBar();
|
||||
|
||||
foreach (var child in this.hostGrid.Children.Where(c => !(c is Image)).ToArray())
|
||||
{
|
||||
this.hostGrid.Children.Remove(child);
|
||||
}
|
||||
|
||||
ImageAnalyzer imageWithFace = this.DataContext as ImageAnalyzer;
|
||||
if (imageWithFace != null)
|
||||
{
|
||||
if (imageWithFace.DetectedEmotion == null)
|
||||
{
|
||||
EmotionDetecting?.Invoke(this, new EventArgs());
|
||||
|
||||
await imageWithFace.DetectEmotionAsync();
|
||||
|
||||
EmotionDetected?.Invoke(this, new EventArgs());
|
||||
}
|
||||
|
||||
double renderedImageXTransform = this.imageControl.RenderSize.Width / this.bitmapImage.PixelWidth;
|
||||
double renderedImageYTransform = this.imageControl.RenderSize.Height / this.bitmapImage.PixelHeight;
|
||||
|
||||
foreach (Emotion emotion in imageWithFace.DetectedEmotion)
|
||||
{
|
||||
FaceIdentificationBorder faceUI = new FaceIdentificationBorder();
|
||||
|
||||
faceUI.Margin = new Thickness((emotion.FaceRectangle.Left * renderedImageXTransform) + ((this.ActualWidth - this.imageControl.RenderSize.Width) / 2),
|
||||
(emotion.FaceRectangle.Top * renderedImageYTransform) + ((this.ActualHeight - this.imageControl.RenderSize.Height) / 2), 0, 0);
|
||||
|
||||
faceUI.BalloonBackground = this.BalloonBackground;
|
||||
faceUI.BalloonForeground = this.BalloonForeground;
|
||||
|
||||
faceUI.ShowFaceRectangle(emotion.FaceRectangle.Width * renderedImageXTransform, emotion.FaceRectangle.Height * renderedImageYTransform);
|
||||
|
||||
faceUI.ShowEmotionData(emotion);
|
||||
this.emotionEmojiControl.UpdateEmotion(emotion.Scores);
|
||||
|
||||
this.hostGrid.Children.Add(faceUI);
|
||||
|
||||
if (!this.ShowMultipleFaces)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//this.progressIndicator.IsActive = false;
|
||||
HideProgressBar();
|
||||
}
|
||||
|
||||
private async Task PreviewImageFaces()
|
||||
{
|
||||
if (!this.DetectFacesOnLoad || this.progressIndicator.Visibility != Visibility.Collapsed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ImageAnalyzer img = this.DataContext as ImageAnalyzer;
|
||||
if (img != null)
|
||||
{
|
||||
img.UpdateDecodedImageSize(this.bitmapImage.PixelHeight, this.bitmapImage.PixelWidth);
|
||||
}
|
||||
|
||||
if (this.ShowEmotionRecognition)
|
||||
{
|
||||
await this.DetectAndShowEmotion();
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnBitmapImageOpened(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await this.PreviewImageFaces();
|
||||
}
|
||||
|
||||
private async void OnImageSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
await this.PreviewImageFaces();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.System;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
|
||||
namespace IntelligentKioskSample.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// A specialized ListView to represent the items in the navigation menu.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class handles the following:
|
||||
/// 1. Sizes the panel that hosts the items so they fit in the hosting pane. Otherwise, the keyboard
|
||||
/// may appear cut off on one side b/c the Pane clips instead of affecting layout.
|
||||
/// 2. Provides a single selection experience where keyboard focus can move without changing selection.
|
||||
/// Both the 'Space' and 'Enter' keys will trigger selection. The up/down arrow keys can move
|
||||
/// keyboard focus without triggering selection. This is different than the default behavior when
|
||||
/// SelectionMode == Single. The default behavior for a ListView in single selection requires using
|
||||
/// the Ctrl + arrow key to move keyboard focus without triggering selection. Users won't expect
|
||||
/// this type of keyboarding model on the nav menu.
|
||||
/// </remarks>
|
||||
public class NavMenuListView : ListView
|
||||
{
|
||||
private SplitView splitViewHost;
|
||||
|
||||
public NavMenuListView()
|
||||
{
|
||||
this.SelectionMode = ListViewSelectionMode.Single;
|
||||
this.IsItemClickEnabled = true;
|
||||
this.ItemClick += ItemClickedHandler;
|
||||
|
||||
// Locate the hosting SplitView control
|
||||
this.Loaded += (s, a) =>
|
||||
{
|
||||
var parent = VisualTreeHelper.GetParent(this);
|
||||
while (parent != null && !(parent is SplitView))
|
||||
{
|
||||
parent = VisualTreeHelper.GetParent(parent);
|
||||
}
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
this.splitViewHost = parent as SplitView;
|
||||
|
||||
splitViewHost.RegisterPropertyChangedCallback(SplitView.IsPaneOpenProperty, (sender, args) =>
|
||||
{
|
||||
this.OnPaneToggled();
|
||||
});
|
||||
|
||||
// Call once to ensure we're in the correct state
|
||||
this.OnPaneToggled();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark the <paramref name="item"/> as selected and ensures everything else is not.
|
||||
/// If the <paramref name="item"/> is null then everything is unselected.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public void SetSelectedItem(ListViewItem item)
|
||||
{
|
||||
int index = -1;
|
||||
if (item != null)
|
||||
{
|
||||
index = this.IndexFromContainer(item);
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.Items.Count; i++)
|
||||
{
|
||||
var lvi = (ListViewItem)this.ContainerFromIndex(i);
|
||||
if (i != index)
|
||||
{
|
||||
lvi.IsSelected = false;
|
||||
}
|
||||
else if (i == index)
|
||||
{
|
||||
lvi.IsSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when an item has been selected
|
||||
/// </summary>
|
||||
public event EventHandler<ListViewItem> ItemInvoked;
|
||||
|
||||
/// <summary>
|
||||
/// This method is a work-around until the bug in FocusManager.TryMoveFocus is fixed.
|
||||
/// </summary>
|
||||
/// <param name="direction"></param>
|
||||
|
||||
private void ItemClickedHandler(object sender, ItemClickEventArgs e)
|
||||
{
|
||||
// Triggered when the item is selected using something other than a keyboard
|
||||
var item = this.ContainerFromItem(e.ClickedItem);
|
||||
this.InvokeItem(item);
|
||||
}
|
||||
|
||||
private void InvokeItem(object focusedItem)
|
||||
{
|
||||
this.SetSelectedItem(focusedItem as ListViewItem);
|
||||
this.ItemInvoked(this, focusedItem as ListViewItem);
|
||||
|
||||
if (this.splitViewHost.IsPaneOpen && (
|
||||
this.splitViewHost.DisplayMode == SplitViewDisplayMode.CompactOverlay ||
|
||||
this.splitViewHost.DisplayMode == SplitViewDisplayMode.Overlay))
|
||||
{
|
||||
this.splitViewHost.IsPaneOpen = false;
|
||||
if (focusedItem is ListViewItem)
|
||||
{
|
||||
((ListViewItem)focusedItem).Focus(FocusState.Programmatic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Re-size the ListView's Panel when the SplitView is compact so the items
|
||||
/// will fit within the visible space and correctly display a keyboard focus rect.
|
||||
/// </summary>
|
||||
private void OnPaneToggled()
|
||||
{
|
||||
if (this.splitViewHost.IsPaneOpen)
|
||||
{
|
||||
this.ItemsPanelRoot.ClearValue(FrameworkElement.WidthProperty);
|
||||
this.ItemsPanelRoot.ClearValue(FrameworkElement.HorizontalAlignmentProperty);
|
||||
}
|
||||
else if (this.splitViewHost.DisplayMode == SplitViewDisplayMode.CompactInline ||
|
||||
this.splitViewHost.DisplayMode == SplitViewDisplayMode.CompactOverlay)
|
||||
{
|
||||
this.ItemsPanelRoot.SetValue(FrameworkElement.WidthProperty, this.splitViewHost.CompactPaneLength);
|
||||
this.ItemsPanelRoot.SetValue(FrameworkElement.HorizontalAlignmentProperty, HorizontalAlignment.Left);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<UserControl
|
||||
x:Name="Root"
|
||||
x:Class="IntelligentKioskSample.Controls.PageHeader"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:IntelligentKioskSample.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
VerticalAlignment="Top"
|
||||
VerticalContentAlignment="Top"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}"
|
||||
Height="48"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400">
|
||||
|
||||
<Grid x:Name="grid" Background="{x:Bind Background}">
|
||||
<Grid x:Name="titleBar">
|
||||
<ContentPresenter x:Name="content"
|
||||
VerticalAlignment="{x:Bind VerticalContentAlignment}"
|
||||
HorizontalAlignment="{x:Bind HorizontalContentAlignment}"
|
||||
Margin="{x:Bind Padding}"
|
||||
Content="{x:Bind HeaderContent}"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using IntelligentKioskSample.Views;
|
||||
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;
|
||||
|
||||
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace IntelligentKioskSample.Controls
|
||||
{
|
||||
public sealed partial class PageHeader : UserControl
|
||||
{
|
||||
public PageHeader()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
this.Loaded += (s, a) =>
|
||||
{
|
||||
AppShell.Current.TogglePaneButtonRectChanged += Current_TogglePaneButtonSizeChanged;
|
||||
this.titleBar.Margin = new Thickness(AppShell.Current.TogglePaneButtonRect.Right, 0, 0, 0);
|
||||
};
|
||||
}
|
||||
|
||||
private void Current_TogglePaneButtonSizeChanged(AppShell sender, Rect e)
|
||||
{
|
||||
this.titleBar.Margin = new Thickness(e.Right, 0, 0, 0);
|
||||
}
|
||||
|
||||
public UIElement HeaderContent
|
||||
{
|
||||
get { return (UIElement)GetValue(HeaderContentProperty); }
|
||||
set { SetValue(HeaderContentProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for HeaderContent. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty HeaderContentProperty =
|
||||
DependencyProperty.Register("HeaderContent", typeof(UIElement), typeof(PageHeader), new PropertyMetadata(DependencyProperty.UnsetValue));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<UserControl
|
||||
x:Class="IntelligentKioskSample.Controls.RealTimeFaceIdentificationBorder"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:IntelligentKioskSample.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
x:Name="userControl"
|
||||
>
|
||||
|
||||
<Grid>
|
||||
<Rectangle x:Name="faceRectangle" Stroke="White" Visibility="Visible" HorizontalAlignment="Left" VerticalAlignment="Top" />
|
||||
<Border x:Name="captionBorder" Visibility="Collapsed" VerticalAlignment="Top" HorizontalAlignment="Left" Width="300" Height="40" >
|
||||
<StackPanel Orientation="Horizontal" FlowDirection="LeftToRight" HorizontalAlignment="Center">
|
||||
<Border Background="#FF1F1F1F">
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Center" >
|
||||
<TextBlock x:Name="captionTextHeader" Margin="6,0,6,0" Foreground="LightGray" FontFamily="Segoe UI Semilight" />
|
||||
<TextBlock x:Name="captionTextSubHeader" Margin="6,0,6,0" Foreground="LightGray" Opacity="0.5" Style="{StaticResource CaptionTextBlockStyle}" FontFamily="Segoe UI Semilight" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<local:EmotionEmojiControl x:Name="emotionEmojiControl" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using Microsoft.ProjectOxford.Common.Contract;
|
||||
using System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace IntelligentKioskSample.Controls
|
||||
{
|
||||
public sealed partial class RealTimeFaceIdentificationBorder : UserControl
|
||||
{
|
||||
public RealTimeFaceIdentificationBorder()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
public void ShowFaceRectangle(double left, double top, double width, double height)
|
||||
{
|
||||
this.faceRectangle.Margin = new Thickness(left, top, 0, 0);
|
||||
this.faceRectangle.Width = width;
|
||||
this.faceRectangle.Height = height;
|
||||
|
||||
this.faceRectangle.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
public void ShowRealTimeEmotionData(EmotionScores scores)
|
||||
{
|
||||
this.emotionEmojiControl.UpdateEmotion(scores);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<UserControl
|
||||
x:Class="IntelligentKioskSample.Controls.UpDownVerticalBarControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:IntelligentKiosk.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400"
|
||||
x:Name="userControl">
|
||||
|
||||
<Grid x:Name="graph" Background="{Binding ElementName=userControl, Path=Background}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition x:Name="topRowDefinition"/>
|
||||
<RowDefinition x:Name="upBarRowDefinition"/>
|
||||
<RowDefinition x:Name="downBarRowDefinition"/>
|
||||
<RowDefinition x:Name="bottomRowDefinition"/>
|
||||
</Grid.RowDefinitions>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,106 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Windows.UI;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
||||
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace IntelligentKioskSample.Controls
|
||||
{
|
||||
public sealed partial class UpDownVerticalBarControl : UserControl
|
||||
{
|
||||
static SolidColorBrush BackgroundColor = new SolidColorBrush(Colors.Transparent);
|
||||
|
||||
public UpDownVerticalBarControl()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
public void DrawDataPoint(double value, Brush barColor, Image toolTip = null)
|
||||
{
|
||||
if (value > 0)
|
||||
{
|
||||
value *= 0.5;
|
||||
topRowDefinition.Height = new GridLength(0.5 - value, GridUnitType.Star);
|
||||
upBarRowDefinition.Height = new GridLength(value, GridUnitType.Star);
|
||||
downBarRowDefinition.Height = new GridLength(0);
|
||||
bottomRowDefinition.Height = new GridLength(0.5, GridUnitType.Star);
|
||||
}
|
||||
else
|
||||
{
|
||||
value *= -0.5;
|
||||
topRowDefinition.Height = new GridLength(0.5, GridUnitType.Star);
|
||||
upBarRowDefinition.Height = new GridLength(0);
|
||||
downBarRowDefinition.Height = new GridLength(value, GridUnitType.Star);
|
||||
bottomRowDefinition.Height = new GridLength(0.5 - value, GridUnitType.Star);
|
||||
}
|
||||
|
||||
Border slice = new Border { Background = BackgroundColor };
|
||||
Grid.SetRow(slice, 0);
|
||||
graph.Children.Add(slice);
|
||||
|
||||
slice = new Border { Background = barColor };
|
||||
Grid.SetRow(slice, 1);
|
||||
graph.Children.Add(slice);
|
||||
|
||||
slice = new Border { Background = barColor };
|
||||
Grid.SetRow(slice, 2);
|
||||
graph.Children.Add(slice);
|
||||
|
||||
slice = new Border { Background = BackgroundColor };
|
||||
Grid.SetRow(slice, 3);
|
||||
graph.Children.Add(slice);
|
||||
|
||||
AddFlyoutToElement(graph, toolTip);
|
||||
}
|
||||
|
||||
private void AddFlyoutToElement(FrameworkElement element, Image toolTip)
|
||||
{
|
||||
if (toolTip != null)
|
||||
{
|
||||
FlyoutBase.SetAttachedFlyout(element, new Flyout { Content = toolTip });
|
||||
|
||||
element.PointerReleased += (s, e) =>
|
||||
{
|
||||
FlyoutBase.ShowAttachedFlyout(element);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="apiKey" value="Replace with your API key from PBI1" />
|
||||
</appSettings>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
|
@ -0,0 +1,79 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{688FD938-16ED-4EBB-A0E3-0801D9461823}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>EmotionAPI_Test</RootNamespace>
|
||||
<AssemblyName>EmotionAPI_Test</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.ProjectOxford.Common, Version=1.0.324.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ProjectOxford.Common.1.0.324\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Microsoft.ProjectOxford.Common.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.ProjectOxford.Emotion, Version=1.0.336.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ProjectOxford.Emotion.1.0.336\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Microsoft.ProjectOxford.Emotion.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.WebRequest" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
|
||||
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
|
||||
<Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
|
||||
</Target>
|
||||
</Project>
|
|
@ -0,0 +1,150 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.ProjectOxford.Emotion;
|
||||
using Microsoft.ProjectOxford.Common.Contract;
|
||||
|
||||
namespace EmotionAPI_Test
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
static string _apiKey;
|
||||
static string ApiKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (String.IsNullOrEmpty(_apiKey))
|
||||
_apiKey = ConfigurationManager.AppSettings["apiKey"];
|
||||
return _apiKey;
|
||||
}
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// Get the image path
|
||||
Console.WriteLine("JPEG image file path:");
|
||||
string imageFilePath = Console.ReadLine();
|
||||
|
||||
// Make the Emotion API call
|
||||
CallEmotionAPI(imageFilePath);
|
||||
|
||||
// Make the Emotion API call by using Project Oxford Libraries
|
||||
CallProjectOxford(imageFilePath);
|
||||
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the image from the passed Path and return it as a byte Array
|
||||
/// </summary>
|
||||
/// <param name="imageFilePath"></param>
|
||||
/// <returns></returns>
|
||||
static byte[] GetImageAsByteArray(string imageFilePath)
|
||||
{
|
||||
using (FileStream stream = new FileStream(imageFilePath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
using (BinaryReader reader = new BinaryReader(stream))
|
||||
{
|
||||
return reader.ReadBytes((int)stream.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static async void CallEmotionAPI(string imageFilePath)
|
||||
{
|
||||
// Declare a new HttpClient to communicate with the Emotion API
|
||||
HttpClient client = new HttpClient();
|
||||
|
||||
// Add the API Key to the request headers
|
||||
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", ApiKey);
|
||||
|
||||
// This url will have to match the region where the cognitive services API was created
|
||||
string url = "https://westus.api.cognitive.microsoft.com/emotion/v1.0/recognize?";
|
||||
|
||||
// Get the image as a byte array
|
||||
byte[] byteData = GetImageAsByteArray(imageFilePath);
|
||||
|
||||
HttpResponseMessage JsonResponse;
|
||||
string responseContent;
|
||||
|
||||
// Prepare the image and the request to query the Emotion API
|
||||
using (ByteArrayContent imageBytes = new ByteArrayContent(byteData))
|
||||
{
|
||||
// Add the proper media type
|
||||
imageBytes.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
|
||||
// Call the emotion API by using the URL and the image content so it can analyze our image
|
||||
JsonResponse = await client.PostAsync(url, imageBytes);
|
||||
|
||||
// Store the Emotion API result, this will be a JSON string that will contain the
|
||||
// identified face (A rectangle surrounding the face) and a emotion score array
|
||||
responseContent = JsonResponse.Content.ReadAsStringAsync().Result;
|
||||
}
|
||||
|
||||
// Show the raw JSON string
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("JSON Response:");
|
||||
Console.WriteLine(responseContent);
|
||||
|
||||
// Use the JSON result string and get the first and second array (face rectangle and emotion score)
|
||||
JToken root = JArray.Parse(responseContent).First;
|
||||
JToken faceDimension = root.First();
|
||||
JToken scores = root.Last();
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Face Rectangle");
|
||||
|
||||
// Navigate through each face rectangle coordinate
|
||||
foreach (JToken size in faceDimension.First.Children())
|
||||
{
|
||||
Console.WriteLine(size);
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Emotion Score");
|
||||
|
||||
// Navigate through each emotion
|
||||
foreach (JToken score in scores.First.Children())
|
||||
{
|
||||
Console.WriteLine(score);
|
||||
}
|
||||
}
|
||||
|
||||
static async void CallProjectOxford(string imageFilePath)
|
||||
{
|
||||
// Declare an EmotionServiceClient object, we will use this object to communicate with our Emotion API
|
||||
EmotionServiceClient client = new EmotionServiceClient(ApiKey);
|
||||
|
||||
// Convert the Image file to a MemoryStream
|
||||
MemoryStream mem = new MemoryStream(GetImageAsByteArray(imageFilePath));
|
||||
// Store the result in an emotion list
|
||||
// With this 3 lines we already make all the communications with the API and store the result
|
||||
// ProjectOxford libraries help us to work easier with cognitive services APIs.
|
||||
IEnumerable<Emotion> emotionList = await client.RecognizeAsync(mem);
|
||||
|
||||
// Print all the dimensions and emotion scores
|
||||
foreach (Emotion emotion in emotionList)
|
||||
{
|
||||
Console.WriteLine("Face");
|
||||
Console.WriteLine($"Top: {emotion.FaceRectangle.Top.ToString()}, Width: {emotion.FaceRectangle.Width.ToString()}" +
|
||||
$"Left: {emotion.FaceRectangle.Left.ToString()}, Height: {emotion.FaceRectangle.Height.ToString()}");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("Emotion");
|
||||
Console.WriteLine($"Anger: {emotion.Scores.Anger.ToString()}," +
|
||||
$"Contempt: {emotion.Scores.Contempt.ToString()}," +
|
||||
$"Disgust: {emotion.Scores.Disgust.ToString()}," +
|
||||
$"Fear: {emotion.Scores.Fear.ToString()}," +
|
||||
$"Happiness: {emotion.Scores.Happiness.ToString()}," +
|
||||
$"Neutral: {emotion.Scores.Neutral.ToString()}," +
|
||||
$"Sadness: {emotion.Scores.Sadness.ToString()}," +
|
||||
$"Surprise: {emotion.Scores.Surprise.ToString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("EmotionAPI_Test")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("EmotionAPI_Test")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("688fd938-16ed-4ebb-a0e3-0801d9461823")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net461" />
|
||||
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net461" />
|
||||
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net461" />
|
||||
<package id="Microsoft.ProjectOxford.Common" version="1.0.324" targetFramework="net461" />
|
||||
<package id="Microsoft.ProjectOxford.Emotion" version="1.0.336" targetFramework="net461" />
|
||||
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
|
||||
</packages>
|
|
@ -0,0 +1,256 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<ProjectGuid>{B08D337A-AF9F-4705-B8C1-C7F07FACD8C5}</ProjectGuid>
|
||||
<OutputType>AppContainerExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>IntelligentKioskSample</RootNamespace>
|
||||
<AssemblyName>IntelligentKioskSample</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.10240.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
|
||||
<AppxBundle>Always</AppxBundle>
|
||||
<AppxBundlePlatforms>x86|x64|arm</AppxBundlePlatforms>
|
||||
<PackageCertificateThumbprint>AFA97E8E34493A24325844C55BC66D56D9F3595C</PackageCertificateThumbprint>
|
||||
<PackageCertificateKeyFile>IntelligentKioskSample_TemporaryKey.pfx</PackageCertificateKeyFile>
|
||||
<ApplicationInsightsResourceId />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\ARM\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
|
||||
<OutputPath>bin\ARM\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="IntelligentKioskSample_TemporaryKey.pfx" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="project.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\FaceIdentificationBorder.xaml.cs">
|
||||
<DependentUpon>FaceIdentificationBorder.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\UpDownVerticalBarControl.xaml.cs">
|
||||
<DependentUpon>UpDownVerticalBarControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\EmotionEmojiControl.xaml.cs">
|
||||
<DependentUpon>EmotionEmojiControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\CameraControl.xaml.cs">
|
||||
<DependentUpon>CameraControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\RealTimeFaceIdentificationBorder.xaml.cs">
|
||||
<DependentUpon>RealTimeFaceIdentificationBorder.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\EmotionMeterControl.xaml.cs">
|
||||
<DependentUpon>EmotionMeterControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ImageWithFaceBorderUserControl.xaml.cs">
|
||||
<DependentUpon>ImageWithFaceBorderUserControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\NavMenuListView.cs" />
|
||||
<Compile Include="Controls\PageHeader.xaml.cs">
|
||||
<DependentUpon>PageHeader.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="NavMenuItem.cs" />
|
||||
<Compile Include="SettingsHelper.cs" />
|
||||
<Compile Include="Util.cs" />
|
||||
<Compile Include="Views\EmotionRecognitionPage.xaml.cs">
|
||||
<DependentUpon>EmotionRecognitionPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\SettingsPage.xaml.cs">
|
||||
<DependentUpon>SettingsPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="AppShell.xaml.cs">
|
||||
<DependentUpon>AppShell.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</AppxManifest>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\BingNewsAnalytics.png" />
|
||||
<Content Include="Assets\BingVisualSearch.jpg" />
|
||||
<Content Include="Assets\camera.png" />
|
||||
<Content Include="Assets\CustomVisionExplorer.png" />
|
||||
<Content Include="Assets\female.png" />
|
||||
<Content Include="Assets\GreetingKiosk.JPG" />
|
||||
<Content Include="Assets\ImageCollectionInsights.JPG" />
|
||||
<Content Include="Assets\male_blue.png" />
|
||||
<Content Include="Assets\EmotionRecognition.PNG" />
|
||||
<Content Include="Assets\FaceAPI.PNG" />
|
||||
<Content Include="Assets\male.png" />
|
||||
<Content Include="Assets\Mall.png" />
|
||||
<Content Include="Assets\new-splash-sdk - Copy.png" />
|
||||
<Content Include="Assets\new-splash-sdk.png" />
|
||||
<Content Include="Assets\oxford-face.png" />
|
||||
<Content Include="Assets\RealTime.PNG" />
|
||||
<Content Include="Assets\RealtimeDriverMonitoring.jpg" />
|
||||
<Content Include="Assets\RealTimeFromVideo.PNG" />
|
||||
<Content Include="Assets\smalltile-sdk.png" />
|
||||
<Content Include="Assets\splash-sdk - Copy.png" />
|
||||
<Content Include="Assets\splash-sdk.png" />
|
||||
<Content Include="Assets\splash-sdk.scale-100.png" />
|
||||
<Content Include="Assets\StoreLogo.png" />
|
||||
<Content Include="Assets\squaretile-sdk.png" />
|
||||
<Content Include="Assets\squaretile-sdk-44.png" />
|
||||
<Content Include="Assets\VisionAPI.jpg" />
|
||||
<Content Include="Properties\Default.rd.xml">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Assets\StoreLogo.scale-10.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Page Include="Controls\FaceIdentificationBorder.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\CameraControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\UpDownVerticalBarControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Controls\RealTimeFaceIdentificationBorder.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Controls\EmotionMeterControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Controls\ImageWithFaceBorderUserControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\PageHeader.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\EmotionEmojiControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Styles\Styles.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Page>
|
||||
<Page Include="Views\EmotionRecognitionPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Views\SettingsPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="AppShell.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="ServiceHelpers\ServiceHelpers.csproj">
|
||||
<Project>{5d9320af-a9e4-48e3-89bc-9f7f0954b298}</Project>
|
||||
<Name>ServiceHelpers</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,106 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.Graphics.DirectX.Direct3D11;
|
||||
using Windows.Graphics.Imaging;
|
||||
using Windows.Media.Effects;
|
||||
using Windows.Media.MediaProperties;
|
||||
|
||||
namespace KioskRuntimeComponent
|
||||
{
|
||||
public sealed class FrameRelayVideoEffect : IBasicVideoEffect
|
||||
{
|
||||
public static SoftwareBitmap LatestSoftwareBitmap { get; private set; }
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyList<VideoEncodingProperties> SupportedEncodingProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<VideoEncodingProperties>();
|
||||
}
|
||||
}
|
||||
|
||||
public MediaMemoryTypes SupportedMemoryTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return MediaMemoryTypes.Cpu;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TimeIndependent
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Close(MediaEffectClosedReason reason)
|
||||
{
|
||||
}
|
||||
|
||||
public void DiscardQueuedFrames()
|
||||
{
|
||||
LatestSoftwareBitmap = null;
|
||||
}
|
||||
|
||||
public static void ResetState()
|
||||
{
|
||||
LatestSoftwareBitmap = null;
|
||||
}
|
||||
|
||||
public void ProcessFrame(ProcessVideoFrameContext context)
|
||||
{
|
||||
LatestSoftwareBitmap = context.InputFrame.SoftwareBitmap;
|
||||
}
|
||||
|
||||
public void SetEncodingProperties(VideoEncodingProperties encodingProperties, IDirect3DDevice device)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetProperties(IPropertySet configuration)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{FC5A0250-B742-40A8-82CA-BEC2DF66982F}</ProjectGuid>
|
||||
<OutputType>winmdobj</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>KioskRuntimeComponent</RootNamespace>
|
||||
<AssemblyName>KioskRuntimeComponent</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.10240.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<AllowCrossPlatformRetargeting>false</AllowCrossPlatformRetargeting>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\ARM\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<OutputPath>bin\ARM\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
|
||||
<None Include="project.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="FrameRelayVideoEffect.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("KioskRuntimeComponent")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("KioskRuntimeComponent")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: ComVisible(false)]
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.UniversalWindowsPlatform": "5.1.0"
|
||||
},
|
||||
"frameworks": {
|
||||
"uap10.0": {}
|
||||
},
|
||||
"runtimes": {
|
||||
"win10-arm": {},
|
||||
"win10-arm-aot": {},
|
||||
"win10-x86": {},
|
||||
"win10-x86-aot": {},
|
||||
"win10-x64": {},
|
||||
"win10-x64-aot": {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace IntelligentKioskSample
|
||||
{
|
||||
/// <summary>
|
||||
/// Data to represent an item in the nav menu.
|
||||
/// </summary>
|
||||
public class NavMenuItem
|
||||
{
|
||||
public string Label { get; set; }
|
||||
public Symbol Symbol { get; set; }
|
||||
public char SymbolAsChar
|
||||
{
|
||||
get
|
||||
{
|
||||
return (char)this.Symbol;
|
||||
}
|
||||
}
|
||||
|
||||
public Type DestPage { get; set; }
|
||||
public object Arguments { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp">
|
||||
<Identity Name="IntelligentKioskSample" Publisher="CN=Kiosk" Version="1.0.0.0" />
|
||||
<mp:PhoneIdentity PhoneProductId="bdf9127b-7e32-469b-a6ed-f57a0a80ae23" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
|
||||
<Properties>
|
||||
<DisplayName>Intelligent Kiosk Sample</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.10240.0" MaxVersionTested="10.0.10240.0" />
|
||||
</Dependencies>
|
||||
<Resources>
|
||||
<Resource Language="x-generate" />
|
||||
</Resources>
|
||||
<Applications>
|
||||
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="IntelligentKioskSample.App">
|
||||
<uap:VisualElements DisplayName="Alpine Ski House Happiness Meter" Square44x44Logo="Assets\squaretile-sdk-44.png" Square150x150Logo="Assets\squaretile-sdk.png" Description="Alpine Ski House Happiness Meter" BackgroundColor="#00B2F0">
|
||||
<uap:SplashScreen Image="Assets\splash-sdk.png" BackgroundColor="#00B2F0" />
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<uap:Capability Name="picturesLibrary" />
|
||||
<DeviceCapability Name="webcam" />
|
||||
<DeviceCapability Name="microphone" />
|
||||
</Capabilities>
|
||||
</Package>
|
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("IntelligentKioskSample")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("IntelligentKioskSample")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2015")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: ComVisible(false)]
|
|
@ -0,0 +1,31 @@
|
|||
<!--
|
||||
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
|
||||
developers. However, you can modify these parameters to modify the behavior of the .NET Native
|
||||
optimizer.
|
||||
|
||||
Runtime Directives are documented at http://go.microsoft.com/fwlink/?LinkID=391919
|
||||
|
||||
To fully enable reflection for App1.MyClass and all of its public/private members
|
||||
<Type Name="App1.MyClass" Dynamic="Required All"/>
|
||||
|
||||
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
|
||||
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
|
||||
|
||||
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
|
||||
<Namespace Name="DataClasses.ViewModels" Seralize="All" />
|
||||
-->
|
||||
|
||||
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
|
||||
<Application>
|
||||
<!--
|
||||
An Assembly element with Name="*Application*" applies to all assemblies in
|
||||
the application package. The asterisks are not wildcards.
|
||||
-->
|
||||
<Assembly Name="*Application*" Dynamic="Required All" />
|
||||
|
||||
|
||||
<!-- Add your application specific runtime directives here. -->
|
||||
|
||||
|
||||
</Application>
|
||||
</Directives>
|
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using Microsoft.ProjectOxford.Common;
|
||||
using Microsoft.ProjectOxford.Face.Contract;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ServiceHelpers
|
||||
{
|
||||
public class CoreUtil
|
||||
{
|
||||
public static uint MinDetectableFaceCoveragePercentage = 0;
|
||||
|
||||
public static bool IsFaceBigEnoughForDetection(int faceHeight, int imageHeight)
|
||||
{
|
||||
if (imageHeight == 0)
|
||||
{
|
||||
// sometimes we don't know the size of the image, so we assume the face is big enough
|
||||
return true;
|
||||
}
|
||||
|
||||
double faceHeightPercentage = 100 * ((double)faceHeight / imageHeight);
|
||||
|
||||
return faceHeightPercentage >= MinDetectableFaceCoveragePercentage;
|
||||
}
|
||||
|
||||
public static bool AreFacesPotentiallyTheSame(Rectangle face1, FaceRectangle face2)
|
||||
{
|
||||
return AreFacesPotentiallyTheSame((int)face1.Left, (int)face1.Top, (int)face1.Width, (int)face1.Height, face2.Left, face2.Top, face2.Width, face2.Height);
|
||||
}
|
||||
|
||||
public static bool AreFacesPotentiallyTheSame(int face1X, int face1Y, int face1Width, int face1Height,
|
||||
int face2X, int face2Y, int face2Width, int face2Height)
|
||||
{
|
||||
double distanceThresholdFactor = 1;
|
||||
double sizeThresholdFactor = 0.5;
|
||||
|
||||
// See if faces are close enough from each other to be considered the "same"
|
||||
if (Math.Abs(face1X - face2X) <= face1Width * distanceThresholdFactor &&
|
||||
Math.Abs(face1Y - face2Y) <= face1Height * distanceThresholdFactor)
|
||||
{
|
||||
// See if faces are shaped similarly enough to be considered the "same"
|
||||
if (Math.Abs(face1Width - face2Width) <= face1Width * sizeThresholdFactor &&
|
||||
Math.Abs(face1Height - face2Height) <= face1Height * sizeThresholdFactor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServiceHelpers
|
||||
{
|
||||
public class EmotionData
|
||||
{
|
||||
public string EmotionName { get; set; }
|
||||
public float EmotionScore { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using Microsoft.ProjectOxford.Common;
|
||||
using Microsoft.ProjectOxford.Common.Contract;
|
||||
using Microsoft.ProjectOxford.Emotion;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServiceHelpers
|
||||
{
|
||||
public static class EmotionServiceHelper
|
||||
{
|
||||
#region Fill Properties
|
||||
|
||||
#endregion
|
||||
|
||||
public static int RetryCountOnQuotaLimitError = 6;
|
||||
public static int RetryDelayOnQuotaLimitError = 500;
|
||||
|
||||
//Implement : You should declare a property, Task 4, Step 1
|
||||
private static EmotionServiceClient emotionClient { get; set; }
|
||||
|
||||
static EmotionServiceHelper()
|
||||
{
|
||||
InitializeEmotionService();
|
||||
}
|
||||
|
||||
public static Action Throttled;
|
||||
|
||||
// Implement: PBI 2, Task 3, Step 2
|
||||
// Create an ApiKey property
|
||||
private static string apiKey;
|
||||
public static string ApiKey
|
||||
{
|
||||
get { return apiKey; }
|
||||
set
|
||||
{
|
||||
var changed = apiKey != value;
|
||||
apiKey = value;
|
||||
if (changed)
|
||||
{
|
||||
InitializeEmotionService();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitializeEmotionService()
|
||||
{
|
||||
// Implement: PBI 2, Task 3, Step 3
|
||||
// Instatiate the EmotionServiceClient object and pass the API key to it so we can communicate with the emotion API.
|
||||
emotionClient = new EmotionServiceClient(ApiKey);
|
||||
}
|
||||
|
||||
private static async Task<TResponse> RunTaskWithAutoRetryOnQuotaLimitExceededError<TResponse>(Func<Task<TResponse>> action)
|
||||
{
|
||||
// Optional Task, Implement: PBI 2, Task 3, Step 5
|
||||
int retriesLeft = 6;
|
||||
int delay = 500;
|
||||
|
||||
TResponse response = default(TResponse);
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
response = await action();
|
||||
break;
|
||||
}
|
||||
catch (ClientException exception) when (exception.HttpStatus == (System.Net.HttpStatusCode)429 && retriesLeft > 0)
|
||||
{
|
||||
ErrorTrackingHelper.TrackException(exception, "Emotion API throttling error");
|
||||
if (retriesLeft == 1 && Throttled != null)
|
||||
{
|
||||
Throttled();
|
||||
}
|
||||
|
||||
await Task.Delay(delay);
|
||||
retriesLeft--;
|
||||
delay *= 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public static async Task<Emotion[]> RecognizeAsync(Func<Task<Stream>> imageStreamCallback)
|
||||
{
|
||||
// Implement: PBI 2, Task 3, Step 5
|
||||
// You should make a call to the EmotionServiceClient object that support a Stream as parameter to identify emotions
|
||||
return await RunTaskWithAutoRetryOnQuotaLimitExceededError<Emotion[]>(async () => await emotionClient.RecognizeAsync(await imageStreamCallback()));
|
||||
}
|
||||
|
||||
public static async Task<Emotion[]> RecognizeAsync(string url)
|
||||
{
|
||||
// Implement: PBI 2, Task 3, Step 5
|
||||
// You should make a call to the EmotionServiceClient object that support an URL as parameter to identify emotions
|
||||
return await RunTaskWithAutoRetryOnQuotaLimitExceededError<Emotion[]>(async () => await emotionClient.RecognizeAsync(url));
|
||||
}
|
||||
|
||||
public static IEnumerable<EmotionData> ScoresToEmotionData(EmotionScores scores)
|
||||
{
|
||||
// Implement: PBI 2, Task 3, Step 4
|
||||
// Create a list of emotions and emotion scores to return as a results.
|
||||
// Use the JSON object result of the EmotionAPI_Test project to undestand how to build this list.
|
||||
List<EmotionData> result = new List<EmotionData>();
|
||||
result.Add(new EmotionData { EmotionName = "Anger", EmotionScore = scores.Anger });
|
||||
result.Add(new EmotionData { EmotionName = "Contempt", EmotionScore = scores.Contempt });
|
||||
result.Add(new EmotionData { EmotionName = "Disgust", EmotionScore = scores.Disgust });
|
||||
result.Add(new EmotionData { EmotionName = "Fear", EmotionScore = scores.Fear });
|
||||
result.Add(new EmotionData { EmotionName = "Happiness", EmotionScore = scores.Happiness });
|
||||
result.Add(new EmotionData { EmotionName = "Neutral", EmotionScore = scores.Neutral });
|
||||
result.Add(new EmotionData { EmotionName = "Sadness", EmotionScore = scores.Sadness });
|
||||
result.Add(new EmotionData { EmotionName = "Surprise", EmotionScore = scores.Surprise });
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServiceHelpers
|
||||
{
|
||||
public static class ErrorTrackingHelper
|
||||
{
|
||||
// callbacks for exception tracking
|
||||
public static Action<Exception, string> TrackException { get; set; }
|
||||
= (exception, message) => { };
|
||||
|
||||
// callbacks for blocking UI error message
|
||||
public static Func<Exception, string, Task> GenericApiCallExceptionHandler { get; set; }
|
||||
= (ex, errorTitle) => Task.FromResult(0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using Microsoft.ProjectOxford.Common.Contract;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServiceHelpers
|
||||
{
|
||||
public class ImageAnalyzer
|
||||
{
|
||||
public event EventHandler EmotionRecognitionCompleted;
|
||||
|
||||
public Func<Task<Stream>> GetImageStreamCallback { get; set; }
|
||||
public string ImageUrl { get; set; }
|
||||
|
||||
//Implement : You should declare a property, Task 4, Step 1
|
||||
public IEnumerable<Emotion> DetectedEmotion { get; set; }
|
||||
|
||||
|
||||
// Default to no errors, since this could trigger a stream of popup errors since we might call this
|
||||
// for several images at once while auto-detecting the Bing Image Search results.
|
||||
public bool ShowDialogOnFaceApiErrors { get; set; } = false;
|
||||
public bool FilterOutSmallFaces { get; set; } = false;
|
||||
public int DecodedImageHeight { get; private set; }
|
||||
public int DecodedImageWidth { get; private set; }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public ImageAnalyzer(string url)
|
||||
{
|
||||
this.ImageUrl = url;
|
||||
}
|
||||
|
||||
public ImageAnalyzer(byte[] data)
|
||||
{
|
||||
this.Data = data;
|
||||
this.GetImageStreamCallback = () => Task.FromResult<Stream>(new MemoryStream(this.Data));
|
||||
}
|
||||
|
||||
public void UpdateDecodedImageSize(int height, int width)
|
||||
{
|
||||
this.DecodedImageHeight = height;
|
||||
this.DecodedImageWidth = width;
|
||||
}
|
||||
|
||||
public async Task DetectEmotionAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Implement #1: If there is ImageUrl you should call the proper EmotionServiceHelper method to detect emotions
|
||||
if (this.ImageUrl != null)
|
||||
{
|
||||
this.DetectedEmotion = await EmotionServiceHelper.RecognizeAsync(this.ImageUrl);
|
||||
}
|
||||
// Implement #2: If GetImageStreamCallback is not null, you should call the proper EmotionServiceHelper method to detect emotions
|
||||
else if (this.GetImageStreamCallback != null)
|
||||
{
|
||||
this.DetectedEmotion = await EmotionServiceHelper.RecognizeAsync(this.GetImageStreamCallback);
|
||||
}
|
||||
|
||||
// Implement #3: If FilterOutSmallFaces is enabled, filter the DetectedEmotion using the CoreUtil IsFaceBigEnoughForDetection method results
|
||||
if (this.FilterOutSmallFaces)
|
||||
{
|
||||
this.DetectedEmotion = this.DetectedEmotion.Where(f => CoreUtil.IsFaceBigEnoughForDetection(f.FaceRectangle.Height, this.DecodedImageHeight));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Implement #4: If there is an error, call the ErrorTrackingHelper helper class to record the issue.
|
||||
// and return an empty emotion list
|
||||
ErrorTrackingHelper.TrackException(e, "Emotion API RecognizeAsync error");
|
||||
|
||||
this.DetectedEmotion = Enumerable.Empty<Emotion>();
|
||||
|
||||
if (this.ShowDialogOnFaceApiErrors)
|
||||
{
|
||||
await ErrorTrackingHelper.GenericApiCallExceptionHandler(e, "Emotion detection failed.");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Implement #5: Call the event OnEmotionRecognitionCompleted
|
||||
this.OnEmotionRecognitionCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEmotionRecognitionCompleted()
|
||||
{
|
||||
if (this.EmotionRecognitionCompleted != null)
|
||||
{
|
||||
this.EmotionRecognitionCompleted(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System.Resources;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("ServiceHelpers")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("ServiceHelpers")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{5D9320AF-A9E4-48E3-89BC-9F7F0954B298}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ServiceHelpers</RootNamespace>
|
||||
<AssemblyName>ServiceHelpers</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CoreUtil.cs" />
|
||||
<Compile Include="EmotionData.cs" />
|
||||
<Compile Include="EmotionServiceHelper.cs" />
|
||||
<Compile Include="ErrorTrackingHelper.cs" />
|
||||
<Compile Include="ImageAnalyzer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.ProjectOxford.Common, Version=1.0.324.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ProjectOxford.Common.1.0.324\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Microsoft.ProjectOxford.Common.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.ProjectOxford.Emotion, Version=1.0.336.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ProjectOxford.Emotion.1.0.336\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Microsoft.ProjectOxford.Emotion.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.ProjectOxford.Face, Version=1.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.ProjectOxford.Face.1.2.5\lib\portable-net45+wp80+win8+wpa81+aspnetcore50\Microsoft.ProjectOxford.Face.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\portable-net45+wp80+win8+wpa81\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\portable-net45+win8\System.Net.Http.Extensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\portable-net45+win8\System.Net.Http.Primitives.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
|
||||
</Target>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.ProjectOxford.Common" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.0.324.0" newVersion="1.0.324.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="portable45-net45+win8" />
|
||||
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="portable45-net45+win8" />
|
||||
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="portable45-net45+win8" />
|
||||
<package id="Microsoft.ProjectOxford.Common" version="1.0.324" targetFramework="portable45-net45+win8" />
|
||||
<package id="Microsoft.ProjectOxford.Emotion" version="1.0.341" targetFramework="portable45-net45+win8" />
|
||||
<package id="Microsoft.ProjectOxford.Face" version="1.3.0" targetFramework="portable45-net45+win8" />
|
||||
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="portable45-net45+win8" />
|
||||
</packages>
|
|
@ -0,0 +1,197 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using IntelligentKioskSample.Views;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace IntelligentKioskSample
|
||||
{
|
||||
internal class SettingsHelper : INotifyPropertyChanged
|
||||
{
|
||||
public event EventHandler SettingsChanged;
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private static SettingsHelper instance;
|
||||
|
||||
static SettingsHelper()
|
||||
{
|
||||
instance = new SettingsHelper();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
LoadRoamingSettings();
|
||||
Windows.Storage.ApplicationData.Current.DataChanged += RoamingDataChanged;
|
||||
}
|
||||
|
||||
private void RoamingDataChanged(ApplicationData sender, object args)
|
||||
{
|
||||
LoadRoamingSettings();
|
||||
instance.OnSettingsChanged();
|
||||
}
|
||||
|
||||
private void OnSettingsChanged()
|
||||
{
|
||||
if (instance.SettingsChanged != null)
|
||||
{
|
||||
instance.SettingsChanged(instance, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnSettingChanged(string propertyName, object value)
|
||||
{
|
||||
if (propertyName == "MallKioskDemoCustomSettings")
|
||||
{
|
||||
// save to file as the content is too big to be saved as a string-like setting
|
||||
StorageFile file = await ApplicationData.Current.RoamingFolder.CreateFileAsync(
|
||||
"MallKioskDemoCustomSettings.xml",
|
||||
CreationCollisionOption.ReplaceExisting);
|
||||
|
||||
using (Stream stream = await file.OpenStreamForWriteAsync())
|
||||
{
|
||||
using (StreamWriter writer = new StreamWriter(stream))
|
||||
{
|
||||
await writer.WriteAsync(value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplicationData.Current.RoamingSettings.Values[propertyName] = value;
|
||||
}
|
||||
|
||||
instance.OnSettingsChanged();
|
||||
instance.OnPropertyChanged(propertyName);
|
||||
}
|
||||
|
||||
private void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
if (instance.PropertyChanged != null)
|
||||
{
|
||||
instance.PropertyChanged(instance, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
public static SettingsHelper Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
private async void LoadRoamingSettings()
|
||||
{
|
||||
object value;
|
||||
|
||||
value = ApplicationData.Current.RoamingSettings.Values["EmotionApiKey"];
|
||||
if (value != null)
|
||||
{
|
||||
this.EmotionApiKey = value.ToString();
|
||||
}
|
||||
|
||||
value = ApplicationData.Current.RoamingSettings.Values["CameraName"];
|
||||
if (value != null)
|
||||
{
|
||||
this.CameraName = value.ToString();
|
||||
}
|
||||
|
||||
value = ApplicationData.Current.RoamingSettings.Values["MinDetectableFaceCoveragePercentage"];
|
||||
if (value != null)
|
||||
{
|
||||
uint size;
|
||||
if (uint.TryParse(value.ToString(), out size))
|
||||
{
|
||||
this.MinDetectableFaceCoveragePercentage = size;
|
||||
}
|
||||
}
|
||||
|
||||
value = ApplicationData.Current.RoamingSettings.Values["ShowDebugInfo"];
|
||||
if (value != null)
|
||||
{
|
||||
bool booleanValue;
|
||||
if (bool.TryParse(value.ToString(), out booleanValue))
|
||||
{
|
||||
this.ShowDebugInfo = booleanValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string emotionApiKey = string.Empty;
|
||||
public string EmotionApiKey
|
||||
{
|
||||
get { return this.emotionApiKey; }
|
||||
set
|
||||
{
|
||||
this.emotionApiKey = value;
|
||||
this.OnSettingChanged("EmotionApiKey", value);
|
||||
}
|
||||
}
|
||||
|
||||
private string cameraName = string.Empty;
|
||||
public string CameraName
|
||||
{
|
||||
get { return cameraName; }
|
||||
set
|
||||
{
|
||||
this.cameraName = value;
|
||||
this.OnSettingChanged("CameraName", value);
|
||||
}
|
||||
}
|
||||
|
||||
private uint minDetectableFaceCoveragePercentage = 7;
|
||||
public uint MinDetectableFaceCoveragePercentage
|
||||
{
|
||||
get { return this.minDetectableFaceCoveragePercentage; }
|
||||
set
|
||||
{
|
||||
this.minDetectableFaceCoveragePercentage = value;
|
||||
this.OnSettingChanged("MinDetectableFaceCoveragePercentage", value);
|
||||
}
|
||||
}
|
||||
|
||||
private bool showDebugInfo = false;
|
||||
public bool ShowDebugInfo
|
||||
{
|
||||
get { return showDebugInfo; }
|
||||
set
|
||||
{
|
||||
this.showDebugInfo = value;
|
||||
this.OnSettingChanged("ShowDebugInfo", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:IntelligentKioskSample">
|
||||
|
||||
<Style x:Key="SplitViewTogglePaneButtonStyle" TargetType="ToggleButton">
|
||||
<Setter Property="FontSize" Value="20" />
|
||||
<Setter Property="FontFamily" Value="{ThemeResource SymbolThemeFontFamily}" />
|
||||
<Setter Property="MinHeight" Value="48" />
|
||||
<Setter Property="MinWidth" Value="48" />
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
<Setter Property="VerticalAlignment" Value="Top" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}" />
|
||||
<Setter Property="Content" Value="" />
|
||||
<Setter Property="AutomationProperties.Name" Value="Menu" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="True"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ToggleButton">
|
||||
<Grid Background="{TemplateBinding Background}" x:Name="LayoutRoot">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Grid.Background)">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Grid.Background)">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListMediumBrush}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Disabled">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="(TextBlock.Foreground)">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Checked"/>
|
||||
<VisualState x:Name="CheckedPointerOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Grid.Background)">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="CheckedPressed">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Grid.Background)">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListMediumBrush}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="CheckedDisabled">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="(TextBlock.Foreground)">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<ContentPresenter x:Name="ContentPresenter"
|
||||
Content="{TemplateBinding Content}"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
AutomationProperties.AccessibilityView="Raw" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="PageTitleTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource BodyTextBlockStyle}">
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
<Setter Property="CharacterSpacing" Value="75"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="Margin" Value="12, 14, 12, 4"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="NavigationBackButtonStyle" TargetType="Button" BasedOn="{StaticResource NavigationBackButtonNormalStyle}">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="Height" Value="48"/>
|
||||
<Setter Property="Width" Value="NaN"/>
|
||||
<Setter Property="MinWidth" Value="48"/>
|
||||
<Setter Property="AutomationProperties.Name" Value="Back"/>
|
||||
<Setter Property="Content">
|
||||
<Setter.Value>
|
||||
<Grid x:Name="RootGrid">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="48" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<FontIcon x:Name="Glyph" Grid.Column="0" FontSize="16" Glyph="" MirroredWhenRightToLeft="True" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<TextBlock x:Name="Text" Grid.Column="1" Style="{ThemeResource BodyTextBlockStyle}" Text="Back" VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="NavMenuItemContainerStyle" TargetType="ListViewItem">
|
||||
<Setter Property="MinWidth" Value="{StaticResource SplitViewCompactPaneThemeLength}"/>
|
||||
<Setter Property="Height" Value="48"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
|
@ -0,0 +1,110 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using ServiceHelpers;
|
||||
using Microsoft.ProjectOxford.Face;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Devices.Enumeration;
|
||||
using Windows.Graphics.Display;
|
||||
using Windows.Graphics.Imaging;
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.Streams;
|
||||
using Windows.UI.Popups;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Microsoft.Rest;
|
||||
|
||||
namespace IntelligentKioskSample
|
||||
{
|
||||
internal static class Util
|
||||
{
|
||||
internal static async Task GenericApiCallExceptionHandler(Exception ex, string errorTitle)
|
||||
{
|
||||
string errorDetails = GetMessageFromException(ex);
|
||||
|
||||
await new MessageDialog(errorDetails, errorTitle).ShowAsync();
|
||||
}
|
||||
internal static string GetMessageFromException(Exception ex)
|
||||
{
|
||||
string errorDetails = ex.Message;
|
||||
|
||||
FaceAPIException faceApiException = ex as FaceAPIException;
|
||||
if (faceApiException?.ErrorMessage != null)
|
||||
{
|
||||
errorDetails = faceApiException.ErrorMessage;
|
||||
}
|
||||
|
||||
Microsoft.ProjectOxford.Common.ClientException commonException = ex as Microsoft.ProjectOxford.Common.ClientException;
|
||||
if (commonException?.Error?.Message != null)
|
||||
{
|
||||
errorDetails = commonException.Error.Message;
|
||||
}
|
||||
|
||||
HttpOperationException httpException = ex as HttpOperationException;
|
||||
if (httpException?.Response?.ReasonPhrase != null)
|
||||
{
|
||||
errorDetails = string.Format("{0}. The error message was \"{1}\".", ex.Message, httpException?.Response?.ReasonPhrase);
|
||||
}
|
||||
|
||||
return errorDetails;
|
||||
}
|
||||
public static async Task<IEnumerable<string>> GetAvailableCameraNamesAsync()
|
||||
{
|
||||
DeviceInformationCollection deviceInfo = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
|
||||
return deviceInfo.OrderBy(d => d.Name).Select(d => d.Name);
|
||||
}
|
||||
internal static async Task<byte[]> GetPixelBytesFromSoftwareBitmapAsync(SoftwareBitmap softwareBitmap)
|
||||
{
|
||||
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
|
||||
{
|
||||
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
|
||||
encoder.SetSoftwareBitmap(softwareBitmap);
|
||||
await encoder.FlushAsync();
|
||||
|
||||
// Read the pixel bytes from the memory stream
|
||||
using (var reader = new DataReader(stream.GetInputStreamAt(0)))
|
||||
{
|
||||
var bytes = new byte[stream.Size];
|
||||
await reader.LoadAsync((uint)stream.Size);
|
||||
reader.ReadBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<Page
|
||||
x:Class="IntelligentKioskSample.Views.EmotionRecognitionPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:IntelligentKioskSample.Views"
|
||||
xmlns:ctl="using:IntelligentKioskSample.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<CommandBar x:Name="commandBar" VerticalAlignment="Top" HorizontalContentAlignment="Stretch">
|
||||
|
||||
<CommandBar.Content>
|
||||
<ctl:PageHeader>
|
||||
<ctl:PageHeader.HeaderContent>
|
||||
<TextBlock Text="EMOTION API EXPLORER" Style="{ThemeResource PageTitleTextBlockStyle}" TextWrapping="NoWrap"/>
|
||||
</ctl:PageHeader.HeaderContent>
|
||||
</ctl:PageHeader>
|
||||
</CommandBar.Content>
|
||||
</CommandBar>
|
||||
|
||||
<Grid Grid.Row="1" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="0.3*"/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="0.3*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="0.1*"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="0.1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="1" Grid.Row="1" x:Name="TxtStatusDescription" Text="{StaticResource TextStatus_Hi}" FontSize="18" HorizontalAlignment="Center" Foreground="{StaticResource StatusTextBrush}" MinHeight="16" MinWidth="96" Width="256" ></TextBlock>
|
||||
|
||||
<Grid Grid.Row="2" Grid.Column="1" x:Name="webCamHostGrid" Visibility="Collapsed" >
|
||||
<!--HERE-->
|
||||
<ctl:ImageWithFaceBorderUserControl BalloonBackground="#ECCF11" BalloonForeground="#D86C2A" FlowDirection="RightToLeft" x:Name="imageFromCameraWithFaces" ShowEmotionRecognition="True" DetectFacesOnLoad="True" ShowMultipleFaces="True" ShowRecognitionResults="True"/>
|
||||
<ctl:CameraControl x:Name="cameraControl"
|
||||
EnableAutoCaptureMode="True"/>
|
||||
</Grid>
|
||||
|
||||
<ctl:ImageWithFaceBorderUserControl BalloonBackground="#ECCF11" BalloonForeground="#D86C2A" Grid.Row="1" Grid.Column="1" x:Name="imageWithFacesControl" ShowEmotionRecognition="True" DetectFacesOnLoad="True" ShowMultipleFaces="True" ShowRecognitionResults="True"/>
|
||||
|
||||
<ProgressRing Grid.Column="1" Grid.Row="3" x:Name="PrgRing1" Width="64" Height="64" />
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,147 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using ServiceHelpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
|
||||
|
||||
namespace IntelligentKioskSample.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class EmotionRecognitionPage : Page
|
||||
{
|
||||
public EmotionRecognitionPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
this.cameraControl.ImageCaptured += CameraControl_ImageCaptured;
|
||||
this.cameraControl.CameraRestarted += CameraControl_CameraRestarted;
|
||||
this.Loaded += EmotionRecognitionPage_Loaded;
|
||||
this.imageFromCameraWithFaces.EmotionDetected += ImageFromCameraWithFaces_EmotionDetected;
|
||||
}
|
||||
|
||||
private void ImageFromCameraWithFaces_EmotionDetected(object sender, EventArgs e)
|
||||
{
|
||||
// AFTER 10s RESET
|
||||
var delay = Task.Delay(10000).ContinueWith(async _ =>
|
||||
{
|
||||
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
//this.cameraControl.CameraControlButtonClick(this, new RoutedEventArgs());
|
||||
this.cameraControl.RestartAutoCaptureCycle();
|
||||
this.PrgRing1.IsActive = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void EmotionRecognitionPage_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
//this.cameraControl.RestartAutoCaptureCycle();
|
||||
this.cameraControl.AutoCaptureStateChanged += CameraControl_AutoCaptureStateChanged;
|
||||
}
|
||||
|
||||
private void CameraControl_AutoCaptureStateChanged(object sender, Controls.AutoCaptureState e)
|
||||
{
|
||||
var txt = "UNK";
|
||||
if (e == Controls.AutoCaptureState.ShowingCapturedPhoto)
|
||||
{
|
||||
txt = "ShowingCapturedPhoto";
|
||||
}
|
||||
else if (e == Controls.AutoCaptureState.ShowingCountdownForCapture)
|
||||
{
|
||||
txt = "Thanks!";
|
||||
PrgRing1.IsActive = true;
|
||||
}
|
||||
else if (e == Controls.AutoCaptureState.WaitingForFaces)
|
||||
{
|
||||
txt = "Hi, how are you doing?";
|
||||
PrgRing1.IsActive = false;
|
||||
}
|
||||
else// if (e == Controls.AutoCaptureState.WaitingForStillFaces)
|
||||
{
|
||||
txt = "Please stand still...";
|
||||
}
|
||||
|
||||
TxtStatusDescription.Text = txt;
|
||||
}
|
||||
|
||||
private async void CameraControl_CameraRestarted(object sender, EventArgs e)
|
||||
{
|
||||
// We induce a delay here to give the camera some time to start rendering before we hide the last captured photo.
|
||||
// This avoids a black flash.
|
||||
await Task.Delay(500);
|
||||
|
||||
this.imageFromCameraWithFaces.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private async void CameraControl_ImageCaptured(object sender, ImageAnalyzer e)
|
||||
{
|
||||
this.imageFromCameraWithFaces.DataContext = e;
|
||||
this.imageFromCameraWithFaces.Visibility = Visibility.Visible;
|
||||
|
||||
await this.cameraControl.StopStreamAsync();
|
||||
}
|
||||
|
||||
protected override async void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
await this.StartWebCameraAsync();
|
||||
base.OnNavigatedTo(e);
|
||||
}
|
||||
|
||||
private async Task StartWebCameraAsync()
|
||||
{
|
||||
webCamHostGrid.Visibility = Visibility.Visible;
|
||||
imageWithFacesControl.Visibility = Visibility.Collapsed;
|
||||
|
||||
await this.cameraControl.StartStreamAsync();
|
||||
await Task.Delay(250);
|
||||
this.imageFromCameraWithFaces.Visibility = Visibility.Collapsed;
|
||||
|
||||
UpdateWebCamHostGridSize();
|
||||
}
|
||||
|
||||
private void UpdateWebCamHostGridSize()
|
||||
{
|
||||
this.webCamHostGrid.Width = this.webCamHostGrid.ActualHeight * (this.cameraControl.CameraAspectRatio != 0 ? this.cameraControl.CameraAspectRatio : 1.777777777777);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
<Page
|
||||
x:Class="IntelligentKioskSample.Views.SettingsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:IntelligentKioskSample.Views"
|
||||
xmlns:ctl="using:IntelligentKioskSample.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<CommandBar x:Name="commandBar" VerticalAlignment="Top" HorizontalContentAlignment="Stretch">
|
||||
<CommandBar.Content>
|
||||
<ctl:PageHeader>
|
||||
<ctl:PageHeader.HeaderContent>
|
||||
<TextBlock Style="{ThemeResource PageTitleTextBlockStyle}" Text="SETTINGS"/>
|
||||
</ctl:PageHeader.HeaderContent>
|
||||
</ctl:PageHeader>
|
||||
</CommandBar.Content>
|
||||
</CommandBar>
|
||||
|
||||
<ScrollViewer Grid.Row="1">
|
||||
|
||||
<StackPanel Orientation="Vertical" Margin="12,12" >
|
||||
<StackPanel >
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="Keys" Style="{StaticResource SubheaderTextBlockStyle}"/>
|
||||
<HyperlinkButton Margin="6,0,0,0" VerticalAlignment="Bottom" NavigateUri="https://azure.microsoft.com/en-us/try/cognitive-services/">Click here if you need keys</HyperlinkButton>
|
||||
</StackPanel>
|
||||
|
||||
<PasswordBox Margin="0,10,0,0" Header="Emotion API Key" Password="{Binding EmotionApiKey, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="0,50,0,0">
|
||||
<TextBlock Text="Miscellaneous" Style="{StaticResource SubheaderTextBlockStyle}"/>
|
||||
<ComboBox x:Name="cameraSourceComboBox" Header="Camera Source" SelectionChanged="OnCameraSourceSelectionChanged"/>
|
||||
<ToggleSwitch IsOn="{Binding ShowDebugInfo, Mode=TwoWay}" Header="Show debug info:" Margin="0,6,0,0"/>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Slider x:Name="MinDetectableFaceSizeSlider" Minimum="0" Maximum="100" Value="{Binding MinDetectableFaceCoveragePercentage, Mode=TwoWay}" SmallChange="1" LargeChange="5" Header="Minimum detectable face size (as % of image height):" HorizontalAlignment="Left" Margin="0,0,0,0" StepFrequency="1"/>
|
||||
<TextBlock Text="{Binding ElementName=MinDetectableFaceSizeSlider, Path=Value}" Style="{StaticResource TitleTextBlockStyle}" VerticalAlignment="Center" Margin="12,0,0,0"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
|
||||
//
|
||||
// Microsoft Cognitive Services Github:
|
||||
// https://github.com/Microsoft/Cognitive
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// MIT License:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage;
|
||||
using Windows.UI.Popups;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
|
||||
|
||||
namespace IntelligentKioskSample.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class SettingsPage : Page
|
||||
{
|
||||
public SettingsPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.DataContext = SettingsHelper.Instance;
|
||||
}
|
||||
|
||||
protected override async void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
this.cameraSourceComboBox.ItemsSource = await Util.GetAvailableCameraNamesAsync();
|
||||
this.cameraSourceComboBox.SelectedItem = SettingsHelper.Instance.CameraName;
|
||||
base.OnNavigatedFrom(e);
|
||||
}
|
||||
|
||||
private void OnCameraSourceSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (this.cameraSourceComboBox.SelectedItem != null)
|
||||
{
|
||||
SettingsHelper.Instance.CameraName = this.cameraSourceComboBox.SelectedItem.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="portable45-net45+win8" />
|
||||
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="portable45-net45+win8" />
|
||||
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="portable45-net45+win8" />
|
||||
</packages>
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.Build": "1.0.21",
|
||||
"Microsoft.NETCore.UniversalWindowsPlatform": "5.2.3",
|
||||
"Microsoft.ProjectOxford.Emotion": "1.0.336",
|
||||
"Microsoft.ProjectOxford.Face": "1.2.5",
|
||||
"Microsoft.Rest.ClientRuntime": "2.3.10",
|
||||
"Newtonsoft.Json": "9.0.1",
|
||||
"System.Net.NameResolution": "4.3.0",
|
||||
"WriteableBitmapEx": "1.5.0"
|
||||
},
|
||||
"frameworks": {
|
||||
"uap10.0.10240": {}
|
||||
},
|
||||
"runtimes": {
|
||||
"win10-arm": {},
|
||||
"win10-arm-aot": {},
|
||||
"win10-x86": {},
|
||||
"win10-x86-aot": {},
|
||||
"win10-x64": {},
|
||||
"win10-x64-aot": {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27004.2006
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ContosoHelpdeskChatBot", "ContosoHelpdeskChatBot\ContosoHelpdeskChatBot.csproj", "{7CEA9614-BE08-47A8-9175-E858235B6231}"
|
||||
EndProject
|
||||
Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "ContosoHelpdeskData", "ContosoHelpdeskData\ContosoHelpdeskData.sqlproj", "{ACE2D83E-26AB-490E-B6C3-737AC7F49975}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ContosoHelpdeskSms", "ContosoHelpdeskSms\ContosoHelpdeskSms.csproj", "{DC4B0541-A167-4AF2-A5BF-D21D9379AE54}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{7CEA9614-BE08-47A8-9175-E858235B6231}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7CEA9614-BE08-47A8-9175-E858235B6231}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7CEA9614-BE08-47A8-9175-E858235B6231}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7CEA9614-BE08-47A8-9175-E858235B6231}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ACE2D83E-26AB-490E-B6C3-737AC7F49975}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ACE2D83E-26AB-490E-B6C3-737AC7F49975}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ACE2D83E-26AB-490E-B6C3-737AC7F49975}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{ACE2D83E-26AB-490E-B6C3-737AC7F49975}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ACE2D83E-26AB-490E-B6C3-737AC7F49975}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ACE2D83E-26AB-490E-B6C3-737AC7F49975}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{DC4B0541-A167-4AF2-A5BF-D21D9379AE54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DC4B0541-A167-4AF2-A5BF-D21D9379AE54}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DC4B0541-A167-4AF2-A5BF-D21D9379AE54}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DC4B0541-A167-4AF2-A5BF-D21D9379AE54}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {2D8005E5-57DD-4910-950A-5950E0BF8DAA}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,37 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Http;
|
||||
|
||||
namespace ContosoHelpdeskChatBot
|
||||
{
|
||||
public static class WebApiConfig
|
||||
{
|
||||
public static void Register(HttpConfiguration config)
|
||||
{
|
||||
// Json settings
|
||||
config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
|
||||
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
||||
config.Formatters.JsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
|
||||
JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
Formatting = Newtonsoft.Json.Formatting.Indented,
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
};
|
||||
|
||||
// Web API configuration and services
|
||||
|
||||
// Web API routes
|
||||
config.MapHttpAttributeRoutes();
|
||||
|
||||
config.Routes.MapHttpRoute(
|
||||
name: "DefaultApi",
|
||||
routeTemplate: "api/{controller}/{id}",
|
||||
defaults: new { id = RouteParameter.Optional }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>
|
||||
</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{7CEA9614-BE08-47A8-9175-E858235B6231}</ProjectGuid>
|
||||
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ContosoHelpdeskChatBot</RootNamespace>
|
||||
<AssemblyName>Bot Application</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
|
||||
<UseIISExpress>true</UseIISExpress>
|
||||
<IISExpressSSLPort />
|
||||
<IISExpressAnonymousAuthentication />
|
||||
<IISExpressWindowsAuthentication />
|
||||
<IISExpressUseClassicPipelineMode />
|
||||
<UseGlobalApplicationHostFile />
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<TargetFrameworkProfile />
|
||||
<Use64BitIISExpress />
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Autofac, Version=4.6.2.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Autofac.4.6.2\lib\net45\Autofac.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Chronic, Version=0.3.2.0, Culture=neutral, PublicKeyToken=3bd1f1ef638b0d3c, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Chronic.Signed.0.3.2\lib\net40\Chronic.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bot.Builder, Version=3.11.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bot.Builder.3.11.0\lib\net46\Microsoft.Bot.Builder.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bot.Builder.Autofac, Version=3.10.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bot.Builder.3.11.0\lib\net46\Microsoft.Bot.Builder.Autofac.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bot.Connector, Version=3.11.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bot.Connector.3.11.1\lib\net45\Microsoft.Bot.Connector.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.IdentityModel.Protocol.Extensions, Version=1.0.40306.1554, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.4.403061554\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Rest.ClientRuntime, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Rest.ClientRuntime.2.3.10\lib\net452\Microsoft.Rest.ClientRuntime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAzure.Configuration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.WindowsAzure.ConfigurationManager.3.2.3\lib\net40\Microsoft.WindowsAzure.Configuration.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.IdentityModel.Tokens.Jwt, Version=4.0.40306.1554, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\System.IdentityModel.Tokens.Jwt.4.0.4.403061554\lib\net45\System.IdentityModel.Tokens.Jwt.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Compression.FileSystem" />
|
||||
<Reference Include="System.Net" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.WebRequest" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Security" />
|
||||
<Reference Include="System.Web.DynamicData" />
|
||||
<Reference Include="System.Web.Entity" />
|
||||
<Reference Include="System.Web.ApplicationServices" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Extensions" />
|
||||
<Reference Include="System.Web.Http, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Http.WebHost, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Web.Services" />
|
||||
<Reference Include="System.EnterpriseServices" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="default.htm" />
|
||||
<Content Include="Global.asax" />
|
||||
<Content Include="Web.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="App_Start\WebApiConfig.cs" />
|
||||
<Compile Include="Controllers\MessagesController.cs" />
|
||||
<Compile Include="Dialogs\LocalAdminDialog.cs" />
|
||||
<Compile Include="Dialogs\ResetPasswordDialog.cs" />
|
||||
<Compile Include="Models\AppMsi.cs" />
|
||||
<Compile Include="Models\ContosoHelpdeskContext.cs" />
|
||||
<Compile Include="Models\InstallApp.cs" />
|
||||
<Compile Include="Models\LocalAdmin.cs" />
|
||||
<Compile Include="Models\LocalAdminPrompt.cs" />
|
||||
<Compile Include="Models\Log.cs" />
|
||||
<Compile Include="Models\ResetPassword.cs" />
|
||||
<Compile Include="Dialogs\CancelScorable.cs" />
|
||||
<Compile Include="Dialogs\InstallAppDialog.cs" />
|
||||
<Compile Include="Dialogs\RootDialog.cs" />
|
||||
<Compile Include="Global.asax.cs">
|
||||
<DependentUpon>Global.asax</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="GlobalMessageHandlersBotModule.cs" />
|
||||
<Compile Include="Models\ResetPasswordPrompt.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="packages.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<None Include="Web.Debug.config">
|
||||
<DependentUpon>Web.config</DependentUpon>
|
||||
</None>
|
||||
<None Include="Web.Release.config">
|
||||
<DependentUpon>Web.config</DependentUpon>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ContosoHelpdeskSms\ContosoHelpdeskSms.csproj">
|
||||
<Project>{dc4b0541-a167-4af2-a5bf-d21d9379ae54}</Project>
|
||||
<Name>ContosoHelpdeskSms</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<EnableMSDeployAppOffline>true</EnableMSDeployAppOffline>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>3979</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:3979/</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,63 @@
|
|||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Http;
|
||||
using Microsoft.Bot.Builder.Dialogs;
|
||||
using Microsoft.Bot.Connector;
|
||||
using System;
|
||||
|
||||
namespace ContosoHelpdeskChatBot
|
||||
{
|
||||
[BotAuthentication]
|
||||
public class MessagesController : ApiController
|
||||
{
|
||||
/// <summary>
|
||||
/// POST: api/Messages
|
||||
/// Receive a message from a user and reply to it
|
||||
/// </summary>
|
||||
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
|
||||
{
|
||||
|
||||
if (activity.Type == ActivityTypes.Message)
|
||||
{
|
||||
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleSystemMessage(activity);
|
||||
}
|
||||
|
||||
var response = Request.CreateResponse(HttpStatusCode.OK);
|
||||
return response;
|
||||
}
|
||||
|
||||
private Activity HandleSystemMessage(Activity message)
|
||||
{
|
||||
if (message.Type == ActivityTypes.DeleteUserData)
|
||||
{
|
||||
// Implement user deletion here
|
||||
// If we handle user deletion, return a real message
|
||||
}
|
||||
else if (message.Type == ActivityTypes.ConversationUpdate)
|
||||
{
|
||||
// Handle conversation state changes, like members being added and removed
|
||||
// Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info
|
||||
// Not available in all channels
|
||||
}
|
||||
else if (message.Type == ActivityTypes.ContactRelationUpdate)
|
||||
{
|
||||
// Handle add/remove from contact lists
|
||||
// Activity.From + Activity.Action represent what happened
|
||||
}
|
||||
else if (message.Type == ActivityTypes.Typing)
|
||||
{
|
||||
// Handle knowing tha the user is typing
|
||||
}
|
||||
else if (message.Type == ActivityTypes.Ping)
|
||||
{
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
namespace ContosoHelpdeskChatBot.Dialogs
|
||||
{
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Bot.Builder.Dialogs.Internals;
|
||||
using Microsoft.Bot.Builder.Internals.Fibers;
|
||||
using Microsoft.Bot.Connector;
|
||||
using Microsoft.Bot.Builder.Scorables.Internals;
|
||||
using Autofac;
|
||||
|
||||
#pragma warning disable 1998
|
||||
|
||||
public class CancelScorable : ScorableBase<IActivity, string, double>
|
||||
{
|
||||
private readonly IDialogTask task;
|
||||
|
||||
public CancelScorable(IDialogTask task)
|
||||
{
|
||||
SetField.NotNull(out this.task, nameof(task), task);
|
||||
}
|
||||
|
||||
protected override async Task<string> PrepareAsync(IActivity activity, CancellationToken token)
|
||||
{
|
||||
var message = activity as IMessageActivity;
|
||||
|
||||
if (message != null && !string.IsNullOrWhiteSpace(message.Text))
|
||||
{
|
||||
if (message.Text.Equals("cancel", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return message.Text;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override bool HasScore(IActivity item, string state)
|
||||
{
|
||||
return state != null;
|
||||
}
|
||||
|
||||
protected override double GetScore(IActivity item, string state)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
protected override async Task PostAsync(IActivity item, string state, CancellationToken token)
|
||||
{
|
||||
var activity = (Activity)item;
|
||||
var reply = activity.CreateReply($"Ok restarting conversation.");
|
||||
|
||||
//Refer to Connector service
|
||||
//https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-connector
|
||||
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
|
||||
await connector.Conversations.ReplyToActivityAsync(reply);
|
||||
|
||||
this.task.Reset();
|
||||
}
|
||||
protected override Task DoneAsync(IActivity item, string state, CancellationToken token)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
namespace ContosoHelpdeskChatBot.Dialogs
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Microsoft.Bot.Builder.Dialogs;
|
||||
using Microsoft.Bot.Builder.FormFlow;
|
||||
using Microsoft.Bot.Connector;
|
||||
using ContosoHelpdeskChatBot.Models;
|
||||
|
||||
[Serializable]
|
||||
public class InstallAppDialog : IDialog<object>
|
||||
{
|
||||
private Models.InstallApp install = new InstallApp();
|
||||
|
||||
public async Task StartAsync(IDialogContext context)
|
||||
{
|
||||
await context.PostAsync("Ok let's get started. What is the name of the application? ");
|
||||
|
||||
context.Wait(appNameAsync);
|
||||
}
|
||||
|
||||
private async Task appNameAsync(IDialogContext context, IAwaitable<IMessageActivity> userReply)
|
||||
{
|
||||
//this will trigger a wait for user's reply
|
||||
//in this case we are waiting for an app name which will be used as keyword to search the AppMsi table
|
||||
var message = await userReply;
|
||||
|
||||
var appname = message.Text;
|
||||
var names = await this.getAppsAsync(appname);
|
||||
|
||||
if (names.Count == 1)
|
||||
{
|
||||
install.AppName = names.First();
|
||||
await context.PostAsync($"Found {install.AppName}. What is the name of the machine to install application?");
|
||||
context.Wait(machineNameAsync);
|
||||
}
|
||||
else if (names.Count > 1)
|
||||
{
|
||||
string appnames = "";
|
||||
for (int i = 0; i < names.Count; i++)
|
||||
{
|
||||
appnames += $"<br/> {i + 1}. " + names[i];
|
||||
}
|
||||
await context.PostAsync($"I found {names.Count()} applications.<br/> {appnames}<br/> Please reply 1 - {names.Count()} to indicate your choice.");
|
||||
|
||||
//at a conversation scope, store state data in ConversationData
|
||||
context.ConversationData.SetValue("AppList", names);
|
||||
context.Wait(multipleAppsAsync);
|
||||
}
|
||||
else
|
||||
{
|
||||
await context.PostAsync($"Sorry, I did not find any application with the name \"{appname}\".");
|
||||
context.Done<object>(null);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task multipleAppsAsync(IDialogContext context, IAwaitable<IMessageActivity> userReply)
|
||||
{
|
||||
//this will trigger a wait for user's reply
|
||||
//here we ask the user which specific app to install when we found more than one
|
||||
var message = await userReply;
|
||||
|
||||
int choice;
|
||||
var isNum = int.TryParse(message.Text, out choice);
|
||||
List<string> applist;
|
||||
|
||||
context.ConversationData.TryGetValue("AppList", out applist);
|
||||
|
||||
if (isNum && choice <= applist.Count && choice > 0)
|
||||
{
|
||||
//minus becoz index zero base
|
||||
this.install.AppName = applist[choice - 1];
|
||||
await context.PostAsync($"What is the name of the machine to install?");
|
||||
context.Wait(machineNameAsync);
|
||||
}
|
||||
else
|
||||
{
|
||||
await context.PostAsync($"Invalid response. Please reply 1 - {applist.Count()} to indicate your choice.");
|
||||
context.Wait(multipleAppsAsync);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task machineNameAsync(IDialogContext context, IAwaitable<IMessageActivity> userReply)
|
||||
{
|
||||
//this will trigger a wait for user's reply
|
||||
//finally we ask for the machine name on which to install the app
|
||||
var message = await userReply;
|
||||
|
||||
var machinename = message.Text;
|
||||
|
||||
this.install.MachineName = machinename;
|
||||
|
||||
//TODO: Save to database
|
||||
using (var db = new ContosoHelpdeskContext())
|
||||
{
|
||||
db.InstallApps.Add(install);
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
await context.PostAsync($"Great, your request to install {this.install.AppName} on {this.install.MachineName} has been scheduled.");
|
||||
context.Done<object>(null);
|
||||
}
|
||||
|
||||
private async Task<List<string>> getAppsAsync(string Name)
|
||||
{
|
||||
//TODO: Add EF to lookup database
|
||||
var names = new List<string>();
|
||||
|
||||
using (var db = new ContosoHelpdeskContext())
|
||||
{
|
||||
names = (from app in db.AppMsis
|
||||
where app.AppName.ToLower().Contains(Name.ToLower())
|
||||
select app.AppName).ToList();
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Bot.Builder.Dialogs;
|
||||
using Microsoft.Bot.Connector;
|
||||
using ContosoHelpdeskChatBot.Models;
|
||||
using Microsoft.Bot.Builder.FormFlow;
|
||||
|
||||
namespace ContosoHelpdeskChatBot.Dialogs
|
||||
{
|
||||
[Serializable]
|
||||
public class LocalAdminDialog : IDialog<object>
|
||||
{
|
||||
private LocalAdmin admin = new LocalAdmin();
|
||||
public async Task StartAsync(IDialogContext context)
|
||||
{
|
||||
await context.PostAsync("Great I will help you request local machine admin.");
|
||||
|
||||
var localAdminDialog = FormDialog.FromForm(this.BuildLocalAdminForm, FormOptions.PromptInStart);
|
||||
|
||||
context.Call(localAdminDialog, this.ResumeAfterLocalAdminFormDialog);
|
||||
}
|
||||
|
||||
private async Task ResumeAfterLocalAdminFormDialog(IDialogContext context, IAwaitable<LocalAdminPrompt> userReply)
|
||||
{
|
||||
|
||||
using (var db = new ContosoHelpdeskContext())
|
||||
{
|
||||
db.LocalAdmins.Add(admin);
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
context.Done<object>(null);
|
||||
}
|
||||
|
||||
private IForm<LocalAdminPrompt> BuildLocalAdminForm()
|
||||
{
|
||||
//here's an example of how validation can be used in form builder
|
||||
return new FormBuilder<LocalAdminPrompt>()
|
||||
.Field(nameof(LocalAdminPrompt.MachineName),
|
||||
validate: async (state, value) =>
|
||||
{
|
||||
var result = new ValidateResult { IsValid = true, Value = value };
|
||||
//add validation here
|
||||
|
||||
this.admin.MachineName = (string)value;
|
||||
return result;
|
||||
})
|
||||
.Field(nameof(LocalAdminPrompt.AdminDuration),
|
||||
validate: async (state, value) =>
|
||||
{
|
||||
var result = new ValidateResult { IsValid = true, Value = value };
|
||||
//add validation here
|
||||
|
||||
this.admin.AdminDuration = Convert.ToInt32((long)value) as int?;
|
||||
return result;
|
||||
})
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Bot.Builder.Dialogs;
|
||||
using Microsoft.Bot.Connector;
|
||||
using Microsoft.Bot.Builder.FormFlow;
|
||||
using ContosoHelpdeskChatBot.Models;
|
||||
using ContosoHelpdeskSms;
|
||||
|
||||
namespace ContosoHelpdeskChatBot.Dialogs
|
||||
{
|
||||
[Serializable]
|
||||
public class ResetPasswordDialog : IDialog<object>
|
||||
{
|
||||
public async Task StartAsync(IDialogContext context)
|
||||
{
|
||||
await context.PostAsync("Alright I will help you create a temp password");
|
||||
|
||||
if (sendPassCode(context))
|
||||
{
|
||||
var resetPasswordDialog = FormDialog.FromForm(this.BuildResetPasswordForm, FormOptions.PromptInStart);
|
||||
|
||||
context.Call(resetPasswordDialog, this.ResumeAfterResetPasswordFormDialog);
|
||||
}
|
||||
else
|
||||
{
|
||||
//here we can simply fail the current dialog because we have root dialog handling all exceptions
|
||||
context.Fail(new Exception("Failed to send SMS. Make sure email & phone number has been added to database."));
|
||||
}
|
||||
}
|
||||
|
||||
private bool sendPassCode(IDialogContext context)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
//Recipient Id varies depending on channel
|
||||
//refer ChannelAccount class https://docs.botframework.com/en-us/csharp/builder/sdkreference/dd/def/class_microsoft_1_1_bot_1_1_connector_1_1_channel_account.html#a0b89cf01fdd73cbc00a524dce9e2ad1a
|
||||
//as well as Activity class https://docs.botframework.com/en-us/csharp/builder/sdkreference/dc/d2f/class_microsoft_1_1_bot_1_1_connector_1_1_activity.html
|
||||
var email = context.Activity.From.Id;
|
||||
int passcode = new Random().Next(1000, 9999);
|
||||
Int64? smsNumber = 0;
|
||||
string smsMessage = "Your Contoso Pass Code is ";
|
||||
string countryDialPrefix = "+1";
|
||||
|
||||
//save PassCode to database
|
||||
using (var db = new ContosoHelpdeskContext())
|
||||
{
|
||||
var reset = db.ResetPasswords.Where(r => r.EmailAddress == email).ToList();
|
||||
if (reset.Count >= 1)
|
||||
{
|
||||
reset.First().PassCode = passcode;
|
||||
smsNumber = reset.First().MobileNumber;
|
||||
result = true;
|
||||
}
|
||||
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
result = Helper.SendSms($"{countryDialPrefix}{smsNumber.ToString()}", $"{smsMessage} {passcode}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private IForm<ResetPasswordPrompt> BuildResetPasswordForm()
|
||||
{
|
||||
return new FormBuilder<ResetPasswordPrompt>()
|
||||
.Field(nameof(ResetPasswordPrompt.PassCode))
|
||||
.Build();
|
||||
}
|
||||
|
||||
private async Task ResumeAfterResetPasswordFormDialog(IDialogContext context, IAwaitable<ResetPasswordPrompt> userReply)
|
||||
{
|
||||
var prompt = await userReply;
|
||||
var email = context.Activity.From.Id;
|
||||
int? passcode;
|
||||
|
||||
using (var db = new ContosoHelpdeskContext())
|
||||
{
|
||||
passcode = db.ResetPasswords.Where(r => r.EmailAddress == email).First().PassCode;
|
||||
}
|
||||
|
||||
if (prompt.PassCode == passcode)
|
||||
{
|
||||
string temppwd = "TempPwd" + new Random().Next(0, 5000);
|
||||
await context.PostAsync($"Your temp password is {temppwd}");
|
||||
}
|
||||
|
||||
context.Done<object>(null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
namespace ContosoHelpdeskChatBot.Dialogs
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Bot.Builder.Dialogs;
|
||||
using Microsoft.Bot.Connector;
|
||||
|
||||
[Serializable]
|
||||
public class RootDialog : IDialog<object>
|
||||
{
|
||||
private static log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private const string InstallAppOption = "Install Application (install)";
|
||||
private const string ResetPasswordOption = "Reset Password (password)";
|
||||
private const string LocalAdminOption = "Request Local Admin (admin)";
|
||||
private const string GreetMessage = "Welcome to **Contoso Helpdesk Chat Bot**.\n\nI am designed to use with mobile email app, make sure your replies do not contain signatures. \n\nFollowing is what I can help you with, just reply with word in parenthesis:";
|
||||
private const string ErrorMessage = "Not a valid option";
|
||||
private static List<string> HelpdeskOptions = new List<string>()
|
||||
{
|
||||
InstallAppOption,
|
||||
ResetPasswordOption,
|
||||
LocalAdminOption
|
||||
};
|
||||
|
||||
public async Task StartAsync(IDialogContext context)
|
||||
{
|
||||
context.Wait(this.MessageReceivedAsync);
|
||||
}
|
||||
|
||||
public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> userReply)
|
||||
{
|
||||
var message = await userReply;
|
||||
|
||||
this.ShowOptions(context);
|
||||
}
|
||||
|
||||
private void ShowOptions(IDialogContext context)
|
||||
{
|
||||
PromptDialog.Choice(context, this.OnOptionSelected, HelpdeskOptions, GreetMessage, ErrorMessage, 3, PromptStyle.PerLine);
|
||||
}
|
||||
|
||||
private async Task OnOptionSelected(IDialogContext context, IAwaitable<string> userReply)
|
||||
{
|
||||
try
|
||||
{
|
||||
string optionSelected = await userReply;
|
||||
|
||||
switch (optionSelected)
|
||||
{
|
||||
case InstallAppOption:
|
||||
context.Call(new InstallAppDialog(), this.ResumeAfterOptionDialog);
|
||||
break;
|
||||
case ResetPasswordOption:
|
||||
context.Call(new ResetPasswordDialog(), this.ResumeAfterOptionDialog);
|
||||
break;
|
||||
case LocalAdminOption:
|
||||
context.Call(new LocalAdminDialog(), this.ResumeAfterOptionDialog);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (TooManyAttemptsException ex)
|
||||
{
|
||||
await context.PostAsync($"Ooops! Too many attemps :(. But don't worry, I'm handling that exception and you can try again!");
|
||||
|
||||
context.Wait(this.MessageReceivedAsync);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ResumeAfterOptionDialog(IDialogContext context, IAwaitable<object> userReply)
|
||||
{
|
||||
try
|
||||
{
|
||||
var message = await userReply;
|
||||
|
||||
var ticketNumber = new Random().Next(0, 20000);
|
||||
await context.PostAsync($"Thank you for using the Helpdesk Bot. Your ticket number is {ticketNumber}.");
|
||||
context.Done(ticketNumber);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await context.PostAsync($"Failed with message: {ex.Message}");
|
||||
|
||||
// In general resume from task after calling a child dialog is a good place to handle exceptions
|
||||
// try catch will capture exceptions from the bot framework awaitable object which is essentially "userReply"
|
||||
logger.Error(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<%@ Application Codebehind="Global.asax.cs" Inherits="ContosoHelpdeskChatBot.WebApiApplication" Language="C#" %>
|
|
@ -0,0 +1,55 @@
|
|||
using Autofac;
|
||||
using Microsoft.Bot.Builder.Dialogs;
|
||||
using Microsoft.Bot.Builder.Dialogs.Internals;
|
||||
using Microsoft.Bot.Builder.Internals.Fibers;
|
||||
using Microsoft.Bot.Connector;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
using System.Web.Routing;
|
||||
|
||||
namespace ContosoHelpdeskChatBot
|
||||
{
|
||||
public class WebApiApplication : System.Web.HttpApplication
|
||||
{
|
||||
protected void Application_Start()
|
||||
{
|
||||
GlobalConfiguration.Configure(WebApiConfig.Register);
|
||||
|
||||
BotConfig.UpdateConversationContainer();
|
||||
this.RegisterBotModules();
|
||||
|
||||
log4net.Config.XmlConfigurator.Configure();
|
||||
}
|
||||
|
||||
//setting Bot data store policy to use last write win
|
||||
//example if bot service got restarted, existing conversation would just overwrite data to store
|
||||
public static class BotConfig
|
||||
{
|
||||
public static void UpdateConversationContainer()
|
||||
{
|
||||
var builder = new ContainerBuilder();
|
||||
|
||||
builder.Register(c => new CachingBotDataStore(c.ResolveKeyed<IBotDataStore<BotData>>(typeof(ConnectorStore)),
|
||||
CachingBotDataStoreConsistencyPolicy.LastWriteWins))
|
||||
.As<IBotDataStore<BotData>>()
|
||||
.AsSelf()
|
||||
.InstancePerLifetimeScope();
|
||||
|
||||
builder.Update(Conversation.Container);
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterBotModules()
|
||||
{
|
||||
Conversation.UpdateContainer(builder =>
|
||||
{
|
||||
builder.RegisterModule(new ReflectionSurrogateModule());
|
||||
builder.RegisterModule<GlobalMessageHandlersBotModule>();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
namespace ContosoHelpdeskChatBot
|
||||
{
|
||||
using Autofac;
|
||||
using Dialogs;
|
||||
using Microsoft.Bot.Builder.Dialogs.Internals;
|
||||
using Microsoft.Bot.Builder.Scorables;
|
||||
using Microsoft.Bot.Connector;
|
||||
|
||||
public class GlobalMessageHandlersBotModule : Module
|
||||
{
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
base.Load(builder);
|
||||
|
||||
builder
|
||||
.Register(c => new CancelScorable(c.Resolve<IDialogTask>()))
|
||||
.As<IScorable<IActivity, double>>()
|
||||
.InstancePerLifetimeScope();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
namespace ContosoHelpdeskChatBot.Models
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Data.Entity.Spatial;
|
||||
|
||||
[Table("AppMsi")]
|
||||
public partial class AppMsi
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public string AppName { get; set; }
|
||||
|
||||
public string MsiPackage { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
namespace ContosoHelpdeskChatBot.Models
|
||||
{
|
||||
using System;
|
||||
using System.Data.Entity;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
|
||||
public partial class ContosoHelpdeskContext : DbContext
|
||||
{
|
||||
public ContosoHelpdeskContext()
|
||||
: base("name=ContosoHelpdeskContext")
|
||||
{
|
||||
}
|
||||
|
||||
public virtual DbSet<AppMsi> AppMsis { get; set; }
|
||||
public virtual DbSet<InstallApp> InstallApps { get; set; }
|
||||
public virtual DbSet<LocalAdmin> LocalAdmins { get; set; }
|
||||
public virtual DbSet<Log> Logs { get; set; }
|
||||
public virtual DbSet<ResetPassword> ResetPasswords { get; set; }
|
||||
|
||||
protected override void OnModelCreating(DbModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<AppMsi>()
|
||||
.Property(e => e.AppName)
|
||||
.IsUnicode(false);
|
||||
|
||||
modelBuilder.Entity<AppMsi>()
|
||||
.Property(e => e.MsiPackage)
|
||||
.IsUnicode(false);
|
||||
|
||||
modelBuilder.Entity<InstallApp>()
|
||||
.Property(e => e.AppName)
|
||||
.IsUnicode(false);
|
||||
|
||||
modelBuilder.Entity<InstallApp>()
|
||||
.Property(e => e.MachineName)
|
||||
.IsUnicode(false);
|
||||
|
||||
modelBuilder.Entity<ResetPassword>()
|
||||
.Property(e => e.EmailAddress)
|
||||
.IsUnicode(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
namespace ContosoHelpdeskChatBot.Models
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Data.Entity.Spatial;
|
||||
|
||||
[Table("InstallApp")]
|
||||
public partial class InstallApp
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public string AppName { get; set; }
|
||||
|
||||
public string MachineName { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
namespace ContosoHelpdeskChatBot.Models
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Data.Entity.Spatial;
|
||||
|
||||
[Table("LocalAdmin")]
|
||||
public partial class LocalAdmin
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public string MachineName { get; set; }
|
||||
|
||||
public int? AdminDuration { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Microsoft.Bot.Builder.FormFlow;
|
||||
|
||||
namespace ContosoHelpdeskChatBot.Models
|
||||
{
|
||||
public class LocalAdminPrompt
|
||||
{
|
||||
[Prompt("What is the machine name to add you to local admin group?")]
|
||||
public string MachineName { get; set; }
|
||||
|
||||
[Prompt("How many days do you need the admin access?")]
|
||||
public int? AdminDuration { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
namespace ContosoHelpdeskChatBot.Models
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Data.Entity.Spatial;
|
||||
|
||||
[Table("Log")]
|
||||
public partial class Log
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
public string Level { get; set; }
|
||||
|
||||
public string Message { get; set; }
|
||||
|
||||
public string Exception { get; set; }
|
||||
}
|
||||
}
|