Initial Commit
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Meta.WitAi.Utilities
|
||||
{
|
||||
public static class AssetDatabaseUtility
|
||||
{
|
||||
// Find Unity asset
|
||||
public static T FindUnityAsset<T>(string filter) where T : UnityEngine.Object
|
||||
{
|
||||
T[] results = FindUnityAssets<T>(filter, true);
|
||||
if (results != null && results.Length > 0)
|
||||
{
|
||||
return results[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get all unity objects matching the name
|
||||
public static T[] FindUnityAssets<T>(string filter, bool ignoreAdditional = false)
|
||||
where T : UnityEngine.Object
|
||||
{
|
||||
List<T> results = new List<T>();
|
||||
string[] guids = AssetDatabase.FindAssets(filter);
|
||||
if (guids != null && guids.Length > 0)
|
||||
{
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
|
||||
T asset = AssetDatabase.LoadAssetAtPath<T>(assetPath);
|
||||
if (asset != null && !results.Contains(asset))
|
||||
{
|
||||
results.Add(asset);
|
||||
if (ignoreAdditional)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
// Gets the absolute string path of the asset(s) with the matching name
|
||||
public static string[] FindUnityAssetPath(string filter, bool ignoreAdditional = false)
|
||||
{
|
||||
var relativePaths = AssetDatabase.FindAssets(filter);
|
||||
char d = Path.DirectorySeparatorChar;
|
||||
|
||||
List<string> results = new List<string>();
|
||||
foreach (var relPath in relativePaths)
|
||||
{
|
||||
results.Add($"{Application.dataPath}{d}..{d}{AssetDatabase.GUIDToAssetPath(relPath)}");
|
||||
if (ignoreAdditional)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return results.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d247ae64c6547e4282a35e0b6b17b6f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+310
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Meta.Conduit.Editor;
|
||||
using Meta.Voice.TelemetryUtilities;
|
||||
using Meta.WitAi.Data.Configuration;
|
||||
using Meta.WitAi.Utilities;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Meta.WitAi.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages the Conduit manifest generation.
|
||||
/// </summary>
|
||||
public class ConduitManifestGenerationManager: IPreprocessBuildWithReport
|
||||
{
|
||||
/// <summary>
|
||||
/// The priority for preprocess build callback.
|
||||
/// </summary>
|
||||
public int callbackOrder => 0;
|
||||
|
||||
/// <summary>
|
||||
/// The assembly miner.
|
||||
/// </summary>
|
||||
private static readonly AssemblyMiner AssemblyMiner = new AssemblyMiner(new WitParameterValidator());
|
||||
|
||||
/// <summary>
|
||||
/// Maps individual configurations to their associated managers. This is needed to allow static resolution
|
||||
/// on global events like building or running.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, ConduitManifestGenerationManager> ConfigurationToManagerMap =
|
||||
new Dictionary<string, ConduitManifestGenerationManager>();
|
||||
|
||||
/// <summary>
|
||||
/// Locally collected Conduit statistics.
|
||||
/// </summary>
|
||||
private static ConduitStatistics _statistics;
|
||||
|
||||
/// <summary>
|
||||
/// Set to true if code had changed since last manifest generation.
|
||||
/// We start with this set to true to handle changes when the editor is not running.
|
||||
/// </summary>
|
||||
private static bool _codeChanged = true;
|
||||
|
||||
/// <summary>
|
||||
/// The manifest generator used for this configuration.
|
||||
/// </summary>
|
||||
private readonly ManifestGenerator _manifestGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// True when a manifest exists locally for this configuration.
|
||||
/// </summary>
|
||||
public bool ManifestAvailable { get; private set; }= false;
|
||||
|
||||
/// <summary>
|
||||
/// The assembly walker associated with this configuration.
|
||||
/// </summary>
|
||||
internal AssemblyWalker AssemblyWalker { get; private set; } = new AssemblyWalker();
|
||||
|
||||
/// <summary>
|
||||
/// Locally collected Conduit statistics.
|
||||
/// </summary>
|
||||
private static ConduitStatistics Statistics
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_statistics == null)
|
||||
{
|
||||
_statistics = new ConduitStatistics(new PersistenceLayer());
|
||||
}
|
||||
return _statistics;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Factory method that creates a manager for the configuration if none exists. Otherwise, creates a new one.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
/// <returns>An instance of this class.</returns>
|
||||
public static ConduitManifestGenerationManager GetInstance(WitConfiguration configuration)
|
||||
{
|
||||
// This key has to match what we set in the constructor.
|
||||
var configurationKey = configuration.name;
|
||||
if (!ConfigurationToManagerMap.ContainsKey(configurationKey))
|
||||
{
|
||||
ConfigurationToManagerMap[configurationKey] = new ConduitManifestGenerationManager(configuration);
|
||||
}
|
||||
|
||||
ConfigurationToManagerMap[configurationKey].GenerateManifestIfNeeded(configuration);
|
||||
|
||||
return ConfigurationToManagerMap[configurationKey];
|
||||
}
|
||||
|
||||
static ConduitManifestGenerationManager()
|
||||
{
|
||||
EditorApplication.playModeStateChanged += OnPlayModeChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This default constructor is intended to be used by Unity only. Do not call it directly.
|
||||
/// </summary>
|
||||
public ConduitManifestGenerationManager()
|
||||
{
|
||||
}
|
||||
|
||||
private ConduitManifestGenerationManager(WitConfiguration configuration)
|
||||
{
|
||||
_manifestGenerator = new ManifestGenerator(AssemblyWalker, AssemblyMiner);
|
||||
ConfigurationToManagerMap[configuration.name] = this;
|
||||
}
|
||||
|
||||
public void OnPreprocessBuild(BuildReport report)
|
||||
{
|
||||
if (_codeChanged)
|
||||
{
|
||||
GenerateAllManifests();
|
||||
}
|
||||
else
|
||||
{
|
||||
GenerateMissingManifests();
|
||||
}
|
||||
}
|
||||
|
||||
[UnityEditor.Callbacks.DidReloadScripts]
|
||||
private static void OnScriptsReloaded()
|
||||
{
|
||||
_codeChanged = true;
|
||||
}
|
||||
|
||||
private static void OnPlayModeChanged(PlayModeStateChange state)
|
||||
{
|
||||
if (state != PlayModeStateChange.EnteredPlayMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_codeChanged)
|
||||
{
|
||||
GenerateAllManifests();
|
||||
}
|
||||
else
|
||||
{
|
||||
GenerateMissingManifests();
|
||||
}
|
||||
}
|
||||
|
||||
public static void PersistStatistics()
|
||||
{
|
||||
Statistics.Persist();
|
||||
}
|
||||
|
||||
private static void GenerateMissingManifests()
|
||||
{
|
||||
foreach (var configuration in WitConfigurationUtility.GetLoadedConfigurations())
|
||||
{
|
||||
if (configuration == null || !configuration.useConduit)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var manager = GetInstance(configuration);
|
||||
manager.GenerateManifest(configuration, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateAllManifests()
|
||||
{
|
||||
foreach (var configuration in WitConfigurationUtility.GetLoadedConfigurations())
|
||||
{
|
||||
if (configuration != null && configuration.useConduit)
|
||||
{
|
||||
var manager = GetInstance(configuration);
|
||||
manager.GenerateManifest(configuration, false);
|
||||
}
|
||||
}
|
||||
|
||||
_codeChanged = false;
|
||||
}
|
||||
|
||||
public List<string> ExtractManifestData()
|
||||
{
|
||||
return _manifestGenerator.ExtractManifestData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a manifest with empty entities and actions lists.
|
||||
/// </summary>
|
||||
/// <param name="domain">A friendly name to use for this app.</param>
|
||||
/// <param name="id">The App ID.</param>
|
||||
/// <returns>A JSON representation of the empty manifest.</returns>
|
||||
public string GenerateEmptyManifest(string domain, string id)
|
||||
{
|
||||
return _manifestGenerator.GenerateEmptyManifest(domain, id);
|
||||
}
|
||||
|
||||
private void GenerateManifestIfNeeded(WitConfiguration configuration)
|
||||
{
|
||||
if (!configuration.useConduit || configuration == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get full manifest path & ensure it exists
|
||||
var manifestPath = configuration.GetManifestEditorPath();
|
||||
ManifestAvailable = File.Exists(manifestPath);
|
||||
|
||||
// Auto-generate manifest
|
||||
if (!ManifestAvailable)
|
||||
{
|
||||
GenerateManifest(configuration, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetManifestFullPath(WitConfiguration configuration, bool shouldCreateDirectoryIfNotExist = false)
|
||||
{
|
||||
string directory = Application.dataPath + "/Oculus/Voice/Resources";
|
||||
if (shouldCreateDirectoryIfNotExist)
|
||||
{
|
||||
IOUtility.CreateDirectory(directory, true);
|
||||
}
|
||||
return directory + "/" + configuration.ManifestLocalPath;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Generates a manifest and optionally opens it in the editor.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration that we are generating the manifest for.</param>
|
||||
/// <param name="openManifest">If true, will open the manifest file in the code editor.</param>
|
||||
public void GenerateManifest(WitConfiguration configuration, bool openManifest)
|
||||
{
|
||||
var instanceKey = Telemetry.StartEvent(Telemetry.TelemetryEventId.GenerateManifest);
|
||||
AssemblyWalker.AssembliesToIgnore = new HashSet<string>(configuration.excludedAssemblies);
|
||||
|
||||
// Generate
|
||||
var startGenerationTime = DateTime.UtcNow;
|
||||
var appInfo = configuration.GetApplicationInfo();
|
||||
var manifest = _manifestGenerator.GenerateManifest(appInfo.name, appInfo.id);
|
||||
var endGenerationTime = DateTime.UtcNow;
|
||||
|
||||
// Get file path
|
||||
var fullPath = configuration.GetManifestEditorPath();
|
||||
if (string.IsNullOrEmpty(fullPath) || !File.Exists(fullPath))
|
||||
{
|
||||
fullPath = GetManifestFullPath(configuration, true);
|
||||
}
|
||||
|
||||
// Write to file
|
||||
try
|
||||
{
|
||||
var writer = new StreamWriter(fullPath);
|
||||
writer.NewLine = "\n";
|
||||
writer.WriteLine(manifest);
|
||||
writer.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
VLog.E($"Conduit manifest failed to generate\nPath: {fullPath}\n{e}");
|
||||
Telemetry.EndEventWithFailure(instanceKey, e.Message);
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var incompatibleSignatures = string.Join(" ", AssemblyMiner.IncompatibleSignatureFrequency.Keys);
|
||||
Telemetry.AnnotateEvent(instanceKey, Telemetry.AnnotationKey.IncompatibleSignatures, incompatibleSignatures);
|
||||
|
||||
var compatibleSignatures = string.Join(" ", AssemblyMiner.SignatureFrequency.Keys);
|
||||
Telemetry.AnnotateEvent(instanceKey, Telemetry.AnnotationKey.CompatibleSignatures, compatibleSignatures);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
VLog.W($"Failed to collect signature telemetry. Exception: {e}");
|
||||
}
|
||||
|
||||
|
||||
Telemetry.EndEvent(instanceKey, Telemetry.ResultType.Success);
|
||||
Statistics.SuccessfulGenerations++;
|
||||
Statistics.AddFrequencies(AssemblyMiner.SignatureFrequency);
|
||||
Statistics.AddIncompatibleFrequencies(AssemblyMiner.IncompatibleSignatureFrequency);
|
||||
var generationTime = endGenerationTime - startGenerationTime;
|
||||
var unityPath = fullPath.Replace(Application.dataPath, "Assets");
|
||||
AssetDatabase.ImportAsset(unityPath);
|
||||
ManifestAvailable = true;
|
||||
|
||||
var configName = configuration.name;
|
||||
var manifestName = Path.GetFileNameWithoutExtension(unityPath);
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
var configPath = AssetDatabase.GetAssetPath(configuration);
|
||||
configName = $"<a href=\"{configPath}\">{configName}</a>";
|
||||
manifestName = $"<a href=\"{unityPath}\">{manifestName}</a>";
|
||||
#endif
|
||||
VLog.D($"Conduit manifest generated\nConfiguration: {configName}\nManifest: {manifestName}\nGeneration Time: {generationTime.TotalMilliseconds} ms");
|
||||
|
||||
if (openManifest)
|
||||
{
|
||||
UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal(fullPath, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 440fa12149634e98aee13b1ef38d530a
|
||||
timeCreated: 1685991879
|
||||
@@ -0,0 +1,714 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Meta.WitAi.CallbackHandlers;
|
||||
using Meta.WitAi.Configuration;
|
||||
using Meta.WitAi.Data;
|
||||
using Meta.WitAi.Json;
|
||||
using Meta.WitAi.Requests;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Meta.WitAi.Windows
|
||||
{
|
||||
public class WitUnderstandingViewer : WitConfigurationWindow
|
||||
{
|
||||
[FormerlySerializedAs("witHeader")] [SerializeField] private Texture2D _witHeader;
|
||||
[FormerlySerializedAs("responseText")] [SerializeField] private string _responseText;
|
||||
private string _utterance;
|
||||
private WitResponseNode _response;
|
||||
private Dictionary<string, bool> _foldouts;
|
||||
|
||||
// Current service
|
||||
private VoiceService[] _services;
|
||||
private string[] _serviceNames;
|
||||
private int _currentService = -1;
|
||||
public VoiceService service => _services != null && _currentService >= 0 && _currentService < _services.Length ? _services[_currentService] : null;
|
||||
public bool HasWit => service != null;
|
||||
|
||||
private DateTime _submitStart;
|
||||
private TimeSpan _requestLength;
|
||||
private string _status;
|
||||
private int _responseCode;
|
||||
private VoiceServiceRequest _request;
|
||||
private int _savePopup;
|
||||
private GUIStyle _hamburgerButton;
|
||||
|
||||
private enum HamburgerMenu
|
||||
{
|
||||
None = -1,
|
||||
Save = 0,
|
||||
CopyToClipboard = 1,
|
||||
CopyRequestID = 2
|
||||
}
|
||||
|
||||
private string[] HambergerMenuStrings = new string[]
|
||||
{
|
||||
"Save", "Copy to Clipboard", "Copy Request ID"
|
||||
};
|
||||
|
||||
class Content
|
||||
{
|
||||
public static GUIContent CopyPath;
|
||||
public static GUIContent CopyCode;
|
||||
public static GUIContent CreateStringValue;
|
||||
public static GUIContent CreateIntValue;
|
||||
public static GUIContent CreateFloatValue;
|
||||
|
||||
static Content()
|
||||
{
|
||||
CreateStringValue = new GUIContent("Create Value Reference/Create String");
|
||||
CreateIntValue = new GUIContent("Create Value Reference/Create Int");
|
||||
CreateFloatValue = new GUIContent("Create Value Reference/Create Float");
|
||||
|
||||
CopyPath = new GUIContent("Copy Path to Clipboard");
|
||||
CopyCode = new GUIContent("Copy Code to Clipboard");
|
||||
}
|
||||
}
|
||||
|
||||
protected override GUIContent Title => WitTexts.UnderstandingTitleContent;
|
||||
protected override WitTexts.WitAppEndpointType HeaderEndpointType => WitTexts.WitAppEndpointType.Understanding;
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||
RefreshVoiceServices();
|
||||
if (!string.IsNullOrEmpty(_responseText))
|
||||
{
|
||||
_response = WitResponseNode.Parse(_responseText);
|
||||
}
|
||||
_status = WitTexts.Texts.UnderstandingViewerPromptLabel;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
|
||||
}
|
||||
|
||||
private void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||
{
|
||||
if (state == PlayModeStateChange.EnteredPlayMode && !HasWit)
|
||||
{
|
||||
RefreshVoiceServices();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSelectionChange()
|
||||
{
|
||||
if (Selection.activeGameObject)
|
||||
{
|
||||
SetVoiceService(Selection.activeGameObject.GetComponent<VoiceService>());
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetStartTime()
|
||||
{
|
||||
_submitStart = System.DateTime.Now;
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private void OnSend(VoiceServiceRequest request)
|
||||
{
|
||||
_request = request;
|
||||
ResetStartTime();
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private void ShowTranscription(string transcription)
|
||||
{
|
||||
_utterance = transcription;
|
||||
Repaint();
|
||||
}
|
||||
|
||||
// On gui
|
||||
protected override void OnGUI()
|
||||
{
|
||||
base.OnGUI();
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
WitEditorUI.LayoutStatusLabel(_status);
|
||||
GUILayout.BeginVertical(GUILayout.Width(24));
|
||||
GUILayout.Space(4);
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(4);
|
||||
var rect = GUILayoutUtility.GetLastRect();
|
||||
|
||||
if (null == _hamburgerButton)
|
||||
{
|
||||
// GUI.skin must be called from OnGUI
|
||||
_hamburgerButton = new GUIStyle(GUI.skin.GetStyle("PaneOptions"));
|
||||
_hamburgerButton.imagePosition = ImagePosition.ImageOnly;
|
||||
}
|
||||
|
||||
var value = (HamburgerMenu) EditorGUILayout.Popup(-1, HambergerMenuStrings, _hamburgerButton, GUILayout.Width(24));
|
||||
switch (value)
|
||||
{
|
||||
case HamburgerMenu.Save:
|
||||
{
|
||||
var path = EditorUtility.SaveFilePanel("Save Response Json", Application.dataPath,
|
||||
"result", "json");
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
File.WriteAllText(path, _response.ToString());
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case HamburgerMenu.CopyToClipboard:
|
||||
{
|
||||
EditorGUIUtility.systemCopyBuffer = _response?.ToString() ?? _responseText;
|
||||
break;
|
||||
}
|
||||
case HamburgerMenu.CopyRequestID:
|
||||
{
|
||||
var requestId = _request?.Options?.RequestId;
|
||||
if (!string.IsNullOrEmpty(requestId))
|
||||
{
|
||||
EditorGUIUtility.systemCopyBuffer = requestId;
|
||||
_status = $"{requestId} copied to clipboard.";
|
||||
}
|
||||
else
|
||||
{
|
||||
_status = "No request id to copy!";
|
||||
}
|
||||
Repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.EndVertical();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
protected override void LayoutContent()
|
||||
{
|
||||
// Get service
|
||||
VoiceService voiceService = null;
|
||||
|
||||
// Runtime Mode
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
// Refresh services
|
||||
if (_services == null)
|
||||
{
|
||||
RefreshVoiceServices();
|
||||
}
|
||||
// Services missing
|
||||
if (_services == null || _serviceNames == null || _services.Length == 0)
|
||||
{
|
||||
WitEditorUI.LayoutErrorLabel(WitTexts.Texts.UnderstandingViewerMissingServicesLabel);
|
||||
return;
|
||||
}
|
||||
// Voice service select
|
||||
int newService = _currentService;
|
||||
bool serviceUpdate = false;
|
||||
GUILayout.BeginHorizontal();
|
||||
// Clamp
|
||||
if (newService < 0 || newService >= _services.Length)
|
||||
{
|
||||
newService = 0;
|
||||
serviceUpdate = true;
|
||||
}
|
||||
// Layout
|
||||
WitEditorUI.LayoutPopup(WitTexts.Texts.UnderstandingViewerServicesLabel, _serviceNames, ref newService, ref serviceUpdate);
|
||||
// Update
|
||||
if (serviceUpdate)
|
||||
{
|
||||
SetVoiceService(newService);
|
||||
}
|
||||
// Select
|
||||
if (_currentService >= 0 && _currentService < _services.Length && WitEditorUI.LayoutTextButton(WitTexts.Texts.UnderstandingViewerSelectLabel))
|
||||
{
|
||||
Selection.activeObject = _services[_currentService];
|
||||
}
|
||||
// Refresh
|
||||
if (WitEditorUI.LayoutTextButton(WitTexts.Texts.ConfigurationRefreshButtonLabel))
|
||||
{
|
||||
RefreshVoiceServices();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
// Ensure service exists
|
||||
voiceService = service;
|
||||
}
|
||||
// Editor Only
|
||||
else
|
||||
{
|
||||
// Configuration select
|
||||
base.LayoutContent();
|
||||
// Ensure configuration exists
|
||||
if (!witConfiguration)
|
||||
{
|
||||
WitEditorUI.LayoutErrorLabel(WitTexts.Texts.UnderstandingViewerMissingConfigLabel);
|
||||
return;
|
||||
}
|
||||
// Check client access token
|
||||
string clientAccessToken = witConfiguration.GetClientAccessToken();
|
||||
if (string.IsNullOrEmpty(clientAccessToken))
|
||||
{
|
||||
WitEditorUI.LayoutErrorLabel(WitTexts.Texts.UnderstandingViewerMissingClientTokenLabel);
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
if (WitEditorUI.LayoutTextButton(WitTexts.Texts.UnderstandingViewerSettingsButtonLabel))
|
||||
{
|
||||
Selection.activeObject = witConfiguration;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if input is allowed
|
||||
bool allowInput = !Application.isPlaying || (service != null && !service.Active);
|
||||
GUI.enabled = allowInput;
|
||||
|
||||
// Utterance field
|
||||
bool updated = false;
|
||||
WitEditorUI.LayoutTextField(new GUIContent(WitTexts.Texts.UnderstandingViewerUtteranceLabel), ref _utterance, ref updated);
|
||||
|
||||
// Begin Buttons
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
// Submit utterance
|
||||
if (allowInput && WitEditorUI.LayoutTextButton(WitTexts.Texts.UnderstandingViewerSubmitButtonLabel))
|
||||
{
|
||||
_responseText = "";
|
||||
if (!string.IsNullOrEmpty(_utterance))
|
||||
{
|
||||
SubmitUtterance();
|
||||
}
|
||||
else
|
||||
{
|
||||
_response = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Service buttons
|
||||
GUI.enabled = true;
|
||||
if (EditorApplication.isPlaying && voiceService)
|
||||
{
|
||||
if (!voiceService.Active)
|
||||
{
|
||||
// Activate
|
||||
if (WitEditorUI.LayoutTextButton(WitTexts.Texts.UnderstandingViewerActivateButtonLabel))
|
||||
{
|
||||
_request = voiceService.Activate(new VoiceServiceRequestEvents());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Deactivate
|
||||
if (WitEditorUI.LayoutTextButton(WitTexts.Texts.UnderstandingViewerDeactivateButtonLabel))
|
||||
{
|
||||
voiceService.Deactivate();
|
||||
}
|
||||
// Abort
|
||||
if (WitEditorUI.LayoutTextButton(WitTexts.Texts.UnderstandingViewerAbortButtonLabel))
|
||||
{
|
||||
voiceService.DeactivateAndAbortRequest();
|
||||
}
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// Results
|
||||
GUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
if (_response != null)
|
||||
{
|
||||
DrawResponse();
|
||||
}
|
||||
else if (voiceService && voiceService.MicActive)
|
||||
{
|
||||
WitEditorUI.LayoutWrapLabel(WitTexts.Texts.UnderstandingViewerListeningLabel);
|
||||
}
|
||||
else if (voiceService && voiceService.IsRequestActive)
|
||||
{
|
||||
WitEditorUI.LayoutWrapLabel(WitTexts.Texts.UnderstandingViewerLoadingLabel);
|
||||
}
|
||||
else if (string.IsNullOrEmpty(_responseText))
|
||||
{
|
||||
WitEditorUI.LayoutWrapLabel(WitTexts.Texts.UnderstandingViewerPromptLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
WitEditorUI.LayoutWrapLabel(_responseText);
|
||||
}
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void SubmitUtterance()
|
||||
{
|
||||
// Remove response
|
||||
_response = null;
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
if (service)
|
||||
{
|
||||
_status = WitTexts.Texts.UnderstandingViewerListeningLabel;
|
||||
_responseText = _status;
|
||||
_request = service.Activate(_utterance, new VoiceServiceRequestEvents());
|
||||
// Hack to watch for loading to complete. Response does not
|
||||
// come back on the main thread so Repaint in onResponse in
|
||||
// the editor does nothing.
|
||||
EditorApplication.update += WatchForWitResponse;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_status = WitTexts.Texts.UnderstandingViewerLoadingLabel;
|
||||
_responseText = _status;
|
||||
_submitStart = System.DateTime.Now;
|
||||
_request = witConfiguration.CreateMessageRequest(new WitRequestOptions(), new VoiceServiceRequestEvents());
|
||||
_request.Options.Text = _utterance;
|
||||
_request.Events.OnSend.AddListener(OnSend);
|
||||
_request.Events.OnComplete.AddListener(OnComplete);
|
||||
_request.Send();
|
||||
}
|
||||
}
|
||||
|
||||
private void WatchForWitResponse()
|
||||
{
|
||||
if (service && !service.Active)
|
||||
{
|
||||
Repaint();
|
||||
EditorApplication.update -= WatchForWitResponse;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnComplete(VoiceServiceRequest request)
|
||||
{
|
||||
_responseCode = request.StatusCode;
|
||||
if (null != request.ResponseData)
|
||||
{
|
||||
ShowResponse(request.ResponseData, false);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(request.Results.Message))
|
||||
{
|
||||
_responseText = request.Results.Message;
|
||||
}
|
||||
else
|
||||
{
|
||||
_responseText = "No response. Status: " + request.StatusCode;
|
||||
}
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private void ShowResponse(WitResponseNode r, bool isPartial)
|
||||
{
|
||||
_response = r;
|
||||
_responseText = _response.ToString();
|
||||
_requestLength = DateTime.Now - _submitStart;
|
||||
_status = $"{(isPartial ? "Partial" : "Full")}Response time: {_requestLength}";
|
||||
}
|
||||
|
||||
private void DrawResponse()
|
||||
{
|
||||
DrawResponseNode(_response);
|
||||
}
|
||||
|
||||
private void DrawResponseNode(WitResponseNode witResponseNode, string path = "")
|
||||
{
|
||||
if (null == witResponseNode?.AsObject) return;
|
||||
|
||||
if(string.IsNullOrEmpty(path)) DrawNode(witResponseNode["text"], "text", path);
|
||||
|
||||
var names = witResponseNode.AsObject.ChildNodeNames;
|
||||
Array.Sort(names);
|
||||
foreach (string child in names)
|
||||
{
|
||||
if (!(string.IsNullOrEmpty(path) && child == "text"))
|
||||
{
|
||||
var childNode = witResponseNode[child];
|
||||
DrawNode(childNode, child, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawNode(WitResponseNode childNode, string child, string path, bool isArrayElement = false)
|
||||
{
|
||||
if (childNode == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
string childPath;
|
||||
|
||||
if (path.Length > 0)
|
||||
{
|
||||
childPath = isArrayElement ? $"{path}[{child}]" : $"{path}.{child}";
|
||||
}
|
||||
else
|
||||
{
|
||||
childPath = child;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(childNode.Value))
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(15 * EditorGUI.indentLevel);
|
||||
if (GUILayout.Button($"{child} = {childNode.Value}", WitStyles.LabelWrap))
|
||||
{
|
||||
ShowNodeMenu(childNode, childPath);
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
else
|
||||
{
|
||||
var childObject = childNode.AsObject;
|
||||
var childArray = childNode.AsArray;
|
||||
|
||||
if ((null != childObject || null != childArray) && Foldout(childPath, child))
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
if (null != childObject)
|
||||
{
|
||||
DrawResponseNode(childNode, childPath);
|
||||
}
|
||||
|
||||
if (null != childArray)
|
||||
{
|
||||
DrawArray(childArray, childPath);
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowNodeMenu(WitResponseNode node, string path)
|
||||
{
|
||||
GenericMenu menu = new GenericMenu();
|
||||
menu.AddItem(Content.CreateStringValue, false, () => WitDataCreation.CreateStringValue(path));
|
||||
menu.AddItem(Content.CreateIntValue, false, () => WitDataCreation.CreateIntValue(path));
|
||||
menu.AddItem(Content.CreateFloatValue, false, () => WitDataCreation.CreateFloatValue(path));
|
||||
menu.AddSeparator("");
|
||||
menu.AddItem(Content.CopyPath, false, () =>
|
||||
{
|
||||
EditorGUIUtility.systemCopyBuffer = path;
|
||||
});
|
||||
menu.AddItem(Content.CopyCode, false, () =>
|
||||
{
|
||||
EditorGUIUtility.systemCopyBuffer = WitResultUtilities.GetCodeFromPath(path);
|
||||
});
|
||||
|
||||
if (Selection.activeGameObject)
|
||||
{
|
||||
menu.AddSeparator("");
|
||||
|
||||
var label =
|
||||
new GUIContent($"Add response matcher to {Selection.activeObject.name}");
|
||||
|
||||
menu.AddItem(label, false, () =>
|
||||
{
|
||||
var valueHandler = Selection.activeGameObject.AddComponent<WitResponseMatcher>();
|
||||
valueHandler.intent = _response.GetIntentName();
|
||||
valueHandler.valueMatchers = new ValuePathMatcher[]
|
||||
{
|
||||
new ValuePathMatcher() { path = path }
|
||||
};
|
||||
});
|
||||
|
||||
AddMultiValueUpdateItems(path, menu);
|
||||
}
|
||||
|
||||
menu.ShowAsContext();
|
||||
}
|
||||
|
||||
private void AddMultiValueUpdateItems(string path, GenericMenu menu)
|
||||
{
|
||||
|
||||
string name = path;
|
||||
int index = path.LastIndexOf('.');
|
||||
if (index > 0)
|
||||
{
|
||||
name = name.Substring(index + 1);
|
||||
}
|
||||
|
||||
var mvhs = Selection.activeGameObject.GetComponents<WitResponseMatcher>();
|
||||
if (mvhs.Length > 1)
|
||||
{
|
||||
for (int i = 0; i < mvhs.Length; i++)
|
||||
{
|
||||
var handler = mvhs[i];
|
||||
menu.AddItem(
|
||||
new GUIContent($"Add {name} matcher to {Selection.activeGameObject.name}/Handler {(i + 1)}"),
|
||||
false, (h) => AddNewEventHandlerPath((WitResponseMatcher) h, path), handler);
|
||||
}
|
||||
}
|
||||
else if (mvhs.Length == 1)
|
||||
{
|
||||
var handler = mvhs[0];
|
||||
menu.AddItem(
|
||||
new GUIContent($"Add {name} matcher to {Selection.activeGameObject.name}'s Response Matcher"),
|
||||
false, (h) => AddNewEventHandlerPath((WitResponseMatcher) h, path), handler);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddNewEventHandlerPath(WitResponseMatcher handler, string path)
|
||||
{
|
||||
Array.Resize(ref handler.valueMatchers, handler.valueMatchers.Length + 1);
|
||||
handler.valueMatchers[handler.valueMatchers.Length - 1] = new ValuePathMatcher()
|
||||
{
|
||||
path = path
|
||||
};
|
||||
}
|
||||
|
||||
private void DrawArray(WitResponseArray childArray, string childPath)
|
||||
{
|
||||
for (int i = 0; i < childArray.Count; i++)
|
||||
{
|
||||
DrawNode(childArray[i], i.ToString(), childPath, true);
|
||||
}
|
||||
}
|
||||
|
||||
private bool Foldout(string path, string label)
|
||||
{
|
||||
if (null == _foldouts) _foldouts = new Dictionary<string, bool>();
|
||||
if (!_foldouts.TryGetValue(path, out var state))
|
||||
{
|
||||
state = false;
|
||||
_foldouts[path] = state;
|
||||
}
|
||||
|
||||
var newState = EditorGUILayout.Foldout(state, label);
|
||||
if (newState != state)
|
||||
{
|
||||
_foldouts[path] = newState;
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
#region SERVICES
|
||||
// Refresh voice services
|
||||
protected void RefreshVoiceServices()
|
||||
{
|
||||
// Remove previous service
|
||||
VoiceService previous = service;
|
||||
SetVoiceService(-1);
|
||||
|
||||
// Get all services
|
||||
VoiceService[] services = Resources.FindObjectsOfTypeAll<VoiceService>();
|
||||
|
||||
// Get unique services
|
||||
List<GameObject> serviceGOs = new List<GameObject>();
|
||||
List<VoiceService> serviceList = new List<VoiceService>();
|
||||
foreach (var s in services)
|
||||
{
|
||||
// Add unique gameobjects
|
||||
GameObject serviceGO = s.gameObject;
|
||||
if (serviceGO.scene.rootCount > 0 && !serviceGOs.Contains(serviceGO))
|
||||
{
|
||||
serviceGOs.Add(serviceGO);
|
||||
serviceList.Add(serviceGO.GetComponent<VoiceService>());
|
||||
}
|
||||
}
|
||||
|
||||
// Get service gameobject names
|
||||
_services = serviceList.ToArray();
|
||||
_serviceNames = new string[_services.Length];
|
||||
for (int i = 0; i < _services.Length; i++)
|
||||
{
|
||||
_serviceNames[i] = GetVoiceServiceName(_services[i]);
|
||||
}
|
||||
|
||||
// Set as first found
|
||||
if (previous == null)
|
||||
{
|
||||
SetVoiceService(0);
|
||||
}
|
||||
// Set as previous
|
||||
else
|
||||
{
|
||||
SetVoiceService(previous);
|
||||
}
|
||||
}
|
||||
// Get voice service name
|
||||
private string GetVoiceServiceName(VoiceService service)
|
||||
{
|
||||
IWitRuntimeConfigProvider configProvider = service.GetComponent<IWitRuntimeConfigProvider>();
|
||||
if (configProvider != null && configProvider.RuntimeConfiguration != null && configProvider.RuntimeConfiguration.witConfiguration != null)
|
||||
{
|
||||
return $"{configProvider.RuntimeConfiguration.witConfiguration.name} [{service.gameObject.name}]";
|
||||
}
|
||||
return service.gameObject.name;
|
||||
}
|
||||
// Set voice service
|
||||
protected void SetVoiceService(VoiceService newService)
|
||||
{
|
||||
// Cannot set without services
|
||||
if (_services == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Find & apply
|
||||
int newServiceIndex = Array.FindIndex(_services, (s) => s == newService);
|
||||
|
||||
// Apply
|
||||
SetVoiceService(newServiceIndex);
|
||||
}
|
||||
// Set
|
||||
protected void SetVoiceService(int newServiceIndex)
|
||||
{
|
||||
// Cannot set without services
|
||||
if (_services == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove listeners to current service
|
||||
RemoveVoiceListeners(service);
|
||||
|
||||
// Get current index
|
||||
_currentService = newServiceIndex;
|
||||
|
||||
// Add listeners to current service
|
||||
AddVoiceListeners(service);
|
||||
}
|
||||
// Add listeners
|
||||
private void AddVoiceListeners(VoiceService voiceService)
|
||||
{
|
||||
// Ignore
|
||||
if (voiceService == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Add delegates
|
||||
voiceService.VoiceEvents.OnSend.AddListener(OnSend);
|
||||
voiceService.VoiceEvents.OnComplete.AddListener(OnComplete);
|
||||
voiceService.VoiceEvents.OnPartialTranscription.AddListener(ShowTranscription);
|
||||
voiceService.VoiceEvents.OnFullTranscription.AddListener(ShowTranscription);
|
||||
voiceService.VoiceEvents.OnStoppedListening.AddListener(ResetStartTime);
|
||||
}
|
||||
// Remove listeners
|
||||
private void RemoveVoiceListeners(VoiceService voiceService)
|
||||
{
|
||||
// Ignore
|
||||
if (voiceService == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Remove delegates
|
||||
voiceService.VoiceEvents.OnSend.RemoveListener(OnSend);
|
||||
voiceService.VoiceEvents.OnComplete.RemoveListener(OnComplete);
|
||||
voiceService.VoiceEvents.OnFullTranscription.RemoveListener(ShowTranscription);
|
||||
voiceService.VoiceEvents.OnPartialTranscription.RemoveListener(ShowTranscription);
|
||||
voiceService.VoiceEvents.OnStoppedListening.RemoveListener(ResetStartTime);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18eb340e3f39b0a4f8f9e9749e97f9b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Meta.WitAi.Events;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Meta.WitAi.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// This class provides a common API for accessing properties and methods of the various *Service classes
|
||||
/// used in the Understanding Viewer. In order to add support for a new Service type, derive a child
|
||||
/// class from this one and provide implementations for the getter methods.
|
||||
/// </summary>
|
||||
public abstract class WitUnderstandingViewerServiceAPI
|
||||
{
|
||||
/// <summary>
|
||||
/// The base Component/Service class this object wraps.
|
||||
/// Child classes will provide a properly-cast reference to the component in their implementation.
|
||||
/// </summary>
|
||||
private MonoBehaviour _serviceComponent;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the service. Gotten once and cached for future use.
|
||||
/// Child classes may override the base implementation if necessary.
|
||||
/// </summary>
|
||||
private String _serviceName;
|
||||
|
||||
/// <summary>
|
||||
/// Flags to indicate whether or not the component supports voice and/or text activation.
|
||||
/// </summary>
|
||||
protected bool _hasVoiceActivation;
|
||||
protected bool _hasTextActivation;
|
||||
|
||||
/// <summary>
|
||||
/// This flag dictates whether or not the service should send a network request as part of its
|
||||
/// (de)activation handling.
|
||||
/// </summary>
|
||||
protected bool _shouldSubmitUtterance;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="serviceComponent">The Service Component (VoiceService, DictationService, etc.
|
||||
/// this API will wrap.</param>
|
||||
public WitUnderstandingViewerServiceAPI(MonoBehaviour serviceComponent)
|
||||
{
|
||||
_serviceComponent = serviceComponent;
|
||||
}
|
||||
|
||||
public MonoBehaviour ServiceComponent
|
||||
{
|
||||
get => _serviceComponent;
|
||||
}
|
||||
|
||||
public bool HasVoiceActivation
|
||||
{
|
||||
get => _hasVoiceActivation;
|
||||
}
|
||||
|
||||
public bool HasTextActivation
|
||||
{
|
||||
get => _hasTextActivation;
|
||||
}
|
||||
|
||||
public bool ShouldSubmitUtterance
|
||||
{
|
||||
get => _shouldSubmitUtterance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Most services have a common way of querying their service name. For those that don't,
|
||||
/// override this method. The name is cached after first query.
|
||||
/// </summary>
|
||||
public virtual string ServiceName {
|
||||
get
|
||||
{
|
||||
// Has the service name been cached to the local variable yet?
|
||||
if (_serviceName == null)
|
||||
{
|
||||
if (_serviceComponent == null)
|
||||
return "";
|
||||
|
||||
var configProvider = _serviceComponent.GetComponent<IWitRuntimeConfigProvider>();
|
||||
|
||||
if (configProvider != null)
|
||||
{
|
||||
// If no Witconfig is set for the component we get a NullPointerException here
|
||||
if (configProvider.RuntimeConfiguration.witConfiguration == null)
|
||||
{
|
||||
VLog.E($"No Wit configuration found for {_serviceComponent.gameObject.name}");
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
_serviceName =
|
||||
$"{configProvider.RuntimeConfiguration.witConfiguration.name} [{_serviceComponent.gameObject.name}]";
|
||||
}
|
||||
else
|
||||
{
|
||||
_serviceName = _serviceComponent.name;
|
||||
}
|
||||
}
|
||||
|
||||
return _serviceName;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract bool Active { get; }
|
||||
|
||||
public abstract bool MicActive { get; }
|
||||
|
||||
public abstract bool IsRequestActive { get; }
|
||||
|
||||
// API methods - override these to provide functionality
|
||||
public abstract void Activate();
|
||||
|
||||
public abstract void Activate(string text);
|
||||
|
||||
public abstract void Deactivate();
|
||||
|
||||
public abstract void DeactivateAndAbortRequest();
|
||||
|
||||
// Event Callback Registration
|
||||
public abstract VoiceServiceRequestEvent OnSend { get; }
|
||||
public abstract WitTranscriptionEvent OnPartialTranscription { get; }
|
||||
public abstract WitTranscriptionEvent OnFullTranscription { get; }
|
||||
public abstract UnityEvent OnStoppedListening { get; }
|
||||
public abstract VoiceServiceRequestEvent OnComplete { get; }
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b05455360ebd3644ebe86cbb40446615
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Meta.WitAi.Windows
|
||||
{
|
||||
public static class WitUnderstandingViewerServiceApiFactory
|
||||
{
|
||||
public delegate WitUnderstandingViewerServiceAPI Create(MonoBehaviour m);
|
||||
|
||||
private static Dictionary<string, Create> factoryMethods = new Dictionary<string, Create>();
|
||||
|
||||
public static void Register(string interfaceName, Create method)
|
||||
{
|
||||
factoryMethods.Add(interfaceName, method);
|
||||
}
|
||||
|
||||
public static WitUnderstandingViewerServiceAPI CreateWrapper(MonoBehaviour service)
|
||||
{
|
||||
foreach (var interfaceType in service.GetType().GetInterfaces())
|
||||
{
|
||||
if (factoryMethods.ContainsKey(interfaceType.Name))
|
||||
{
|
||||
return factoryMethods[interfaceType.Name](service);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fcd6b77ae500a7b43923e35d15cc5144
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Meta.WitAi.Events;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Meta.WitAi.Windows
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public class WitUnderstandingViewerVoiceServiceAPI : WitUnderstandingViewerServiceAPI
|
||||
{
|
||||
private VoiceService _service;
|
||||
|
||||
static WitUnderstandingViewerVoiceServiceAPI()
|
||||
{
|
||||
WitUnderstandingViewerServiceApiFactory.Register("IVoiceService", CreateApiWrapper);
|
||||
}
|
||||
|
||||
public WitUnderstandingViewerVoiceServiceAPI(VoiceService service) : base(service)
|
||||
{
|
||||
_service = service;
|
||||
|
||||
_hasVoiceActivation = true;
|
||||
_hasTextActivation = true;
|
||||
_shouldSubmitUtterance = true;
|
||||
}
|
||||
|
||||
public override bool Active
|
||||
{
|
||||
get => _service.Active;
|
||||
}
|
||||
|
||||
public override bool MicActive
|
||||
{
|
||||
get => _service.MicActive;
|
||||
}
|
||||
|
||||
public override bool IsRequestActive
|
||||
{
|
||||
get => _service.IsRequestActive;
|
||||
}
|
||||
|
||||
public override void Activate()
|
||||
{
|
||||
_service.Activate();
|
||||
}
|
||||
|
||||
public override void Activate(string text)
|
||||
{
|
||||
_service.Activate(text);
|
||||
}
|
||||
|
||||
public override void Deactivate()
|
||||
{
|
||||
_service.Deactivate();
|
||||
}
|
||||
|
||||
public override void DeactivateAndAbortRequest()
|
||||
{
|
||||
_service.DeactivateAndAbortRequest();
|
||||
}
|
||||
|
||||
public override VoiceServiceRequestEvent OnSend
|
||||
{
|
||||
get => _service.VoiceEvents.OnSend;
|
||||
}
|
||||
|
||||
public override WitTranscriptionEvent OnPartialTranscription
|
||||
{
|
||||
get => _service.VoiceEvents.OnPartialTranscription;
|
||||
}
|
||||
|
||||
public override WitTranscriptionEvent OnFullTranscription
|
||||
{
|
||||
get => _service.VoiceEvents.OnFullTranscription;
|
||||
}
|
||||
|
||||
public override UnityEvent OnStoppedListening
|
||||
{
|
||||
get => _service.VoiceEvents.OnStoppedListening;
|
||||
}
|
||||
|
||||
public override VoiceServiceRequestEvent OnComplete
|
||||
{
|
||||
get => _service.VoiceEvents.OnComplete;
|
||||
}
|
||||
|
||||
public static WitUnderstandingViewerServiceAPI CreateApiWrapper(MonoBehaviour service)
|
||||
{
|
||||
return new WitUnderstandingViewerVoiceServiceAPI((VoiceService)service);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd3a9e82a16233040a917414603b56f6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user