Initial Commit

This commit is contained in:
2025-07-04 20:33:06 +03:00
commit 8f09347ae0
9219 changed files with 2447903 additions and 0 deletions
@@ -0,0 +1,100 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*/
using Meta.WitAi.Events;
using Meta.WitAi.Json;
namespace Meta.WitAi.Requests
{
/// <summary>
/// A Facade to easily map events from a VoiceServiceRequestEvents event object to a VoiceEvents object's callbacks.
/// </summary>
public class VoiceEventToRequestEventMapper : VoiceServiceRequestEventsWrapper
{
private VoiceEvents _voiceEvents;
public VoiceEvents VoiceEvents
{
get => _voiceEvents;
set => _voiceEvents = value;
}
public VoiceEventToRequestEventMapper()
{
}
public VoiceEventToRequestEventMapper(VoiceEvents voiceEvents)
{
_voiceEvents = voiceEvents;
}
protected override void OnStateChange(VoiceServiceRequest request)
{
}
protected override void OnStopListening(VoiceServiceRequest request)
{
_voiceEvents.OnStoppedListening.Invoke();
}
protected override void OnStartListening(VoiceServiceRequest request)
{
_voiceEvents.OnStartListening.Invoke();
}
protected override void OnFullTranscription(string transcription)
{
_voiceEvents.OnFullTranscription.Invoke(transcription);
}
protected override void OnPartialTranscription(string transcription)
{
_voiceEvents.OnPartialTranscription.Invoke(transcription);
}
protected override void OnPartialResponse(WitResponseNode response)
{
_voiceEvents.OnPartialResponse.Invoke(response);
}
protected override void OnFullResponse(WitResponseNode response)
{
_voiceEvents.OnResponse.Invoke(response);
}
protected override void OnSuccess(VoiceServiceRequest request)
{
}
protected override void OnSend(VoiceServiceRequest request)
{
}
protected override void OnInit(VoiceServiceRequest request)
{
}
protected override void OnFailed(VoiceServiceRequest request)
{
_voiceEvents.OnError.Invoke(request.Results.Message, "Error: " + request.Results.StatusCode);
}
protected override void OnComplete(VoiceServiceRequest request)
{
_voiceEvents.OnComplete.Invoke(request);
}
protected override void OnCancel(VoiceServiceRequest request)
{
_voiceEvents.OnCanceled.Invoke(request.Results?.Message ?? "");
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1df98f02f15946ae88fe53b693a10130
timeCreated: 1678915277
@@ -0,0 +1,231 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*/
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using Meta.Voice;
using Meta.WitAi.Configuration;
using Meta.WitAi.Json;
using UnityEngine;
namespace Meta.WitAi.Requests
{
[Serializable]
public abstract class VoiceServiceRequest
: NLPRequest<VoiceServiceRequestEvent, WitRequestOptions, VoiceServiceRequestEvents, VoiceServiceRequestResults>
{
/// <summary>
/// Constructor for Voice Service requests
/// </summary>
/// <param name="newInputType">The request input type (text/audio) to be used</param>
/// <param name="newOptions">The request parameters to be used</param>
/// <param name="newEvents">The request events to be called throughout it's lifecycle</param>
protected VoiceServiceRequest(NLPRequestInputType newInputType, WitRequestOptions newOptions, VoiceServiceRequestEvents newEvents) : base(newInputType, newOptions, newEvents) {}
/// <summary>
/// The status code returned from the last request
/// </summary>
public int StatusCode
{
get => Results == null ? 0 : Results.StatusCode;
protected set
{
int newCode = value;
if (newCode.Equals(Results == null ? 0 : Results.StatusCode))
{
return;
}
if (Results == null)
{
Results = new VoiceServiceRequestResults();
}
Results.StatusCode = newCode;
}
}
#region Simulation
protected override bool OnSimulateResponse()
{
if (null == simulatedResponse) return false;
// Begin calling on main thread if needed
WatchMainThreadCallbacks();
SimulateResponse();
return true;
}
private async void SimulateResponse()
{
var stackTrace = new StackTrace();
StatusCode = simulatedResponse.code;
var statusDescription = simulatedResponse.responseDescription;
for (int i = 0; i < simulatedResponse.messages.Count - 1; i++)
{
var message = simulatedResponse.messages[i];
await System.Threading.Tasks.Task.Delay((int)(message.delay * 1000));
var partialResponse = WitResponseNode.Parse(message.responseBody);
HandlePartialNlpResponse(partialResponse);
}
var lastMessage = simulatedResponse.messages.Last();
await System.Threading.Tasks.Task.Delay((int)(lastMessage.delay * 1000));
var lastResponseData = WitResponseNode.Parse(lastMessage.responseBody);
MainThreadCallback(() =>
{
// Send partial data if not previously sent
if (!lastResponseData.HasResponse())
{
HandlePartialNlpResponse(lastResponseData);
}
// Apply error if needed
if (null != lastResponseData)
{
var error = lastResponseData["error"];
if (!string.IsNullOrEmpty(error))
{
statusDescription += $"\n{error}";
}
}
// Call completion delegate
HandleFinalNlpResponse(lastResponseData,
StatusCode == (int)HttpStatusCode.OK
? string.Empty
: $"{statusDescription}\n\nStackTrace:\n{stackTrace}\n\n");
});
}
#endregion
#region Thread Safety
// Check performing
private CoroutineUtility.CoroutinePerformer _performer = null;
// All actions
private ConcurrentQueue<Action> _mainThreadCallbacks = new ConcurrentQueue<Action>();
// While active, perform any sent callbacks
protected void WatchMainThreadCallbacks()
{
// Ignore if already performing
if (_performer != null)
{
return;
}
// Check callbacks every frame (editor or runtime)
_performer = CoroutineUtility.StartCoroutine(PerformMainThreadCallbacks());
}
// Every frame check for callbacks & perform any found
private System.Collections.IEnumerator PerformMainThreadCallbacks()
{
// While checking, continue
while (HasMainThreadCallbacks())
{
// Wait for frame
if (Application.isPlaying && !Application.isBatchMode)
{
yield return new WaitForEndOfFrame();
}
// Wait for a tick
else
{
yield return null;
}
// Perform if possible
while (_mainThreadCallbacks.Count > 0 && _mainThreadCallbacks.TryDequeue(out var result))
{
result();
}
}
_performer = null;
}
// If active or performing callbacks
private bool HasMainThreadCallbacks()
{
return IsActive || _mainThreadCallbacks.Count > 0;
}
// Called from background thread
protected void MainThreadCallback(Action action)
{
if (action == null)
{
return;
}
_mainThreadCallbacks.Enqueue(action);
}
#endregion
/// <summary>
/// Returns an empty result object with the current status code
/// </summary>
/// <param name="newMessage">The message to be set on the results</param>
protected override VoiceServiceRequestResults GetResultsWithMessage(string newMessage)
{
VoiceServiceRequestResults results = new VoiceServiceRequestResults(newMessage);
results.StatusCode = StatusCode;
results.ResponseData = ResponseData;
return results;
}
/// <summary>
/// Applies a transcription to the current results
/// </summary>
/// <param name="newTranscription">The transcription returned</param>
/// <param name="newIsFinal">Whether the transcription has completed building</param>
protected override void ApplyTranscription(string newTranscription, bool newIsFinal)
{
if (Results == null)
{
Results = new VoiceServiceRequestResults();
}
Results.Transcription = newTranscription;
Results.IsFinalTranscription = newIsFinal;
if (Results.IsFinalTranscription)
{
List<string> transcriptions = new List<string>();
if (Results.FinalTranscriptions != null)
{
transcriptions.AddRange(Results.FinalTranscriptions);
}
transcriptions.Add(Results.Transcription);
Results.FinalTranscriptions = transcriptions.ToArray();
}
OnTranscriptionChanged();
}
/// <summary>
/// Applies response data to the current results
/// </summary>
/// <param name="newData">The returned response data</param>
protected override void ApplyResultResponseData(WitResponseNode newData)
{
if (Results == null)
{
Results = new VoiceServiceRequestResults();
}
Results.ResponseData = newData;
}
/// <summary>
/// Performs an event callback with this request as the parameter
/// </summary>
/// <param name="eventCallback">The voice service request event to be called</param>
protected override void RaiseEvent(VoiceServiceRequestEvent eventCallback)
{
eventCallback?.Invoke(this);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 699863ddb3283fc43ba82acc73b12979
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,164 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*/
using System;
using Meta.Voice;
using Meta.WitAi.Json;
using UnityEngine.Events;
namespace Meta.WitAi.Requests
{
/// <summary>
/// A set of events associated with a Voice Service activation.
/// </summary>
[Serializable]
public class VoiceServiceRequestEvents
: NLPRequestEvents<VoiceServiceRequestEvent>
{
}
/// <summary>
/// A UnityEvent with a parameter of VoiceServiceRequest
/// </summary>
[Serializable]
public class VoiceServiceRequestEvent : UnityEvent<VoiceServiceRequest> {}
/// <summary>
/// A base class to provide quick overridable methods that map to events from VoiceServiceRequestEvents.
/// </summary>
public class VoiceServiceRequestEventsWrapper
{
/// <summary>
/// Adds all listeners for VoiceServiceRequestEvents to overridable methods
/// </summary>
/// <param name="events"></param>
public void Wrap(VoiceServiceRequestEvents events)
{
events.OnCancel.AddListener(OnCancel);
events.OnComplete.AddListener(OnComplete);
events.OnFailed.AddListener(OnFailed);
events.OnInit.AddListener(OnInit);
events.OnSend.AddListener(OnSend);
events.OnSuccess.AddListener(OnSuccess);
events.OnAudioActivation.AddListener(OnAudioActivation);
events.OnAudioDeactivation.AddListener(OnAudioDeactivation);
events.OnFullResponse.AddListener(OnFullResponse);
events.OnPartialResponse.AddListener(OnPartialResponse);
events.OnPartialTranscription.AddListener(OnPartialTranscription);
events.OnFullTranscription.AddListener(OnFullTranscription);
events.OnStartListening.AddListener(OnStartListening);
events.OnStopListening.AddListener(OnStopListening);
events.OnStateChange.AddListener(OnStateChange);
events.OnDownloadProgressChange.AddListener(OnDownloadProgressChange);
events.OnUploadProgressChange.AddListener(OnUploadProgressChange);
events.OnAudioInputStateChange.AddListener(OnAudioInputStateChange);
}
/// <summary>
/// Removes all listeners for the provided VoiceServiceRequestEvents event object.
/// </summary>
/// <param name="events"></param>
public void Unwrap(VoiceServiceRequestEvents events)
{
events.OnCancel.RemoveListener(OnCancel);
events.OnComplete.RemoveListener(OnComplete);
events.OnFailed.RemoveListener(OnFailed);
events.OnInit.RemoveListener(OnInit);
events.OnSend.RemoveListener(OnSend);
events.OnSuccess.RemoveListener(OnSuccess);
events.OnAudioActivation.RemoveListener(OnAudioActivation);
events.OnAudioDeactivation.RemoveListener(OnAudioDeactivation);
events.OnFullResponse.RemoveListener(OnFullResponse);
events.OnPartialResponse.RemoveListener(OnPartialResponse);
events.OnPartialTranscription.RemoveListener(OnPartialTranscription);
events.OnFullTranscription.RemoveListener(OnFullTranscription);
events.OnStartListening.RemoveListener(OnStartListening);
events.OnStopListening.RemoveListener(OnStopListening);
events.OnStateChange.RemoveListener(OnStateChange);
events.OnDownloadProgressChange.RemoveListener(OnDownloadProgressChange);
events.OnUploadProgressChange.RemoveListener(OnUploadProgressChange);
events.OnAudioInputStateChange.RemoveListener(OnAudioInputStateChange);
}
protected virtual void OnAudioInputStateChange(VoiceServiceRequest request)
{
}
protected virtual void OnUploadProgressChange(VoiceServiceRequest request)
{
}
protected virtual void OnDownloadProgressChange(VoiceServiceRequest request)
{
}
protected virtual void OnStateChange(VoiceServiceRequest request)
{
}
protected virtual void OnStopListening(VoiceServiceRequest request)
{
}
protected virtual void OnStartListening(VoiceServiceRequest request)
{
}
protected virtual void OnFullTranscription(string transcription)
{
}
protected virtual void OnPartialTranscription(string transcription)
{
}
protected virtual void OnPartialResponse(WitResponseNode request)
{
}
protected virtual void OnFullResponse(WitResponseNode request)
{
}
protected virtual void OnAudioDeactivation(VoiceServiceRequest request)
{
}
protected virtual void OnAudioActivation(VoiceServiceRequest request)
{
}
protected virtual void OnSuccess(VoiceServiceRequest request)
{
}
protected virtual void OnSend(VoiceServiceRequest request)
{
}
protected virtual void OnInit(VoiceServiceRequest request)
{
}
protected virtual void OnFailed(VoiceServiceRequest request)
{
}
protected virtual void OnComplete(VoiceServiceRequest request)
{
}
protected virtual void OnCancel(VoiceServiceRequest request)
{
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e716f6c2b8f83ef48a5b56ede17bec91
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,76 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*/
using System;
using System.Collections.Generic;
using Meta.Voice;
namespace Meta.WitAi.Requests
{
public class VoiceServiceRequestOptions : INLPAudioRequestOptions, INLPTextRequestOptions
{
/// <summary>
/// Unique request id used for request tracking internally & externally
/// </summary>
public string RequestId { get; private set; }
/// <summary>
/// Additional request query parameters to be sent with the request
/// </summary>
public Dictionary<string, string> QueryParams { get; private set; }
public class QueryParam
{
public string key;
public string value;
}
/// <summary>
/// The text to be submitted for a text request
/// </summary>
public string Text { get; set; }
/// <summary>
/// The threshold to be used for an audio request
/// </summary>
public float AudioThreshold { get; set; }
/// <summary>
/// Setup with a randomly generated guid
/// </summary>
public VoiceServiceRequestOptions(params QueryParam[] newParams)
{
RequestId = GetUniqueRequestId();
QueryParams = ConvertQueryParams(newParams);
}
/// <summary>
/// Setup with a specific guid
/// </summary>
public VoiceServiceRequestOptions(string newRequestId, params QueryParam[] newParams)
{
RequestId = string.IsNullOrEmpty(newRequestId) ? GetUniqueRequestId() : newRequestId;
QueryParams = ConvertQueryParams(newParams);
}
/// <summary>
/// Generates a random guid
/// </summary>
protected virtual string GetUniqueRequestId() => Guid.NewGuid().ToString();
/// <summary>
/// Generates a dictionary of key/value strings from a query param array
/// </summary>
public static Dictionary<string, string> ConvertQueryParams(QueryParam[] newParams)
{
Dictionary<string, string> results = new Dictionary<string, string>();
foreach (var param in newParams)
{
if (!string.IsNullOrEmpty(param.key))
{
results[param.key] = results[param.value];
}
}
return results;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9eb9c94105a2d374d9690cffa971179e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,58 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*/
using Meta.Voice;
using Meta.WitAi.Json;
namespace Meta.WitAi.Requests
{
public class VoiceServiceRequestResults
: INLPTextRequestResults, INLPAudioRequestResults
{
/// <summary>
/// Request status code if applicable
/// </summary>
public int StatusCode { get; internal set; }
/// <summary>
/// Request cancelation/error message
/// </summary>
public string Message { get; private set; }
/// <summary>
/// Response transcription
/// </summary>
public string Transcription { get; internal set; }
/// <summary>
/// Response transcription
/// </summary>
public bool IsFinalTranscription { get; internal set; }
/// <summary>
/// Response transcription
/// </summary>
public string[] FinalTranscriptions { get; internal set; }
/// <summary>
/// Parsed json response data
/// </summary>
public WitResponseNode ResponseData { get; internal set; }
/// <summary>
/// Default constructor without message
/// </summary>
public VoiceServiceRequestResults()
{
Message = string.Empty;
}
/// <summary>
/// Constructor with a specific message
/// </summary>
public VoiceServiceRequestResults(string newMessage)
{
Message = newMessage;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1888bdd84781aa14d8993f1d9ca09384
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,160 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*/
using System;
using Meta.Voice;
using Meta.WitAi.Configuration;
using Meta.WitAi.Data.Configuration;
using Meta.WitAi.Json;
using UnityEngine;
namespace Meta.WitAi.Requests
{
/// <summary>
/// A class used to track Wit text 'Message' requests
/// </summary>
[Serializable]
public class WitUnityRequest : VoiceServiceRequest
{
/// <summary>
/// The configuration to be used for the request
/// </summary>
public WitConfiguration Configuration { get; private set; }
/// <summary>
/// Unity request wrapper for Wit
/// </summary>
private readonly WitVRequest _request;
/// <summary>
/// Endpoint to be used
/// </summary>
public string Endpoint { get; set; }
/// <summary>
/// Endpoint to be used
/// </summary>
public bool ShouldPost { get; set; }
/// <summary>
/// Apply configuration
/// </summary>
/// <param name="newConfiguration"></param>
/// <param name="newOptions"></param>
/// <param name="newEvents"></param>
public WitUnityRequest(WitConfiguration newConfiguration, NLPRequestInputType newDataType, WitRequestOptions newOptions, VoiceServiceRequestEvents newEvents) : base(newDataType, newOptions, newEvents)
{
// Apply configuration & generate request
Configuration = newConfiguration;
// Generate a message WitVRequest
if (InputType == NLPRequestInputType.Text)
{
_request = new WitMessageVRequest(Configuration, newOptions.RequestId, SetDownloadProgress);
Endpoint = Configuration.GetEndpointInfo().Message;
_request.Timeout = Mathf.RoundToInt(Configuration.timeoutMS / 1000f);
ShouldPost = false;
}
// Generate an audio WitVRequest
else if (InputType == NLPRequestInputType.Audio)
{
// TODO: T121060485: Add audio support to WitVRequest
Endpoint = Configuration.GetEndpointInfo().Speech;
ShouldPost = true;
}
// Initialized
_initialized = true;
SetState(VoiceRequestState.Initialized);
}
/// <summary>
/// Ignore state changes unless setup
/// </summary>
private bool _initialized = false;
protected override void SetState(VoiceRequestState newState)
{
if (_initialized)
{
base.SetState(newState);
}
}
/// <summary>
/// Get send error options
/// </summary>
protected override string GetSendError()
{
if (Configuration == null)
{
return "Cannot send request without a valid configuration.";
}
if (_request == null)
{
return "Request creation failed.";
}
return base.GetSendError();
}
/// <summary>
/// Performs a wit message request
/// </summary>
/// <param name="onSendComplete">Callback that handles send completion</param>
protected override void HandleSend()
{
// Send message request
if (_request is WitMessageVRequest messageRequest)
{
messageRequest.MessageRequest(Endpoint, ShouldPost,
Options.Text, Options.QueryParams,
HandleFinalNlpResponse);
}
}
/// <summary>
/// Set status code prior to handling response
/// </summary>
protected override void HandleFinalNlpResponse(WitResponseNode responseData, string error)
{
StatusCode = _request.ResponseCode;
base.HandleFinalNlpResponse(responseData, error);
}
/// <summary>
/// Handle cancellation
/// </summary>
protected override void HandleCancel()
{
if (_request != null)
{
_request.Cancel();
}
}
#region AUDIO CALLBACKS
// TODO: T121060485: Add audio support to WitVRequest
/// <summary>
/// Error returned if audio cannot be activated
/// </summary>
protected override string GetActivateAudioError()
{
return "Audio request not yet implemented";
}
/// <summary>
/// Activates audio & calls activated callback once complete
/// </summary>
protected override void HandleAudioActivation()
{
SetAudioInputState(VoiceAudioInputState.On);
}
/// <summary>
/// Deactivates audio asap & calls deactivated callback once complete
/// </summary>
protected override void HandleAudioDeactivation()
{
SetAudioInputState(VoiceAudioInputState.Off);
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 434cbd5af67981840ab365556140f9d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: