clean project
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d054f5543f909634a88982d2b2dc8e55
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Facebook.WitAi.CallbackHandlers
|
||||
{
|
||||
public class SimpleIntentHandler : WitResponseHandler
|
||||
{
|
||||
[SerializeField] public string intent;
|
||||
[Range(0, 1f)]
|
||||
[SerializeField] public float confidence = .9f;
|
||||
[SerializeField] private UnityEvent onIntentTriggered = new UnityEvent();
|
||||
|
||||
public UnityEvent OnIntentTriggered => onIntentTriggered;
|
||||
|
||||
protected override void OnHandleResponse(WitResponseNode response)
|
||||
{
|
||||
var intentNode = WitResultUtilities.GetFirstIntent(response);
|
||||
if (intent == intentNode["name"].Value && intentNode["confidence"].AsFloat > confidence)
|
||||
{
|
||||
onIntentTriggered.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d2d3ff93ff48bd40ab5bca3cf4e6d2c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Facebook.WitAi.CallbackHandlers
|
||||
{
|
||||
public class SimpleStringEntityHandler : WitResponseHandler
|
||||
{
|
||||
[SerializeField] public string intent;
|
||||
[SerializeField] public string entity;
|
||||
[Range(0, 1f)] [SerializeField] public float confidence = .9f;
|
||||
|
||||
[SerializeField] public string format;
|
||||
|
||||
[SerializeField] private StringEntityMatchEvent onIntentEntityTriggered
|
||||
= new StringEntityMatchEvent();
|
||||
|
||||
public StringEntityMatchEvent OnIntentEntityTriggered => onIntentEntityTriggered;
|
||||
|
||||
protected override void OnHandleResponse(WitResponseNode response)
|
||||
{
|
||||
var intentNode = WitResultUtilities.GetFirstIntent(response);
|
||||
if (intent == intentNode["name"].Value && intentNode["confidence"].AsFloat > confidence)
|
||||
{
|
||||
var entityValue = WitResultUtilities.GetFirstEntityValue(response, entity);
|
||||
if (!string.IsNullOrEmpty(format))
|
||||
{
|
||||
onIntentEntityTriggered.Invoke(format.Replace("{value}", entityValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
onIntentEntityTriggered.Invoke(entityValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class StringEntityMatchEvent : UnityEvent<string> {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77dceeee73817ec4c844564714e05c77
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Facebook.WitAi.CallbackHandlers
|
||||
{
|
||||
public abstract class WitResponseHandler : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public VoiceService wit;
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
if (!wit) wit = FindObjectOfType<VoiceService>();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (!wit) wit = FindObjectOfType<VoiceService>();
|
||||
if (!wit)
|
||||
{
|
||||
Debug.LogError("Wit not found in scene. Disabling " + GetType().Name + " on " +
|
||||
name);
|
||||
enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
wit.events.OnResponse.AddListener(OnHandleResponse);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
wit.events.OnResponse.RemoveListener(OnHandleResponse);
|
||||
}
|
||||
|
||||
protected abstract void OnHandleResponse(WitResponseNode response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 097381abbd7a3364f80ac4460551a2cb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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.Text.RegularExpressions;
|
||||
using Facebook.WitAi.Data;
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Facebook.WitAi.CallbackHandlers
|
||||
{
|
||||
public class WitResponseMatcher : WitResponseHandler
|
||||
{
|
||||
[Header("Intent")]
|
||||
[SerializeField] public string intent;
|
||||
[FormerlySerializedAs("confidence")]
|
||||
[Range(0, 1f), SerializeField] public float confidenceThreshold = .6f;
|
||||
|
||||
[FormerlySerializedAs("valuePaths")]
|
||||
[Header("Value Matching")]
|
||||
[SerializeField] public ValuePathMatcher[] valueMatchers;
|
||||
|
||||
[Header("Output")]
|
||||
[SerializeField] private FormattedValueEvents[] formattedValueEvents;
|
||||
[SerializeField] private MultiValueEvent onMultiValueEvent = new MultiValueEvent();
|
||||
|
||||
|
||||
private static Regex valueRegex = new Regex(Regex.Escape("{value}"), RegexOptions.Compiled);
|
||||
|
||||
|
||||
protected override void OnHandleResponse(WitResponseNode response)
|
||||
{
|
||||
if (IntentMatches(response))
|
||||
{
|
||||
if (ValueMatches(response))
|
||||
{
|
||||
for (int j = 0; j < formattedValueEvents.Length; j++)
|
||||
{
|
||||
var formatEvent = formattedValueEvents[j];
|
||||
var result = formatEvent.format;
|
||||
for (int i = 0; i < valueMatchers.Length; i++)
|
||||
{
|
||||
var reference = valueMatchers[i].Reference;
|
||||
var value = reference.GetStringValue(response);
|
||||
if (!string.IsNullOrEmpty(formatEvent.format))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
result = valueRegex.Replace(result, value, 1);
|
||||
result = result.Replace("{" + i + "}", value);
|
||||
}
|
||||
else if (result.Contains("{" + i + "}"))
|
||||
{
|
||||
result = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(result))
|
||||
{
|
||||
formatEvent.onFormattedValueEvent?.Invoke(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<string> values = new List<string>();
|
||||
for (int i = 0; i < valueMatchers.Length; i++)
|
||||
{
|
||||
var value = valueMatchers[i].Reference.GetStringValue(response);
|
||||
values.Add(value);
|
||||
}
|
||||
|
||||
onMultiValueEvent.Invoke(values.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValueMatches(WitResponseNode response)
|
||||
{
|
||||
bool matches = true;
|
||||
for (int i = 0; i < valueMatchers.Length && matches; i++)
|
||||
{
|
||||
var matcher = valueMatchers[i];
|
||||
var value = matcher.Reference.GetStringValue(response);
|
||||
matches &= !matcher.contentRequired || !string.IsNullOrEmpty(value);
|
||||
|
||||
switch (matcher.matchMethod)
|
||||
{
|
||||
case MatchMethod.RegularExpression:
|
||||
matches &= Regex.Match(value, matcher.matchValue).Success;
|
||||
break;
|
||||
case MatchMethod.Text:
|
||||
matches &= value == matcher.matchValue;
|
||||
break;
|
||||
case MatchMethod.IntegerComparison:
|
||||
matches &= CompareInt(value, matcher);
|
||||
break;
|
||||
case MatchMethod.FloatComparison:
|
||||
matches &= CompareFloat(value, matcher);
|
||||
break;
|
||||
case MatchMethod.DoubleComparison:
|
||||
matches &= CompareDouble(value, matcher);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
private bool CompareDouble(string value, ValuePathMatcher matcher)
|
||||
{
|
||||
double dValue;
|
||||
|
||||
// This one is freeform based on the input so we will retrun false if it is not parsable
|
||||
if (!double.TryParse(value, out dValue)) return false;
|
||||
|
||||
// We will throw an exception if match value is not a numeric value. This is a developer
|
||||
// error.
|
||||
double dMatchValue = double.Parse(matcher.matchValue);
|
||||
|
||||
switch (matcher.comparisonMethod)
|
||||
{
|
||||
case ComparisonMethod.Equals:
|
||||
return Math.Abs(dValue - dMatchValue) < matcher.floatingPointComparisonTolerance;
|
||||
case ComparisonMethod.NotEquals:
|
||||
return Math.Abs(dValue - dMatchValue) > matcher.floatingPointComparisonTolerance;
|
||||
case ComparisonMethod.Greater:
|
||||
return dValue > dMatchValue;
|
||||
case ComparisonMethod.Less:
|
||||
return dValue < dMatchValue;
|
||||
case ComparisonMethod.GreaterThanOrEqualTo:
|
||||
return dValue >= dMatchValue;
|
||||
case ComparisonMethod.LessThanOrEqualTo:
|
||||
return dValue <= dMatchValue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool CompareFloat(string value, ValuePathMatcher matcher)
|
||||
{
|
||||
float dValue;
|
||||
|
||||
// This one is freeform based on the input so we will retrun false if it is not parsable
|
||||
if (!float.TryParse(value, out dValue)) return false;
|
||||
|
||||
// We will throw an exception if match value is not a numeric value. This is a developer
|
||||
// error.
|
||||
float dMatchValue = float.Parse(matcher.matchValue);
|
||||
|
||||
switch (matcher.comparisonMethod)
|
||||
{
|
||||
case ComparisonMethod.Equals:
|
||||
return Math.Abs(dValue - dMatchValue) <
|
||||
matcher.floatingPointComparisonTolerance;
|
||||
case ComparisonMethod.NotEquals:
|
||||
return Math.Abs(dValue - dMatchValue) >
|
||||
matcher.floatingPointComparisonTolerance;
|
||||
case ComparisonMethod.Greater:
|
||||
return dValue > dMatchValue;
|
||||
case ComparisonMethod.Less:
|
||||
return dValue < dMatchValue;
|
||||
case ComparisonMethod.GreaterThanOrEqualTo:
|
||||
return dValue >= dMatchValue;
|
||||
case ComparisonMethod.LessThanOrEqualTo:
|
||||
return dValue <= dMatchValue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool CompareInt(string value, ValuePathMatcher matcher)
|
||||
{
|
||||
int dValue;
|
||||
|
||||
// This one is freeform based on the input so we will retrun false if it is not parsable
|
||||
if (!int.TryParse(value, out dValue)) return false;
|
||||
|
||||
// We will throw an exception if match value is not a numeric value. This is a developer
|
||||
// error.
|
||||
int dMatchValue = int.Parse(matcher.matchValue);
|
||||
|
||||
switch (matcher.comparisonMethod)
|
||||
{
|
||||
case ComparisonMethod.Equals:
|
||||
return dValue == dMatchValue;
|
||||
case ComparisonMethod.NotEquals:
|
||||
return dValue != dMatchValue;
|
||||
case ComparisonMethod.Greater:
|
||||
return dValue > dMatchValue;
|
||||
case ComparisonMethod.Less:
|
||||
return dValue < dMatchValue;
|
||||
case ComparisonMethod.GreaterThanOrEqualTo:
|
||||
return dValue >= dMatchValue;
|
||||
case ComparisonMethod.LessThanOrEqualTo:
|
||||
return dValue <= dMatchValue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IntentMatches(WitResponseNode response)
|
||||
{
|
||||
var intentNode = response.GetFirstIntent();
|
||||
if (string.IsNullOrEmpty(intent))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (intent == intentNode["name"].Value)
|
||||
{
|
||||
var actualConfidence = intentNode["confidence"].AsFloat;
|
||||
if (actualConfidence >= confidenceThreshold)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Debug.Log($"{intent} matched, but confidence ({actualConfidence.ToString("F")}) was below threshold ({confidenceThreshold.ToString("F")})");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class MultiValueEvent : UnityEvent<string[]>
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ValueEvent : UnityEvent<string>
|
||||
{ }
|
||||
|
||||
[Serializable]
|
||||
public class FormattedValueEvents
|
||||
{
|
||||
[Tooltip("Modify the string output, values can be inserted with {value} or {0}, {1}, {2}")]
|
||||
public string format;
|
||||
public ValueEvent onFormattedValueEvent = new ValueEvent();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ValuePathMatcher
|
||||
{
|
||||
[Tooltip("The path to a value within a WitResponseNode")]
|
||||
public string path;
|
||||
[Tooltip("A reference to a wit value object")]
|
||||
public WitValue witValueReference;
|
||||
[Tooltip("Does this path need to have text in the value to be considered a match")]
|
||||
public bool contentRequired = true;
|
||||
[Tooltip("If set the match value will be treated as a regular expression.")]
|
||||
public MatchMethod matchMethod;
|
||||
[Tooltip("The operator used to compare the value with the match value. Ex: response.value > matchValue")]
|
||||
public ComparisonMethod comparisonMethod;
|
||||
[Tooltip("Value used to compare with the result when Match Required is set")]
|
||||
public string matchValue;
|
||||
|
||||
[Tooltip("The variance allowed when comparing two floating point values for equality")]
|
||||
public double floatingPointComparisonTolerance = .0001f;
|
||||
|
||||
private WitResponseReference pathReference;
|
||||
public WitResponseReference Reference
|
||||
{
|
||||
get
|
||||
{
|
||||
if (witValueReference) return witValueReference.Reference;
|
||||
|
||||
if (null == pathReference || pathReference.path != path)
|
||||
{
|
||||
pathReference = WitResultUtilities.GetWitResponseReference(path);
|
||||
}
|
||||
|
||||
return pathReference;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ComparisonMethod
|
||||
{
|
||||
Equals,
|
||||
NotEquals,
|
||||
Greater,
|
||||
GreaterThanOrEqualTo,
|
||||
Less,
|
||||
LessThanOrEqualTo
|
||||
}
|
||||
|
||||
public enum MatchMethod
|
||||
{
|
||||
None,
|
||||
Text,
|
||||
RegularExpression,
|
||||
IntegerComparison,
|
||||
FloatComparison,
|
||||
DoubleComparison
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 591c3d6f017c11b4faa41506d75635b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
using Facebook.WitAi.Lib;
|
||||
using Facebook.WitAi.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Facebook.WitAi.CallbackHandlers
|
||||
{
|
||||
public class WitUtteranceMatcher : WitResponseHandler
|
||||
{
|
||||
[SerializeField] private string searchText;
|
||||
[SerializeField] private bool exactMatch = true;
|
||||
[SerializeField] private bool useRegex;
|
||||
|
||||
[SerializeField] private StringEvent onUtteranceMatched = new StringEvent();
|
||||
|
||||
private Regex regex;
|
||||
|
||||
protected override void OnHandleResponse(WitResponseNode response)
|
||||
{
|
||||
var text = response["text"].Value;
|
||||
|
||||
if (useRegex)
|
||||
{
|
||||
if (null == regex)
|
||||
{
|
||||
regex = new Regex(searchText, RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
var match = regex.Match(text);
|
||||
if (match.Success)
|
||||
{
|
||||
if (exactMatch && match.Value == text)
|
||||
{
|
||||
onUtteranceMatched?.Invoke(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
onUtteranceMatched?.Invoke(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (exactMatch && text.ToLower() == searchText.ToLower())
|
||||
{
|
||||
onUtteranceMatched?.Invoke(text);
|
||||
}
|
||||
else if (text.ToLower().Contains(searchText.ToLower()))
|
||||
{
|
||||
onUtteranceMatched?.Invoke(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d0a93535f06eabe47bf93b4b504873c8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/Data.meta
Normal file
8
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/Data.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c9bc9136c8441e48996d814209d4c2e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Facebook.WitAi.Data
|
||||
{
|
||||
[Serializable]
|
||||
public class AudioEncoding
|
||||
{
|
||||
public enum Endian
|
||||
{
|
||||
Big,
|
||||
Little
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The expected encoding of the mic pcm data
|
||||
/// </summary>
|
||||
public string encoding = "signed-integer";
|
||||
|
||||
/// <summary>
|
||||
/// The number of bits per sample
|
||||
/// </summary>
|
||||
public int bits = 16;
|
||||
|
||||
/// <summary>
|
||||
/// The sample rate used to capture audio
|
||||
/// </summary>
|
||||
public int samplerate = 16000;
|
||||
|
||||
/// <summary>
|
||||
/// The endianess of the data
|
||||
/// </summary>
|
||||
public Endian endian = Endian.Little;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"audio/raw;bits={bits};rate={samplerate / 1000}k;encoding={encoding};endian={endian.ToString().ToLower()}";
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 991b11599dd41ac448cf8d6114e29d36
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d99f42b1387bffe4b845b1bf9f9cf5cb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Configuration;
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Facebook.WitAi.Data.Configuration
|
||||
{
|
||||
|
||||
[Serializable]
|
||||
public class WitApplication : WitConfigurationData
|
||||
{
|
||||
[SerializeField] public string name;
|
||||
[SerializeField] public string id;
|
||||
[SerializeField] public string lang;
|
||||
[SerializeField] public bool isPrivate;
|
||||
[SerializeField] public string createdAt;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected override WitRequest OnCreateRequest()
|
||||
{
|
||||
return witConfiguration.GetAppRequest(id);
|
||||
}
|
||||
|
||||
public override void UpdateData(WitResponseNode appWitResponse)
|
||||
{
|
||||
id = appWitResponse["id"].Value;
|
||||
name = appWitResponse["name"].Value;
|
||||
lang = appWitResponse["lang"].Value;
|
||||
isPrivate = appWitResponse["private"].AsBool;
|
||||
createdAt = appWitResponse["created_at"].Value;
|
||||
}
|
||||
|
||||
public static WitApplication FromJson(WitResponseNode appWitResponse)
|
||||
{
|
||||
var app = new WitApplication();
|
||||
app.UpdateData(appWitResponse);
|
||||
return app;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ca958861dc343789f31f1d597fd24cf
|
||||
timeCreated: 1621351239
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Configuration;
|
||||
using Facebook.WitAi.Data.Entities;
|
||||
using Facebook.WitAi.Data.Intents;
|
||||
using Facebook.WitAi.Data.Traits;
|
||||
using UnityEngine;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Facebook.WitAi.Data.Configuration
|
||||
{
|
||||
public class WitConfiguration : ScriptableObject
|
||||
{
|
||||
[HideInInspector]
|
||||
[SerializeField] public WitApplication application;
|
||||
[HideInInspector] [SerializeField] public string configId;
|
||||
|
||||
/// <summary>
|
||||
/// Access token used in builds to make requests for data from Wit.ai
|
||||
/// </summary>
|
||||
[Tooltip("Access token used in builds to make requests for data from Wit.ai")]
|
||||
[SerializeField] public string clientAccessToken;
|
||||
|
||||
[Tooltip("The number of milliseconds to wait before requests to Wit.ai will timeout")]
|
||||
[SerializeField] public int timeoutMS = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration parameters to set up a custom endpoint for testing purposes and request forwarding. The default values here will work for most.
|
||||
/// </summary>
|
||||
[Tooltip("Configuration parameters to set up a custom endpoint for testing purposes and request forwarding. The default values here will work for most.")]
|
||||
[SerializeField] public WitEndpointConfig endpointConfiguration = new WitEndpointConfig();
|
||||
|
||||
[SerializeField] public WitEntity[] entities;
|
||||
[SerializeField] public WitIntent[] intents;
|
||||
[SerializeField] public WitTrait[] traits;
|
||||
|
||||
public WitApplication Application => application;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (string.IsNullOrEmpty(configId))
|
||||
{
|
||||
configId = GUID.Generate().ToString();
|
||||
EditorUtility.SetDirty(this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae5a46bda3295124c99b0e6537ac7252
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Data.Configuration;
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Facebook.WitAi.Configuration
|
||||
{
|
||||
[Serializable]
|
||||
public abstract class WitConfigurationData
|
||||
{
|
||||
[SerializeField] public WitConfiguration witConfiguration;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public void UpdateData(Action onUpdateComplete = null)
|
||||
{
|
||||
if (!witConfiguration)
|
||||
{
|
||||
onUpdateComplete?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
var request = OnCreateRequest();
|
||||
request.onResponse = (r) => OnUpdateData(r, onUpdateComplete);
|
||||
request.Request();
|
||||
}
|
||||
|
||||
protected abstract WitRequest OnCreateRequest();
|
||||
|
||||
private void OnUpdateData(WitRequest request, Action onUpdateComplete)
|
||||
{
|
||||
if (request.StatusCode == 200)
|
||||
{
|
||||
UpdateData(request.ResponseData);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError(request.StatusDescription);
|
||||
}
|
||||
|
||||
onUpdateComplete?.Invoke();
|
||||
}
|
||||
|
||||
public abstract void UpdateData(WitResponseNode data);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 002ec29e2fc64951b9d57ab4cdbf659e
|
||||
timeCreated: 1621354945
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Data.Configuration;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Facebook.WitAi.Configuration
|
||||
{
|
||||
[Serializable]
|
||||
public class WitEndpointConfig
|
||||
{
|
||||
private static WitEndpointConfig defaultEndpointConfig = new WitEndpointConfig();
|
||||
|
||||
public string uriScheme;
|
||||
public string authority;
|
||||
public int port;
|
||||
|
||||
public string witApiVersion;
|
||||
|
||||
public string speech;
|
||||
public string message;
|
||||
|
||||
public string UriScheme => string.IsNullOrEmpty(uriScheme) ? WitRequest.URI_SCHEME : uriScheme;
|
||||
public string Authority =>
|
||||
string.IsNullOrEmpty(authority) ? WitRequest.URI_AUTHORITY : authority;
|
||||
public string WitApiVersion => string.IsNullOrEmpty(witApiVersion)
|
||||
? WitRequest.WIT_API_VERSION
|
||||
: witApiVersion;
|
||||
|
||||
public string Speech =>
|
||||
string.IsNullOrEmpty(speech) ? WitRequest.WIT_ENDPOINT_SPEECH : speech;
|
||||
|
||||
public string Message =>
|
||||
string.IsNullOrEmpty(message) ? WitRequest.WIT_ENDPOINT_MESSAGE : message;
|
||||
|
||||
public static WitEndpointConfig GetEndpointConfig(WitConfiguration witConfig)
|
||||
{
|
||||
return witConfig && null != witConfig.endpointConfiguration
|
||||
? witConfig.endpointConfiguration
|
||||
: defaultEndpointConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61a0415bfdfa4d64e89801fbc0b30ec7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Facebook.WitAi.Interfaces;
|
||||
|
||||
namespace Facebook.WitAi.Configuration
|
||||
{
|
||||
public class WitRequestOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface that provides a list of entities that should be used for nlu resolution.
|
||||
/// </summary>
|
||||
public IDynamicEntitiesProvider dynamicEntities;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of intent matches to return
|
||||
/// </summary>
|
||||
public int nBestIntents = -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6834fd3c55fb41a1885302e6043f5d6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Data.Configuration;
|
||||
using Facebook.WitAi.Interfaces;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Facebook.WitAi.Configuration
|
||||
{
|
||||
[Serializable]
|
||||
public class WitRuntimeConfiguration
|
||||
{
|
||||
[Tooltip("Configuration for the application used in this instance of Wit.ai services")]
|
||||
[SerializeField]
|
||||
public WitConfiguration witConfiguration;
|
||||
|
||||
[Header("Keepalive")]
|
||||
[Tooltip("The minimum volume from the mic needed to keep the activation alive")]
|
||||
[SerializeField]
|
||||
public float minKeepAliveVolume = .0005f;
|
||||
|
||||
[FormerlySerializedAs("minKeepAliveTime")]
|
||||
[Tooltip(
|
||||
"The amount of time in seconds an activation will be kept open after volume is under the keep alive threshold")]
|
||||
[SerializeField]
|
||||
public float minKeepAliveTimeInSeconds = 2f;
|
||||
|
||||
[FormerlySerializedAs("minTranscriptionKeepAliveTime")]
|
||||
[Tooltip(
|
||||
"The amount of time in seconds an activation will be kept open after words have been detected in the live transcription")]
|
||||
[SerializeField]
|
||||
public float minTranscriptionKeepAliveTimeInSeconds = 1f;
|
||||
|
||||
[Tooltip("The maximum amount of time in seconds the mic will stay active")]
|
||||
[Range(0, 20f)]
|
||||
[SerializeField]
|
||||
public float maxRecordingTime = 20;
|
||||
|
||||
[Header("Sound Activation")]
|
||||
[Tooltip("The minimum volume level needed to be heard to start collecting data from the audio source.")]
|
||||
[SerializeField] public float soundWakeThreshold = .0005f;
|
||||
|
||||
[Tooltip("The length of the individual samples read from the audio source")]
|
||||
[Range(10, 500)] [SerializeField] public int sampleLengthInMs = 10;
|
||||
|
||||
[Tooltip("The total audio data that should be buffered for lookback purposes on sound based activations.")]
|
||||
[SerializeField] public float micBufferLengthInSeconds = 1;
|
||||
|
||||
[Header("Custom Transcription")]
|
||||
[Tooltip(
|
||||
"If true, the audio recorded in the activation will be sent to Wit.ai for processing. If a custom transcription provider is set and this is false, only the transcription will be sent to Wit.ai for processing")]
|
||||
[SerializeField]
|
||||
public bool sendAudioToWit = true;
|
||||
|
||||
[Tooltip("A custom provider that returns text to be used for nlu processing on activation instead of sending audio.")]
|
||||
[SerializeField] public CustomTranscriptionProvider customTranscriptionProvider;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd8d40c9f75b44b5940fcc21769d6af0
|
||||
timeCreated: 1629397017
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d92a289db3a8408dba9dd973090b1ade
|
||||
timeCreated: 1632287743
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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 Facebook.WitAi.Interfaces;
|
||||
using Facebook.WitAi.Lib;
|
||||
|
||||
namespace Facebook.WitAi.Data.Entities
|
||||
{
|
||||
public class WitDynamicEntities : IDynamicEntitiesProvider
|
||||
{
|
||||
public WitResponseClass entities;
|
||||
|
||||
public WitDynamicEntities()
|
||||
{
|
||||
entities = new WitResponseClass();
|
||||
}
|
||||
|
||||
public void Add(WitSimpleDynamicEntity entity)
|
||||
{
|
||||
KeyValuePair<string, WitResponseArray> pair = entity.GetEntityPair();
|
||||
entities.Add(pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
public void Add(WitDynamicEntity entity)
|
||||
{
|
||||
KeyValuePair<string, WitResponseArray> pair = entity.GetEntityPair();
|
||||
entities.Add(pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
public string ToJSON()
|
||||
{
|
||||
return entities.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a296282c67dc244dd974baca4699c554
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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 Facebook.WitAi.Interfaces;
|
||||
using Facebook.WitAi.Lib;
|
||||
|
||||
namespace Facebook.WitAi.Data.Entities
|
||||
{
|
||||
public class WitDynamicEntity : IDynamicEntitiesProvider
|
||||
{
|
||||
public string entity;
|
||||
public Dictionary<string, List<string>> keywordsToSynonyms;
|
||||
|
||||
public WitDynamicEntity(string entity, Dictionary<string, List<string>> keywordsToSynonyms)
|
||||
{
|
||||
this.entity = entity;
|
||||
this.keywordsToSynonyms = keywordsToSynonyms;
|
||||
}
|
||||
|
||||
public KeyValuePair<string, WitResponseArray> GetEntityPair() {
|
||||
var keywordEntries = new WitResponseArray();
|
||||
foreach (var keywordToSynonyms in keywordsToSynonyms)
|
||||
{
|
||||
var synonyms = new WitResponseArray();
|
||||
foreach (string synonym in keywordToSynonyms.Value)
|
||||
{
|
||||
synonyms.Add(new WitResponseData(synonym));
|
||||
}
|
||||
|
||||
var keywordEntry = new WitResponseClass();
|
||||
keywordEntry.Add("keyword", new WitResponseData(keywordToSynonyms.Key));
|
||||
keywordEntry.Add("synonyms", synonyms);
|
||||
|
||||
keywordEntries.Add(keywordEntry);
|
||||
}
|
||||
return new KeyValuePair<string, WitResponseArray>(entity, keywordEntries);
|
||||
}
|
||||
|
||||
public string ToJSON()
|
||||
{
|
||||
KeyValuePair<string, WitResponseArray> pair = this.GetEntityPair();
|
||||
var root = new WitResponseClass();
|
||||
root.Add(pair.Key, pair.Value);
|
||||
return root.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efe24d6c4ed424d25a19396c7a2eec38
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Configuration;
|
||||
using Facebook.WitAi.Data.Keywords;
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Facebook.WitAi.Data.Entities
|
||||
{
|
||||
|
||||
[Serializable]
|
||||
public class WitEntity : WitConfigurationData
|
||||
{
|
||||
[SerializeField] public string id;
|
||||
[SerializeField] public string name;
|
||||
[SerializeField] public string[] lookups;
|
||||
[SerializeField] public WitEntityRole[] roles;
|
||||
[SerializeField] public WitKeyword[] keywords;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected override WitRequest OnCreateRequest()
|
||||
{
|
||||
return witConfiguration.GetEntityRequest(name);
|
||||
}
|
||||
|
||||
public override void UpdateData(WitResponseNode entityWitResponse)
|
||||
{
|
||||
id = entityWitResponse["id"].Value;
|
||||
name = entityWitResponse["name"].Value;
|
||||
lookups = entityWitResponse["lookups"].AsStringArray;
|
||||
var roleArray = entityWitResponse["roles"].AsArray;
|
||||
roles = new WitEntityRole[roleArray.Count];
|
||||
for (int i = 0; i < roleArray.Count; i++)
|
||||
{
|
||||
roles[i] = WitEntityRole.FromJson(roleArray[i]);
|
||||
}
|
||||
var keywordArray = entityWitResponse["keywords"].AsArray;
|
||||
keywords = new WitKeyword[keywordArray.Count];
|
||||
for (int i = 0; i < keywordArray.Count; i++)
|
||||
{
|
||||
keywords[i] = WitKeyword.FromJson(keywordArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static WitEntity FromJson(WitResponseNode entityWitResponse)
|
||||
{
|
||||
var entity = new WitEntity();
|
||||
entity.UpdateData(entityWitResponse);
|
||||
return entity;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b8d1931ec6f428ba4f36da3ddcb15f3
|
||||
timeCreated: 1621351104
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Facebook.WitAi.Data.Keywords
|
||||
{
|
||||
[Serializable]
|
||||
public class WitEntityRole
|
||||
{
|
||||
[SerializeField] public string id;
|
||||
[SerializeField] public string name;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static WitEntityRole FromJson(WitResponseNode roleNode)
|
||||
{
|
||||
return new WitEntityRole()
|
||||
{
|
||||
id = roleNode["id"],
|
||||
name = roleNode["name"]
|
||||
};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f1cc15e5a59a854e837f452c8f4f4d6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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 Facebook.WitAi.Interfaces;
|
||||
using Facebook.WitAi.Lib;
|
||||
|
||||
namespace Facebook.WitAi.Data.Entities
|
||||
{
|
||||
public class WitSimpleDynamicEntity : IDynamicEntitiesProvider
|
||||
{
|
||||
public List<string> keywords;
|
||||
public string entity;
|
||||
|
||||
public WitSimpleDynamicEntity(string entityIdentifier, List<string> words)
|
||||
{
|
||||
entity = entityIdentifier;
|
||||
keywords = words;
|
||||
}
|
||||
|
||||
public KeyValuePair<string, WitResponseArray> GetEntityPair() {
|
||||
var keywordEntries = new WitResponseArray();
|
||||
foreach (string keyword in keywords)
|
||||
{
|
||||
var synonyms = new WitResponseArray();
|
||||
synonyms.Add(new WitResponseData(keyword));
|
||||
|
||||
var keywordEntry = new WitResponseClass();
|
||||
keywordEntry.Add("keyword", new WitResponseData(keyword));
|
||||
keywordEntry.Add("synonyms", synonyms);
|
||||
|
||||
keywordEntries.Add(keywordEntry);
|
||||
}
|
||||
return new KeyValuePair<string, WitResponseArray>(entity, keywordEntries);
|
||||
}
|
||||
|
||||
public string ToJSON()
|
||||
{
|
||||
KeyValuePair<string, WitResponseArray> pair = this.GetEntityPair();
|
||||
var root = new WitResponseClass();
|
||||
root.Add(pair.Key, pair.Value);
|
||||
return root.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e15f31f7f3b6c49fb96d0553d125fe22
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7de07ce5d8884e15924606bffef7ed67
|
||||
timeCreated: 1632287863
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Configuration;
|
||||
using Facebook.WitAi.Data.Entities;
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Facebook.WitAi.Data.Intents
|
||||
{
|
||||
|
||||
[Serializable]
|
||||
public class WitIntent : WitConfigurationData
|
||||
{
|
||||
[SerializeField] public string id;
|
||||
[SerializeField] public string name;
|
||||
[SerializeField] public WitEntity[] entities;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected override WitRequest OnCreateRequest()
|
||||
{
|
||||
return witConfiguration.GetIntentRequest(name);
|
||||
}
|
||||
|
||||
public override void UpdateData(WitResponseNode intentWitResponse)
|
||||
{
|
||||
id = intentWitResponse["id"].Value;
|
||||
name = intentWitResponse["name"].Value;
|
||||
var entityArray = intentWitResponse["entities"].AsArray;
|
||||
var n = entityArray.Count;
|
||||
entities = new WitEntity[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
entities[i] = WitEntity.FromJson(entityArray[i]);
|
||||
entities[i].witConfiguration = witConfiguration;
|
||||
}
|
||||
}
|
||||
|
||||
public static WitIntent FromJson(WitResponseNode intentWitResponse)
|
||||
{
|
||||
var intent = new WitIntent();
|
||||
intent.UpdateData(intentWitResponse);
|
||||
return intent;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ce915454f6441089c0cc0ff88d57e00
|
||||
timeCreated: 1621351293
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90f74c8768a041f1803383e7c62e89e0
|
||||
timeCreated: 1632287849
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Facebook.WitAi.Data.Keywords
|
||||
{
|
||||
[Serializable]
|
||||
public class WitKeyword
|
||||
{
|
||||
[SerializeField] public string keyword;
|
||||
[SerializeField] public string[] synonyms;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static WitKeyword FromJson(WitResponseNode keywordNode)
|
||||
{
|
||||
return new WitKeyword()
|
||||
{
|
||||
keyword = keywordNode["keyword"],
|
||||
synonyms = keywordNode["synonyms"].AsStringArray
|
||||
};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe1fb6d27cfb4950b5a20bf9277959c2
|
||||
timeCreated: 1621351323
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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;
|
||||
|
||||
namespace Facebook.WitAi.Data
|
||||
{
|
||||
public class RingBuffer<T>
|
||||
{
|
||||
public delegate void OnDataAdded(T[] data, int offset, int length);
|
||||
|
||||
public OnDataAdded OnDataAddedEvent;
|
||||
|
||||
private T[] buffer;
|
||||
private int bufferIndex;
|
||||
private long bufferDataLength;
|
||||
public int Capacity => buffer.Length;
|
||||
|
||||
public void Clear(bool eraseData = false)
|
||||
{
|
||||
bufferIndex = 0;
|
||||
bufferDataLength = 0;
|
||||
|
||||
if (eraseData)
|
||||
{
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
buffer[i] = default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Marker
|
||||
{
|
||||
public long bufferDataIndex;
|
||||
public int index;
|
||||
public RingBuffer<T> ringBuffer;
|
||||
|
||||
public bool IsValid => ringBuffer.bufferDataLength - bufferDataIndex <= ringBuffer.Capacity;
|
||||
|
||||
public int Read(T[] buffer, int offset, int length, bool skipToNextValid = false)
|
||||
{
|
||||
int read = -1;
|
||||
if (!IsValid && skipToNextValid && ringBuffer.bufferDataLength > ringBuffer.Capacity)
|
||||
{
|
||||
bufferDataIndex = ringBuffer.bufferDataLength - ringBuffer.Capacity;
|
||||
}
|
||||
|
||||
if (IsValid)
|
||||
{
|
||||
read = this.ringBuffer.Read(buffer, offset, length, bufferDataIndex);
|
||||
bufferDataIndex += read;
|
||||
index += read;
|
||||
if (index > buffer.Length) index -= buffer.Length;
|
||||
}
|
||||
|
||||
|
||||
return read;
|
||||
}
|
||||
}
|
||||
|
||||
public RingBuffer(int capacity)
|
||||
{
|
||||
buffer = new T[capacity];
|
||||
}
|
||||
|
||||
private int CopyToBuffer(T[] data, int offset, int length, int bufferIndex)
|
||||
{
|
||||
if (length > buffer.Length)
|
||||
throw new ArgumentException(
|
||||
"Push data exceeds buffer size.");
|
||||
|
||||
if (bufferIndex + length < buffer.Length)
|
||||
{
|
||||
Array.Copy(data, offset, buffer, bufferIndex, length);
|
||||
return bufferIndex + length;
|
||||
}
|
||||
else
|
||||
{
|
||||
int len = Mathf.Min(length, buffer.Length);
|
||||
int endChunkLength = buffer.Length - bufferIndex;
|
||||
int wrappedChunkLength = len - endChunkLength;
|
||||
try
|
||||
{
|
||||
|
||||
Array.Copy(data, offset, buffer, bufferIndex, endChunkLength);
|
||||
Array.Copy(data, offset + endChunkLength, buffer, 0, wrappedChunkLength);
|
||||
return wrappedChunkLength;
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int CopyFromBuffer(T[] data, int offset, int length, int bufferIndex)
|
||||
{
|
||||
if (length > buffer.Length)
|
||||
throw new ArgumentException(
|
||||
$"Push data exceeds buffer size {length} < {buffer.Length}" );
|
||||
|
||||
if (bufferIndex + length < buffer.Length)
|
||||
{
|
||||
Array.Copy(buffer, bufferIndex, data, offset, length);
|
||||
return bufferIndex + length;
|
||||
}
|
||||
else
|
||||
{
|
||||
var l = Mathf.Min(buffer.Length, length);
|
||||
int endChunkLength = buffer.Length - bufferIndex;
|
||||
int wrappedChunkLength = l - endChunkLength;
|
||||
|
||||
Array.Copy(buffer, bufferIndex, data, offset, endChunkLength);
|
||||
Array.Copy(buffer, 0, data, offset + endChunkLength, wrappedChunkLength);
|
||||
return wrappedChunkLength;
|
||||
}
|
||||
}
|
||||
|
||||
public void Push(T[] data, int offset, int length)
|
||||
{
|
||||
lock (buffer)
|
||||
{
|
||||
bufferIndex = CopyToBuffer(data, offset, length, bufferIndex);
|
||||
bufferDataLength += length;
|
||||
OnDataAddedEvent?.Invoke(data, offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
public int Read(T[] data, int offset, int length, long bufferDataIndex)
|
||||
{
|
||||
lock (buffer)
|
||||
{
|
||||
int read = (int) (Math.Min(bufferDataIndex + length, bufferDataLength) -
|
||||
bufferDataIndex);
|
||||
|
||||
int bufferIndex = this.bufferIndex - (int) (bufferDataLength - bufferDataIndex);
|
||||
if (bufferIndex < 0)
|
||||
{
|
||||
bufferIndex = buffer.Length + bufferIndex;
|
||||
}
|
||||
|
||||
CopyFromBuffer(data, offset, length, bufferIndex);
|
||||
|
||||
return read;
|
||||
}
|
||||
}
|
||||
|
||||
public Marker CreateMarker(int offset = 0)
|
||||
{
|
||||
var markerPosition = bufferDataLength + offset;
|
||||
if (markerPosition < 0)
|
||||
{
|
||||
markerPosition = 0;
|
||||
}
|
||||
|
||||
int bufIndex = bufferIndex + offset;
|
||||
if (bufIndex < 0)
|
||||
{
|
||||
bufIndex = buffer.Length + bufIndex;
|
||||
}
|
||||
|
||||
if (bufIndex > buffer.Length)
|
||||
{
|
||||
bufIndex = bufIndex - buffer.Length;
|
||||
}
|
||||
|
||||
var marker = new Marker()
|
||||
{
|
||||
ringBuffer = this,
|
||||
bufferDataIndex = markerPosition,
|
||||
index = bufIndex
|
||||
};
|
||||
return marker;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e01ee0aa0d794f7abb30675495fd7ca9
|
||||
timeCreated: 1626392023
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 982d60138e5147b88a5117adc9ded942
|
||||
timeCreated: 1632287691
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Configuration;
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Facebook.WitAi.Data.Traits
|
||||
{
|
||||
[Serializable]
|
||||
public class WitTrait : WitConfigurationData
|
||||
{
|
||||
[SerializeField] public string id;
|
||||
[SerializeField] public string name;
|
||||
[SerializeField] public WitTraitValue[] values;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected override WitRequest OnCreateRequest()
|
||||
{
|
||||
return witConfiguration.GetTraitRequest(name);
|
||||
}
|
||||
|
||||
public override void UpdateData(WitResponseNode traitWitResponse)
|
||||
{
|
||||
id = traitWitResponse["id"].Value;
|
||||
name = traitWitResponse["name"].Value;
|
||||
var valueArray = traitWitResponse["values"].AsArray;
|
||||
var n = valueArray.Count;
|
||||
values = new WitTraitValue[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
values[i] = WitTraitValue.FromJson(valueArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static WitTrait FromJson(WitResponseNode traitWitResponse)
|
||||
{
|
||||
var trait = new WitTrait();
|
||||
trait.UpdateData(traitWitResponse);
|
||||
return trait;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79360a5e236054d4b85a1370ec7d7a96
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Facebook.WitAi.Data.Traits
|
||||
{
|
||||
[Serializable]
|
||||
public class WitTraitValue
|
||||
{
|
||||
[SerializeField] public string id;
|
||||
[SerializeField] public string value;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static WitTraitValue FromJson(WitResponseNode traitValueNode)
|
||||
{
|
||||
return new WitTraitValue()
|
||||
{
|
||||
id = traitValueNode["id"],
|
||||
value = traitValueNode["value"]
|
||||
};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3dfd1d331e52e46608615baf91fad0b3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Facebook.WitAi.Data
|
||||
{
|
||||
public class WitFloatValue : WitValue
|
||||
{
|
||||
[SerializeField] public float equalityTolerance = .0001f;
|
||||
|
||||
public override object GetValue(WitResponseNode response)
|
||||
{
|
||||
return GetFloatValue(response);
|
||||
}
|
||||
|
||||
public override bool Equals(WitResponseNode response, object value)
|
||||
{
|
||||
float fValue = 0;
|
||||
if (value is float f)
|
||||
{
|
||||
fValue = f;
|
||||
}
|
||||
else if(null != value && !float.TryParse("" + value, out fValue))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Math.Abs(GetFloatValue(response) - fValue) < equalityTolerance;
|
||||
}
|
||||
|
||||
public float GetFloatValue(WitResponseNode response)
|
||||
{
|
||||
return Reference.GetFloatValue(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab8864132457433b8281c87f23398770
|
||||
timeCreated: 1624318241
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Facebook.WitAi.Lib;
|
||||
|
||||
namespace Facebook.WitAi.Data
|
||||
{
|
||||
public class WitIntValue : WitValue
|
||||
{
|
||||
public override object GetValue(WitResponseNode response)
|
||||
{
|
||||
return GetIntValue(response);
|
||||
}
|
||||
|
||||
public override bool Equals(WitResponseNode response, object value)
|
||||
{
|
||||
int iValue = 0;
|
||||
if (value is int i)
|
||||
{
|
||||
iValue = i;
|
||||
}
|
||||
else if (null != value && !int.TryParse("" + value, out iValue))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetIntValue(response) == iValue;
|
||||
}
|
||||
|
||||
public int GetIntValue(WitResponseNode response)
|
||||
{
|
||||
return Reference.GetIntValue(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02641aecd6e142a1b375ed2fb84b8303
|
||||
timeCreated: 1624318209
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Facebook.WitAi.Lib;
|
||||
|
||||
namespace Facebook.WitAi.Data
|
||||
{
|
||||
public class WitStringValue : WitValue
|
||||
{
|
||||
public override object GetValue(WitResponseNode response)
|
||||
{
|
||||
return GetStringValue(response);
|
||||
}
|
||||
|
||||
public override bool Equals(WitResponseNode response, object value)
|
||||
{
|
||||
if (value is string sValue)
|
||||
{
|
||||
return GetStringValue(response) == sValue;
|
||||
}
|
||||
|
||||
return "" + value == GetStringValue(response);
|
||||
}
|
||||
|
||||
public string GetStringValue(WitResponseNode response)
|
||||
{
|
||||
return Reference.GetStringValue(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 872feba58ea14c069669a1d25959b22c
|
||||
timeCreated: 1624318051
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Facebook.WitAi.Data
|
||||
{
|
||||
public abstract class WitValue : ScriptableObject
|
||||
{
|
||||
[SerializeField] public string path;
|
||||
private WitResponseReference reference;
|
||||
|
||||
public WitResponseReference Reference
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == reference)
|
||||
{
|
||||
reference = WitResultUtilities.GetWitResponseReference(path);
|
||||
}
|
||||
|
||||
return reference;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract object GetValue(WitResponseNode response);
|
||||
|
||||
public abstract bool Equals(WitResponseNode response, object value);
|
||||
|
||||
public string ToString(WitResponseNode response)
|
||||
{
|
||||
return Reference.GetStringValue(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d14d7c8a51621ce419693992b114e2ce
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 401db7761c526c3448f1af1d549ec9f9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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 UnityEngine.Events;
|
||||
|
||||
namespace Facebook.WitAi.Events
|
||||
{
|
||||
[Serializable]
|
||||
public class VoiceEvents
|
||||
{
|
||||
[Header("Activation Result Events")]
|
||||
[Tooltip("Called when a response from Wit.ai has been received")]
|
||||
public WitResponseEvent OnResponse = new WitResponseEvent();
|
||||
|
||||
[Tooltip(
|
||||
"Called when there was an error with a WitRequest or the RuntimeConfiguration is not properly configured.")]
|
||||
public WitErrorEvent OnError = new WitErrorEvent();
|
||||
|
||||
[Tooltip(
|
||||
"Called when the activation stopped because the network request was aborted. This can be via a timeout or call to AbortActivation.")]
|
||||
public UnityEvent OnAborted = new UnityEvent();
|
||||
|
||||
[Tooltip(
|
||||
"Called when a a request has completed and all response and error callbacks have fired.")]
|
||||
public UnityEvent OnRequestCompleted = new UnityEvent();
|
||||
|
||||
[Header("Mic Events")]
|
||||
[Tooltip("Called when the volume level of the mic input has changed")]
|
||||
public WitMicLevelChangedEvent OnMicLevelChanged = new WitMicLevelChangedEvent();
|
||||
|
||||
/// <summary>
|
||||
/// Called when a request is created. This happens at the beginning of
|
||||
/// an activation before the microphone is activated (if in use).
|
||||
/// </summary>
|
||||
[Header("Activation/Deactivation Events")]
|
||||
[Tooltip(
|
||||
"Called when a request is created. This happens at the beginning of an activation before the microphone is activated (if in use)")]
|
||||
public WitRequestCreatedEvent OnRequestCreated = new WitRequestCreatedEvent();
|
||||
|
||||
[Tooltip("Called when the microphone has started collecting data collecting data to be sent to Wit.ai. There may be some buffering before data transmission starts.")]
|
||||
public UnityEvent OnStartListening = new UnityEvent();
|
||||
|
||||
[Tooltip(
|
||||
"Called when the voice service is no longer collecting data from the microphone")]
|
||||
public UnityEvent OnStoppedListening = new UnityEvent();
|
||||
|
||||
[Tooltip(
|
||||
"Called when the microphone input volume has been below the volume threshold for the specified duration and microphone data is no longer being collected")]
|
||||
public UnityEvent OnStoppedListeningDueToInactivity = new UnityEvent();
|
||||
|
||||
[Tooltip(
|
||||
"The microphone has stopped recording because maximum recording time has been hit for this activation")]
|
||||
public UnityEvent OnStoppedListeningDueToTimeout = new UnityEvent();
|
||||
|
||||
[Tooltip("The Deactivate() method has been called ending the current activation.")]
|
||||
public UnityEvent OnStoppedListeningDueToDeactivation = new UnityEvent();
|
||||
|
||||
[Tooltip("Fired when recording stops, the minimum volume threshold was hit, and data is being sent to the server.")]
|
||||
public UnityEvent OnMicDataSent = new UnityEvent();
|
||||
|
||||
[Tooltip("Fired when the minimum wake threshold is hit after an activation")]
|
||||
public UnityEvent OnMinimumWakeThresholdHit = new UnityEvent();
|
||||
|
||||
[Header("Transcription Events")]
|
||||
[Tooltip("Message fired when a partial transcription has been received.")]
|
||||
public WitTranscriptionEvent OnPartialTranscription = new WitTranscriptionEvent();
|
||||
|
||||
[Tooltip("Message received when a complete transcription is received.")]
|
||||
public WitTranscriptionEvent OnFullTranscription = new WitTranscriptionEvent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 371044f8a8a85b34aa78547a31c99aa0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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.Events;
|
||||
|
||||
namespace Facebook.WitAi.Events
|
||||
{
|
||||
[Serializable]
|
||||
public class WitErrorEvent : UnityEvent<string, string>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a3a49a4b636e7e4d937f923f434789a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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.Events;
|
||||
|
||||
namespace Facebook.WitAi.Events
|
||||
{
|
||||
[Serializable]
|
||||
public class WitMicLevelChangedEvent : UnityEvent<float>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 533049bdcc7a20a41b6fc9f90b951fd0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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.Events;
|
||||
|
||||
namespace Facebook.WitAi.Events
|
||||
{
|
||||
[Serializable]
|
||||
public class WitRequestCreatedEvent : UnityEvent<WitRequest>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2134bc577e5e4ae2a9a3a1e37f1ac0dc
|
||||
timeCreated: 1623191846
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Facebook.WitAi.Events
|
||||
{
|
||||
[Serializable]
|
||||
public class WitResponseEvent : UnityEvent<WitResponseNode>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ef88cd3e80185c4a90060968bd7c213
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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.Events;
|
||||
|
||||
namespace Facebook.WitAi.Events
|
||||
{
|
||||
[Serializable]
|
||||
public class WitTranscriptionEvent : UnityEvent<string> { }
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 984bfa2088e54a9ca440be6b82c17409
|
||||
timeCreated: 1627418910
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "Facebook.WitAI",
|
||||
"references": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4504b1a6e0fdcc3498c30b266e4a63bf
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a21d7613f5cf4e8e84108c72a77f7982
|
||||
timeCreated: 1627419158
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Facebook.WitAi.Events;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Facebook.WitAi.Interfaces
|
||||
{
|
||||
public abstract class CustomTranscriptionProvider : MonoBehaviour, ITranscriptionProvider
|
||||
{
|
||||
[SerializeField] private bool overrideMicLevel = false;
|
||||
|
||||
private WitTranscriptionEvent onPartialTranscription = new WitTranscriptionEvent();
|
||||
private WitTranscriptionEvent onFullTranscription = new WitTranscriptionEvent();
|
||||
private UnityEvent onStoppedListening = new UnityEvent();
|
||||
private UnityEvent onStartListening = new UnityEvent();
|
||||
private WitMicLevelChangedEvent onMicLevelChanged = new WitMicLevelChangedEvent();
|
||||
|
||||
public string LastTranscription { get; }
|
||||
public WitTranscriptionEvent OnPartialTranscription => onPartialTranscription;
|
||||
public WitTranscriptionEvent OnFullTranscription => onFullTranscription;
|
||||
public UnityEvent OnStoppedListening => onStoppedListening;
|
||||
public UnityEvent OnStartListening => onStartListening;
|
||||
public WitMicLevelChangedEvent OnMicLevelChanged => onMicLevelChanged;
|
||||
public bool OverrideMicLevel => overrideMicLevel;
|
||||
|
||||
public abstract void Activate();
|
||||
public abstract void Deactivate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50fac6ce6a884eaa84d6cfb63f450670
|
||||
timeCreated: 1627419888
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Data;
|
||||
|
||||
namespace Facebook.WitAi.Interfaces
|
||||
{
|
||||
public interface IAudioInputSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked when the instance starts Recording.
|
||||
/// </summary>
|
||||
event Action OnStartRecording;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when an AudioClip couldn't be created to start recording.
|
||||
/// </summary>
|
||||
event Action OnStartRecordingFailed;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked everytime an audio frame is collected. Includes the frame.
|
||||
/// </summary>
|
||||
event Action<int, float[], float> OnSampleReady;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the instance stop Recording.
|
||||
/// </summary>
|
||||
event Action OnStopRecording;
|
||||
|
||||
void StartRecording(int sampleLen);
|
||||
|
||||
void StopRecording();
|
||||
|
||||
bool IsRecording { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Settings determining how audio is encoded by the source.
|
||||
///
|
||||
/// NOTE: Default values for AudioEncoding are server optimized to reduce latency.
|
||||
/// </summary>
|
||||
AudioEncoding AudioEncoding { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Return true if input is available.
|
||||
/// </summary>
|
||||
bool IsInputAvailable { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81c62281766f8244abee4cbc076cc41c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
namespace Facebook.WitAi.Interfaces
|
||||
{
|
||||
public interface IDynamicEntitiesProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to get dynamic entities
|
||||
/// </summary>
|
||||
string ToJSON();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8d2a4f3de747488da5e7ae246145740
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Facebook.WitAi.Events;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Facebook.WitAi.Interfaces
|
||||
{
|
||||
public interface ITranscriptionProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides the last transcription value (could be a partial transcription)
|
||||
/// </summary>
|
||||
string LastTranscription { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Callback used to notify Wit subscribers of a partial transcription.
|
||||
/// </summary>
|
||||
WitTranscriptionEvent OnPartialTranscription { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Callback used to notify Wit subscribers of a full transcription
|
||||
/// </summary>
|
||||
WitTranscriptionEvent OnFullTranscription { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Callback used to notify Wit subscribers when the mic is active and transcription has begun
|
||||
/// </summary>
|
||||
UnityEvent OnStoppedListening { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Callback used to notify Wit subscribers when the mic is inactive and transcription has stopped
|
||||
/// </summary>
|
||||
UnityEvent OnStartListening { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Callback used to notify Wit subscribers on mic volume level changes
|
||||
/// </summary>
|
||||
WitMicLevelChangedEvent OnMicLevelChanged { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Tells Wit if the mic input levels from the transcription service should be used directly
|
||||
/// </summary>
|
||||
bool OverrideMicLevel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Called when wit is activated
|
||||
/// </summary>
|
||||
void Activate();
|
||||
|
||||
/// <summary>
|
||||
/// Called when
|
||||
/// </summary>
|
||||
void Deactivate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bec6f48a64514913a8463a5c3b28657f
|
||||
timeCreated: 1627419181
|
||||
9
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/Lib.meta
Normal file
9
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/Lib.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4bed4430ab45442989d8b3e16635c337
|
||||
folderAsset: yes
|
||||
timeCreated: 1457198032
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
324
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/Lib/Mic.cs
Normal file
324
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/Lib/Mic.cs
Normal file
@@ -0,0 +1,324 @@
|
||||
// This code is licensed under the MIT License.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files(the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions :
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
// Source: https://github.com/adrenak/unimic/blob/master/Assets/UniMic/Runtime/Mic.cs
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Facebook.WitAi.Data;
|
||||
using Facebook.WitAi.Interfaces;
|
||||
|
||||
namespace Facebook.WitAi.Lib
|
||||
{
|
||||
[RequireComponent(typeof(AudioSource))]
|
||||
public class Mic : MonoBehaviour, IAudioInputSource
|
||||
{
|
||||
// ================================================
|
||||
|
||||
#region MEMBERS
|
||||
|
||||
// ================================================
|
||||
/// <summary>
|
||||
/// Whether the microphone is running
|
||||
/// </summary>
|
||||
public bool IsRecording { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Settings used to encode audio. Defaults to optimal server settings
|
||||
/// </summary>
|
||||
public AudioEncoding AudioEncoding { get; } = new AudioEncoding();
|
||||
|
||||
/// <summary>
|
||||
/// Last populated audio sample
|
||||
/// </summary>
|
||||
public float[] Sample { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sample duration/length in milliseconds
|
||||
/// </summary>
|
||||
public int SampleDurationMS { get; private set; }
|
||||
|
||||
public bool IsInputAvailable => AudioClip;
|
||||
|
||||
/// <summary>
|
||||
/// The length of the sample float array
|
||||
/// </summary>
|
||||
public int SampleLength
|
||||
{
|
||||
get { return AudioEncoding.samplerate * SampleDurationMS / 1000; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The AudioClip currently being streamed in the Mic
|
||||
/// </summary>
|
||||
public AudioClip AudioClip { get; private set; }
|
||||
|
||||
private List<string> devices;
|
||||
|
||||
/// <summary>
|
||||
/// List of all the available Mic devices
|
||||
/// </summary>
|
||||
public List<string> Devices
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == devices)
|
||||
{
|
||||
devices = new List<string>();
|
||||
foreach (var device in Microphone.devices)
|
||||
{
|
||||
devices.Add(device);
|
||||
}
|
||||
}
|
||||
|
||||
return devices;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Index of the current Mic device in m_Devices
|
||||
/// </summary>
|
||||
public int CurrentDeviceIndex { get; private set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the Mic device currently in use
|
||||
/// </summary>
|
||||
public string CurrentDeviceName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (CurrentDeviceIndex < 0 || CurrentDeviceIndex >= Devices.Count)
|
||||
return string.Empty;
|
||||
return Devices[CurrentDeviceIndex];
|
||||
}
|
||||
}
|
||||
|
||||
int m_SampleCount = 0;
|
||||
|
||||
#endregion
|
||||
|
||||
// ================================================
|
||||
|
||||
#region EVENTS
|
||||
|
||||
// ================================================
|
||||
/// <summary>
|
||||
/// Invoked when the instance starts Recording.
|
||||
/// </summary>
|
||||
public event Action OnStartRecording;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when an AudioClip couldn't be created to start recording.
|
||||
/// </summary>
|
||||
public event Action OnStartRecordingFailed;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked everytime an audio frame is collected. Includes the frame.
|
||||
/// </summary>
|
||||
public event Action<int, float[], float> OnSampleReady;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the instance stop Recording.
|
||||
/// </summary>
|
||||
public event Action OnStopRecording;
|
||||
|
||||
#endregion
|
||||
|
||||
// ================================================
|
||||
|
||||
#region METHODS
|
||||
|
||||
// ================================================
|
||||
|
||||
static Mic m_Instance;
|
||||
|
||||
public static Mic Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Instance == null)
|
||||
m_Instance = GameObject.FindObjectOfType<Mic>();
|
||||
if (m_Instance == null)
|
||||
{
|
||||
m_Instance = new GameObject("UniMic.Mic").AddComponent<Mic>();
|
||||
DontDestroyOnLoad(m_Instance.gameObject);
|
||||
}
|
||||
|
||||
return m_Instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static Mic Instantiate()
|
||||
{
|
||||
return Instance;
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
CurrentDeviceIndex = 0;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
StartMicrophone();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
StopMicrophone();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes to a Mic device for Recording
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the Mic device. Refer to <see cref="Devices"/></param>
|
||||
public void ChangeDevice(int index)
|
||||
{
|
||||
StopMicrophone();
|
||||
CurrentDeviceIndex = index;
|
||||
StartMicrophone();
|
||||
}
|
||||
|
||||
private void StartMicrophone()
|
||||
{
|
||||
Debug.Log("[Mic] Reserved mic " + CurrentDeviceName);
|
||||
AudioClip = Microphone.Start(CurrentDeviceName, true, 1, AudioEncoding.samplerate);
|
||||
}
|
||||
|
||||
private void StopMicrophone()
|
||||
{
|
||||
Debug.Log("[Mic] Released mic " + CurrentDeviceName);
|
||||
Microphone.End(CurrentDeviceName);
|
||||
Destroy(AudioClip);
|
||||
AudioClip = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts to stream the input of the current Mic device
|
||||
/// </summary>
|
||||
public void StartRecording(int sampleLen = 10)
|
||||
{
|
||||
if (!IsInputAvailable)
|
||||
{
|
||||
Debug.LogWarning("Tried to start recording when no input is available.");
|
||||
return;
|
||||
}
|
||||
|
||||
StopRecording();
|
||||
|
||||
if (!Microphone.IsRecording(CurrentDeviceName))
|
||||
{
|
||||
Debug.Log("[Mic] " + CurrentDeviceName + " was not started when starting recording, restarting mic.");
|
||||
StartMicrophone();
|
||||
}
|
||||
|
||||
IsRecording = true;
|
||||
|
||||
SampleDurationMS = sampleLen;
|
||||
|
||||
Sample = new float[AudioEncoding.samplerate / 1000 * SampleDurationMS * AudioClip.channels];
|
||||
|
||||
if (AudioClip)
|
||||
{
|
||||
StartCoroutine(ReadRawAudio());
|
||||
|
||||
// Make sure we seek before we start reading data
|
||||
Microphone.GetPosition(CurrentDeviceName);
|
||||
|
||||
Debug.Log("[Mic] Started recording with " + CurrentDeviceName);
|
||||
if (OnStartRecording != null)
|
||||
OnStartRecording.Invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnStartRecordingFailed.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ends the Mic stream.
|
||||
/// </summary>
|
||||
public void StopRecording()
|
||||
{
|
||||
if (!IsRecording) return;
|
||||
|
||||
IsRecording = false;
|
||||
|
||||
StopCoroutine(ReadRawAudio());
|
||||
|
||||
Debug.Log("[Mic] Stopped recording with " + CurrentDeviceName);
|
||||
if (OnStopRecording != null)
|
||||
OnStopRecording.Invoke();
|
||||
}
|
||||
|
||||
IEnumerator ReadRawAudio()
|
||||
{
|
||||
int loops = 0;
|
||||
int readAbsPos = Microphone.GetPosition(CurrentDeviceName);
|
||||
int prevPos = readAbsPos;
|
||||
float[] temp = new float[Sample.Length];
|
||||
|
||||
while (AudioClip != null && Microphone.IsRecording(CurrentDeviceName) && IsRecording)
|
||||
{
|
||||
bool isNewDataAvailable = true;
|
||||
|
||||
while (isNewDataAvailable && AudioClip)
|
||||
{
|
||||
int currPos = Microphone.GetPosition(CurrentDeviceName);
|
||||
if (currPos < prevPos)
|
||||
loops++;
|
||||
prevPos = currPos;
|
||||
|
||||
var currAbsPos = loops * AudioClip.samples + currPos;
|
||||
var nextReadAbsPos = readAbsPos + temp.Length;
|
||||
float levelMax = 0;
|
||||
|
||||
if (nextReadAbsPos < currAbsPos)
|
||||
{
|
||||
AudioClip.GetData(temp, readAbsPos % AudioClip.samples);
|
||||
|
||||
for (int i = 0; i < temp.Length; i++)
|
||||
{
|
||||
float wavePeak = temp[i] * temp[i];
|
||||
if (levelMax < wavePeak)
|
||||
{
|
||||
levelMax = wavePeak;
|
||||
}
|
||||
}
|
||||
|
||||
Sample = temp;
|
||||
m_SampleCount++;
|
||||
OnSampleReady?.Invoke(m_SampleCount, Sample, levelMax);
|
||||
|
||||
readAbsPos = nextReadAbsPos;
|
||||
isNewDataAvailable = true;
|
||||
}
|
||||
else
|
||||
isNewDataAvailable = false;
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8114fd1d3bfe3ce48bffcfaec698d3f0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1235
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/Lib/WitResponse.cs
Normal file
1235
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/Lib/WitResponse.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ef328494fca85148bb746014c16c292
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eaaa645786994d1eacdac103429cb049
|
||||
timeCreated: 1626731133
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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 UnityEngine.Events;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Facebook.WitAi.Utilities
|
||||
{
|
||||
public static class CoroutineUtility
|
||||
{
|
||||
// Start coroutine
|
||||
public static CoroutinePerformer StartCoroutine(IEnumerator asyncMethod)
|
||||
{
|
||||
CoroutinePerformer performer = GetPerformer();
|
||||
performer.CoroutineBegin(asyncMethod);
|
||||
return performer;
|
||||
}
|
||||
// Get performer
|
||||
private static CoroutinePerformer GetPerformer()
|
||||
{
|
||||
CoroutinePerformer performer = new GameObject("Coroutine").AddComponent<CoroutinePerformer>();
|
||||
//performer.gameObject.hideFlags = HideFlags.DontSave;
|
||||
performer.gameObject.hideFlags = HideFlags.HideAndDontSave;
|
||||
return performer;
|
||||
}
|
||||
// Coroutine performer
|
||||
public class CoroutinePerformer : MonoBehaviour
|
||||
{
|
||||
// Coroutine
|
||||
public bool isRunning { get; private set; }
|
||||
private Coroutine _runtimeCoroutine;
|
||||
|
||||
// Dont destroy
|
||||
private void Awake()
|
||||
{
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
|
||||
// Perform coroutine
|
||||
public void CoroutineBegin(IEnumerator asyncMethod)
|
||||
{
|
||||
// Cannot call twice
|
||||
if (isRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Begin running
|
||||
isRunning = true;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Editor mode
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
_editorMethod = asyncMethod;
|
||||
UnityEditor.EditorApplication.update += EditorCoroutineIterate;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Begin coroutine
|
||||
_runtimeCoroutine = StartCoroutine(RuntimeCoroutineIterate(asyncMethod));
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Editor iterate
|
||||
private IEnumerator _editorMethod;
|
||||
private void EditorCoroutineIterate()
|
||||
{
|
||||
if (_editorMethod != null)
|
||||
{
|
||||
if (!_editorMethod.MoveNext())
|
||||
{
|
||||
CoroutineComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Runtime iterate
|
||||
private IEnumerator RuntimeCoroutineIterate(IEnumerator asyncMethod)
|
||||
{
|
||||
// Wait for completion
|
||||
yield return StartCoroutine(asyncMethod);
|
||||
// Complete
|
||||
CoroutineComplete();
|
||||
}
|
||||
|
||||
// Cancel on destroy
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (isRunning)
|
||||
{
|
||||
CoroutineCancel();
|
||||
}
|
||||
}
|
||||
// Cancel coroutine
|
||||
public void CoroutineCancel()
|
||||
{
|
||||
if (isRunning)
|
||||
{
|
||||
CoroutineComplete();
|
||||
}
|
||||
}
|
||||
// Completed
|
||||
private void CoroutineComplete()
|
||||
{
|
||||
// Ignore unless running
|
||||
if (!isRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Done
|
||||
isRunning = false;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Complete
|
||||
if (_editorMethod != null)
|
||||
{
|
||||
UnityEditor.EditorApplication.update -= EditorCoroutineIterate;
|
||||
_editorMethod = null;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Stop coroutine
|
||||
if (_runtimeCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_runtimeCoroutine);
|
||||
_runtimeCoroutine = null;
|
||||
}
|
||||
|
||||
// Destroy
|
||||
DestroyImmediate(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 035128205ec689d418add9b65e3e21a7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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 UnityEngine.Events;
|
||||
|
||||
namespace Facebook.WitAi.Utilities
|
||||
{
|
||||
public class FloatToStringEvent : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private string format;
|
||||
[SerializeField] private StringEvent onFloatToString = new StringEvent();
|
||||
|
||||
public void ConvertFloatToString(float value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(format))
|
||||
{
|
||||
onFloatToString?.Invoke(value.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
onFloatToString?.Invoke(value.ToString(format));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class StringEvent : UnityEvent<string> {}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c63293fa01c74b159135d721528a5c47
|
||||
timeCreated: 1626731148
|
||||
150
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/VoiceService.cs
Normal file
150
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/VoiceService.cs
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using Facebook.WitAi.Configuration;
|
||||
using Facebook.WitAi.Events;
|
||||
using Facebook.WitAi.Interfaces;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Facebook.WitAi
|
||||
{
|
||||
public abstract class VoiceService : MonoBehaviour, IVoiceService
|
||||
{
|
||||
[Tooltip("Events that will fire before, during and after an activation")] [SerializeField]
|
||||
public VoiceEvents events = new VoiceEvents();
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this voice service is currently active and listening with the mic
|
||||
/// </summary>
|
||||
public abstract bool Active { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the service is actively communicating with Wit.ai during an Activation. The mic may or may not still be active while this is true.
|
||||
/// </summary>
|
||||
public abstract bool IsRequestActive { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets/Sets a custom transcription provider. This can be used to replace any built in asr
|
||||
/// with an on device model or other provided source
|
||||
/// </summary>
|
||||
public abstract ITranscriptionProvider TranscriptionProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this voice service is currently reading data from the microphone
|
||||
/// </summary>
|
||||
public abstract bool MicActive { get; }
|
||||
|
||||
public VoiceEvents VoiceEvents
|
||||
{
|
||||
get => events;
|
||||
set => events = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the audio input should be read in an activation
|
||||
/// </summary>
|
||||
protected abstract bool ShouldSendMicData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Start listening for sound or speech from the user and start sending data to Wit.ai once sound or speech has been detected.
|
||||
/// </summary>
|
||||
public abstract void Activate();
|
||||
|
||||
/// <summary>
|
||||
/// Activate the microphone and send data for NLU processing. Includes optional additional request parameters like dynamic entities and maximum results.
|
||||
/// </summary>
|
||||
/// <param name="requestOptions"></param>
|
||||
public abstract void Activate(WitRequestOptions requestOptions);
|
||||
|
||||
/// <summary>
|
||||
/// Activate the microphone and send data for NLU processing immediately without waiting for sound/speech from the user to begin.
|
||||
/// </summary>
|
||||
public abstract void ActivateImmediately();
|
||||
|
||||
/// <summary>
|
||||
/// Activate the microphone and send data for NLU processing immediately without waiting for sound/speech from the user to begin. Includes optional additional request parameters like dynamic entities and maximum results.
|
||||
/// </summary>
|
||||
public abstract void ActivateImmediately(WitRequestOptions requestOptions);
|
||||
|
||||
/// <summary>
|
||||
/// Stop listening and submit any remaining buffered microphone data for processing.
|
||||
/// </summary>
|
||||
public abstract void Deactivate();
|
||||
|
||||
/// <summary>
|
||||
/// Stop listening and abort any requests that may be active without waiting for a response.
|
||||
/// </summary>
|
||||
public abstract void DeactivateAndAbortRequest();
|
||||
|
||||
/// <summary>
|
||||
/// Send text data for NLU processing. Results will return the same way a voice based activation would.
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public abstract void Activate(string text);
|
||||
|
||||
/// <summary>
|
||||
/// Send text data for NLU processing with custom request options.
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="requestOptions"></param>
|
||||
public abstract void Activate(string text, WitRequestOptions requestOptions);
|
||||
}
|
||||
|
||||
public interface IVoiceService
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns true if this voice service is currently active and listening with the mic
|
||||
/// </summary>
|
||||
bool Active { get; }
|
||||
|
||||
bool IsRequestActive { get; }
|
||||
|
||||
bool MicActive { get; }
|
||||
|
||||
VoiceEvents VoiceEvents { get; set; }
|
||||
|
||||
ITranscriptionProvider TranscriptionProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Activate the microphone and send data for NLU processing.
|
||||
/// </summary>
|
||||
void Activate();
|
||||
|
||||
/// <summary>
|
||||
/// Activate the microphone and send data for NLU processing with custom request options.
|
||||
/// </summary>
|
||||
/// <param name="requestOptions"></param>
|
||||
void Activate(WitRequestOptions requestOptions);
|
||||
|
||||
void ActivateImmediately();
|
||||
void ActivateImmediately(WitRequestOptions requestOptions);
|
||||
|
||||
/// <summary>
|
||||
/// Stop listening and submit the collected microphone data for processing.
|
||||
/// </summary>
|
||||
void Deactivate();
|
||||
|
||||
/// <summary>
|
||||
/// Stop listening and abort any requests that may be active without waiting for a response.
|
||||
/// </summary>
|
||||
void DeactivateAndAbortRequest();
|
||||
|
||||
/// <summary>
|
||||
/// Send text data for NLU processing
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
void Activate(string transcription);
|
||||
|
||||
/// <summary>
|
||||
/// Send text data for NLU processing with custom request options.
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="requestOptions"></param>
|
||||
void Activate(string text, WitRequestOptions requestOptions);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f35aa1bc031e0946bf0aae2b8137ea1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
543
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/Wit.cs
Normal file
543
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/Wit.cs
Normal file
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net;
|
||||
using Facebook.WitAi.Configuration;
|
||||
using Facebook.WitAi.Data;
|
||||
using Facebook.WitAi.Interfaces;
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Facebook.WitAi
|
||||
{
|
||||
public class Wit : VoiceService, IWitRuntimeConfigProvider
|
||||
{
|
||||
[Header("Wit Configuration")]
|
||||
[FormerlySerializedAs("configuration")]
|
||||
[Tooltip("The configuration that will be used when activating wit. This includes api key.")]
|
||||
[SerializeField]
|
||||
private WitRuntimeConfiguration runtimeConfiguration = new WitRuntimeConfiguration();
|
||||
|
||||
private float activationTime;
|
||||
private IAudioInputSource micInput;
|
||||
private WitRequestOptions currentRequestOptions;
|
||||
private float lastMinVolumeLevelTime;
|
||||
private WitRequest activeRequest;
|
||||
|
||||
private bool isSoundWakeActive;
|
||||
private RingBuffer<byte> micDataBuffer;
|
||||
private RingBuffer<byte>.Marker lastSampleMarker;
|
||||
private byte[] writeBuffer;
|
||||
private bool minKeepAliveWasHit;
|
||||
private bool isActive;
|
||||
private byte[] byteDataBuffer;
|
||||
|
||||
private ITranscriptionProvider activeTranscriptionProvider;
|
||||
private Coroutine timeLimitCoroutine;
|
||||
|
||||
// Transcription based endpointing
|
||||
private bool receivedTranscription;
|
||||
private float lastWordTime;
|
||||
|
||||
#if DEBUG_SAMPLE
|
||||
private FileStream sampleFile;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if wit is currently active and listening with the mic
|
||||
/// </summary>
|
||||
public override bool Active => isActive || IsRequestActive;
|
||||
|
||||
public override bool IsRequestActive => null != activeRequest && activeRequest.IsActive;
|
||||
|
||||
public WitRuntimeConfiguration RuntimeConfiguration
|
||||
{
|
||||
get => runtimeConfiguration;
|
||||
set => runtimeConfiguration = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets/Sets a custom transcription provider. This can be used to replace any built in asr
|
||||
/// with an on device model or other provided source
|
||||
/// </summary>
|
||||
public override ITranscriptionProvider TranscriptionProvider
|
||||
{
|
||||
get => activeTranscriptionProvider;
|
||||
set
|
||||
{
|
||||
if (null != activeTranscriptionProvider)
|
||||
{
|
||||
activeTranscriptionProvider.OnFullTranscription.RemoveListener(
|
||||
OnFullTranscription);
|
||||
activeTranscriptionProvider.OnPartialTranscription.RemoveListener(
|
||||
OnPartialTranscription);
|
||||
activeTranscriptionProvider.OnMicLevelChanged.RemoveListener(
|
||||
OnTranscriptionMicLevelChanged);
|
||||
activeTranscriptionProvider.OnStartListening.RemoveListener(
|
||||
OnStartListening);
|
||||
activeTranscriptionProvider.OnStoppedListening.RemoveListener(
|
||||
OnStoppedListening);
|
||||
}
|
||||
|
||||
activeTranscriptionProvider = value;
|
||||
|
||||
if (null != activeTranscriptionProvider)
|
||||
{
|
||||
activeTranscriptionProvider.OnFullTranscription.AddListener(
|
||||
OnFullTranscription);
|
||||
activeTranscriptionProvider.OnPartialTranscription.AddListener(
|
||||
OnPartialTranscription);
|
||||
activeTranscriptionProvider.OnMicLevelChanged.AddListener(
|
||||
OnTranscriptionMicLevelChanged);
|
||||
activeTranscriptionProvider.OnStartListening.AddListener(
|
||||
OnStartListening);
|
||||
activeTranscriptionProvider.OnStoppedListening.AddListener(
|
||||
OnStoppedListening);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool MicActive => null != micInput && micInput.IsRecording;
|
||||
|
||||
protected override bool ShouldSendMicData => runtimeConfiguration.sendAudioToWit ||
|
||||
null == activeTranscriptionProvider;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (null == activeTranscriptionProvider &&
|
||||
runtimeConfiguration.customTranscriptionProvider)
|
||||
{
|
||||
TranscriptionProvider = runtimeConfiguration.customTranscriptionProvider;
|
||||
}
|
||||
|
||||
micInput = GetComponent<IAudioInputSource>();
|
||||
if (micInput == null)
|
||||
{
|
||||
micInput = gameObject.AddComponent<Mic>();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Make sure we have a mic input after a script recompile
|
||||
if (null == micInput)
|
||||
{
|
||||
micInput = GetComponent<IAudioInputSource>();
|
||||
}
|
||||
#endif
|
||||
|
||||
micInput.OnSampleReady += OnSampleReady;
|
||||
micInput.OnStartRecording += OnStartListening;
|
||||
micInput.OnStopRecording += OnStoppedListening;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
micInput.OnSampleReady -= OnSampleReady;
|
||||
micInput.OnStartRecording -= OnStartListening;
|
||||
micInput.OnStopRecording -= OnStoppedListening;
|
||||
}
|
||||
|
||||
private void OnSampleReady(int sampleCount, float[] sample, float levelMax)
|
||||
{
|
||||
if (null == TranscriptionProvider || !TranscriptionProvider.OverrideMicLevel)
|
||||
{
|
||||
OnMicLevelChanged(levelMax);
|
||||
}
|
||||
|
||||
if (null != micDataBuffer)
|
||||
{
|
||||
if (isSoundWakeActive && levelMax > runtimeConfiguration.soundWakeThreshold)
|
||||
{
|
||||
lastSampleMarker = micDataBuffer.CreateMarker(
|
||||
(int) (-runtimeConfiguration.micBufferLengthInSeconds * 1000 *
|
||||
runtimeConfiguration.sampleLengthInMs));
|
||||
}
|
||||
|
||||
byte[] data = Convert(sample);
|
||||
micDataBuffer.Push(data, 0, data.Length);
|
||||
#if DEBUG_SAMPLE
|
||||
sampleFile.Write(data, 0, data.Length);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (IsRequestActive && activeRequest.IsRequestStreamActive)
|
||||
{
|
||||
if (null != micDataBuffer && micDataBuffer.Capacity > 0)
|
||||
{
|
||||
if (null == writeBuffer)
|
||||
{
|
||||
writeBuffer = new byte[sample.Length * 2];
|
||||
}
|
||||
|
||||
// Flush the marker buffer to catch up
|
||||
int read;
|
||||
while ((read = lastSampleMarker.Read(writeBuffer, 0, writeBuffer.Length, true)) > 0)
|
||||
{
|
||||
activeRequest.Write(writeBuffer, 0, read);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] sampleBytes = Convert(sample);
|
||||
activeRequest.Write(sampleBytes, 0, sampleBytes.Length);
|
||||
}
|
||||
|
||||
|
||||
if (receivedTranscription)
|
||||
{
|
||||
if (Time.time - lastWordTime >
|
||||
runtimeConfiguration.minTranscriptionKeepAliveTimeInSeconds)
|
||||
{
|
||||
Debug.Log("Deactivated due to inactivity. No new words detected.");
|
||||
DeactivateRequest();
|
||||
events.OnStoppedListeningDueToInactivity?.Invoke();
|
||||
}
|
||||
}
|
||||
else if (Time.time - lastMinVolumeLevelTime >
|
||||
runtimeConfiguration.minKeepAliveTimeInSeconds)
|
||||
{
|
||||
Debug.Log("Deactivated input due to inactivity.");
|
||||
DeactivateRequest();
|
||||
events.OnStoppedListeningDueToInactivity?.Invoke();
|
||||
}
|
||||
}
|
||||
else if (isSoundWakeActive && levelMax > runtimeConfiguration.soundWakeThreshold)
|
||||
{
|
||||
events.OnMinimumWakeThresholdHit?.Invoke();
|
||||
isSoundWakeActive = false;
|
||||
ActivateImmediately(currentRequestOptions);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFullTranscription(string transcription)
|
||||
{
|
||||
DeactivateRequest();
|
||||
events.OnFullTranscription?.Invoke(transcription);
|
||||
if (runtimeConfiguration.customTranscriptionProvider)
|
||||
{
|
||||
SendTranscription(transcription, new WitRequestOptions());
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPartialTranscription(string transcription)
|
||||
{
|
||||
receivedTranscription = true;
|
||||
lastWordTime = Time.time;
|
||||
events.OnPartialTranscription.Invoke(transcription);
|
||||
}
|
||||
|
||||
private void OnTranscriptionMicLevelChanged(float level)
|
||||
{
|
||||
if (null != TranscriptionProvider && TranscriptionProvider.OverrideMicLevel)
|
||||
{
|
||||
OnMicLevelChanged(level);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMicLevelChanged(float level)
|
||||
{
|
||||
if (level > runtimeConfiguration.minKeepAliveVolume)
|
||||
{
|
||||
lastMinVolumeLevelTime = Time.time;
|
||||
minKeepAliveWasHit = true;
|
||||
}
|
||||
|
||||
events.OnMicLevelChanged?.Invoke(level);
|
||||
}
|
||||
|
||||
private void OnStoppedListening()
|
||||
{
|
||||
events?.OnStoppedListening?.Invoke();
|
||||
}
|
||||
|
||||
private void OnStartListening()
|
||||
{
|
||||
events?.OnStartListening?.Invoke();
|
||||
}
|
||||
|
||||
private IEnumerator DeactivateDueToTimeLimit()
|
||||
{
|
||||
yield return new WaitForSeconds(runtimeConfiguration.maxRecordingTime);
|
||||
Debug.Log("Deactivated due to time limit.");
|
||||
DeactivateRequest();
|
||||
events.OnStoppedListeningDueToTimeout?.Invoke();
|
||||
timeLimitCoroutine = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Activate the microphone and send data to Wit for NLU processing.
|
||||
/// </summary>
|
||||
public override void Activate()
|
||||
{
|
||||
Activate(new WitRequestOptions());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Activate the microphone and send data to Wit for NLU processing.
|
||||
/// </summary>
|
||||
public override void Activate(WitRequestOptions requestOptions)
|
||||
{
|
||||
if (isActive) return;
|
||||
if (micInput.IsRecording) micInput.StopRecording();
|
||||
|
||||
if (!micInput.IsRecording && ShouldSendMicData)
|
||||
{
|
||||
if (null == micDataBuffer && runtimeConfiguration.micBufferLengthInSeconds > 0)
|
||||
{
|
||||
micDataBuffer = new RingBuffer<byte>((int) Mathf.Ceil(2 *
|
||||
runtimeConfiguration.micBufferLengthInSeconds * 1000 *
|
||||
runtimeConfiguration.sampleLengthInMs));
|
||||
}
|
||||
|
||||
minKeepAliveWasHit = false;
|
||||
isSoundWakeActive = true;
|
||||
|
||||
#if DEBUG_SAMPLE
|
||||
var file = Application.dataPath + "/test.pcm";
|
||||
sampleFile = File.Open(file, FileMode.Create);
|
||||
Debug.Log("Writing recording to file: " + file);
|
||||
#endif
|
||||
|
||||
if (micInput.IsInputAvailable)
|
||||
{
|
||||
micInput.StartRecording(sampleLen: runtimeConfiguration.sampleLengthInMs);
|
||||
}
|
||||
else
|
||||
{
|
||||
events.OnError.Invoke("Input Error", "No input source was available. Cannot activate for voice input.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!isActive)
|
||||
{
|
||||
activeTranscriptionProvider?.Activate();
|
||||
isActive = true;
|
||||
|
||||
lastMinVolumeLevelTime = float.PositiveInfinity;
|
||||
currentRequestOptions = requestOptions;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ActivateImmediately()
|
||||
{
|
||||
ActivateImmediately(new WitRequestOptions());
|
||||
}
|
||||
|
||||
public override void ActivateImmediately(WitRequestOptions requestOptions)
|
||||
{
|
||||
// Make sure we aren't checking activation time until
|
||||
// the mic starts recording. If we're already recording for a live
|
||||
// recording, we just triggered an activation so we will reset the
|
||||
// last minvolumetime to ensure a minimum time from activation time
|
||||
activationTime = float.PositiveInfinity;
|
||||
lastMinVolumeLevelTime = float.PositiveInfinity;
|
||||
lastWordTime = float.PositiveInfinity;
|
||||
receivedTranscription = false;
|
||||
|
||||
if (ShouldSendMicData)
|
||||
{
|
||||
activeRequest = RuntimeConfiguration.witConfiguration.SpeechRequest(requestOptions);
|
||||
activeRequest.audioEncoding = micInput.AudioEncoding;
|
||||
activeRequest.onPartialTranscription = OnPartialTranscription;
|
||||
activeRequest.onFullTranscription = OnFullTranscription;
|
||||
activeRequest.onInputStreamReady = r => OnWitReadyForData();
|
||||
activeRequest.onResponse = HandleResult;
|
||||
events.OnRequestCreated?.Invoke(activeRequest);
|
||||
activeRequest.Request();
|
||||
timeLimitCoroutine = StartCoroutine(DeactivateDueToTimeLimit());
|
||||
}
|
||||
|
||||
if (!isActive)
|
||||
{
|
||||
activeTranscriptionProvider?.Activate();
|
||||
isActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWitReadyForData()
|
||||
{
|
||||
activationTime = Time.time;
|
||||
lastMinVolumeLevelTime = Time.time;
|
||||
if (!micInput.IsRecording && micInput.IsInputAvailable)
|
||||
{
|
||||
micInput.StartRecording(runtimeConfiguration.sampleLengthInMs);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop listening and submit the collected microphone data to wit for processing.
|
||||
/// </summary>
|
||||
public override void Deactivate()
|
||||
{
|
||||
var recording = micInput.IsRecording;
|
||||
DeactivateRequest();
|
||||
|
||||
if (recording)
|
||||
{
|
||||
events.OnStoppedListeningDueToDeactivation?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop listening and abort any requests that may be active without waiting for a response.
|
||||
/// </summary>
|
||||
public override void DeactivateAndAbortRequest()
|
||||
{
|
||||
var recording = micInput.IsRecording;
|
||||
DeactivateRequest(true);
|
||||
if (recording)
|
||||
{
|
||||
events.OnStoppedListeningDueToDeactivation?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private void DeactivateRequest(bool abort = false)
|
||||
{
|
||||
if (null != timeLimitCoroutine)
|
||||
{
|
||||
StopCoroutine(timeLimitCoroutine);
|
||||
timeLimitCoroutine = null;
|
||||
}
|
||||
|
||||
if (micInput.IsRecording)
|
||||
{
|
||||
micInput.StopRecording();
|
||||
|
||||
#if DEBUG_SAMPLE
|
||||
sampleFile.Close();
|
||||
#endif
|
||||
}
|
||||
|
||||
micDataBuffer?.Clear();
|
||||
writeBuffer = null;
|
||||
lastSampleMarker = null;
|
||||
minKeepAliveWasHit = false;
|
||||
|
||||
activeTranscriptionProvider?.Deactivate();
|
||||
|
||||
if (IsRequestActive)
|
||||
{
|
||||
if (abort)
|
||||
{
|
||||
activeRequest.AbortRequest();
|
||||
}
|
||||
else
|
||||
{
|
||||
activeRequest.CloseRequestStream();
|
||||
}
|
||||
|
||||
if (minKeepAliveWasHit)
|
||||
{
|
||||
events.OnMicDataSent?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
private byte[] Convert(float[] samples)
|
||||
{
|
||||
var sampleCount = samples.Length;
|
||||
|
||||
if (null == byteDataBuffer || byteDataBuffer.Length != sampleCount)
|
||||
{
|
||||
byteDataBuffer = new byte[sampleCount * 2];
|
||||
}
|
||||
|
||||
int rescaleFactor = 32767; //to convert float to Int16
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
short data = (short) (samples[i] * rescaleFactor);
|
||||
byteDataBuffer[i * 2] = (byte) data;
|
||||
byteDataBuffer[i * 2 + 1] = (byte) (data >> 8);
|
||||
}
|
||||
|
||||
return byteDataBuffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send text data to Wit.ai for NLU processing
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="requestOptions"></param>
|
||||
public override void Activate(string text, WitRequestOptions requestOptions)
|
||||
{
|
||||
if (Active) return;
|
||||
|
||||
SendTranscription(text, requestOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send text data to Wit.ai for NLU processing
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public override void Activate(string text)
|
||||
{
|
||||
Activate(text, new WitRequestOptions());
|
||||
}
|
||||
|
||||
private void SendTranscription(string transcription, WitRequestOptions requestOptions)
|
||||
{
|
||||
isActive = true;
|
||||
activeRequest =
|
||||
RuntimeConfiguration.witConfiguration.MessageRequest(transcription, requestOptions);
|
||||
activeRequest.onResponse = HandleResult;
|
||||
events.OnRequestCreated?.Invoke(activeRequest);
|
||||
activeRequest.Request();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Main thread call to handle result callbacks
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
private void HandleResult(WitRequest request)
|
||||
{
|
||||
isActive = false;
|
||||
if (request.StatusCode == (int) HttpStatusCode.OK)
|
||||
{
|
||||
if (null != request.ResponseData)
|
||||
{
|
||||
events?.OnResponse?.Invoke(request.ResponseData);
|
||||
}
|
||||
else
|
||||
{
|
||||
events?.OnError?.Invoke("No Data", "No data was returned from the server.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DeactivateRequest();
|
||||
if (request.StatusCode != WitRequest.ERROR_CODE_ABORTED)
|
||||
{
|
||||
events?.OnError?.Invoke("HTTP Error " + request.StatusCode,
|
||||
request.StatusDescription);
|
||||
}
|
||||
else
|
||||
{
|
||||
events?.OnAborted?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
events?.OnRequestCompleted?.Invoke();
|
||||
|
||||
activeRequest = null;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IWitRuntimeConfigProvider
|
||||
{
|
||||
WitRuntimeConfiguration RuntimeConfiguration { get; }
|
||||
}
|
||||
}
|
||||
12
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/Wit.cs.meta
Normal file
12
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/Wit.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89cc923dc7c7b4f0b91a7df096c80b00
|
||||
timeCreated: 1459040294
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
131
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/WitAuthUtility.cs
Normal file
131
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/WitAuthUtility.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Facebook.WitAi.Data.Configuration;
|
||||
using UnityEngine;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Facebook.WitAi
|
||||
{
|
||||
public class WitAuthUtility
|
||||
{
|
||||
public static ITokenValidationProvider tokenValidator = new DefaultTokenValidatorProvider();
|
||||
|
||||
public static bool IsServerTokenValid()
|
||||
{
|
||||
return tokenValidator.IsServerTokenValid(ServerToken);
|
||||
}
|
||||
|
||||
public static bool IsServerTokenValid(string token)
|
||||
{
|
||||
return tokenValidator.IsServerTokenValid(token);
|
||||
}
|
||||
|
||||
private static string serverToken;
|
||||
|
||||
public static string GetAppServerToken(WitConfiguration configuration,
|
||||
string defaultValue = "")
|
||||
{
|
||||
return GetAppServerToken(configuration?.application?.id, defaultValue);
|
||||
}
|
||||
|
||||
public static string GetAppServerToken(string appId, string defaultValue = "")
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return EditorPrefs.GetString("Wit::AppIdToToken::" + appId, defaultValue);
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
public static string GetAppId(string serverToken, string defaultValue = "")
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return EditorPrefs.GetString("Wit::TokenToAppId::" + serverToken, defaultValue);
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void SetAppServerToken(string appId, string token)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorPrefs.SetString("Wit::AppIdToToken::" + appId, token);
|
||||
EditorPrefs.SetString("Wit::TokenToAppId::" + token, appId);
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void SavePrefs()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static string ServerToken
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
get
|
||||
{
|
||||
if (null == serverToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
serverToken = EditorPrefs.GetString("Wit::ServerToken", "");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// This will happen if we don't prime the server token on the main thread and
|
||||
// we access the server token editorpref value in a request.
|
||||
Debug.LogError(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
return serverToken;
|
||||
}
|
||||
set
|
||||
{
|
||||
serverToken = value;
|
||||
EditorPrefs.SetString("Wit::ServerToken", serverToken);
|
||||
}
|
||||
#else
|
||||
get => "";
|
||||
#endif
|
||||
}
|
||||
|
||||
public class DefaultTokenValidatorProvider : ITokenValidationProvider
|
||||
{
|
||||
public bool IsTokenValid(string appId, string token)
|
||||
{
|
||||
return IsServerTokenValid(token);
|
||||
}
|
||||
|
||||
public bool IsServerTokenValid(string serverToken)
|
||||
{
|
||||
return null != serverToken && serverToken.Length == 32;
|
||||
}
|
||||
}
|
||||
|
||||
public interface ITokenValidationProvider
|
||||
{
|
||||
bool IsTokenValid(string appId, string token);
|
||||
bool IsServerTokenValid(string serverToken);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static void InitEditorTokens()
|
||||
{
|
||||
if (null == serverToken)
|
||||
{
|
||||
serverToken = EditorPrefs.GetString("Wit::ServerToken", "");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 429feb10fcc04f544b5d400a5c0cabd3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
764
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/WitRequest.cs
Normal file
764
Assets/Oculus/Voice/Lib/Wit.ai/Scripts/Runtime/WitRequest.cs
Normal file
@@ -0,0 +1,764 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Facebook.WitAi.Configuration;
|
||||
using Facebook.WitAi.Data;
|
||||
using Facebook.WitAi.Data.Configuration;
|
||||
using Facebook.WitAi.Lib;
|
||||
using UnityEngine;
|
||||
using SystemInfo = UnityEngine.SystemInfo;
|
||||
using Facebook.WitAi.Utilities;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Facebook.WitAi
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages a single request lifecycle when sending/receiving data from Wit.ai.
|
||||
///
|
||||
/// Note: This is not intended to be instantiated directly. Requests should be created with the
|
||||
/// WitRequestFactory
|
||||
/// </summary>
|
||||
public class WitRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Error code thrown when an exception is caught during processing or
|
||||
/// some other general error happens that is not an error from the server
|
||||
/// </summary>
|
||||
public const int ERROR_CODE_GENERAL = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Error code returned when no configuration is defined
|
||||
/// </summary>
|
||||
public const int ERROR_CODE_NO_CONFIGURATION = -2;
|
||||
|
||||
/// <summary>
|
||||
/// Error code returned when the client token has not been set in the
|
||||
/// Wit configuration.
|
||||
/// </summary>
|
||||
public const int ERROR_CODE_NO_CLIENT_TOKEN = -3;
|
||||
|
||||
/// <summary>
|
||||
/// No data was returned from the server.
|
||||
/// </summary>
|
||||
public const int ERROR_CODE_NO_DATA_FROM_SERVER = -4;
|
||||
|
||||
/// <summary>
|
||||
/// Invalid data was returned from the server.
|
||||
/// </summary>
|
||||
public const int ERROR_CODE_INVALID_DATA_FROM_SERVER = -5;
|
||||
|
||||
/// <summary>
|
||||
/// Request was aborted
|
||||
/// </summary>
|
||||
public const int ERROR_CODE_ABORTED = -6;
|
||||
|
||||
/// <summary>
|
||||
/// Request to the server timeed out
|
||||
/// </summary>
|
||||
public const int ERROR_CODE_TIMEOUT = -7;
|
||||
|
||||
public const string URI_SCHEME = "https";
|
||||
public const string URI_AUTHORITY = "api.wit.ai";
|
||||
|
||||
public const string WIT_API_VERSION = "20210928";
|
||||
public const string WIT_SDK_VERSION = "0.0.25";
|
||||
|
||||
public const string WIT_ENDPOINT_SPEECH = "speech";
|
||||
public const string WIT_ENDPOINT_MESSAGE = "message";
|
||||
public const string WIT_ENDPOINT_ENTITIES = "entities";
|
||||
public const string WIT_ENDPOINT_INTENTS = "intents";
|
||||
public const string WIT_ENDPOINT_TRAITS = "traits";
|
||||
public const string WIT_ENDPOINT_APPS = "apps";
|
||||
public const string WIT_ENDPOINT_UTTERANCES = "utterances";
|
||||
|
||||
private WitConfiguration configuration;
|
||||
|
||||
private Stream activeStream;
|
||||
|
||||
private string command;
|
||||
private string path;
|
||||
|
||||
public QueryParam[] queryParams;
|
||||
|
||||
private HttpWebRequest request;
|
||||
private HttpWebResponse response;
|
||||
|
||||
private WitResponseNode responseData;
|
||||
|
||||
private bool isActive;
|
||||
private bool responseStarted;
|
||||
|
||||
public byte[] postData;
|
||||
public string postContentType;
|
||||
|
||||
private object streamLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Callback called when a response is received from the server
|
||||
/// </summary>
|
||||
public Action<WitRequest> onResponse;
|
||||
|
||||
/// <summary>
|
||||
/// Callback called when the server is ready to receive data from the WitRequest's input
|
||||
/// stream. See WitRequest.Write()
|
||||
/// </summary>
|
||||
public Action<WitRequest> onInputStreamReady;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the raw string response that was received before converting it to a JSON object.
|
||||
///
|
||||
/// NOTE: This response comes back on a different thread. Do not attempt ot set UI control
|
||||
/// values or other interactions from this callback. This is intended to be used for demo
|
||||
/// and test UI, not for regular use.
|
||||
/// </summary>
|
||||
public Action<string> onRawResponse;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a partial utterance from an in process request
|
||||
///
|
||||
/// NOTE: This response comes back on a different thread.
|
||||
/// </summary>
|
||||
public Action<string> onPartialTranscription;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a full utterance from a completed request
|
||||
///
|
||||
/// NOTE: This response comes back on a different thread.
|
||||
/// </summary>
|
||||
public Action<string> onFullTranscription;
|
||||
|
||||
public delegate Uri OnCustomizeUriEvent(UriBuilder uriBuilder);
|
||||
/// <summary>
|
||||
/// Provides an opportunity to customize the url just before a request executed
|
||||
/// </summary>
|
||||
public OnCustomizeUriEvent onCustomizeUri;
|
||||
|
||||
public delegate Dictionary<string, string> OnProvideCustomHeadersEvent();
|
||||
/// <summary>
|
||||
/// Provides an opportunity to provide custom headers for the request just before it is
|
||||
/// executed.
|
||||
/// </summary>
|
||||
public OnProvideCustomHeadersEvent onProvideCustomHeaders;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if a request is pending. Will return false after data has been populated
|
||||
/// from the response.
|
||||
/// </summary>
|
||||
public bool IsActive => isActive;
|
||||
|
||||
/// <summary>
|
||||
/// JSON data that was received as a response from the server after onResponse has been
|
||||
/// called
|
||||
/// </summary>
|
||||
public WitResponseNode ResponseData => responseData;
|
||||
|
||||
/// <summary>
|
||||
/// Encoding settings for audio based requests
|
||||
/// </summary>
|
||||
public AudioEncoding audioEncoding = new AudioEncoding();
|
||||
|
||||
private int statusCode;
|
||||
public int StatusCode => statusCode;
|
||||
|
||||
private string statusDescription;
|
||||
private bool isRequestStreamActive;
|
||||
public bool IsRequestStreamActive => IsActive && isRequestStreamActive;
|
||||
|
||||
public bool HasResponseStarted => responseStarted;
|
||||
|
||||
private bool isServerAuthRequired;
|
||||
public string StatusDescription => statusDescription;
|
||||
|
||||
public int Timeout => configuration ? configuration.timeoutMS : 10000;
|
||||
|
||||
private static string operatingSystem;
|
||||
private static string deviceModel;
|
||||
private static string deviceName;
|
||||
private static string appIdentifier;
|
||||
private bool configurationRequired;
|
||||
private string serverToken;
|
||||
private string callingStackTrace;
|
||||
private DateTime requestStartTime;
|
||||
private ConcurrentQueue<byte[]> writeBuffer = new ConcurrentQueue<byte[]>();
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
public WitRequest(WitConfiguration configuration, string path,
|
||||
params QueryParam[] queryParams)
|
||||
{
|
||||
if (!configuration) throw new ArgumentException("Configuration is not set.");
|
||||
configurationRequired = true;
|
||||
this.configuration = configuration;
|
||||
this.command = path.Split('/').First();
|
||||
this.path = path;
|
||||
this.queryParams = queryParams;
|
||||
|
||||
if (null == operatingSystem) operatingSystem = SystemInfo.operatingSystem;
|
||||
if (null == deviceModel) deviceModel = SystemInfo.deviceModel;
|
||||
if (null == deviceName) deviceName = SystemInfo.deviceName;
|
||||
if (null == appIdentifier) appIdentifier = Application.identifier;
|
||||
}
|
||||
|
||||
public WitRequest(WitConfiguration configuration, string path, bool isServerAuthRequired,
|
||||
params QueryParam[] queryParams)
|
||||
{
|
||||
if (!isServerAuthRequired && !configuration)
|
||||
throw new ArgumentException("Configuration is not set.");
|
||||
configurationRequired = true;
|
||||
this.configuration = configuration;
|
||||
this.isServerAuthRequired = isServerAuthRequired;
|
||||
this.command = path.Split('/').First();
|
||||
this.path = path;
|
||||
this.queryParams = queryParams;
|
||||
if (isServerAuthRequired)
|
||||
{
|
||||
serverToken = WitAuthUtility.GetAppServerToken(configuration?.application?.id);
|
||||
}
|
||||
}
|
||||
|
||||
public WitRequest(string serverToken, string path, params QueryParam[] queryParams)
|
||||
{
|
||||
configurationRequired = false;
|
||||
this.isServerAuthRequired = true;
|
||||
this.command = path.Split('/').First();
|
||||
this.path = path;
|
||||
this.queryParams = queryParams;
|
||||
this.serverToken = serverToken;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Key value pair that is sent as a query param in the Wit.ai uri
|
||||
/// </summary>
|
||||
public class QueryParam
|
||||
{
|
||||
public string key;
|
||||
public string value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the async request for data from the Wit.ai servers
|
||||
/// </summary>
|
||||
public void Request()
|
||||
{
|
||||
responseStarted = false;
|
||||
|
||||
UriBuilder uriBuilder = new UriBuilder();
|
||||
|
||||
var endpointConfig = WitEndpointConfig.GetEndpointConfig(configuration);
|
||||
|
||||
uriBuilder.Scheme = endpointConfig.UriScheme;
|
||||
|
||||
uriBuilder.Host = endpointConfig.Authority;
|
||||
|
||||
var api = endpointConfig.WitApiVersion;
|
||||
if (endpointConfig.port > 0)
|
||||
{
|
||||
uriBuilder.Port = endpointConfig.port;
|
||||
}
|
||||
|
||||
uriBuilder.Query = $"v={api}";
|
||||
|
||||
uriBuilder.Path = path;
|
||||
|
||||
callingStackTrace = Environment.StackTrace;
|
||||
|
||||
if (queryParams.Any())
|
||||
{
|
||||
var p = queryParams.Select(par =>
|
||||
$"{par.key}={Uri.EscapeDataString(par.value)}");
|
||||
uriBuilder.Query += "&" + string.Join("&", p);
|
||||
}
|
||||
|
||||
var uri = null == onCustomizeUri ? uriBuilder.Uri : onCustomizeUri(uriBuilder);
|
||||
StartRequest(uri);
|
||||
}
|
||||
|
||||
private void StartRequest(Uri uri)
|
||||
{
|
||||
if (!configuration && configurationRequired)
|
||||
{
|
||||
statusDescription = "Configuration is not set. Cannot start request.";
|
||||
Debug.LogError(statusDescription);
|
||||
statusCode = ERROR_CODE_NO_CONFIGURATION;
|
||||
SafeInvoke(onResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isServerAuthRequired && string.IsNullOrEmpty(configuration.clientAccessToken))
|
||||
{
|
||||
statusDescription = "Client access token is not defined. Cannot start request.";
|
||||
Debug.LogError(statusDescription);
|
||||
statusCode = ERROR_CODE_NO_CLIENT_TOKEN;
|
||||
SafeInvoke(onResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
request = (HttpWebRequest) WebRequest.Create(uri);
|
||||
|
||||
if (isServerAuthRequired)
|
||||
{
|
||||
request.Headers["Authorization"] =
|
||||
$"Bearer {serverToken}";
|
||||
}
|
||||
else
|
||||
{
|
||||
request.Headers["Authorization"] =
|
||||
$"Bearer {configuration.clientAccessToken.Trim()}";
|
||||
}
|
||||
|
||||
if (null != postContentType)
|
||||
{
|
||||
request.Method = "POST";
|
||||
request.ContentType = postContentType;
|
||||
request.ContentLength = postData.Length;
|
||||
}
|
||||
|
||||
// Configure additional headers
|
||||
if (WitEndpointConfig.GetEndpointConfig(configuration).Speech == command)
|
||||
{
|
||||
request.ContentType = audioEncoding.ToString();
|
||||
request.Method = "POST";
|
||||
request.SendChunked = true;
|
||||
}
|
||||
|
||||
var configId = "not-yet-configured";
|
||||
#if UNITY_EDITOR
|
||||
if (configuration)
|
||||
{
|
||||
if (string.IsNullOrEmpty(configuration.configId))
|
||||
{
|
||||
configuration.configId = Guid.NewGuid().ToString();
|
||||
EditorUtility.SetDirty(configuration);
|
||||
}
|
||||
|
||||
configId = configuration.configId;
|
||||
}
|
||||
#endif
|
||||
|
||||
request.UserAgent = $"voice-sdk-37.0.0.112.109,wit-unity-{WIT_SDK_VERSION},{operatingSystem},{deviceModel},{configId},{appIdentifier}";
|
||||
|
||||
#if UNITY_EDITOR
|
||||
request.UserAgent += ",Editor";
|
||||
#else
|
||||
request.UserAgent += ",Runtime";
|
||||
#endif
|
||||
|
||||
requestStartTime = DateTime.UtcNow;
|
||||
isActive = true;
|
||||
statusCode = 0;
|
||||
statusDescription = "Starting request";
|
||||
request.Timeout = configuration ? configuration.timeoutMS : 10000;
|
||||
WatchMainThreadCallbacks();
|
||||
|
||||
if (null != onProvideCustomHeaders)
|
||||
{
|
||||
foreach (var header in onProvideCustomHeaders())
|
||||
{
|
||||
request.Headers[header.Key] = header.Value;
|
||||
}
|
||||
}
|
||||
|
||||
if (request.Method == "POST")
|
||||
{
|
||||
var getRequestTask = request.BeginGetRequestStream(HandleRequestStream, request);
|
||||
ThreadPool.RegisterWaitForSingleObject(getRequestTask.AsyncWaitHandle,
|
||||
HandleTimeoutTimer, request, Timeout, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
StartResponse();
|
||||
}
|
||||
}
|
||||
|
||||
private void StartResponse()
|
||||
{
|
||||
var result = request.BeginGetResponse(HandleResponse, request);
|
||||
ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, HandleTimeoutTimer,
|
||||
request, Timeout, true);
|
||||
}
|
||||
|
||||
private void HandleTimeoutTimer(object state, bool timedout)
|
||||
{
|
||||
if (!timedout) return;
|
||||
|
||||
// Clean up the current request if it is still going
|
||||
var request = (HttpWebRequest) state;
|
||||
if (null != this.request)
|
||||
{
|
||||
Debug.Log("Request timed out after " + (DateTime.UtcNow - requestStartTime));
|
||||
request.Abort();
|
||||
}
|
||||
|
||||
isActive = false;
|
||||
|
||||
// Close any open stream resources and clean up streaming state flags
|
||||
CloseRequestStream();
|
||||
|
||||
// Update the error state to indicate the request timed out
|
||||
statusCode = ERROR_CODE_TIMEOUT;
|
||||
statusDescription = "Request timed out.";
|
||||
|
||||
SafeInvoke(onResponse);
|
||||
}
|
||||
|
||||
private void HandleResponse(IAsyncResult ar)
|
||||
{
|
||||
string stringResponse = "";
|
||||
responseStarted = true;
|
||||
try
|
||||
{
|
||||
response = (HttpWebResponse) request.EndGetResponse(ar);
|
||||
|
||||
statusCode = (int) response.StatusCode;
|
||||
statusDescription = response.StatusDescription;
|
||||
|
||||
try
|
||||
{
|
||||
var responseStream = response.GetResponseStream();
|
||||
if (response.Headers["Transfer-Encoding"] == "chunked")
|
||||
{
|
||||
byte[] buffer = new byte[10240];
|
||||
int bytes = 0;
|
||||
int offset = 0;
|
||||
int totalRead = 0;
|
||||
while ((bytes = responseStream.Read(buffer, offset, buffer.Length - offset)) > 0)
|
||||
{
|
||||
totalRead += bytes;
|
||||
stringResponse = Encoding.UTF8.GetString(buffer, 0, totalRead);
|
||||
if (stringResponse.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
responseData = WitResponseJson.Parse(stringResponse);
|
||||
|
||||
offset = 0;
|
||||
|
||||
totalRead = 0;
|
||||
if (null != responseData)
|
||||
{
|
||||
var transcription = responseData["text"];
|
||||
if (!string.IsNullOrEmpty(transcription))
|
||||
{
|
||||
MainThreadCallback(() => onPartialTranscription?.Invoke(transcription));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONParseException e)
|
||||
{
|
||||
// TODO: t105419819 Update the protocol to better handle this issue.
|
||||
// This is a bit of a hack to get around an issue with a full
|
||||
// socket buffer or partial server response. We will need to
|
||||
// address this server side to make sure we're reading all data
|
||||
// rather than relying on a json parse exception to catch this.
|
||||
// Test case: Utterance with multiple entity responses pushing
|
||||
// final data > 1024 bytes.
|
||||
offset = bytes;
|
||||
Debug.LogWarning("Received what appears to be a partial response or invalid json. Attempting to continue reading. Parsing error: " + e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stringResponse.Length > 0 && null != responseData)
|
||||
{
|
||||
MainThreadCallback(() => onFullTranscription?.Invoke(responseData["text"]));
|
||||
MainThreadCallback(() => onRawResponse?.Invoke(stringResponse));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(responseStream))
|
||||
{
|
||||
stringResponse = reader.ReadToEnd();
|
||||
MainThreadCallback(() => onRawResponse?.Invoke(stringResponse));
|
||||
responseData = WitResponseJson.Parse(stringResponse);
|
||||
}
|
||||
}
|
||||
|
||||
responseStream.Close();
|
||||
}
|
||||
catch (JSONParseException e)
|
||||
{
|
||||
Debug.LogError("Server returned invalid data: " + e.Message + "\n" +
|
||||
stringResponse);
|
||||
statusCode = ERROR_CODE_INVALID_DATA_FROM_SERVER;
|
||||
statusDescription = "Server returned invalid data.";
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"{e.Message}\nRequest Stack Trace:\n{callingStackTrace}\nResponse Stack Trace:\n{e.StackTrace}");
|
||||
statusCode = ERROR_CODE_GENERAL;
|
||||
statusDescription = e.Message;
|
||||
}
|
||||
|
||||
response.Close();
|
||||
}
|
||||
catch (WebException e)
|
||||
{
|
||||
statusCode = (int) e.Status;
|
||||
if (e.Response is HttpWebResponse errorResponse)
|
||||
{
|
||||
statusCode = (int) errorResponse.StatusCode;
|
||||
|
||||
try
|
||||
{
|
||||
var stream = errorResponse.GetResponseStream();
|
||||
if (null != stream)
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(stream))
|
||||
{
|
||||
stringResponse = reader.ReadToEnd();
|
||||
MainThreadCallback(() => onRawResponse?.Invoke(stringResponse));
|
||||
responseData = WitResponseJson.Parse(stringResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONParseException)
|
||||
{
|
||||
// Response wasn't encoded error, ignore it.
|
||||
}
|
||||
catch (Exception errorResponseError)
|
||||
{
|
||||
// We've already caught that there is an error, we'll ignore any errors
|
||||
// reading error response data and use the status/original error for validation
|
||||
Debug.LogWarning(errorResponseError);
|
||||
}
|
||||
}
|
||||
|
||||
statusDescription = e.Message;
|
||||
if (e.Status != WebExceptionStatus.RequestCanceled)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"Http Request Failed [{statusCode}]: {e.Message}\nRequest Stack Trace:\n{callingStackTrace}\nResponse Stack Trace:\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
CloseRequestStream();
|
||||
|
||||
if (null != responseData)
|
||||
{
|
||||
var error = responseData["error"];
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
{
|
||||
statusDescription = $"Error: {responseData["code"]}. {error}";
|
||||
statusCode = statusCode == 200 ? ERROR_CODE_GENERAL : statusCode;
|
||||
}
|
||||
}
|
||||
else if (statusCode == 200)
|
||||
{
|
||||
statusCode = ERROR_CODE_NO_DATA_FROM_SERVER;
|
||||
statusDescription = "Server did not return a valid json response.";
|
||||
Debug.LogWarning(
|
||||
"No valid data was received from the server even though the request was successful. Actual potential response data: \n" +
|
||||
stringResponse);
|
||||
}
|
||||
|
||||
SafeInvoke(onResponse);
|
||||
}
|
||||
|
||||
private void HandleRequestStream(IAsyncResult ar)
|
||||
{
|
||||
StartResponse();
|
||||
var stream = request.EndGetRequestStream(ar);
|
||||
|
||||
if (null != postData)
|
||||
{
|
||||
stream.Write(postData, 0, postData.Length);
|
||||
CloseRequestStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (null == onInputStreamReady)
|
||||
{
|
||||
CloseRequestStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
isRequestStreamActive = true;
|
||||
SafeInvoke(onInputStreamReady);
|
||||
}
|
||||
}
|
||||
|
||||
new Thread(ExecuteWriteThread).Start(stream);
|
||||
}
|
||||
|
||||
private void ExecuteWriteThread(object obj)
|
||||
{
|
||||
Stream stream = (Stream) obj;
|
||||
|
||||
try
|
||||
{
|
||||
while (isRequestStreamActive)
|
||||
{
|
||||
FlushBuffer(stream);
|
||||
Thread.Yield();
|
||||
}
|
||||
|
||||
FlushBuffer(stream);
|
||||
stream.Close();
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// Handling edge case where stream is closed remotely
|
||||
// This problem occurs when the Web server resets or closes the connection after
|
||||
// the client application sends the HTTP header.
|
||||
// https://support.microsoft.com/en-us/topic/fix-you-receive-a-system-objectdisposedexception-exception-when-you-try-to-access-a-stream-object-that-is-returned-by-the-endgetrequeststream-method-in-the-net-framework-2-0-bccefe57-0a61-517a-5d5f-2dce0cc63265
|
||||
Debug.LogWarning(
|
||||
"Stream already disposed. It is likely the server reset the connection before streaming started.");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Debug.LogWarning(e.Message);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void FlushBuffer(Stream stream)
|
||||
{
|
||||
while (writeBuffer.Count > 0)
|
||||
{
|
||||
if (writeBuffer.TryDequeue(out var buffer))
|
||||
{
|
||||
stream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SafeInvoke(Action<WitRequest> action)
|
||||
{
|
||||
MainThreadCallback(() =>
|
||||
{
|
||||
// We want to allow each invocation to run even if there is an exception thrown by one
|
||||
// of the callbacks in the invocation list. This protects shared invocations from
|
||||
// clients blocking things like UI updates from other parts of the sdk being invoked.
|
||||
foreach (var responseDelegate in action.GetInvocationList())
|
||||
{
|
||||
try
|
||||
{
|
||||
responseDelegate.DynamicInvoke(this);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void AbortRequest()
|
||||
{
|
||||
CloseRequestStream();
|
||||
Debug.Log("Abort");
|
||||
request.Abort();
|
||||
statusCode = ERROR_CODE_ABORTED;
|
||||
statusDescription = "Request was aborted";
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to close the input stream of data being sent during the lifecycle of this request
|
||||
///
|
||||
/// If a post method was used, this will need to be called before the request will complete.
|
||||
/// </summary>
|
||||
public void CloseRequestStream()
|
||||
{
|
||||
lock (streamLock)
|
||||
{
|
||||
isRequestStreamActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write request data to the Wit.ai post's body input stream
|
||||
///
|
||||
/// Note: If the stream is not open (IsActive) this will throw an IOException.
|
||||
/// Data will be written synchronously. This should not be called from the main thread.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
public void Write(byte[] data, int offset, int length)
|
||||
{
|
||||
// TODO: This is going to cause additional allocations, we can probably improve this
|
||||
var buffer = new byte[data.Length];
|
||||
Array.Copy(data, offset, buffer, 0, length);
|
||||
writeBuffer.Enqueue(buffer);
|
||||
}
|
||||
|
||||
#region CALLBACKS
|
||||
// Check performing
|
||||
private bool _performing = false;
|
||||
// All actions
|
||||
private ConcurrentQueue<Action> _mainThreadCallbacks = new ConcurrentQueue<Action>();
|
||||
// Called from background thread
|
||||
private void MainThreadCallback(Action action)
|
||||
{
|
||||
_mainThreadCallbacks.Enqueue(action);
|
||||
}
|
||||
// While active, perform any sent callbacks
|
||||
private void WatchMainThreadCallbacks()
|
||||
{
|
||||
// Ifnore if already performing
|
||||
if (_performing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check callbacks every frame (editor or runtime)
|
||||
CoroutineUtility.StartCoroutine(PerformMainThreadCallbacks());
|
||||
}
|
||||
// Every frame check for callbacks & perform any found
|
||||
private System.Collections.IEnumerator PerformMainThreadCallbacks()
|
||||
{
|
||||
// Begin performing
|
||||
_performing = true;
|
||||
|
||||
// While checking, continue
|
||||
while (HasMainThreadCallbacks())
|
||||
{
|
||||
// Wait for frame
|
||||
yield return new WaitForEndOfFrame();
|
||||
|
||||
// Perform if possible
|
||||
while (_mainThreadCallbacks.Count > 0 && _mainThreadCallbacks.TryDequeue(out var result))
|
||||
{
|
||||
result();
|
||||
}
|
||||
}
|
||||
|
||||
// Done performing
|
||||
_performing = false;
|
||||
}
|
||||
// Check actions
|
||||
private bool HasMainThreadCallbacks()
|
||||
{
|
||||
return IsActive || isRequestStreamActive || _mainThreadCallbacks.Count > 0;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user