WitResponseHandler.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * Copyright (c) Meta Platforms, Inc. and affiliates.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the license found in the
  6. * LICENSE file in the root directory of this source tree.
  7. */
  8. using System;
  9. using Meta.WitAi.Data;
  10. using Meta.WitAi.Json;
  11. using Meta.WitAi.Requests;
  12. using UnityEngine;
  13. using UnityEngine.Events;
  14. using UnityEngine.Serialization;
  15. namespace Meta.WitAi.CallbackHandlers
  16. {
  17. [Serializable]
  18. public class WitResponseEvent : UnityEvent<WitResponseNode> {}
  19. [Serializable]
  20. public class WitResponseErrorEvent : UnityEvent<WitResponseNode, string> {}
  21. public abstract class WitResponseHandler : MonoBehaviour
  22. {
  23. [FormerlySerializedAs("wit")]
  24. [SerializeField] public VoiceService Voice;
  25. [SerializeField] public bool ValidateEarly = false;
  26. // Whether validated early
  27. private bool _validated = false;
  28. private void OnValidate()
  29. {
  30. if (!Voice) Voice = FindObjectOfType<VoiceService>();
  31. }
  32. protected virtual void OnEnable()
  33. {
  34. if (!Voice) Voice = FindObjectOfType<VoiceService>();
  35. if (!Voice)
  36. {
  37. VLog.E($"VoiceService not found in scene.\nDisabling {GetType().Name} on {gameObject.name}");
  38. enabled = false;
  39. }
  40. else
  41. {
  42. Voice.VoiceEvents.OnSend.AddListener(OnRequestSend);
  43. Voice.VoiceEvents.OnValidatePartialResponse.AddListener(HandleValidateEarlyResponse);
  44. Voice.VoiceEvents.OnResponse.AddListener(HandleFinalResponse);
  45. }
  46. }
  47. protected virtual void OnDisable()
  48. {
  49. if (Voice)
  50. {
  51. Voice.VoiceEvents.OnSend.RemoveListener(OnRequestSend);
  52. Voice.VoiceEvents.OnValidatePartialResponse.RemoveListener(HandleValidateEarlyResponse);
  53. Voice.VoiceEvents.OnResponse.RemoveListener(HandleFinalResponse);
  54. }
  55. }
  56. protected virtual void OnRequestSend(VoiceServiceRequest request)
  57. {
  58. _validated = false;
  59. }
  60. protected virtual void HandleValidateEarlyResponse(VoiceSession session)
  61. {
  62. if (ValidateEarly && !_validated)
  63. {
  64. string invalidReason = OnValidateResponse(session.response, true);
  65. if (string.IsNullOrEmpty(invalidReason))
  66. {
  67. _validated = true;
  68. OnResponseSuccess(session.response);
  69. session.validResponse = true;
  70. }
  71. }
  72. }
  73. protected virtual void HandleFinalResponse(WitResponseNode response)
  74. {
  75. // Not yet handled
  76. if (!_validated)
  77. {
  78. string invalidReason = OnValidateResponse(response, false);
  79. if (!string.IsNullOrEmpty(invalidReason))
  80. {
  81. OnResponseInvalid(response, invalidReason);
  82. }
  83. else
  84. {
  85. OnResponseSuccess(response);
  86. }
  87. _validated = true;
  88. }
  89. }
  90. // Handle validation
  91. protected abstract string OnValidateResponse(WitResponseNode response, bool isEarlyResponse);
  92. // Handle invalid
  93. protected abstract void OnResponseInvalid(WitResponseNode response, string error);
  94. // Handle valid
  95. protected abstract void OnResponseSuccess(WitResponseNode response);
  96. #if UNITY_EDITOR
  97. // For tests
  98. public void HandleResponse(WitResponseNode response) => HandleFinalResponse(response);
  99. #endif
  100. /// <summary>
  101. /// Refresh confidence range
  102. /// </summary>
  103. /// <param name="confidence"></param>
  104. /// <param name="confidenceRanges"></param>
  105. /// <param name="allowConfidenceOverlap"></param>
  106. /// <returns></returns>
  107. public static bool RefreshConfidenceRange(float confidence, ConfidenceRange[] confidenceRanges, bool allowConfidenceOverlap)
  108. {
  109. // Whether found
  110. bool foundIn = false;
  111. bool foundOut = false;
  112. // Iterate confidences
  113. for (int i = 0; null != confidenceRanges && i < confidenceRanges.Length; i++)
  114. {
  115. var range = confidenceRanges[i];
  116. // Within Range
  117. if (confidence >= range.minConfidence &&
  118. confidence <= range.maxConfidence)
  119. {
  120. // Ignore overlap
  121. if (!allowConfidenceOverlap && foundIn)
  122. {
  123. continue;
  124. }
  125. // Within delegate
  126. range.onWithinConfidenceRange?.Invoke();
  127. foundIn = true;
  128. }
  129. // Out of Range
  130. else
  131. {
  132. // Ignore overlap
  133. if (!allowConfidenceOverlap && foundOut)
  134. {
  135. continue;
  136. }
  137. // Outside delegate
  138. range.onOutsideConfidenceRange?.Invoke();
  139. foundOut = true;
  140. }
  141. }
  142. // Return if found within
  143. return foundIn;
  144. }
  145. }
  146. }