Initial Commit

This commit is contained in:
2025-07-04 20:33:06 +03:00
commit 8f09347ae0
9219 changed files with 2447903 additions and 0 deletions
@@ -0,0 +1,46 @@
/*
* 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.Data.Configuration;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.Windows
{
public abstract class BaseWitWindow : EditorWindow
{
// Scroll offset
private Vector2 ScrollOffset;
// Override values
protected abstract GUIContent Title { get; }
protected virtual Texture2D HeaderIcon => WitTexts.HeaderIcon;
protected virtual string HeaderUrl => WitTexts.WitUrl;
protected virtual string DocsUrl => WitTexts.Texts.WitDocsUrl;
// Window open
protected virtual void OnEnable()
{
titleContent = Title;
WitConfigurationUtility.ReloadConfigurationData();
}
// Window close
protected virtual void OnDisable()
{
ScrollOffset = Vector2.zero;
}
// Handle Layout
protected virtual void OnGUI()
{
Vector2 size;
WitEditorUI.LayoutWindow(Title.text, HeaderIcon, HeaderUrl, DocsUrl, LayoutContent, ref ScrollOffset, out size);
}
// Draw content of window
protected abstract void LayoutContent();
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: cb1fb949657a24a43bce2710d35ef1df
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- m_ViewDataDictionary: {instanceID: 0}
- witIcon: {fileID: 2800000, guid: d3b5ac4c8b01ef14a8a66d7e2a4991cc, type: 3}
- mainHeader: {fileID: 2800000, guid: 6a61dbb599169b64ca5584c8eebeb69e, type: 3}
- continueButton: {fileID: 2800000, guid: 2ed0be21c4a8bce4fadffab71d5b6e85, type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 26754a049aa53d445a323de4dcb955e3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,29 @@
/*
* 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 UnityEditor;
namespace Meta.WitAi.CallbackHandlers
{
[CustomEditor(typeof(SimpleIntentHandler))]
public class SimpleIntentHandlerEditor : WitIntentMatcherEditor
{
protected override void OnEnable()
{
base.OnEnable();
_fieldGUI.onAdditionalGuiLayout = OnInspectorAdditionalGUI;
}
private void OnInspectorAdditionalGUI()
{
EditorGUILayout.Space();
EditorGUILayout.LabelField("Output", EditorStyles.boldLabel);
var eventProperty = serializedObject.FindProperty("onIntentTriggered");
EditorGUILayout.PropertyField(eventProperty);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 10996c842bbaede43a73adef9cddba5a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,52 @@
/*
* 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.Linq;
using System.Reflection;
using Meta.WitAi.Data.Info;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.CallbackHandlers
{
[CustomEditor(typeof(SimpleStringEntityHandler))]
public class SimpleStringEntityHandlerEditor : WitIntentMatcherEditor
{
// Entity values
private string[] _entityNames;
private int _entityIndex;
// Set app info
protected override void SetAppInfo(WitAppInfo appInfo)
{
base.SetAppInfo(appInfo);
if (appInfo.entities != null)
{
_entityNames = appInfo.entities.Select(i => i.name).ToArray();
_entityIndex = Array.IndexOf(_entityNames, ((SimpleStringEntityHandler)_matcher).entity);
}
}
// Custom GUI
protected override bool OnInspectorCustomGUI(FieldInfo fieldInfo)
{
base.OnInspectorCustomGUI(fieldInfo);
// Custom layout
if (string.Equals(fieldInfo.Name, "entity"))
{
EditorGUILayout.Space();
EditorGUILayout.LabelField("Entity", EditorStyles.boldLabel);
WitEditorUI.LayoutSerializedObjectPopup(serializedObject, "entity",
_entityNames, ref _entityIndex);
return true;
}
// Layout intent triggered
return false;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a303e99a01d07d54e9659f3b46adbe25
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,248 @@
/*
* 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 Meta.WitAi.Data;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.CallbackHandlers
{
public class ValuePathMatcherPropertyDrawer : PropertyDrawer
{
private string currentEditPath;
class Properties
{
public const string witValueRef = "witValueReference";
public const string path = "path";
public const string contentRequired = "contentRequired";
public const string matchMethod = "matchMethod";
public const string comparisonMethod = "comparisonMethod";
public const string matchValue = "matchValue";
public const string floatingPointComparisonTolerance =
"floatingPointComparisonTolerance";
}
private Dictionary<string, bool> foldouts =
new Dictionary<string, bool>();
private string GetPropertyPath(SerializedProperty property)
{
var valueRefProp = property.FindPropertyRelative(Properties.witValueRef);
if (valueRefProp.objectReferenceValue)
{
return ((WitValue) valueRefProp.objectReferenceValue).path;
}
return property.FindPropertyRelative(Properties.path).stringValue;
}
private bool IsEditingProperty(SerializedProperty property)
{
var path = GetPropertyPath(property);
return path == currentEditPath || string.IsNullOrEmpty(path);
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
float height = 0;
// Path
height += EditorGUIUtility.singleLineHeight;
if (IsExpanded(property))
{
// Content Required
height += EditorGUIUtility.singleLineHeight;
// Match Method
height += EditorGUIUtility.singleLineHeight;
if (ComparisonMethodsVisible(property))
{
// Comparison Method
height += EditorGUIUtility.singleLineHeight;
}
if (ComparisonValueVisible(property))
{
// Comparison Value
height += EditorGUIUtility.singleLineHeight;
}
if (FloatingToleranceVisible(property))
{
// Floating Point Tolerance
height += EditorGUIUtility.singleLineHeight;
}
height += 4;
}
return height;
}
private bool IsExpanded(SerializedProperty property)
{
return foldouts.TryGetValue(GetPropertyPath(property), out bool value) && value;
}
private bool Foldout(Rect rect, SerializedProperty property)
{
var path = GetPropertyPath(property);
if (!foldouts.TryGetValue(path, out var value))
{
foldouts[path] = false;
}
foldouts[path] = EditorGUI.Foldout(rect, value, "");
return foldouts[path];
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var rect = new Rect(position)
{
height = EditorGUIUtility.singleLineHeight
};
var path = property.FindPropertyRelative(Properties.path);
var valueRefProp = property.FindPropertyRelative(Properties.witValueRef);
var editIconWidth = 24;
var pathRect = new Rect(rect);
pathRect.width -= editIconWidth;
var pathValue = GetPropertyPath(property);
if (IsEditingProperty(property))
{
if (!valueRefProp.objectReferenceValue)
{
pathRect.width -= WitStyles.IconButtonSize;
var value = EditorGUI.TextField(pathRect, path.stringValue);
if (value != path.stringValue)
{
path.stringValue = value;
}
pathRect.width += WitStyles.IconButtonSize;
var pickerRect = new Rect(pathRect)
{
x = pathRect.x + pathRect.width - 20,
width = 20
};
if (GUI.Button(pickerRect, WitStyles.ObjectPickerIcon, "Label"))
{
var id = EditorGUIUtility.GetControlID(FocusType.Passive) + 100;
EditorGUIUtility.ShowObjectPicker<WitValue>(
(WitValue) valueRefProp.objectReferenceValue, false, "", id);
}
}
else
{
EditorGUI.PropertyField(pathRect, valueRefProp, new GUIContent());
}
if (Event.current.commandName == "ObjectSelectorClosed")
{
valueRefProp.objectReferenceValue = EditorGUIUtility.GetObjectPickerObject();
}
pathValue = GetPropertyPath(property);
if (pathValue != currentEditPath && null != currentEditPath)
{
foldouts[currentEditPath] = false;
currentEditPath = GetPropertyPath(property);
foldouts[currentEditPath] = true;
}
}
else
{
if (valueRefProp.objectReferenceValue)
{
EditorGUI.LabelField(pathRect, valueRefProp.objectReferenceValue.name);
}
else
{
EditorGUI.LabelField(pathRect, path.stringValue);
}
}
var editRect = new Rect(rect)
{
x = pathRect.x + pathRect.width + 8
};
if (Foldout(rect, property))
{
if (GUI.Button(editRect, WitStyles.EditIcon, "Label"))
{
if (currentEditPath == pathValue)
{
currentEditPath = null;
}
else
{
currentEditPath = pathValue;
}
}
rect.x += WitStyles.IconButtonSize;
rect.width -= WitStyles.IconButtonSize;
rect.y += rect.height;
EditorGUI.PropertyField(rect, property.FindPropertyRelative(Properties.contentRequired));
rect.y += rect.height;
EditorGUI.PropertyField(rect, property.FindPropertyRelative(Properties.matchMethod));
if (ComparisonMethodsVisible(property))
{
rect.y += rect.height;
EditorGUI.PropertyField(rect,
property.FindPropertyRelative(Properties.comparisonMethod));
}
if (ComparisonValueVisible(property))
{
rect.y += rect.height;
EditorGUI.PropertyField(rect,
property.FindPropertyRelative(Properties.matchValue));
}
if (FloatingToleranceVisible(property))
{
rect.y += rect.height;
EditorGUI.PropertyField(rect,
property.FindPropertyRelative(Properties.floatingPointComparisonTolerance));
}
}
}
private bool ComparisonMethodsVisible(SerializedProperty property)
{
var matchedMethodProperty = property.FindPropertyRelative(Properties.matchMethod);
return matchedMethodProperty.enumValueIndex > (int) MatchMethod.RegularExpression;
}
private bool ComparisonValueVisible(SerializedProperty property)
{
var matchedMethodProperty = property.FindPropertyRelative(Properties.matchMethod);
return matchedMethodProperty.enumValueIndex > 0;
}
private bool FloatingToleranceVisible(SerializedProperty property)
{
var matchedMethodProperty = property.FindPropertyRelative(Properties.matchMethod);
var comparisonMethodProperty =
property.FindPropertyRelative(Properties.comparisonMethod);
var comparisonMethod = comparisonMethodProperty.enumValueIndex;
return matchedMethodProperty.enumValueIndex >= (int) MatchMethod.FloatComparison &&
(comparisonMethod == (int) ComparisonMethod.Equals || comparisonMethod == (int) ComparisonMethod.NotEquals);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 70c91e08d884bfe4a99b40d2706b15d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,90 @@
/*
* 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.Linq;
using System.Reflection;
using Meta.WitAi.Data.Info;
using Meta.WitAi.Windows;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.CallbackHandlers
{
public class WitIntentMatcherEditor : Editor
{
// The matcher
protected WitIntentMatcher _matcher;
// Custom field gui
protected FieldGUI _fieldGUI;
// Intents & current intent
private string[] _intentNames;
private int _intentIndex;
// On enable, setup gui
protected virtual void OnEnable()
{
_matcher = target as WitIntentMatcher;
// Setup field gui
if (_fieldGUI == null)
{
_fieldGUI = new FieldGUI();
_fieldGUI.onCustomGuiLayout = OnInspectorCustomGUI;
}
}
// Inspector gui
public override void OnInspectorGUI()
{
if (!_matcher.Voice)
{
GUILayout.Label("VoiceService component is not present in the scene. Add voice service to scene to get intent suggestions.",
EditorStyles.helpBox);
}
// Intent suggestions
if (_matcher && _matcher.Voice && null == _intentNames)
{
if (_matcher.Voice is IWitRuntimeConfigProvider provider
&& null != provider.RuntimeConfiguration
&& provider.RuntimeConfiguration.witConfiguration)
{
SetAppInfo(provider.RuntimeConfiguration.witConfiguration.GetApplicationInfo());
}
}
// Layout fields
_fieldGUI.OnGuiLayout(serializedObject);
}
// Set app info
protected virtual void SetAppInfo(WitAppInfo appInfo)
{
if (appInfo.intents != null)
{
_intentNames = appInfo.intents.Select(i => i.name).ToArray();
_intentIndex = Array.IndexOf(_intentNames, _matcher.intent);
}
}
// Custom GUI
protected virtual bool OnInspectorCustomGUI(FieldInfo fieldInfo)
{
// Custom layout
if (string.Equals(fieldInfo.Name, "intent"))
{
EditorGUILayout.Space();
EditorGUILayout.LabelField("Validation Settings", EditorStyles.boldLabel);
WitEditorUI.LayoutSerializedObjectPopup(serializedObject, "intent",
_intentNames, ref _intentIndex);
return true;
}
// Layout intent triggered
return false;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5ef9650649f4f6740a0b7d5b6b4e5dd2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 817d0e10131c4339849a5c99f8fb082b
timeCreated: 1624319154
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d192dfd6dc3ff0240b7171d81525428b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,14 @@
/*
* 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.
*/
namespace Meta.WitAi.Data.Configuration
{
public interface IApplicationDetailProvider
{
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7ed426c1b615d4b44a3c55c12850ce15
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8b74ce5059d44106941f1fcb6419a0e6
timeCreated: 1677872564
@@ -0,0 +1,30 @@
/*
* 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;
using Meta.WitAi.Data.Info;
namespace Meta.WitAi.Data.Configuration.Tabs
{
public class WitConfigurationApplicationTab : WitConfigurationEditorTab
{
public override Type DataType => null;
public override string TabID { get; } = "application";
public override int TabOrder { get; } = 0;
public override string TabLabel { get; } = WitTexts.Texts.ConfigurationApplicationTabLabel;
public override string MissingLabel { get; } = WitTexts.Texts.ConfigurationApplicationMissingLabel;
public override bool ShouldTabShow(WitAppInfo appInfo)
{
return true;
}
public override string GetPropertyName(string tabID)
{
return "_appInfo";
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bebd7edc23f2449f86d2b4c28582465c
timeCreated: 1677872642
@@ -0,0 +1,39 @@
/*
* 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.Text;
using Meta.WitAi.Data.Info;
using UnityEditor;
namespace Meta.WitAi.Data.Configuration.Tabs
{
public abstract class WitConfigurationEditorTab
{
// the WitConfigurationData type relevant to this tab
public abstract Type DataType { get; }
public abstract string TabID { get; }
public abstract int TabOrder { get; }
public abstract string TabLabel { get; }
public abstract string MissingLabel { get; }
public abstract bool ShouldTabShow(WitAppInfo appInfo);
public virtual bool ShouldTabShow(WitConfiguration configuration) { return false; }
public virtual string GetPropertyName(string tabID)
{
StringBuilder sb = new StringBuilder();
sb.Append("_appInfo");
sb.Append($".{TabID}");
return sb.ToString();
}
public virtual string GetTabText(bool titleLabel)
{
return titleLabel ? TabLabel : MissingLabel;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6dedb23257484140becc3ef2e04f3bc1
timeCreated: 1677855364
@@ -0,0 +1,27 @@
/*
* 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;
using Meta.WitAi.Data.Info;
namespace Meta.WitAi.Data.Configuration.Tabs
{
public class WitConfigurationEntitiesTab: WitConfigurationEditorTab
{
public override int TabOrder { get; } = 2;
public override Type DataType => null;
public override string TabID { get; } = "entities";
public override string TabLabel { get; } = WitTexts.Texts.ConfigurationEntitiesTabLabel;
public override string MissingLabel { get; } = WitTexts.Texts.ConfigurationEntitiesMissingLabel;
public override bool ShouldTabShow(WitAppInfo appInfo)
{
return null != appInfo.entities;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5bd06d8523c94460b26f1228c2efd3e8
timeCreated: 1677872927
@@ -0,0 +1,26 @@
/*
* 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;
using Meta.WitAi.Data.Info;
namespace Meta.WitAi.Data.Configuration.Tabs
{
public class WitConfigurationIntentsTab : WitConfigurationEditorTab
{
public override Type DataType => null;
public override int TabOrder { get; } = 1;
public override string TabID { get; } = "intents";
public override string TabLabel { get; } = WitTexts.Texts.ConfigurationIntentsTabLabel;
public override string MissingLabel { get; } = WitTexts.Texts.ConfigurationIntentsMissingLabel;
public override bool ShouldTabShow(WitAppInfo appInfo)
{
return null != appInfo.intents;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c693b199fe184d9fb432dd65a4b47bee
timeCreated: 1677872672
@@ -0,0 +1,26 @@
/*
* 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;
using Meta.WitAi.Data.Info;
namespace Meta.WitAi.Data.Configuration.Tabs
{
public class WitConfigurationTraitsTab : WitConfigurationEditorTab
{
public override Type DataType => null;
public override int TabOrder { get; } = 3;
public override string TabID { get; } = "traits";
public override string TabLabel { get; } = WitTexts.Texts.ConfigurationTraitsTabLabel;
public override string MissingLabel { get; } = WitTexts.Texts.ConfigurationTraitsMissingLabel;
public override bool ShouldTabShow(WitAppInfo appInfo)
{
return null != appInfo.traits;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e918e26b57b74f01af337608e8d9a531
timeCreated: 1677872967
@@ -0,0 +1,26 @@
/*
* 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;
using Meta.WitAi.Data.Info;
namespace Meta.WitAi.Data.Configuration.Tabs
{
public class WitConfigurationVoicesTab: WitConfigurationEditorTab
{
public override Type DataType => null;
public override int TabOrder { get; } = 4;
public override string TabID { get; } = "voices";
public override string TabLabel { get; } = WitTexts.Texts.ConfigurationVoicesTabLabel;
public override string MissingLabel { get; } = WitTexts.Texts.ConfigurationVoicesMissingLabel;
public override bool ShouldTabShow(WitAppInfo appInfo)
{
return null != appInfo.voices;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d61288c0131e4c43bf0bce4d39f9d829
timeCreated: 1677869703
@@ -0,0 +1,14 @@
/*
* 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.
*/
namespace Meta.WitAi.Data.Configuration
{
public class WitApplicationDetailProvider : IApplicationDetailProvider
{
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 394d4d63ba17f4ed5918eccdd3b7059f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,631 @@
/*
* 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.Linq;
using Meta.WitAi.Data.Configuration.Tabs;
using Lib.Wit.Runtime.Requests;
using Meta.Conduit.Editor;
using Meta.WitAi.Configuration;
using Meta.WitAi.Data.Configuration;
using Meta.Conduit;
using Meta.Voice.TelemetryUtilities;
using Meta.WitAi.Lib;
using UnityEditor;
using UnityEngine;
using Meta.WitAi.Windows.Components;
namespace Meta.WitAi.Windows
{
[InitializeOnLoadAttribute]
public class WitConfigurationEditor : Editor
{
private ConduitManifestGenerationManager _conduitManifestGenerationManager;
public WitConfiguration Configuration {
get => _configuration;
private set
{
if (_configuration == value)
{
return;
}
_configuration = value;
_conduitManifestGenerationManager = ConduitManifestGenerationManager.GetInstance(_configuration);
}
}
private WitConfiguration _configuration;
private string _serverToken;
private string _appName;
private string _appID;
private bool _initialized = false;
public bool drawHeader = true;
private bool _foldout = true;
private int _requestTab = 0;
private bool _syncInProgress = false;
private bool _didCheckAutoTrainAvailability = false;
private bool _isAutoTrainAvailable = false;
/// <summary>
/// Whether or not server specific functionality like sync
/// should be disabled for this configuration
/// </summary>
protected virtual bool _disableServerPost => false;
private static readonly ManifestLoader ManifestLoader = new ManifestLoader();
private static readonly IWitVRequestFactory VRequestFactory = new WitVRequestFactory();
private EnumSynchronizer _enumSynchronizer;
private static Type[] _tabTypes;
private WitConfigurationEditorTab[] _tabs;
private const string ENTITY_SYNC_CONSENT_KEY = "Conduit.EntitySync.Consent";
protected virtual Texture2D HeaderIcon => WitTexts.HeaderIcon;
public virtual string HeaderUrl => WitTexts.GetAppURL(Configuration.GetApplicationId(), WitTexts.WitAppEndpointType.Settings);
protected virtual string DocsUrl => WitTexts.Texts.WitDocsUrl;
protected virtual string OpenButtonLabel => WitTexts.Texts.WitOpenButtonLabel;
public void Initialize()
{
// Shared between all WitConfigurationEditors
if (_tabTypes == null)
{
_tabTypes = typeof(WitConfigurationEditorTab).GetSubclassTypes().ToArray();
}
// Generate tab instances
if (_tabs == null)
{
_tabs = _tabTypes.Select(type => (WitConfigurationEditorTab)Activator.CreateInstance(type))
.OrderBy(tab =>tab.TabOrder)
.ToArray();
}
// Refresh configuration & auth tokens
Configuration = target as WitConfiguration;
// Get app server token
_serverToken = WitAuthUtility.GetAppServerToken(Configuration);
if (CanConfigurationRefresh(Configuration) && WitConfigurationUtility.IsServerTokenValid(_serverToken))
{
// Get client token if needed
_appID = Configuration.GetApplicationId();
if (string.IsNullOrEmpty(_appID))
{
Configuration.SetServerToken(_serverToken);
}
// Refresh additional data
else
{
SafeRefresh();
}
}
}
public void OnDisable()
{
ConduitManifestGenerationManager.PersistStatistics();
}
public override void OnInspectorGUI()
{
// Init if needed
if (!_initialized || Configuration != target)
{
Initialize();
_initialized = true;
}
// Draw header
WitEditorUI.LayoutHeaderText(target.name, HeaderUrl, DocsUrl);
// Layout content
LayoutContent();
}
private void LayoutConduitContent()
{
if (_conduitManifestGenerationManager == null)
{
_conduitManifestGenerationManager = ConduitManifestGenerationManager.GetInstance(Configuration);
}
var isServerTokenValid = WitConfigurationUtility.IsServerTokenValid(_serverToken);
if (!isServerTokenValid && !_disableServerPost)
{
GUILayout.TextArea(WitTexts.Texts.ConfigurationConduitMissingTokenLabel, WitStyles.LabelError);
}
EditorGUI.indentLevel++;
// Set conduit
var updated = false;
WitEditorUI.LayoutToggle(new GUIContent(WitTexts.Texts.ConfigurationConduitUseConduitLabel), ref Configuration.useConduit, ref updated);
if (updated)
{
EditorUtility.SetDirty(Configuration);
}
// Configuration buttons
GUILayout.Space(EditorGUI.indentLevel * WitStyles.ButtonMargin);
{
GUI.enabled = Configuration.useConduit;
updated = false;
WitEditorUI.LayoutToggle(
new GUIContent(WitTexts.Texts.ConfigurationConduitRelaxedResolutionsLabel,
WitTexts.Texts.ConfigurationConduitRelaxedResolutionsTooltip),
ref Configuration.relaxedResolution, ref updated);
if (updated)
{
EditorUtility.SetDirty(Configuration);
}
GUILayout.BeginHorizontal();
{
if (_conduitManifestGenerationManager != null && WitEditorUI.LayoutTextButton(_conduitManifestGenerationManager.ManifestAvailable ? WitTexts.Texts.ConfigurationConduitUpdateManifestLabel : WitTexts.Texts.ConfigurationConduitGenerateManifestLabel))
{
_conduitManifestGenerationManager.GenerateManifest(Configuration, true);
}
GUI.enabled = Configuration.useConduit && _conduitManifestGenerationManager.ManifestAvailable ;
if (WitEditorUI.LayoutTextButton(WitTexts.Texts.ConfigurationConduitSelectManifestLabel) && _conduitManifestGenerationManager.ManifestAvailable )
{
Selection.activeObject =
AssetDatabase.LoadAssetAtPath<TextAsset>(Configuration.GetManifestEditorPath());
}
GUI.enabled = Configuration.useConduit;
if (WitEditorUI.LayoutTextButton(WitTexts.Texts.ConfigurationConduitSpecifyAssembliesLabel))
{
PresentAssemblySelectionDialog();
}
if (isServerTokenValid && !_disableServerPost)
{
GUI.enabled = Configuration.useConduit && _conduitManifestGenerationManager.ManifestAvailable && !_syncInProgress;
if (WitEditorUI.LayoutTextButton(WitTexts.Texts.ConfigurationConduitSyncEntitiesLabel))
{
SyncEntities();
GUIUtility.ExitGUI();
return;
}
if (_isAutoTrainAvailable)
{
if (WitEditorUI.LayoutTextButton(WitTexts.Texts.ConfigurationConduitAutoTrainLabel) && _conduitManifestGenerationManager.ManifestAvailable )
{
SyncEntities(() => { AutoTrainOnWitAi(Configuration); });
}
}
}
GUI.enabled = true;
}
GUILayout.EndHorizontal();
}
EditorGUI.indentLevel--;
}
protected virtual void LayoutContent()
{
// Begin vertical box
GUILayout.BeginVertical(EditorStyles.helpBox);
// Check for app name/id update
ReloadAppData();
// Title Foldout
GUILayout.BeginHorizontal();
string foldoutText = WitTexts.Texts.ConfigurationHeaderLabel;
if (!string.IsNullOrEmpty(_appName))
{
foldoutText = foldoutText + " - " + _appName;
}
_foldout = WitEditorUI.LayoutFoldout(new GUIContent(foldoutText), _foldout);
// Refresh button
if (CanConfigurationRefresh(Configuration))
{
if (string.IsNullOrEmpty(_appName))
{
bool isValid = WitConfigurationUtility.IsServerTokenValid(_serverToken);
GUI.enabled = isValid;
if (WitEditorUI.LayoutTextButton(WitTexts.Texts.ConfigurationRefreshButtonLabel))
{
ApplyServerToken(_serverToken);
}
}
else
{
bool isRefreshing = Configuration.IsUpdatingData();
GUI.enabled = !isRefreshing;
if (WitEditorUI.LayoutTextButton(isRefreshing ? WitTexts.Texts.ConfigurationRefreshingButtonLabel : WitTexts.Texts.ConfigurationRefreshButtonLabel))
{
SafeRefresh();
}
}
}
GUI.enabled = true;
GUILayout.EndHorizontal();
GUILayout.Space(WitStyles.ButtonMargin);
// Show configuration app data
if (_foldout)
{
// Indent
EditorGUI.indentLevel++;
// Server access token
bool updated = false;
WitEditorUI.LayoutPasswordField(WitTexts.ConfigurationServerTokenContent, ref _serverToken, ref updated);
if (updated && WitConfigurationUtility.IsServerTokenValid(_serverToken))
{
ApplyServerToken(_serverToken);
}
// Additional data
if (Configuration)
{
LayoutConfigurationData();
}
// Undent
EditorGUI.indentLevel--;
}
// End vertical box layout
GUILayout.EndVertical();
GUILayout.BeginVertical(EditorStyles.helpBox);
LayoutConduitContent();
GUILayout.EndVertical();
// Layout configuration request tabs
LayoutConfigurationRequestTabs();
// Additional open wit button
GUILayout.FlexibleSpace();
if (GUILayout.Button(OpenButtonLabel, WitStyles.TextButton))
{
Application.OpenURL(HeaderUrl);
}
}
// Reload app data if needed
private void ReloadAppData()
{
// Check for changes
string checkID = "";
string checkName = "";
if (Configuration != null)
{
checkID = Configuration.GetApplicationId();
if (!string.IsNullOrEmpty(checkID))
{
checkName = Configuration.GetApplicationInfo().name;
}
}
// Reset
if (!string.Equals(_appName, checkName) || !string.Equals(_appID, checkID))
{
// Refresh app data
_appName = checkName;
_appID = checkID;
// Do not clear token if failed to set
string newToken = WitAuthUtility.GetAppServerToken(Configuration);
if (!string.IsNullOrEmpty(newToken))
{
_serverToken = newToken;
}
}
}
// Apply server token
public void ApplyServerToken(string newToken)
{
if (newToken != _serverToken)
{
_serverToken = newToken;
Configuration.ResetData();
}
WitAuthUtility.ServerToken = _serverToken;
Configuration.SetServerToken(_serverToken);
_conduitManifestGenerationManager.GenerateManifest(Configuration, false);
}
// Whether or not to allow a configuration to refresh
protected virtual bool CanConfigurationRefresh(WitConfiguration configuration)
{
return configuration;
}
// Layout configuration data
protected virtual void LayoutConfigurationData()
{
// Reset update
bool updated = false;
// Client access field
string clientAccessToken = Configuration.GetClientAccessToken();
WitEditorUI.LayoutPasswordField(WitTexts.ConfigurationClientTokenContent, ref clientAccessToken, ref updated);
if (updated && string.IsNullOrEmpty(clientAccessToken))
{
VLog.E("Client access token is not defined. Cannot perform requests with '" + Configuration.name + "'.");
}
// Timeout field
WitEditorUI.LayoutIntField(WitTexts.ConfigurationRequestTimeoutContent, ref Configuration.timeoutMS, ref updated);
// Updated
if (updated)
{
Configuration.SetClientAccessToken(clientAccessToken);
}
// Show configuration app data
LayoutConfigurationEndpoint();
}
// Layout endpoint data
protected virtual void LayoutConfigurationEndpoint()
{
// Generate if needed
if (Configuration.endpointConfiguration == null)
{
Configuration.endpointConfiguration = new WitEndpointConfig();
EditorUtility.SetDirty(Configuration);
}
// Handle via serialized object
var serializedObj = new SerializedObject(Configuration);
var serializedProp = serializedObj.FindProperty("endpointConfiguration");
EditorGUILayout.PropertyField(serializedProp);
serializedObj.ApplyModifiedProperties();
}
// Tabs
protected virtual void LayoutConfigurationRequestTabs()
{
// Application info
Data.Info.WitAppInfo appInfo = Configuration.GetApplicationInfo();
// Indent
EditorGUI.indentLevel++;
// Iterate tabs
if (_tabs != null)
{
GUILayout.BeginHorizontal();
for (int i = 0; i < _tabs.Length; i++)
{
// Enable if not selected
GUI.enabled = _requestTab != i;
// If valid and clicked, begin selecting
if (null != appInfo.id &&
(_tabs[i].ShouldTabShow(appInfo) || _tabs[i].ShouldTabShow(Configuration)))
{
if (WitEditorUI.LayoutTabButton(_tabs[i].GetTabText(true)))
{
_requestTab = i;
}
}
// If invalid, stop selecting
else if (_requestTab == i)
{
_requestTab = -1;
}
}
GUI.enabled = true;
GUILayout.EndHorizontal();
// Layout selected tab using property id
string propertyID = _requestTab >= 0 && _requestTab < _tabs.Length
? _tabs[_requestTab].TabID
: string.Empty;
if (!string.IsNullOrEmpty(propertyID) && Configuration != null)
{
var newConfigData = Array.Find(Configuration.GetConfigData(), d => d.GetType() == _tabs[_requestTab].DataType);
SerializedObject serializedObj;
if (newConfigData == null)
{
serializedObj = new SerializedObject(Configuration);
}
else
{
serializedObj = new SerializedObject(newConfigData);
}
SerializedProperty serializedProp = serializedObj.FindProperty(_tabs[_requestTab].GetPropertyName(propertyID));
if (serializedProp == null)
{
WitEditorUI.LayoutErrorLabel(_tabs[_requestTab].GetTabText(false));
}
else if (!serializedProp.isArray)
{
EditorGUILayout.PropertyField(serializedProp);
}
else if (serializedProp.arraySize == 0)
{
WitEditorUI.LayoutErrorLabel(_tabs[_requestTab].GetTabText(false));
}
else
{
for (int i = 0; i < serializedProp.arraySize; i++)
{
SerializedProperty serializedPropChild = serializedProp.GetArrayElementAtIndex(i);
EditorGUILayout.PropertyField(serializedPropChild);
}
}
serializedObj.ApplyModifiedProperties();
}
}
// Undent
EditorGUI.indentLevel--;
}
// Safe refresh
protected virtual void SafeRefresh()
{
if (EditorApplication.isPlayingOrWillChangePlaymode) return;
if (WitConfigurationUtility.IsServerTokenValid(_serverToken))
{
Configuration.SetServerToken(_serverToken);
Configuration.UpdateDataAssets();
}
else if (WitConfigurationUtility.IsClientTokenValid(Configuration.GetClientAccessToken()))
{
Configuration.RefreshAppInfo();
Configuration.UpdateDataAssets();
}
if (Configuration.useConduit)
{
CheckAutoTrainAvailabilityIfNeeded();
}
}
private void CheckAutoTrainAvailabilityIfNeeded()
{
if (_didCheckAutoTrainAvailability || !WitConfigurationUtility.IsServerTokenValid(_serverToken)) {
return;
}
_didCheckAutoTrainAvailability = true;
CheckAutoTrainIsAvailable(Configuration, (isAvailable) => {
_isAutoTrainAvailable = isAvailable;
Telemetry.LogInstantEvent(Telemetry.TelemetryEventId.CheckAutoTrain, new Dictionary<Telemetry.AnnotationKey, string>
{
{ Telemetry.AnnotationKey.IsAvailable, isAvailable.ToString() }
});
});
}
// Show dialog to disable/enable assemblies
private void PresentAssemblySelectionDialog()
{
var assemblyWalker = _conduitManifestGenerationManager.AssemblyWalker;
var assemblyNames = assemblyWalker.GetAllAssemblies().Select(a => a.FullName).ToList();
assemblyWalker.AssembliesToIgnore = new HashSet<string>(Configuration.excludedAssemblies);
WitMultiSelectionPopup.Show(assemblyNames, assemblyWalker.AssembliesToIgnore, (disabledAssemblies) => {
assemblyWalker.AssembliesToIgnore = new HashSet<string>(disabledAssemblies);
Configuration.excludedAssemblies = new List<string>(assemblyWalker.AssembliesToIgnore);
_conduitManifestGenerationManager.GenerateManifest(Configuration, false);
});
}
// Sync entities
private void SyncEntities(Action successCallback = null)
{
var instanceKey = Telemetry.StartEvent(Telemetry.TelemetryEventId.SyncEntities);
if (!EditorUtility.DisplayDialog("Synchronizing with Wit.Ai entities", "This will synchronize local enums with Wit.Ai entities. Part of this process involves generating code locally and may result in overwriting existing code. Please make sure to backup your work before proceeding.", "Proceed", "Cancel", DialogOptOutDecisionType.ForThisSession, ENTITY_SYNC_CONSENT_KEY))
{
Telemetry.EndEvent(instanceKey, Telemetry.ResultType.Cancel);
VLog.D("Entity Sync cancelled");
return;
}
// Fail without server token
var validServerToken = WitConfigurationUtility.IsServerTokenValid(_serverToken);
if (!validServerToken)
{
Telemetry.EndEventWithFailure(instanceKey, "Invalid server token");
VLog.E($"Conduit Sync Failed\nError: Invalid server token");
return;
}
// Generate
if (_enumSynchronizer == null)
{
var assemblyWalker = _conduitManifestGenerationManager.AssemblyWalker;
_enumSynchronizer = new EnumSynchronizer(Configuration, assemblyWalker, new FileIo(), VRequestFactory);
}
// Sync
_syncInProgress = true;
EditorUtility.DisplayProgressBar("Conduit Entity Sync", "Generating Manifest.", 0f );
_conduitManifestGenerationManager.GenerateManifest(Configuration, false);
var manifest = LoadManifest(Configuration.ManifestLocalPath);
const float initializationProgress = 0.1f;
EditorUtility.DisplayProgressBar("Conduit Entity Sync", "Synchronizing entities. Please wait...", initializationProgress);
VLog.D("Synchronizing enums with Wit.Ai entities");
CoroutineUtility.StartCoroutine(_enumSynchronizer.SyncWitEntities(manifest, (success, data) =>
{
_syncInProgress = false;
EditorUtility.ClearProgressBar();
if (!success)
{
Telemetry.EndEventWithFailure(instanceKey, data);
VLog.E($"Conduit failed to synchronize entities\nError: {data}");
}
else
{
Telemetry.EndEvent(instanceKey, Telemetry.ResultType.Success);
VLog.D("Conduit successfully synchronized entities");
successCallback?.Invoke();
}
},
(status, progress) =>
{
EditorUtility.DisplayProgressBar("Conduit Entity Sync", status,
initializationProgress + (1f - initializationProgress) * progress);
}));
}
private void AutoTrainOnWitAi(WitConfiguration configuration)
{
var instanceKey = Telemetry.StartEvent(Telemetry.TelemetryEventId.AutoTrain);
var manifest = LoadManifest(configuration.ManifestLocalPath);
var intents = _conduitManifestGenerationManager.ExtractManifestData();
VLog.D($"Auto training on WIT.ai: {intents.Count} intents.");
configuration.ImportData(manifest, (isSuccess, error) =>
{
if (isSuccess)
{
Telemetry.EndEvent(instanceKey, Telemetry.ResultType.Success);
EditorUtility.DisplayDialog("Auto Train", "Successfully started auto train process on WIT.ai.",
"OK");
}
else
{
var failureMessage =
$"Failed to import generated manifest JSON into WIT.ai: {error}. Manifest:\n{manifest}";
Telemetry.EndEventWithFailure(instanceKey, failureMessage);
VLog.E(failureMessage);
EditorUtility.DisplayDialog("Auto Train", "Failed to start auto train process on WIT.ai.", "OK");
}
});
}
private void CheckAutoTrainIsAvailable(WitConfiguration configuration, Action<bool> onComplete)
{
var appInfo = configuration.GetApplicationInfo();
var manifestText = _conduitManifestGenerationManager.GenerateEmptyManifest(appInfo.name, appInfo.id);
var manifest = ManifestLoader.LoadManifestFromString(manifestText);
configuration.ImportData(manifest, (result, error) => onComplete(result), true);
}
private static Manifest LoadManifest(string manifestPath)
{
var instanceKey = Telemetry.StartEvent(Telemetry.TelemetryEventId.LoadManifest);
var manifest = ManifestLoader.LoadManifest(manifestPath);
if (manifest == null)
{
Telemetry.EndEventWithFailure(instanceKey);
}
Telemetry.EndEvent(instanceKey, Telemetry.ResultType.Success);
return manifest;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fda2e192978913c42af9533c9a0baa01
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,21 @@
/*
* 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 UnityEditor;
namespace Meta.WitAi.Data.Configuration
{
public class WitConfigurationPostprocessor : AssetPostprocessor
{
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets,
string[] movedFromAssetPaths)
{
WitConfigurationUtility.NeedsConfigReload();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 16fe7d4f8f3e51a42ab214947550a298
timeCreated: 1631316958
@@ -0,0 +1,391 @@
/*
* 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.
*/
#if UNITY_EDITOR
//#define VERBOSE_LOG
#endif
using System;
using System.Collections.Generic;
using Meta.Conduit;
using Meta.Voice.TelemetryUtilities;
using Meta.WitAi.Json;
using UnityEditor;
using UnityEngine;
using Meta.WitAi.Lib;
using Meta.WitAi.Requests;
using Meta.WitAi.Windows;
using Meta.WitAi.Interfaces;
using UnityEngine.SceneManagement;
namespace Meta.WitAi.Data.Configuration
{
public static class WitConfigurationUtility
{
#region ACCESS
// Return wit configs
public static WitConfiguration[] WitConfigs
{
get
{
// Reload if not setup
if (_witConfigs == null)
{
ReloadConfigurationData();
}
// Force reload
if (_needsConfigReload)
{
ReloadConfigurationData();
}
// Return config data
return _witConfigs;
}
}
// Wit configuration assets
private static WitConfiguration[] _witConfigs = null;
// Wit configuration asset names
public static string[] WitConfigNames => _witConfigNames;
private static string[] _witConfigNames = Array.Empty<string>();
// Config reload
private static bool _needsConfigReload = false;
// Has configuration
public static bool HasValidCustomConfig()
{
// Find a valid custom configuration
return Array.Exists(WitConfigs, (c) => !c.isDemoOnly);
}
// Enable config reload on next access
public static void NeedsConfigReload()
{
_needsConfigReload = true;
}
// Refresh configuration asset list
public static void ReloadConfigurationData()
{
// Reloaded
_needsConfigReload = false;
// Find all Wit Configurations
List<WitConfiguration> loaded = GetLoadedConfigurations();
List<WitConfiguration> found = new List<WitConfiguration>();
string[] guids = AssetDatabase.FindAssets("t:WitConfiguration");
foreach (var guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
WitConfiguration config = AssetDatabase.LoadAssetAtPath<WitConfiguration>(path);
if (!config.isDemoOnly || loaded.Contains(config))
{
found.Add(config);
}
}
// Store wit configuration data
_witConfigs = found.ToArray();
// Obtain all names
_witConfigNames = new string[_witConfigs.Length];
for (int i = 0; i < _witConfigs.Length; i++)
{
_witConfigNames[i] = _witConfigs[i].name;
}
}
// Get configuration index
public static int GetConfigurationIndex(WitConfiguration configuration)
{
// Search through configs
return Array.FindIndex(WitConfigs, (checkConfig) => checkConfig == configuration );
}
// Get configuration index
public static int GetConfigurationIndex(string configurationName)
{
// Search through configs
return Array.FindIndex(WitConfigs, (checkConfig) => string.Equals(checkConfig.name, configurationName));
}
// Return all configurations referenced in loaded scenes
public static List<WitConfiguration> GetLoadedConfigurations()
{
// Get results
List<WitConfiguration> results = new List<WitConfiguration>();
// Iterate loaded scenes
for (int sceneIndex = 0; sceneIndex < SceneManager.sceneCount; sceneIndex++)
{
Scene scene = SceneManager.GetSceneAt(sceneIndex);
if (!scene.IsValid() || !scene.isLoaded)
{
continue;
}
foreach (var rootGameObject in scene.GetRootGameObjects())
{
IWitConfigurationProvider[] providers = rootGameObject.GetComponentsInChildren<IWitConfigurationProvider>(true);
if (providers != null)
{
foreach (var provider in providers)
{
WitConfiguration config = provider.Configuration;
if (config != null && !results.Contains(config))
{
results.Add(config);
}
}
}
}
}
// Return results list
return results;
}
#endregion
#region MANAGEMENT
// Create configuration for token with blank configuration
public static int CreateConfiguration(string serverToken)
{
// Generate blank asset
WitConfiguration configurationAsset = ScriptableObject.CreateInstance<WitConfiguration>();
configurationAsset.name = WitTexts.Texts.ConfigurationFileNameLabel;
configurationAsset.ResetData();
// Create
int index = SaveConfiguration(serverToken, configurationAsset);
if (index == -1)
{
configurationAsset.DestroySafely();
}
// Return new index
return index;
}
// Get asset save directory
public static string GetFileSaveDirectory(string title, string fileName, string fileExt)
{
// Determine root directory with selection if possible
string rootDirectory = Application.dataPath;
if (Selection.activeObject)
{
// Get asset path
string selectedPath = AssetDatabase.GetAssetPath(Selection.activeObject);
// Only allow if in assets
if (selectedPath.StartsWith("Assets"))
{
if (AssetDatabase.IsValidFolder(selectedPath))
{
rootDirectory = selectedPath;
}
else if (!string.IsNullOrEmpty(selectedPath))
{
rootDirectory = new System.IO.FileInfo(selectedPath).DirectoryName;
}
}
}
// Save panel
return EditorUtility.SaveFilePanel(title, rootDirectory, fileName, fileExt);
}
// Save configuration after determining path
public static int SaveConfiguration(string serverToken, WitConfiguration configurationAsset)
{
string savePath = GetFileSaveDirectory(WitTexts.Texts.ConfigurationFileManagerLabel, WitTexts.Texts.ConfigurationFileNameLabel, "asset");
return SaveConfiguration(savePath, serverToken, configurationAsset);
}
// Save configuration to selected location
public static int SaveConfiguration(string savePath, string serverToken, WitConfiguration configurationAsset)
{
// Ensure valid save path
if (string.IsNullOrEmpty(savePath))
{
return -1;
}
// Must be in assets
string unityPath = savePath.Replace("\\", "/");
if (!unityPath.StartsWith(Application.dataPath))
{
VLog.E($"Configuration Utility - Cannot Create Configuration Outside of Assets Directory\nPath: {unityPath}");
return -1;
}
// Determine local unity path
unityPath = unityPath.Replace(Application.dataPath, "Assets");
AssetDatabase.CreateAsset(configurationAsset, unityPath);
AssetDatabase.SaveAssets();
configurationAsset.UpdateDataAssets(); //must be done after SaveAssets
// Refresh configurations
ReloadConfigurationData();
// Get new index following reload
string name = System.IO.Path.GetFileNameWithoutExtension(unityPath);
int index = GetConfigurationIndex(name);
// Set server token
if (!string.IsNullOrEmpty(serverToken))
{
_witConfigs[index].SetServerToken(serverToken);
}
// Return index
return index;
}
#endregion
#region TOKENS
// Token valid check
public static bool IsServerTokenValid(string serverToken)
{
return !string.IsNullOrEmpty(serverToken) && WitAuthUtility.IsServerTokenValid(serverToken);
}
// Token valid check
public static bool IsClientTokenValid(string clientToken)
{
return !string.IsNullOrEmpty(clientToken) && clientToken.Length == 32;
}
// Sets server token for all configurations if possible
public static void SetServerToken(string serverToken, Action<string> onSetComplete = null)
{
// Invalid token
if (!IsServerTokenValid(serverToken))
{
SetServerTokenComplete(string.Empty, "", onSetComplete);
return;
}
// Perform a list app request to get app for token
WitAppInfoUtility.GetAppInfo(serverToken, (clientToken, info, error) =>
{
SetServerTokenComplete(serverToken, error, onSetComplete);
});
}
// Set server token complete
private static void SetServerTokenComplete(string serverToken, string error, Action<string> onSetComplete)
{
// Failed
if (!string.IsNullOrEmpty(error))
{
VLog.E($"Set Server Token Failed\n{error}");
WitAuthUtility.ServerToken = "";
}
// Success
else
{
// Log Success
VLog.D("Set Server Token Success");
// Apply token
WitAuthUtility.ServerToken = serverToken;
// Refresh configurations
ReloadConfigurationData();
}
// On complete
onSetComplete?.Invoke(error);
}
// Sets server token for specified configuration by updating it's application data
public static void SetServerToken(this WitConfiguration configuration, string serverToken, Action<string> onSetComplete = null)
{
var instanceKey = Telemetry.StartEvent(Telemetry.TelemetryEventId.SupplyToken);
// Invalid
if (!IsServerTokenValid(serverToken))
{
onSetComplete?.Invoke("Invalid Token");
return;
}
// Perform a list app request to get app for token
WitAppInfoUtility.GetAppInfo(serverToken, (clientToken, info, error) =>
{
// Set client access token
configuration.SetClientAccessToken(clientToken);
// Set application info
configuration.SetApplicationInfo(info);
// Set server token
if (!string.IsNullOrEmpty(info.id))
{
WitAuthUtility.SetAppServerToken(info.id, serverToken);
}
// Complete
if (!string.IsNullOrEmpty(error))
{
Telemetry.EndEventWithFailure(instanceKey, error);
}
else
{
Telemetry.EndEvent(instanceKey, Telemetry.ResultType.Success);
}
onSetComplete?.Invoke(error);
});
}
// Determine if is a server token
public static VRequest CheckServerToken(string serverToken, Action<bool> onComplete) => WitAppInfoUtility.CheckServerToken(serverToken, onComplete);
#endregion
#region APP DATA IMPORT
/// <summary>
/// Import supplied Manifest into WIT.ai.
/// </summary>
internal static void ImportData(this WitConfiguration configuration, Manifest manifest, VRequest.RequestCompleteDelegate<bool> onComplete = null, bool suppressLogs = false)
{
var manifestData = GetSanitizedManifestString(manifest);
var request = new WitSyncVRequest(configuration);
VLog.SuppressLogs = suppressLogs;
request.RequestImportData(manifestData, (error, responseData) =>
{
VLog.SuppressLogs = false;
if (!string.IsNullOrEmpty(error))
{
onComplete?.Invoke(false, error);
}
else
{
onComplete?.Invoke(true, string.Empty);
}
});
}
/// <summary>
/// Returns a serialized version of the manifest after removing internal data that should not be sent to IDM.
/// </summary>
/// <param name="manifest">The manifest to process.</param>
private static string GetSanitizedManifestString(Manifest manifest)
{
var filter = new WitParameterFilter();
foreach (var action in manifest.Actions)
{
action.Parameters.RemoveAll(a => filter.ShouldFilterOut(a.EntityType));
}
return JsonConvert.SerializeObject(manifest);
}
#endregion
#region REFRESH
// Refreshes configuration data
public static void RefreshAppInfo(this WitConfiguration configuration, Action<string> onRefreshComplete = null)
{
// Ignore during runtime
if (Application.isPlaying)
{
onRefreshComplete?.Invoke(null);
return;
}
// Update application info
WitAppInfoUtility.Update(configuration, (info, s) =>
{
// Set application info
configuration.SetApplicationInfo(info);
// Complete
onRefreshComplete?.Invoke(s);
});
}
#endregion
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 67da0cb4ba914f6cb2a97a343ff81db1
timeCreated: 1631316958
@@ -0,0 +1,94 @@
/*
* 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 UnityEditor;
using System.Reflection;
using Meta.WitAi.Configuration;
namespace Meta.WitAi.Windows
{
[CustomPropertyDrawer(typeof(WitEndpointConfig))]
public class WitEndpointConfigDrawer : WitPropertyDrawer
{
// All WitEndpointConfig parameters
private const string FIELD_URISCHEME = "_uriScheme";
private const string FIELD_AUTHORITY = "_authority";
private const string FIELD_PORT = "_port";
private const string FIELD_API = "_witApiVersion";
private const string FIELD_SPEECH = "_speech";
private const string FIELD_MESSAGE = "_message";
private const string FIELD_DICTATION = "_dictation";
private const string FIELD_SYNTHESIZE = "_synthesize";
// Allow edit with lock
protected override WitPropertyEditType EditType => WitPropertyEditType.LockEdit;
// Get default fields
protected override string GetDefaultFieldValue(SerializedProperty property, FieldInfo subfield)
{
// Iterate options
switch (subfield.Name)
{
case FIELD_URISCHEME:
return WitConstants.URI_SCHEME;
case FIELD_AUTHORITY:
return WitConstants.URI_AUTHORITY;
case FIELD_PORT:
return "0";
case FIELD_API:
return WitConstants.API_VERSION;
case FIELD_SPEECH:
return WitConstants.ENDPOINT_SPEECH;
case FIELD_MESSAGE:
return WitConstants.ENDPOINT_MESSAGE;
case FIELD_DICTATION:
return WitConstants.ENDPOINT_DICTATION;
case FIELD_SYNTHESIZE:
return WitConstants.ENDPOINT_TTS;
case "_event":
return WitConstants.ENDPOINT_COMPOSER_MESSAGE;
case "_converse":
return WitConstants.ENDPOINT_COMPOSER_SPEECH;
}
// Return base
return base.GetDefaultFieldValue(property, subfield);
}
// Use name value for title if possible
protected override string GetLocalizedText(SerializedProperty property, string key)
{
// Iterate options
switch (key)
{
case LocalizedTitleKey:
return WitTexts.Texts.ConfigurationEndpointTitleLabel;
case FIELD_URISCHEME:
return WitTexts.Texts.ConfigurationEndpointUriLabel;
case FIELD_AUTHORITY:
return WitTexts.Texts.ConfigurationEndpointAuthLabel;
case FIELD_PORT:
return WitTexts.Texts.ConfigurationEndpointPortLabel;
case FIELD_API:
return WitTexts.Texts.ConfigurationEndpointApiLabel;
case FIELD_SPEECH:
return WitTexts.Texts.ConfigurationEndpointSpeechLabel;
case FIELD_MESSAGE:
return WitTexts.Texts.ConfigurationEndpointMessageLabel;
case FIELD_DICTATION:
return WitTexts.Texts.ConfigurationEndpointDictationLabel;
case FIELD_SYNTHESIZE:
return WitTexts.Texts.ConfigurationEndpointSynthesizeLabel;
case "_event":
return WitTexts.Texts.ConfigurationEndpointComposerEventLabel;
case "_converse":
return WitTexts.Texts.ConfigurationEndpointComposerConverseLabel;
}
// Default to base
return base.GetLocalizedText(property, key);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5fff8addd8c86d94d9e793036f5e5538
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,38 @@
/*
* 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 Meta.WitAi.Data;
using Meta.WitAi.Lib;
using Meta.Conduit.Editor;
using Meta.WitAi.Json;
namespace Meta.WitAi.Windows
{
/// <summary>
/// Filters out parameters of specific types.
/// </summary>
internal class WitParameterFilter : IParameterFilter
{
/// <summary>
/// Tests if a parameter type should be filtered out.
/// </summary>
/// <param name="type">The data type.</param>
/// <returns>True if the parameter type should be filtered out. False otherwise.</returns>
public bool ShouldFilterOut(Type type)
{
return type == typeof(WitResponseNode) || type == typeof(VoiceSession);
}
public bool ShouldFilterOut(string typeName)
{
return typeName == nameof(WitResponseNode) || typeName == nameof(VoiceSession);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 32bad071f0c2d4fa1b657f119f712adc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,38 @@
/*
* 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 Meta.WitAi.Data;
using Meta.WitAi.Json;
using Meta.Conduit.Editor;
namespace Meta.WitAi.Windows
{
/// <summary>
/// Validates whether a data type if supported by Wit.
/// </summary>
internal class WitParameterValidator : IParameterValidator
{
/// <summary>
/// These are the types that we natively support.
/// </summary>
private readonly HashSet<Type> _builtInTypes = new HashSet<Type>()
{ typeof(string), typeof(int), typeof(DateTime), typeof(float), typeof(double), typeof(decimal) };
/// <summary>
/// Tests if a parameter type can be supplied directly to a callback method from.
/// </summary>
/// <param name="type">The data type.</param>
/// <returns>True if the parameter type is supported. False otherwise.</returns>
public bool IsSupportedParameterType(Type type)
{
return type.IsEnum || _builtInTypes.Contains(type) || type == typeof(WitResponseNode) || type == typeof(VoiceSession) || type == typeof(Exception);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b06aba70db204455b215439ad07b8253
timeCreated: 1653423412
@@ -0,0 +1,175 @@
/*
* 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 UnityEngine;
using Meta.WitAi.Data.Configuration;
using Meta.WitAi.Lib;
using Meta.WitAi.Requests;
namespace Meta.WitAi.Windows
{
public class WitWelcomeWizard : WitScriptableWizard
{
protected string serverToken;
public Action<WitConfiguration> successAction;
protected override Texture2D HeaderIcon => WitTexts.HeaderIcon;
protected override GUIContent Title => WitTexts.SetupTitleContent;
protected override string ButtonLabel => WitTexts.Texts.SetupSubmitButtonLabel;
protected override string ContentSubheaderLabel => WitTexts.Texts.SetupSubheaderLabel;
// Whether currently using a client token
private bool _isCheckingToken = false;
private bool _usingClientToken = false;
private VRequest _request;
protected override void OnEnable()
{
base.OnEnable();
_isCheckingToken = false;
_usingClientToken = false;
serverToken = string.Empty;
WitAuthUtility.ServerToken = serverToken;
}
protected virtual void OnDisable()
{
StopTokenCheck();
}
protected override bool DrawWizardGUI()
{
// Layout base
base.DrawWizardGUI();
// True if valid server token
return WitConfigurationUtility.IsServerTokenValid(serverToken);
}
protected override void LayoutFields()
{
// Token label
string serverTokenLabelText = WitTexts.Texts.SetupServerTokenLabel;
serverTokenLabelText = serverTokenLabelText.Replace(WitStyles.WitLinkKey, WitStyles.WitLinkColor);
if (GUILayout.Button(serverTokenLabelText, WitStyles.Label))
{
Application.OpenURL(WitTexts.GetAppURL("", WitTexts.WitAppEndpointType.Settings));
}
// Token field
bool updated = false;
WitEditorUI.LayoutPasswordField(null, ref serverToken, ref updated);
// Verifying
if (_isCheckingToken)
{
WitEditorUI.LayoutLabel(WitTexts.Texts.SetupServerTokenVerifyLabel);
}
// Client token warning
else if (_usingClientToken)
{
WitEditorUI.LayoutErrorLabel(WitTexts.Texts.SetupClientTokenWarningLabel);
}
// Determine if new token is a server token
if (updated && WitConfigurationUtility.IsServerTokenValid(serverToken))
{
CheckToken();
}
}
private void CheckToken()
{
// Cancel previous check
StopTokenCheck();
// Begin checking
_isCheckingToken = true;
// Perform request
_request = WitConfigurationUtility.CheckServerToken(serverToken, (success) =>
{
_usingClientToken = !success;
_isCheckingToken = false;
});
}
private void StopTokenCheck()
{
// Ignore if not checking
if (!_isCheckingToken)
{
return;
}
// Kill request
if (_request != null)
{
_request.Cancel();
_request = null;
}
// Done checking
_isCheckingToken = false;
}
protected override void OnWizardCreate()
{
ValidateAndClose();
}
protected virtual void ValidateAndClose()
{
// Verify
if (_isCheckingToken)
{
VLog.E(WitTexts.Texts.SetupServerTokenVerifyWarning);
return;
}
// Check client token
if (_usingClientToken)
{
if (!WitConfigurationUtility.IsClientTokenValid(serverToken))
{
VLog.E(WitTexts.Texts.SetupSubmitFailLabel);
return;
}
}
// Check server token
else
{
WitAuthUtility.ServerToken = serverToken;
if (!WitAuthUtility.IsServerTokenValid())
{
VLog.E(WitTexts.Texts.SetupSubmitFailLabel);
return;
}
}
// Create configuration
int index = CreateConfiguration(serverToken);
if (index != -1)
{
// Complete
Close();
WitConfiguration c = WitConfigurationUtility.WitConfigs[index];
if (successAction == null)
{
WitWindowUtility.OpenConfigurationWindow(c);
}
else
{
successAction(c);
}
}
}
protected virtual int CreateConfiguration(string newToken)
{
// Generate asset with client token
if (_usingClientToken)
{
WitConfiguration configuration = ScriptableObject.CreateInstance<WitConfiguration>();
configuration.SetClientAccessToken(newToken);
return WitConfigurationUtility.SaveConfiguration(string.Empty, configuration);
}
// Generate asset with server token
return WitConfigurationUtility.CreateConfiguration(newToken);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 842ab427b28d8450597f95ef8c8689f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,224 @@
/*
* 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.Linq;
using Meta.Voice.TelemetryUtilities;
using UnityEditor;
using UnityEngine;
using Meta.WitAi.Data.Configuration;
namespace Meta.WitAi.Windows
{
public class WitWindow : WitConfigurationWindow
{
protected WitConfigurationEditor witInspector;
protected string serverToken;
protected override GUIContent Title => WitTexts.SettingsTitleContent;
protected override string HeaderUrl => witInspector ? witInspector.HeaderUrl : base.HeaderUrl;
// VLog log level
private static int _logLevel = -1;
private static string[] _logLevelNames;
private static readonly VLogLevel[] _logLevels = (Enum.GetValues(typeof(VLogLevel)) as VLogLevel[])?.Reverse().ToArray();
#if VSDK_TELEMETRY_AVAILABLE
private static int _telemetryLogLevel = -1;
private static string[] _telemetryLogLevelNames;
private static readonly TelemetryLogLevel[] _telemetryLogLevels = new TelemetryLogLevel[]
{ TelemetryLogLevel.Off, TelemetryLogLevel.Basic, TelemetryLogLevel.Verbose };
#endif
public virtual bool ShowWitConfiguration => true;
public virtual bool ShowGeneralSettings => true;
public static bool ShowTooltips
{
get => EditorPrefs.GetBool("VSDK::Settings::Tooltips", true);
set => EditorPrefs.SetBool("VSDK::Settings::Tooltips", value);
}
protected override void OnEnable()
{
base.OnEnable();
if (string.IsNullOrEmpty(serverToken))
{
serverToken = WitAuthUtility.ServerToken;
}
RefreshLogLevel();
InitializeTelemetryLevelOptions();
SetWitEditor();
}
protected virtual void SetWitEditor()
{
// Destroy inspector
if (witInspector != null)
{
DestroyImmediate(witInspector);
witInspector = null;
}
// Generate new inspector & initialize immediately
if (witConfiguration)
{
witInspector = (WitConfigurationEditor)Editor.CreateEditor(witConfiguration);
witInspector.drawHeader = false;
witInspector.Initialize();
}
}
protected override void LayoutContent()
{
if (ShowGeneralSettings) DrawGeneralSettings();
if (ShowWitConfiguration) DrawWitConfigurations();
}
private void DrawGeneralSettings()
{
// VLog level
bool updated = false;
RefreshLogLevel();
int logLevel = _logLevel;
WitEditorUI.LayoutPopup(WitTexts.Texts.VLogLevelLabel, _logLevelNames, ref logLevel, ref updated);
if (updated)
{
SetLogLevel(logLevel);
}
var showTooltips = ShowTooltips;
WitEditorUI.LayoutToggle(new GUIContent(WitTexts.Texts.ShowTooltipsLabel), ref showTooltips, ref updated);
if (updated)
{
ShowTooltips = showTooltips;
}
#if VSDK_TELEMETRY_AVAILABLE && UNITY_EDITOR_WIN
var enableTelemetry = TelemetryConsentManager.ConsentProvided;
WitEditorUI.LayoutToggle(new GUIContent(WitTexts.Texts.TelemetryEnabledLabel), ref enableTelemetry, ref updated);
if (updated)
{
TelemetryConsentManager.ConsentProvided = enableTelemetry;
}
var telemetryLogLevel = _telemetryLogLevel;
WitEditorUI.LayoutPopup(WitTexts.Texts.TelemetryLevelLabel, _telemetryLogLevelNames, ref telemetryLogLevel, ref updated);
if (updated)
{
_telemetryLogLevel = Math.Max(0, telemetryLogLevel);
Telemetry.LogLevel = _telemetryLogLevels[_telemetryLogLevel];
}
#endif
}
private void DrawWitConfigurations()
{
// Server access token
GUILayout.BeginHorizontal();
bool updated = false;
WitEditorUI.LayoutPasswordField(WitTexts.SettingsServerTokenContent, ref serverToken, ref updated);
if (updated)
{
RelinkServerToken(false);
}
if (WitEditorUI.LayoutTextButton(WitTexts.Texts.SettingsRelinkButtonLabel))
{
RelinkServerToken(true);
}
if (WitEditorUI.LayoutTextButton(WitTexts.Texts.SettingsAddButtonLabel))
{
OpenConfigGenerationWindow();
}
GUILayout.EndHorizontal();
GUILayout.Space(WitStyles.ButtonMargin);
// Configuration select
base.LayoutContent();
// Update inspector if needed
if (witInspector == null || witConfiguration == null || witInspector.Configuration != witConfiguration)
{
SetWitEditor();
}
// Layout configuration inspector
if (witConfiguration && witInspector)
{
witInspector.OnInspectorGUI();
}
}
// Apply server token
private void RelinkServerToken(bool closeIfInvalid)
{
// Open Setup if Invalid
bool invalid = !WitConfigurationUtility.IsServerTokenValid(serverToken);
if (invalid)
{
// Clear if desired
if (string.IsNullOrEmpty(serverToken))
{
WitAuthUtility.ServerToken = serverToken;
}
// Open New & Close
if (closeIfInvalid)
{
// Generate new configuration
OpenConfigGenerationWindow();
// Close
Close();
}
return;
}
// Set valid server token
WitAuthUtility.ServerToken = serverToken;
WitConfigurationUtility.SetServerToken(serverToken);
}
private static void RefreshLogLevel()
{
if (_logLevelNames != null && _logLevelNames.Length == _logLevels.Length)
{
return;
}
List<string> logLevelOptions = new List<string>();
foreach (var level in _logLevels)
{
logLevelOptions.Add(level.ToString());
}
_logLevelNames = logLevelOptions.ToArray();
VLog.Init();
_logLevel = logLevelOptions.IndexOf(VLog.EditorLogLevel.ToString());
}
private void SetLogLevel(int newLevel)
{
_logLevel = Mathf.Clamp(0, newLevel, _logLevels.Length);
VLog.EditorLogLevel = _logLevels[_logLevel];
}
private static void InitializeTelemetryLevelOptions()
{
#if VSDK_TELEMETRY_AVAILABLE
_telemetryLogLevelNames = new string [_telemetryLogLevels.Length];
for (int i = 0; i < _telemetryLogLevelNames.Length; ++i)
{
_telemetryLogLevelNames[i] = _telemetryLogLevels[i].ToString();
}
var currentLevel = Telemetry.LogLevel.ToString();
for (int i = 0; i < _telemetryLogLevelNames.Length; ++i)
{
if (_telemetryLogLevelNames[i] == currentLevel)
{
_telemetryLogLevel = i;
return;
}
}
#endif
}
}
}
@@ -0,0 +1,16 @@
fileFormatVersion: 2
guid: 15c29f496a2443b4aa5e0ab283126a83
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- m_ViewDataDictionary: {instanceID: 0}
- witIcon: {fileID: 2800000, guid: d3b5ac4c8b01ef14a8a66d7e2a4991cc, type: 3}
- mainHeader: {fileID: 2800000, guid: 6a61dbb599169b64ca5584c8eebeb69e, type: 3}
- continueButton: {fileID: 2800000, guid: 2ed0be21c4a8bce4fadffab71d5b6e85, type: 3}
- witConfiguration: {instanceID: 0}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,101 @@
/*
* 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.Globalization;
using System.Text.RegularExpressions;
using Meta.WitAi.Configuration;
using Meta.WitAi.Data.Configuration;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.Data
{
public class WitDataCreation
{
const string PATH_KEY = "Facebook::Wit::ValuePath";
public static WitConfiguration FindDefaultWitConfig()
{
string[] guids = AssetDatabase.FindAssets("t:WitConfiguration");
if(guids.Length > 0)
{
string path = AssetDatabase.GUIDToAssetPath(guids[0]);
return AssetDatabase.LoadAssetAtPath<WitConfiguration>(path);
}
return null;
}
public static void AddWitToScene()
{
var witGo = new GameObject
{
name = "Wit"
};
var wit = witGo.AddComponent<Wit>();
var runtimeConfiguration = new WitRuntimeConfiguration()
{
witConfiguration = FindDefaultWitConfig()
};
wit.RuntimeConfiguration = runtimeConfiguration;
}
public static WitStringValue CreateStringValue(string path)
{
var asset = ScriptableObject.CreateInstance<WitStringValue>();
CreateValueAsset("Create String Value", path, asset);
return asset;
}
public static WitFloatValue CreateFloatValue(string path)
{
var asset = ScriptableObject.CreateInstance<WitFloatValue>();
CreateValueAsset("Create Float Value", path, asset);
return asset;
}
public static WitIntValue CreateIntValue(string path)
{
var asset = ScriptableObject.CreateInstance<WitIntValue>();
CreateValueAsset("Create Int Value", path, asset);
return asset;
}
private static void CreateValueAsset(string label, string path, WitValue asset)
{
asset.path = path;
var saveDir = EditorPrefs.GetString(PATH_KEY, Application.dataPath);
string name;
if (!string.IsNullOrEmpty(path))
{
name = Regex.Replace(path, @"\[[\]0-9]+", "");
name = name.Replace(".", " ");
name = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(name);
}
else
{
name = asset.GetType().Name;
}
var filePath = EditorUtility.SaveFilePanelInProject(label, name, "asset", "Please select a location for your asset.");
if (!string.IsNullOrEmpty(filePath))
{
EditorPrefs.SetString(PATH_KEY, filePath);
if (filePath.StartsWith("Assets/StreamingAssets"))
{
EditorUtility.DisplayDialog("Restricted Folder","Cannot use StreamingAssets folder for saving normal assets. \nPlease select another folder inside Assets.", "OK");
return;
}
AssetDatabase.CreateAsset(asset, filePath);
AssetDatabase.SaveAssets();
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 40da7661eee64aaa81d3a0886ce34911
timeCreated: 1624319178
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7c20804a44a34d2e96ef9eccbcd956b3
timeCreated: 1656461095
@@ -0,0 +1,63 @@
/*
* 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.Reflection;
using Meta.WitAi.Utilities;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.Drawers
{
[CustomPropertyDrawer(typeof(DynamicRangeAttribute))]
public class DynamicRangeAttributeDrawer : PropertyDrawer
{
private Object _targetObject;
private float _min;
private float _max;
private PropertyInfo _rangePropertyField;
private object _parentValue;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var value = property.floatValue;
var attr = attribute as DynamicRangeAttribute;
var parentPropertyName =
property.propertyPath.Substring(0, property.propertyPath.IndexOf("."));
var parentProperty = property.serializedObject.FindProperty(parentPropertyName);
var targetObject = property.serializedObject.targetObject;
if(targetObject != _targetObject)
{
_targetObject = targetObject;
var targetObjectClassType = targetObject.GetType();
var field = targetObjectClassType.GetField(parentProperty.propertyPath,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (null != field)
{
_parentValue = field.GetValue(targetObject);
var parentType = _parentValue.GetType();
_rangePropertyField = parentType.GetProperty(attr.RangeProperty,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
}
}
_min = attr.DefaultMin;
_max = attr.DefaultMax;
if (null != _rangePropertyField)
{
var range = (Vector2) _rangePropertyField.GetValue(_parentValue);
_min = range.x;
_max = range.y;
}
property.floatValue = EditorGUI.Slider(position, label, property.floatValue,
_min, _max);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c71bbccdffacf4cfea501a346b0b9d1b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,88 @@
/*
* 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.Data.ValueReferences;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.Drawers
{
[CustomPropertyDrawer(typeof(StringReference<>), true)]
public class StringReferenceDrawer : PropertyDrawer
{
private const int buttonWidth = 20;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
SerializedProperty stringValueProperty = property.FindPropertyRelative("stringValue");
SerializedProperty stringObjectProperty = property.FindPropertyRelative("stringObject");
EditorGUI.BeginProperty(position, label, property);
// Draw the label
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
// Draw the text field
Rect textFieldRect = new Rect(position);
textFieldRect.width -= buttonWidth;
Rect objFieldRect = new Rect(position.x + textFieldRect.width, position.y, buttonWidth,
EditorGUIUtility.singleLineHeight);
EditorGUI.PropertyField(stringObjectProperty.objectReferenceValue == null ? objFieldRect : position,
stringObjectProperty, GUIContent.none);
if (stringObjectProperty.objectReferenceValue == null)
{
stringValueProperty.stringValue = EditorGUI.TextField(textFieldRect, stringValueProperty.stringValue);
}
else
{
stringValueProperty.stringValue = ((IStringReference)stringObjectProperty.objectReferenceValue).Value;
}
Type targetType = fieldInfo.FieldType.BaseType.GenericTypeArguments[0];
// Handle drag and drop
if (Event.current.type == EventType.DragUpdated && textFieldRect.Contains(Event.current.mousePosition))
{
var validType = false;
foreach (var draggedObject in DragAndDrop.objectReferences)
{
if (draggedObject.GetType() == targetType)
{
validType = true;
break;
}
}
if (validType)
{
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
}
Event.current.Use();
}
else if (Event.current.type == EventType.DragPerform && textFieldRect.Contains(Event.current.mousePosition))
{
DragAndDrop.AcceptDrag();
foreach (var draggedObject in DragAndDrop.objectReferences)
{
if (draggedObject.GetType() == targetType)
{
stringObjectProperty.objectReferenceValue = draggedObject;
property.serializedObject.ApplyModifiedProperties();
break;
}
}
Event.current.Use();
}
EditorGUI.EndProperty();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e885f2612e2647c1813153fb6981e5e9
timeCreated: 1680299773
@@ -0,0 +1,52 @@
/*
* 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.Attributes;
using Meta.WitAi.Windows;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.Drawers
{
[CustomPropertyDrawer(typeof(TooltipBoxAttribute))]
public class TooltipBoxDrawer : DecoratorDrawer
{
private float _spaceAfterBox = 4;
private float _iconSize = 32;
private float _lastViewWidth;
public override float GetHeight()
{
if (!WitWindow.ShowTooltips) return 0;
TooltipBoxAttribute infoBoxAttribute = (TooltipBoxAttribute)attribute;
var height = EditorStyles.helpBox.CalcHeight(new GUIContent(infoBoxAttribute.Text), _lastViewWidth - _iconSize);
return Mathf.Max(_iconSize, height) + _spaceAfterBox;
}
public override void OnGUI(Rect position)
{
if (!WitWindow.ShowTooltips) return;
_lastViewWidth = EditorGUIUtility.currentViewWidth;
var iconRect = EditorGUI.IndentedRect(position);
iconRect.width = _iconSize;
iconRect.height = _iconSize;
GUIContent infoIcon = EditorGUIUtility.IconContent("console.infoicon");
infoIcon.tooltip = "You can turn off these tooltips in Voice SDK Settings.";
EditorGUI.LabelField(iconRect, infoIcon);
var tooltip = (TooltipBoxAttribute) attribute;
var rect = EditorGUI.IndentedRect(position);
rect.x += _iconSize;
rect.width -= _iconSize;
rect.height -= _spaceAfterBox;
EditorGUI.TextArea(rect, tooltip.Text, EditorStyles.helpBox);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5be6165094d84fbb9377d595397a1dbc
timeCreated: 1680127468
@@ -0,0 +1,30 @@
{
"name": "Meta.WitAi.Editor",
"rootNamespace": "",
"references": [
"GUID:1c28d8b71ced07540b7c271537363cc6",
"GUID:4504b1a6e0fdcc3498c30b266e4a63bf",
"GUID:f02292e638368584080af0193f81ff5c",
"GUID:70c988d11fbc4814db519eecb47cca75",
"GUID:5c61c7ae4b0c6f94299e51352f802670",
"GUID:3e75c68ea2ce130409f7b96ae2110237",
"GUID:4c3436cc699cb25459568e9fa95b7fd7"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.meta.xr.sdk.voice.telemetry",
"expression": "",
"define": "VSDK_TELEMETRY_AVAILABLE"
}
],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: fa958eb9f0171754fb207d563a15ddfa
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8bd8be981a6845f186f01908998f57e8
timeCreated: 1626727424
@@ -0,0 +1,277 @@
/*
* 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.Linq;
using System.Reflection;
using UnityEngine;
using UnityEditor;
namespace Meta.WitAi.Events.Editor
{
public abstract class EventPropertyDrawer<T> : PropertyDrawer
{
private const int CONTROL_SPACING = 5;
private const int UNSELECTED = -1;
private const int BUTTON_WIDTH = 75;
private const int PROPERTY_FIELD_SPACING = 25;
private bool showEvents = false;
private int selectedCategoryIndex = 0;
private int selectedEventIndex = 0;
private int propertyOffset;
private static Dictionary<string, string[]> _eventCategories;
public virtual string DocumentationUrl => string.Empty;
public virtual string DocumentationTooltip => string.Empty;
private const BindingFlags FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
private void InitializeEventCategories(Type eventsType)
{
// Get all category events in type & base type
Dictionary<string, List<string>> categoryLists = new Dictionary<string, List<string>>();
foreach (var field in eventsType.GetFields(FLAGS))
{
AddCustomField(field, categoryLists);
}
foreach (var baseField in eventsType.BaseType.GetFields(FLAGS))
{
AddCustomField(baseField, categoryLists);
}
// Apply
_eventCategories = new Dictionary<string, string[]>();
foreach (var category in categoryLists.Keys)
{
_eventCategories[category] = categoryLists[category].ToArray();
}
}
private void AddCustomField(FieldInfo field, Dictionary<string, List<string>> categoryLists)
{
if (!ShouldShowField(field))
{
return;
}
EventCategoryAttribute[] attributes = field.GetCustomAttributes(
typeof(EventCategoryAttribute), false) as EventCategoryAttribute[];
if (attributes == null || attributes.Length == 0)
{
return;
}
foreach (var eventCategory in attributes)
{
List<string> values = categoryLists.ContainsKey(eventCategory.Category) ? categoryLists[eventCategory.Category] : new List<string>();
string fieldName = GetDisplayFieldName(field);
if (!values.Contains(fieldName))
{
values.Add(fieldName);
}
categoryLists[eventCategory.Category] = values;
}
}
private bool ShouldShowField(FieldInfo field)
{
if (field.IsStatic)
{
return false;
}
if (!field.IsPublic && !Attribute.IsDefined(field, typeof(SerializeField)))
{
return false;
}
if (Attribute.IsDefined(field, typeof(HideInInspector)))
{
return false;
}
return Attribute.IsDefined(field, typeof(EventCategoryAttribute));
}
private string GetDisplayFieldName(FieldInfo field)
{
string result = field.Name.TrimStart('_');
return result[0].ToString().ToUpper() + result.Substring(1, result.Length - 1);
}
private string GetFieldNameFromDisplay(string fieldDisplayName)
{
return "_" + fieldDisplayName[0].ToString().ToLower() + fieldDisplayName.Substring(1, fieldDisplayName.Length - 1);
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
var eventObject = fieldInfo.GetValue(property.serializedObject.targetObject) as EventRegistry;
var lineHeight = EditorGUIUtility.singleLineHeight;
var lines = 1;
var height = 0;
// Allocate enough lines to display dropdown elements depending on which ones are showing.
if (showEvents && Selection.activeTransform)
lines++;
if (showEvents && selectedCategoryIndex != UNSELECTED)
lines++;
height = Mathf.RoundToInt(lineHeight * lines);
// By default, the property elements appear directly below the dropdowns.
propertyOffset = height + (int)WitStyles.TextButtonPadding;
// If the Events foldout is expanded and there are overridden properties, allocate space for them.
if (eventObject != null && eventObject.OverriddenCallbacks.Count != 0 && showEvents)
{
var callbacksArray = eventObject.OverriddenCallbacks.ToArray();
foreach (var callback in callbacksArray)
{
var fieldProperty = GetPropertyFromDisplayFieldName(property, callback);
if (fieldProperty != null)
{
height += Mathf.RoundToInt(EditorGUI.GetPropertyHeight(fieldProperty, true) + CONTROL_SPACING);
}
}
// Add some extra space so the last property field's +/- buttons don't overlap the next control.
height += PROPERTY_FIELD_SPACING;
}
return height;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
showEvents = EditorGUI.Foldout(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), showEvents, "Events");
string url = DocumentationUrl;
if (!string.IsNullOrEmpty(url))
{
Texture texture = WitStyles.HelpIcon.image;
if (texture != null)
{
// Add a ? button
Vector2 textureSize = WitStyles.IconButton.CalcSize(WitStyles.HelpIcon);
Rect buttonRect = new Rect(position.x + position.width - textureSize.x, position.y, textureSize.x, textureSize.y);
if (GUI.Button(buttonRect,
new GUIContent(WitStyles.HelpIcon.image, DocumentationTooltip), WitStyles.IconButton))
{
Application.OpenURL(url);
}
// Add a tooltip
if (!string.IsNullOrEmpty(DocumentationTooltip))
{
GUI.Label(buttonRect, GUI.tooltip);
}
}
}
if (showEvents && Selection.activeTransform)
{
if (_eventCategories == null)
InitializeEventCategories(fieldInfo.FieldType);
var eventObject = fieldInfo.GetValue(property.serializedObject.targetObject) as EventRegistry;
var eventCategoriesKeyArray = _eventCategories.Keys.ToArray();
EditorGUI.indentLevel++;
// Shift the control rectangle down one line to accomodate the category dropdown.
position.y += EditorGUIUtility.singleLineHeight;
position.height = EditorGUIUtility.singleLineHeight;
selectedCategoryIndex = EditorGUI.Popup(position, "Event Category",
selectedCategoryIndex, eventCategoriesKeyArray);
if (selectedCategoryIndex != UNSELECTED)
{
var eventsArray = _eventCategories[eventCategoriesKeyArray[selectedCategoryIndex]];
if (selectedEventIndex >= eventsArray.Length)
selectedEventIndex = 0;
// Create a new rectangle to position the events dropdown and Add button.
var selectedEventDropdownPosition = new Rect(position);
selectedEventDropdownPosition.y += EditorGUIUtility.singleLineHeight + 2;
selectedEventDropdownPosition.width = position.width - (BUTTON_WIDTH + (int)WitStyles.TextButtonPadding);
selectedEventIndex = EditorGUI.Popup(selectedEventDropdownPosition, "Event", selectedEventIndex,
eventsArray);
var selectedEventButtonPosition = new Rect(selectedEventDropdownPosition);
selectedEventButtonPosition.width = BUTTON_WIDTH;
selectedEventButtonPosition.x =
selectedEventDropdownPosition.x + selectedEventDropdownPosition.width + CONTROL_SPACING;
if (GUI.Button(selectedEventButtonPosition, "Add"))
{
var eventName = _eventCategories[eventCategoriesKeyArray[selectedCategoryIndex]][
selectedEventIndex];
if (eventObject != null && selectedEventIndex != UNSELECTED &&
!eventObject.IsCallbackOverridden(eventName))
{
var fieldName = GetFieldNameFromDisplay(eventName);
if (eventObject.IsCallbackOverridden(fieldName))
{
eventObject.RemoveOverriddenCallback(fieldName);
}
fieldName = GetFieldNameFromDisplay(eventName).Substring(1);
if (eventObject.IsCallbackOverridden(fieldName))
{
eventObject.RemoveOverriddenCallback(fieldName);
}
eventObject.RegisterOverriddenCallback(eventName);
}
}
}
// If any overrides have been added to the property, allow them to be edited
if (eventObject != null && eventObject.OverriddenCallbacks.Count != 0)
{
var propertyRect = new Rect(position.x, position.y + propertyOffset, position.width, 0);
foreach (var callback in eventObject.OverriddenCallbacks)
{
var fieldProperty = GetPropertyFromDisplayFieldName(property, callback);
if (fieldProperty == null)
{
continue;
}
propertyRect.height = EditorGUI.GetPropertyHeight(fieldProperty, true);
EditorGUI.PropertyField(propertyRect, fieldProperty);
propertyRect.y += propertyRect.height + CONTROL_SPACING;
}
}
EditorGUI.indentLevel--;
}
}
private SerializedProperty GetPropertyFromDisplayFieldName(SerializedProperty property, string fieldName)
{
SerializedProperty result = property.FindPropertyRelative(fieldName);
if (result == null)
{
string fieldName2 = GetFieldNameFromDisplay(fieldName);
result = property.FindPropertyRelative(fieldName2);
if (result == null)
{
Debug.LogError($"Could not find serialized property field: {fieldName} ({fieldName2})");
}
}
return result;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c7a8ed72b9df46b794029f8801197ec8
timeCreated: 1658431087
@@ -0,0 +1,57 @@
/*
* 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.IO;
using UnityEditor;
namespace Meta.WitAi.Events.Editor
{
[CustomPropertyDrawer(typeof(VoiceEvents))]
public class VoiceEventPropertyDrawer : EventPropertyDrawer<VoiceEvents>
{
/// <summary>
/// Voice event diagram name
/// </summary>
public const string VOICE_EVENT_DIAGRAM_NAME = "VoiceEventsDiagram";
/// <summary>
/// Voice event tooltip
/// </summary>
public const string VOICE_EVENT_DIAGRAM_TOOLTIP = "Open " + VOICE_EVENT_DIAGRAM_NAME + ".pdf";
/// <summary>
/// Open voice event pdf
/// </summary>
public override string DocumentationUrl
{
get
{
if (_documentationUrl == null)
{
string[] assetPaths = AssetDatabase.FindAssets(VOICE_EVENT_DIAGRAM_NAME);
if (assetPaths == null || assetPaths.Length == 0)
{
_documentationUrl = string.Empty;
}
else
{
string guid = assetPaths[0];
string localPath = AssetDatabase.GUIDToAssetPath(guid);
_documentationUrl = $"file://{Path.GetFullPath(localPath)}";
}
}
return _documentationUrl;
}
}
private static string _documentationUrl = null;
/// <summary>
/// Voice pdf tooltip
/// </summary>
public override string DocumentationTooltip => VOICE_EVENT_DIAGRAM_TOOLTIP;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 77caabce96000174bb6230dea05b47f0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,178 @@
/*
* 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.Voice;
using Meta.WitAi.Configuration;
using Meta.WitAi.Requests;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.Inspectors
{
public class WitInspector : Editor
{
// Text invocation message
private string _activationMessage;
// Target
private IVoiceActivationHandler _activationHandler;
private IVoiceEventProvider _eventProvider;
// Current service request
private VoiceServiceRequest _request;
// Transcription data tracking
private string _lastTranscription;
// Mic data tracking
private float _micMin;
private float _micMax;
private float _micCurrent;
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
// Ignore if not playing
if (!Application.isPlaying)
{
return;
}
if (target is IVoiceEventProvider)
{
_eventProvider = (IVoiceEventProvider) target;
}
if (target is IVoiceActivationHandler)
{
_activationHandler = (IVoiceActivationHandler) target;
}
if (_activationHandler == null)
{
return;
}
// Header
EditorGUILayout.Space();
GUILayout.Label("Editor Requests", EditorStyles.boldLabel);
// Add activation button
if (_request != null && _request.IsActive)
{
// Deactivates current target
GUILayout.BeginHorizontal();
if (_request.InputType == NLPRequestInputType.Audio && GUILayout.Button("Deactivate"))
{
_request.DeactivateAudio();
}
// Deactivate & abort
if (GUILayout.Button("Deactivate & Abort"))
{
_request.Cancel("Deactivated");
}
GUILayout.EndHorizontal();
// Current request state
GUILayout.Label($"State: {_request.State}");
}
else
{
// Activates via voice
if (GUILayout.Button("Activate"))
{
_request = _activationHandler.Activate(GetRequestOptions(), GetRequestEvents());
}
// Activates via text
GUILayout.BeginHorizontal();
_activationMessage = GUILayout.TextField(_activationMessage);
if (GUILayout.Button("Send", GUILayout.Width(50)))
{
_request = _activationHandler.Activate(_activationMessage, GetRequestOptions(), GetRequestEvents());
}
GUILayout.EndHorizontal();
}
EditorGUILayout.Space();
// Transcription data
GUILayout.Label("Last Transcription", EditorStyles.boldLabel);
GUILayout.TextArea(_lastTranscription);
// Mic data
GUILayout.Label("Mic Status", EditorStyles.boldLabel);
GUILayout.Label($"Mic range: {_micMin.ToString("F5")} - {_micMax.ToString("F5")}");
GUILayout.Label($"Mic current: {_micCurrent.ToString("F5")}");
}
// Returns events
private WitRequestOptions GetRequestOptions() => new WitRequestOptions();
// Return events
private VoiceServiceRequestEvents GetRequestEvents()
{
VoiceServiceRequestEvents events = new VoiceServiceRequestEvents();
events.OnInit.AddListener(OnRequestInit);
events.OnPartialTranscription.AddListener(OnTranscriptionChanged);
events.OnFullTranscription.AddListener(OnTranscriptionChanged);
events.OnComplete.AddListener(OnRequestComplete);
return events;
}
// Setup during an activation
private void OnRequestInit(VoiceServiceRequest request)
{
// Add events
if (_eventProvider != null)
{
_eventProvider.VoiceEvents.OnMicLevelChanged.AddListener(OnMicLevelChanged);
}
// Init mic data
_micMin = Mathf.Infinity;
_micMax = Mathf.NegativeInfinity;
// Start repaint on update
EditorApplication.update += UpdateForRepaint;
}
// Mic level updates
private void OnMicLevelChanged(float volume)
{
_micCurrent = volume;
_micMin = Mathf.Min(volume, _micMin);
_micMax = Mathf.Max(volume, _micMax);
}
// Transcription updates
private void OnTranscriptionChanged(string transcription)
{
_lastTranscription = transcription;
}
// Repaint
private void UpdateForRepaint()
{
Repaint();
}
// Request completed
private void OnRequestComplete(VoiceServiceRequest request)
{
// Remove events
if (_eventProvider != null)
{
_eventProvider.VoiceEvents.OnMicLevelChanged.RemoveListener(OnMicLevelChanged);
}
// Stop repaint on update
EditorApplication.update -= UpdateForRepaint;
// Remove request
_request = null;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 55ca91fb24174b4db43031a3ab4b0214
timeCreated: 1626727432
@@ -0,0 +1,15 @@
/*
* 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 UnityEditor;
namespace Meta.WitAi.Inspectors
{
[CustomEditor(typeof(WitService))]
public class WitServiceInspector : WitInspector { }
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9bf649b62b784cb8905a93125b8f754e
timeCreated: 1648513941
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4f4bf1d9c20d66943bc5dab13c5d8d58
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fc134e9335ed3814184f8a12b011b172
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,30 @@
/*
* 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.Lib;
using UnityEditor;
namespace Meta.WitAi.Lib
{
[CustomEditor(typeof(Mic))]
public class MicEditor : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
var mic = (Mic) target;
int index = EditorGUILayout.Popup("Input", mic.CurrentDeviceIndex, mic.Devices.ToArray());
if (index != mic.CurrentDeviceIndex)
{
mic.ChangeDevice(index);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 342830ab77bbe9c47a0f68027cc80da4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1aae00c8b15744747a605c719bafd378
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -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:
@@ -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);
}
}
}
}
@@ -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:
@@ -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; }
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b05455360ebd3644ebe86cbb40446615
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -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;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fcd6b77ae500a7b43923e35d15cc5144
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -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);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dd3a9e82a16233040a917414603b56f6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 238ea3e4fd8c0934d914485b43977e1f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9b85d9061b83ffc449be84c9b95e52f7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,25 @@
/*
* 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 UnityEditor;
using UnityEngine;
namespace Meta.WitAi.Windows.Components
{
public static class WitMultiSelectionPopup
{
public static void Show(IList<string> options, HashSet<string> disabledOptions, Action<IList<string>> callback) {
// TODO It should be a rect of a button which triggers this popup, so the popup is shown next to that button.
Rect parentRect = new Rect(0, 0, 50, 50);
WitMultiSelectionPopupContent content = new WitMultiSelectionPopupContent(options, disabledOptions, callback);
PopupWindow.Show(parentRect, content);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b64f2d401365d47218d23cd6e1295d63
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,59 @@
/*
* 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.Linq;
using UnityEditor;
using UnityEngine;
namespace Meta.WitAi.Windows.Components
{
public class WitMultiSelectionPopupContent: PopupWindowContent
{
private Dictionary<string, bool> options;
private Action<IList<string>> callback;
private const float WINDOW_WIDTH = 400f;
public WitMultiSelectionPopupContent(IList<string> options, HashSet<string> disabledOptions, Action<IList<string>> callback)
{
this.options = new Dictionary<string, bool>();
this.callback = callback;
options.ToList().ForEach(optName => this.options[optName] = !disabledOptions.Contains(optName));
}
public override Vector2 GetWindowSize()
{
var lineHeight = 20;
var height = 25 + (options.Count() * lineHeight);
return new Vector2(WINDOW_WIDTH, height);
}
public override void OnGUI(Rect rect)
{
var initialLabelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = WINDOW_WIDTH - 30;
GUILayout.Label("Assemblies to include in the generated Manifest", EditorStyles.boldLabel);
var keys = new List<string>(options.Keys);
foreach (var optName in keys) {
options[optName] = EditorGUILayout.Toggle(optName, options[optName], WitStyles.Toggle);
}
EditorGUIUtility.labelWidth = initialLabelWidth;
}
public override void OnClose()
{
var deselectedValues = this.options.Keys.Where(optName => false == this.options[optName]).ToList();
callback(deselectedValues);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b720c5fa963394864bd7ed8ef330d0bc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,113 @@
/*
* 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.Reflection;
using UnityEditor;
namespace Meta.WitAi.Windows
{
public class FieldGUI
{
// Base type
public Type baseType { get; private set; }
// Fields
public FieldInfo[] fields { get; private set; }
/// <summary>
/// Custom gui layout callback, returns true if field is
/// </summary>
public Func<FieldInfo, bool> onCustomGuiLayout;
/// <summary>
/// Custom gui layout callback, returns true if field is
/// </summary>
public Action onAdditionalGuiLayout;
// Refresh field list
public void RefreshFields(Type newBaseType)
{
// Set base type
baseType = newBaseType;
// Obtain all public, instance fields
fields = GetFields(baseType);
}
// Obtain all public, instance fields
public static FieldInfo[] GetFields(Type newBaseType, Comparison<FieldInfo> customSort = null)
{
// Results
FieldInfo[] results = newBaseType.GetFields(BindingFlags.Public | BindingFlags.Instance);
// Sort parent class fields to top
Comparison<FieldInfo> sort = customSort ?? ((f1, f2) =>
{
if (f1.DeclaringType != f2.DeclaringType)
{
if (f1.DeclaringType == newBaseType)
{
return 1;
}
if (f2.DeclaringType == newBaseType)
{
return -1;
}
}
return 0;
});
// Sort
Array.Sort(results, sort);
// Return results
return results;
}
// Gui Layout
public void OnGuiLayout(SerializedObject serializedObject)
{
// Ignore without object
if (serializedObject == null || serializedObject.targetObject == null)
{
return;
}
// Attempt a setup if needed
Type desType = serializedObject.targetObject.GetType();
if (baseType != desType || fields == null)
{
RefreshFields(desType);
}
// Ignore
if (fields == null)
{
return;
}
// Iterate all fields
foreach (var field in fields)
{
// Custom handle
if (onCustomGuiLayout != null && onCustomGuiLayout(field))
{
continue;
}
// Default layout
var property = serializedObject.FindProperty(field.Name);
EditorGUILayout.PropertyField(property);
}
// Additional items
onAdditionalGuiLayout?.Invoke();
// Apply
serializedObject.ApplyModifiedProperties();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c6c2ebe0a6e80f4fa83611a03e7fecd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5e6781ff766e1a740ab27299b2e559ae
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,108 @@
/*
* 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 UnityEditor;
using UnityEngine;
using Meta.WitAi.CallbackHandlers;
namespace Meta.WitAi.Windows
{
[CustomPropertyDrawer(typeof(ConfidenceRange))]
public class ConfidenceRangeDrawer : WitPropertyDrawer
{
private Vector2 fieldScroll;
private bool showOutsideConfidence;
private Dictionary<SerializedProperty, bool> eventFoldouts =
new Dictionary<SerializedProperty, bool>();
private float GetEventContentsHeight(SerializedProperty property)
{
var height = EditorGUIUtility.singleLineHeight;
var trigger = property.FindPropertyRelative("onWithinConfidenceRange");
if (trigger.isExpanded)
{
height += EditorGUI.GetPropertyHeight(trigger);
if (showOutsideConfidence)
{
trigger = property.FindPropertyRelative("onOutsideConfidenceRange");
height += EditorGUI.GetPropertyHeight(trigger);
}
height += EditorGUIUtility.singleLineHeight * 1.5f;
}
return height;
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
var height = EditorGUIUtility.singleLineHeight * 4;
height += GetEventContentsHeight(property);
return height;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
var rect = position;
rect.height = EditorGUIUtility.singleLineHeight;
var minConfidence = property.FindPropertyRelative("minConfidence");
var maxConfidence = property.FindPropertyRelative("maxConfidence");
var minVal = minConfidence.floatValue;
var maxVal = maxConfidence.floatValue;
EditorGUI.MinMaxSlider(rect, ref minVal, ref maxVal, 0, 1);
rect.y += EditorGUIUtility.singleLineHeight;
var minRect = new Rect(rect);
minRect.width = Mathf.Min(position.width / 2.0f - 4, 75f);
EditorGUI.TextField(minRect, minVal.ToString());
var maxRect = new Rect(minRect);
maxRect.xMin = position.xMax - maxRect.width;
maxRect.xMax = position.xMax;
EditorGUI.TextField(maxRect, maxVal.ToString());
rect.y += EditorGUIUtility.singleLineHeight * 1.5f;
minConfidence.floatValue = minVal;
maxConfidence.floatValue = maxVal;
var eventRect = new Rect(rect);
eventRect.height = GetEventContentsHeight(property);
EditorGUI.DrawRect(eventRect, Color.gray);
rect.xMin += 16;
rect.width = rect.xMax - rect.xMin - 16;
var trigger = property.FindPropertyRelative("onWithinConfidenceRange");
trigger.isExpanded = EditorGUI.Foldout(rect, trigger.isExpanded, "Events");
rect.y += EditorGUIUtility.singleLineHeight;
if (trigger.isExpanded)
{
rect.height = EditorGUI.GetPropertyHeight(trigger);
EditorGUI.PropertyField(rect, trigger);
rect.y += rect.height;
rect.height = EditorGUIUtility.singleLineHeight;
showOutsideConfidence = EditorGUI.Foldout(rect, showOutsideConfidence,
"Outside Confidence Range Triggers");
rect.y += EditorGUIUtility.singleLineHeight;
if (showOutsideConfidence)
{
trigger = property.FindPropertyRelative("onOutsideConfidenceRange");
rect.height = EditorGUI.GetPropertyHeight(trigger);
EditorGUI.PropertyField(rect, trigger);
}
}
EditorGUI.EndProperty();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6225499212e66974991865e4777c77ab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,65 @@
/*
* 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 UnityEditor;
using System.Reflection;
namespace Meta.WitAi.Windows
{
public class WitApplicationPropertyDrawer : WitPropertyDrawer
{
// Whether to use a foldout
protected override bool FoldoutEnabled => false;
// Use name value for title if possible
protected override string GetLocalizedText(SerializedProperty property, string key)
{
// Determine by ids
switch (key)
{
case LocalizedTitleKey:
return WitTexts.Texts.ConfigurationApplicationTabLabel;
case LocalizedMissingKey:
return WitTexts.Texts.ConfigurationApplicationMissingLabel;
case "name":
return WitTexts.Texts.ConfigurationApplicationNameLabel;
case "id":
return WitTexts.Texts.ConfigurationApplicationIdLabel;
case "lang":
return WitTexts.Texts.ConfigurationApplicationLanguageLabel;
case "isPrivate":
return WitTexts.Texts.ConfigurationApplicationPrivateLabel;
case "createdAt":
return WitTexts.Texts.ConfigurationApplicationCreatedLabel;
case "trainingStatus":
return WitTexts.Texts.ConfigurationApplicationTrainingStatus;
case "lastTrainDuration":
return WitTexts.Texts.ConfigurationApplicationTrainingLastDuration;
case "lastTrainedAt":
return WitTexts.Texts.ConfigurationApplicationTrainingLast;
case "nextTrainAt":
return WitTexts.Texts.ConfigurationApplicationTrainingNext;
}
// Default to base
return base.GetLocalizedText(property, key);
}
// Skip wit configuration field
protected override bool ShouldLayoutField(SerializedProperty property, FieldInfo subfield)
{
switch (subfield.Name)
{
case "intents":
case "entities":
case "traits":
case "voices":
return false;
}
return base.ShouldLayoutField(property, subfield);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: abf5ee4c48cd9b646ada260f9bf23b3d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,87 @@
/*
* 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 UnityEditor;
using System.Reflection;
using Meta.WitAi.Data.Configuration;
using Meta.WitAi.Data.Info;
namespace Meta.WitAi.Windows
{
[CustomPropertyDrawer(typeof(WitEntityInfo))]
public class WitEntityPropertyDrawer : WitPropertyDrawer
{
// Use name value for title if possible
protected override string GetLocalizedText(SerializedProperty property, string key)
{
// Determine by ids
switch (key)
{
case LocalizedTitleKey:
string title = GetFieldStringValue(property, "name");
if (!string.IsNullOrEmpty(title))
{
return title;
}
break;
case "id":
return WitTexts.Texts.ConfigurationEntitiesIdLabel;
case "lookups":
return WitTexts.Texts.ConfigurationEntitiesLookupsLabel;
case "roles":
return WitTexts.Texts.ConfigurationEntitiesRolesLabel;
case "keywords":
return WitTexts.Texts.ConfigurationEntitiesKeywordsLabel;
}
// Default to base
return base.GetLocalizedText(property, key);
}
// Determine if should layout field
protected override bool ShouldLayoutField(SerializedProperty property, FieldInfo subfield)
{
switch (subfield.Name)
{
case "name":
return false;
}
return base.ShouldLayoutField(property, subfield);
}
protected override void OnDrawLabelInline(SerializedProperty property)
{
var configuration = property.serializedObject.targetObject as WitConfiguration;
if (configuration == null || !configuration.useConduit)
{
return;
}
var assemblyWalker = ConduitManifestGenerationManager.GetInstance(configuration).AssemblyWalker;
if (assemblyWalker == null)
{
return;
}
var entityName = property.displayName;
if (WitEditorUI.LayoutIconButton(EditorGUIUtility.IconContent("UxmlScript Icon")))
{
var manifest = ManifestLoader.LoadManifest(configuration.ManifestLocalPath);
var sourceCodeFile = CodeMapper.GetSourceFilePathFromTypeName(entityName, manifest, assemblyWalker);
if (string.IsNullOrEmpty(sourceCodeFile))
{
VLog.W($"Failed to local source code for {entityName}");
return;
}
UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal(sourceCodeFile, 1);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 005e6c58c9128dd4e8a1f14f07ce0fc8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,28 @@
/*
* 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 UnityEditor;
using Meta.WitAi.Data.Info;
namespace Meta.WitAi.Windows
{
[CustomPropertyDrawer(typeof(WitEntityRoleInfo))]
public class WitEntityRolePropertyDrawer : WitSimplePropertyDrawer
{
// Key = Name
protected override string GetKeyFieldName()
{
return "name";
}
// Value = ID
protected override string GetValueFieldName()
{
return "id";
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f8fe3908d473555449a5fed7799862a3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More