mscorlib.dll 中发生类型 'System.Runtime.Serialization.SerializationException' 的异常
An exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll
我正在尝试使用 bing 语音 api 向使用语音到文本识别的机器人添加呼叫功能。
当我 运行 我的应用程序时,它在 运行 时间给我一个例外(在标题中给出)。我不确定如何处理它以及导致它的原因。
它发生在 SendToBot 方法中的以下行。
await postToBot.PostAsync(activity, CancellationToken.None);
Microsoft.Bot.Builder.Internals.Fibers.NullWait`1[[Microsoft.Bot.Builder.Dialogs.Internals.DialogTask,
Microsoft.Bot.Builder, Version=3.5.5.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35]]' in Assembly 'Microsoft.Bot.Builder,
Version=3.5.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' is
not marked as serializable.
堆栈跟踪:
at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type)
at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context)
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo()
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)
at Microsoft.Bot.Builder.Internals.Fibers.FormatterStore`1.Microsoft.Bot.Builder.Internals.Fibers.IStore<T>.Save(T item)
at Microsoft.Bot.Builder.Internals.Fibers.ErrorResilientStore`1.Microsoft.Bot.Builder.Internals.Fibers.IStore<T>.Save(T item)
at Microsoft.Bot.Builder.Internals.Fibers.FactoryStore`1.Microsoft.Bot.Builder.Internals.Fibers.IStore<T>.Save(T item)
at Microsoft.Bot.Builder.Dialogs.Internals.DialogTask.<Microsoft-Bot-Builder-Base-IEventLoop-PollAsync>d__23.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.ReactiveDialogTask.<Microsoft-Bot-Builder-Base-IEventLoop-PollAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.ScoringEventLoop`1.<Microsoft-Bot-Builder-Base-IEventLoop-PollAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.EventLoopDialogTask.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.SetAmbientThreadCulture.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.PersistentDialogTask.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Bot.Builder.Dialogs.Internals.PersistentDialogTask.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.ExceptionTranslationDialogTask.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.SerializeByConversation.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.PostUnhandledExceptionToUser.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Bot.Builder.Dialogs.Internals.PostUnhandledExceptionToUser.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.LogPostToBot.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at JoeBot.BingSpeech.<SendToBot>d__14.MoveNext() in D:\PARIS\JoeBot\CallingBot\BingSpeech.cs:line 123
BingSpeech 中的以下方法class(最后给出)
private async Task SendToBot(RecognizedPhrase recognizedPhrase)
{
Activity activity = new Activity()
{
From = new ChannelAccount { Id = conversationResult.Id },
Conversation = new ConversationAccount { Id = conversationResult.Id },
Recipient = new ChannelAccount { Id = "Bot" },
ServiceUrl = "https://skype.botframework.com",
ChannelId = "skype",
};
activity.Text = recognizedPhrase.DisplayText;
using (var scope = Microsoft.Bot.Builder.Dialogs.Conversation
.Container.BeginLifetimeScope(DialogModule.LifetimeScopeTag, Configure))
{
scope.Resolve<IMessageActivity>
(TypedParameter.From((IMessageActivity)activity));
DialogModule_MakeRoot.Register
(scope, () => new LUISDialogClass());
var postToBot = scope.Resolve<IPostToBot>();
await postToBot.PostAsync(activity, CancellationToken.None);
}
}
我的 LUISDialogClass() 被标记为可序列化。 LUIS 是根对话框,它根据 intent/Entity 匹配将请求转发到进一步的 WikipediaDialog class。我还在此处使用静态 class 和字段(用于某些特殊目的/将其发送到服务器)创建 JSON 字符串。
[Serializable]
public class LUISDialogClass : LuisDialog<object>
{
[LuisIntent("")]
[LuisIntent("None")]
public async Task None(IDialogContext context, LuisResult result)
{
var message = result;
await context.PostAsync("Intent match : None");
context.Wait(MessageReceived);
}
[LuisIntent("FindInfo")]
public async Task FindInfo(IDialogContext context, LuisResult result)
{
try
{
var message = result;
for (int i = 1; i < 2; i++)
{
JSONDataObjects.data[i] = new Datum();
JSONDataObjects.data[i].dataKind = "luisResponse";
JSONDataObjects.data[i].query = message.Query;
JSONDataObjects.data[i].intents = new Intent[message.Intents.Count];
JSONDataObjects.data[i].entities = new Entity[message.Entities.Count];
for (int j = 0; j < message.Intents.Count; j++)
{
JSONDataObjects.data[i].intents[j] = new Intent();
JSONDataObjects.data[i].intents[j].intent = message.Intents[j]?.Intent;
JSONDataObjects.data[i].intents[j].score = (float)message.Intents[j]?.Score;
}
for (int j = 0; j < message.Entities.Count; j++)
{
JSONDataObjects.data[i].entities[j] = new Entity();
JSONDataObjects.data[i].entities[j].entity = message.Entities[j]?.Entity;
JSONDataObjects.data[i].entities[j].type = message.Entities[j]?.Type;
JSONDataObjects.data[i].entities[j].startIndex = (int)message.Entities[j]?.StartIndex;
JSONDataObjects.data[i].entities[j].endIndex = (int)message.Entities[j]?.EndIndex;
JSONDataObjects.data[i].entities[j].score = (float)message.Entities[j]?.Score;
}
}
// See if the intent has a > .70 match
bool boolIntentMatch = false;
foreach (var objIntent in message.Intents)
{
// If the FindInfo Intent is detected
// and it's score is greater than or = to .70
// set boolIntentMatch = true
if (
(objIntent.Intent == "FindInfo")
&& (objIntent.Score >= .70f)
)
{
boolIntentMatch = true;
}
}
if (boolIntentMatch)
{
// ** To Do: Code to handle a Match **
string item = "";
EntityRecommendation rec;
if (message.TryFindEntity("objects", out rec))
{
item = rec.Entity;
}
else if (message.TryFindEntity("location", out rec))
{
item = rec.Entity;
}
Activity messageActivity = (Activity)context.MakeMessage();
messageActivity.Text = item;
messageActivity.ChannelId = "emulator";
await context.Forward(new WikipediaDialog(), ResumeAfterWikipedia, messageActivity, System.Threading.CancellationToken.None);
}
else
{
// Not a match -- Ask to rephrase the question
await context.PostAsync("Please try to rephrase your question. Not a good intent match found");
}
}
catch (Exception ex)
{
//Debug.WriteLine(ex);
await context.PostAsync($"Failed and caught in FindInfo LUIS Dialog, with Exception: {ex.Message}");
}
}
private async Task ResumeAfterWikipedia(IDialogContext context, IAwaitable<object> result)
{
try
{
var message = await result;
}
catch (Exception ex)
{
await context.PostAsync($"Failed and caught in ResumeAfterWikipedia Dialog, with Exception: {ex.Message}");
}
finally
{
context.Wait(this.MessageReceived);
}
}
}
}
我正在使用 CallingController class 来处理以下调用
[BotAuthentication]
// Prefix route for your calling controller
[RoutePrefix("api/calling")]
public class CallingController : ApiController
{
public CallingController()
: base()
{
CallingConversation.RegisterCallingBot(c => new JoeCallingBot(c));
}
// Callback route for Skype calling events.
// Make sure to set the Microsoft.Bot.Builder.Calling.CallbackUrl in web.config
[Route("callback")]
public async Task<HttpResponseMessage> ProcessCallingEventAsync()
{
return await CallingConversation.SendAsync(Request, CallRequestType.CallingEvent);
}
// Route for incoming call events
[Route("call")]
public async Task<HttpResponseMessage> ProcessIncomingCallAsync()
{
return await CallingConversation.SendAsync(Request, CallRequestType.IncomingCall);
}
}
我的 JoeCallingBot class 正在关注
public class JoeCallingBot : ICallingBot
{
public ICallingBotService CallingBotService
{
get; private set;
}
private List<string> response = new List<string>();
int silenceTimes = 0;
bool sttFailed = false;
public JoeCallingBot(ICallingBotService callingBotService)
{
if (callingBotService == null)
throw new ArgumentNullException(nameof(callingBotService));
this.CallingBotService = callingBotService;
CallingBotService.OnIncomingCallReceived += OnIncomingCallReceived;
CallingBotService.OnPlayPromptCompleted += OnPlayPromptCompleted;
CallingBotService.OnRecordCompleted += OnRecordCompleted;
CallingBotService.OnHangupCompleted += OnHangupCompleted;
}
private Task OnIncomingCallReceived(IncomingCallEvent incomingCallEvent)
{
var id = Guid.NewGuid().ToString();
incomingCallEvent.ResultingWorkflow.Actions = new List<ActionBase>
{
new Answer { OperationId = id },
GetRecordForText("Welcome! How can I help you?")
};
return Task.FromResult(true);
}
private ActionBase GetRecordForText(string promptText)
{
PlayPrompt prompt;
if (string.IsNullOrEmpty(promptText))
prompt = null;
else
prompt = GetPromptForText(promptText);
var id = Guid.NewGuid().ToString();
return new Record()
{
OperationId = id,
PlayPrompt = prompt,
MaxDurationInSeconds = 10,
InitialSilenceTimeoutInSeconds = 5,
MaxSilenceTimeoutInSeconds = 2,
PlayBeep = false,
RecordingFormat = RecordingFormat.Wav,
StopTones = new List<char> { '#' }
};
}
private Task OnPlayPromptCompleted(PlayPromptOutcomeEvent playPromptOutcomeEvent)
{
if (response.Count > 0)
{
silenceTimes = 0;
var actionList = new List<ActionBase>();
foreach (var res in response)
{
Debug.WriteLine($"Response ----- {res}");
}
actionList.Add(GetPromptForText(response));
actionList.Add(GetRecordForText(string.Empty));
playPromptOutcomeEvent.ResultingWorkflow.Actions = actionList;
response.Clear();
}
else
{
if (sttFailed)
{
playPromptOutcomeEvent.ResultingWorkflow.Actions = new List<ActionBase>
{
GetRecordForText("I didn't catch that, would you kindly repeat?")
};
sttFailed = false;
silenceTimes = 0;
}
else if (silenceTimes > 2)
{
playPromptOutcomeEvent.ResultingWorkflow.Actions = new List<ActionBase>
{
GetPromptForText("Something went wrong. Call again later."),
new Hangup() { OperationId = Guid.NewGuid().ToString() }
};
playPromptOutcomeEvent.ResultingWorkflow.Links = null;
silenceTimes = 0;
}
else
{
silenceTimes++;
playPromptOutcomeEvent.ResultingWorkflow.Actions = new List<ActionBase>
{
GetSilencePrompt(2000)
};
}
}
return Task.CompletedTask;
}
private async Task OnRecordCompleted(RecordOutcomeEvent recordOutcomeEvent)
{
if (recordOutcomeEvent.RecordOutcome.Outcome == Outcome.Success)
{
var record = await recordOutcomeEvent.RecordedContent;
BingSpeech bs = new BingSpeech(recordOutcomeEvent.ConversationResult, t => response.Add(t), s => sttFailed = s);
bs.CreateDataRecoClient();
bs.SendAudioHelper(record);
recordOutcomeEvent.ResultingWorkflow.Actions = new List<ActionBase>
{
GetSilencePrompt()
};
}
else
{
if (silenceTimes > 1)
{
recordOutcomeEvent.ResultingWorkflow.Actions = new List<ActionBase>
{
GetPromptForText("Thank you for calling"),
new Hangup() { OperationId = Guid.NewGuid().ToString() }
};
recordOutcomeEvent.ResultingWorkflow.Links = null;
silenceTimes = 0;
}
else
{
silenceTimes++;
recordOutcomeEvent.ResultingWorkflow.Actions = new List<ActionBase>
{
GetRecordForText("I didn't catch that, would you kinly repeat?")
};
}
}
}
private Task OnHangupCompleted(HangupOutcomeEvent hangupOutcomeEvent)
{
hangupOutcomeEvent.ResultingWorkflow = null;
return Task.FromResult(true);
}
private static PlayPrompt GetPromptForText(string text)
{
var prompt = new Prompt { Value = text, Voice = VoiceGender.Female };
return new PlayPrompt { OperationId = Guid.NewGuid().ToString(), Prompts = new List<Prompt> { prompt } };
}
private static PlayPrompt GetPromptForText(List<string> text)
{
var prompts = new List<Prompt>();
foreach (var txt in text)
{
if (!string.IsNullOrEmpty(txt))
prompts.Add(new Prompt { Value = txt, Voice = VoiceGender.Female });
}
if (prompts.Count == 0)
return GetSilencePrompt(1000);
return new PlayPrompt { OperationId = Guid.NewGuid().ToString(), Prompts = prompts };
}
private static PlayPrompt GetSilencePrompt(uint silenceLengthInMilliseconds = 3000)
{
var prompt = new Prompt { Value = string.Empty, Voice = VoiceGender.Female, SilenceLengthInMilliseconds = silenceLengthInMilliseconds };
return new PlayPrompt { OperationId = Guid.NewGuid().ToString(), Prompts = new List<Prompt> { prompt } };
}
}
我完整的 BingSpeech class 如下
public class BingSpeech
{
private DataRecognitionClient dataClient;
private Action<string> _callback;
private ConversationResult conversationResult;
private Action<bool> _failedCallback;
public BingSpeech(ConversationResult conversationResult, Action<string> callback, Action<bool> failedCallback)
{
this.conversationResult = conversationResult;
_callback = callback;
_failedCallback = failedCallback;
}
public string DefaultLocale { get; } = "en-US";
public string SubscriptionKey { get; } = "Bing Speech API KEY"; //Bing Speech Recognition Key
public void CreateDataRecoClient()
{
this.dataClient = SpeechRecognitionServiceFactory.CreateDataClient(
SpeechRecognitionMode.ShortPhrase,
this.DefaultLocale,
this.SubscriptionKey);
this.dataClient.OnResponseReceived += this.OnDataShortPhraseResponseReceivedHandler;
}
public void SendAudioHelper(Stream recordedStream)
{
// Note for wave files, we can just send data from the file right to the server.
// In the case you are not an audio file in wave format, and instead you have just
// raw data (for example audio coming over bluetooth), then before sending up any
// audio data, you must first send up an SpeechAudioFormat descriptor to describe
// the layout and format of your raw audio data via DataRecognitionClient's sendAudioFormat() method.
int bytesRead = 0;
byte[] buffer = new byte[1024];
try
{
do
{
// Get more Audio data to send into byte buffer.
bytesRead = recordedStream.Read(buffer, 0, buffer.Length);
// Send of audio data to service.
this.dataClient.SendAudio(buffer, bytesRead);
}
while (bytesRead > 0);
}
catch (Exception ex)
{
WriteLine("Exception ------------ " + ex.Message);
}
finally
{
// We are done sending audio. Final recognition results will arrive in OnResponseReceived event call.
this.dataClient.EndAudio();
}
}
private async void OnDataShortPhraseResponseReceivedHandler(object sender, SpeechResponseEventArgs e)
{
this.WriteLine("--- OnDataShortPhraseResponseReceivedHandler ---");
this.WriteResponseResult(e);
// we got the final result, so it we can end the mic reco. No need to do this
// for dataReco, since we already called endAudio() on it as soon as we were done
// sending all the data.
// Send to bot
if (e.PhraseResponse.RecognitionStatus == RecognitionStatus.RecognitionSuccess)
{
await SendToBot(e.PhraseResponse.Results
.OrderBy(k => k.Confidence)
.FirstOrDefault());
}
else
{
_failedCallback(true);
}
}
private async Task SendToBot(RecognizedPhrase recognizedPhrase)
{
Activity activity = new Activity()
{
From = new ChannelAccount { Id = conversationResult.Id },
Conversation = new ConversationAccount { Id = conversationResult.Id },
Recipient = new ChannelAccount { Id = "Bot" },
ServiceUrl = "https://skype.botframework.com",
ChannelId = "skype",
};
activity.Text = recognizedPhrase.DisplayText;
using (var scope = Microsoft.Bot.Builder.Dialogs.Conversation
.Container.BeginLifetimeScope(DialogModule.LifetimeScopeTag, Configure))
{
scope.Resolve<IMessageActivity>
(TypedParameter.From((IMessageActivity)activity));
DialogModule_MakeRoot.Register
(scope, () => new LUISDialogClass());
var postToBot = scope.Resolve<IPostToBot>();
try
{
await postToBot.PostAsync(activity, CancellationToken.None);
}
catch (SerializationException ex)
{
Debug.WriteLine("Exception: " + ex.StackTrace);
}
}
}
private void Configure(ContainerBuilder builder)
{
builder.Register(c => new BotToUserSpeech(c.Resolve<IMessageActivity>(), _callback))
.As<IBotToUser>()
.InstancePerLifetimeScope();
}
private void WriteResponseResult(SpeechResponseEventArgs e)
{
if (e.PhraseResponse.Results.Length == 0)
{
this.WriteLine("No phrase response is available.");
}
else
{
this.WriteLine("********* Final n-BEST Results *********");
for (int i = 0; i < e.PhraseResponse.Results.Length; i++)
{
this.WriteLine(
"[{0}] Confidence={1}, Text=\"{2}\"",
i,
e.PhraseResponse.Results[i].Confidence,
e.PhraseResponse.Results[i].DisplayText);
}
this.WriteLine(string.Empty);
}
}
private void WriteLine(string format, params object[] args)
{
var formattedStr = string.Format(format, args);
Trace.WriteLine(formattedStr);
Debug.WriteLine(formattedStr);
}
}
流程如下:
呼叫到达 CallingController class,后者将其转发给 JoeCallingBot class,后者将其转发给 BingSpeech class,后者随后将其转发给 LUISDialog class
使用 Bot.Builder 版本 3.3.3 解决了这个问题。但是较新版本的 Bot Builder SDK 导致了这个问题。 Github 上有一个未解决的问题:
将 Bot Builder 升级到 3。9.x 解决了问题:)
我正在尝试使用 bing 语音 api 向使用语音到文本识别的机器人添加呼叫功能。 当我 运行 我的应用程序时,它在 运行 时间给我一个例外(在标题中给出)。我不确定如何处理它以及导致它的原因。 它发生在 SendToBot 方法中的以下行。
await postToBot.PostAsync(activity, CancellationToken.None);
Microsoft.Bot.Builder.Internals.Fibers.NullWait`1[[Microsoft.Bot.Builder.Dialogs.Internals.DialogTask, Microsoft.Bot.Builder, Version=3.5.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]' in Assembly 'Microsoft.Bot.Builder, Version=3.5.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' is not marked as serializable.
堆栈跟踪:
at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type)
at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context)
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo()
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)
at Microsoft.Bot.Builder.Internals.Fibers.FormatterStore`1.Microsoft.Bot.Builder.Internals.Fibers.IStore<T>.Save(T item)
at Microsoft.Bot.Builder.Internals.Fibers.ErrorResilientStore`1.Microsoft.Bot.Builder.Internals.Fibers.IStore<T>.Save(T item)
at Microsoft.Bot.Builder.Internals.Fibers.FactoryStore`1.Microsoft.Bot.Builder.Internals.Fibers.IStore<T>.Save(T item)
at Microsoft.Bot.Builder.Dialogs.Internals.DialogTask.<Microsoft-Bot-Builder-Base-IEventLoop-PollAsync>d__23.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.ReactiveDialogTask.<Microsoft-Bot-Builder-Base-IEventLoop-PollAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.ScoringEventLoop`1.<Microsoft-Bot-Builder-Base-IEventLoop-PollAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.EventLoopDialogTask.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.SetAmbientThreadCulture.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.PersistentDialogTask.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Bot.Builder.Dialogs.Internals.PersistentDialogTask.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.ExceptionTranslationDialogTask.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.SerializeByConversation.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.PostUnhandledExceptionToUser.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Bot.Builder.Dialogs.Internals.PostUnhandledExceptionToUser.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Builder.Dialogs.Internals.LogPostToBot.<Microsoft-Bot-Builder-Dialogs-Internals-IPostToBot-PostAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at JoeBot.BingSpeech.<SendToBot>d__14.MoveNext() in D:\PARIS\JoeBot\CallingBot\BingSpeech.cs:line 123
BingSpeech 中的以下方法class(最后给出)
private async Task SendToBot(RecognizedPhrase recognizedPhrase)
{
Activity activity = new Activity()
{
From = new ChannelAccount { Id = conversationResult.Id },
Conversation = new ConversationAccount { Id = conversationResult.Id },
Recipient = new ChannelAccount { Id = "Bot" },
ServiceUrl = "https://skype.botframework.com",
ChannelId = "skype",
};
activity.Text = recognizedPhrase.DisplayText;
using (var scope = Microsoft.Bot.Builder.Dialogs.Conversation
.Container.BeginLifetimeScope(DialogModule.LifetimeScopeTag, Configure))
{
scope.Resolve<IMessageActivity>
(TypedParameter.From((IMessageActivity)activity));
DialogModule_MakeRoot.Register
(scope, () => new LUISDialogClass());
var postToBot = scope.Resolve<IPostToBot>();
await postToBot.PostAsync(activity, CancellationToken.None);
}
}
我的 LUISDialogClass() 被标记为可序列化。 LUIS 是根对话框,它根据 intent/Entity 匹配将请求转发到进一步的 WikipediaDialog class。我还在此处使用静态 class 和字段(用于某些特殊目的/将其发送到服务器)创建 JSON 字符串。
[Serializable]
public class LUISDialogClass : LuisDialog<object>
{
[LuisIntent("")]
[LuisIntent("None")]
public async Task None(IDialogContext context, LuisResult result)
{
var message = result;
await context.PostAsync("Intent match : None");
context.Wait(MessageReceived);
}
[LuisIntent("FindInfo")]
public async Task FindInfo(IDialogContext context, LuisResult result)
{
try
{
var message = result;
for (int i = 1; i < 2; i++)
{
JSONDataObjects.data[i] = new Datum();
JSONDataObjects.data[i].dataKind = "luisResponse";
JSONDataObjects.data[i].query = message.Query;
JSONDataObjects.data[i].intents = new Intent[message.Intents.Count];
JSONDataObjects.data[i].entities = new Entity[message.Entities.Count];
for (int j = 0; j < message.Intents.Count; j++)
{
JSONDataObjects.data[i].intents[j] = new Intent();
JSONDataObjects.data[i].intents[j].intent = message.Intents[j]?.Intent;
JSONDataObjects.data[i].intents[j].score = (float)message.Intents[j]?.Score;
}
for (int j = 0; j < message.Entities.Count; j++)
{
JSONDataObjects.data[i].entities[j] = new Entity();
JSONDataObjects.data[i].entities[j].entity = message.Entities[j]?.Entity;
JSONDataObjects.data[i].entities[j].type = message.Entities[j]?.Type;
JSONDataObjects.data[i].entities[j].startIndex = (int)message.Entities[j]?.StartIndex;
JSONDataObjects.data[i].entities[j].endIndex = (int)message.Entities[j]?.EndIndex;
JSONDataObjects.data[i].entities[j].score = (float)message.Entities[j]?.Score;
}
}
// See if the intent has a > .70 match
bool boolIntentMatch = false;
foreach (var objIntent in message.Intents)
{
// If the FindInfo Intent is detected
// and it's score is greater than or = to .70
// set boolIntentMatch = true
if (
(objIntent.Intent == "FindInfo")
&& (objIntent.Score >= .70f)
)
{
boolIntentMatch = true;
}
}
if (boolIntentMatch)
{
// ** To Do: Code to handle a Match **
string item = "";
EntityRecommendation rec;
if (message.TryFindEntity("objects", out rec))
{
item = rec.Entity;
}
else if (message.TryFindEntity("location", out rec))
{
item = rec.Entity;
}
Activity messageActivity = (Activity)context.MakeMessage();
messageActivity.Text = item;
messageActivity.ChannelId = "emulator";
await context.Forward(new WikipediaDialog(), ResumeAfterWikipedia, messageActivity, System.Threading.CancellationToken.None);
}
else
{
// Not a match -- Ask to rephrase the question
await context.PostAsync("Please try to rephrase your question. Not a good intent match found");
}
}
catch (Exception ex)
{
//Debug.WriteLine(ex);
await context.PostAsync($"Failed and caught in FindInfo LUIS Dialog, with Exception: {ex.Message}");
}
}
private async Task ResumeAfterWikipedia(IDialogContext context, IAwaitable<object> result)
{
try
{
var message = await result;
}
catch (Exception ex)
{
await context.PostAsync($"Failed and caught in ResumeAfterWikipedia Dialog, with Exception: {ex.Message}");
}
finally
{
context.Wait(this.MessageReceived);
}
}
}
}
我正在使用 CallingController class 来处理以下调用
[BotAuthentication]
// Prefix route for your calling controller
[RoutePrefix("api/calling")]
public class CallingController : ApiController
{
public CallingController()
: base()
{
CallingConversation.RegisterCallingBot(c => new JoeCallingBot(c));
}
// Callback route for Skype calling events.
// Make sure to set the Microsoft.Bot.Builder.Calling.CallbackUrl in web.config
[Route("callback")]
public async Task<HttpResponseMessage> ProcessCallingEventAsync()
{
return await CallingConversation.SendAsync(Request, CallRequestType.CallingEvent);
}
// Route for incoming call events
[Route("call")]
public async Task<HttpResponseMessage> ProcessIncomingCallAsync()
{
return await CallingConversation.SendAsync(Request, CallRequestType.IncomingCall);
}
}
我的 JoeCallingBot class 正在关注
public class JoeCallingBot : ICallingBot
{
public ICallingBotService CallingBotService
{
get; private set;
}
private List<string> response = new List<string>();
int silenceTimes = 0;
bool sttFailed = false;
public JoeCallingBot(ICallingBotService callingBotService)
{
if (callingBotService == null)
throw new ArgumentNullException(nameof(callingBotService));
this.CallingBotService = callingBotService;
CallingBotService.OnIncomingCallReceived += OnIncomingCallReceived;
CallingBotService.OnPlayPromptCompleted += OnPlayPromptCompleted;
CallingBotService.OnRecordCompleted += OnRecordCompleted;
CallingBotService.OnHangupCompleted += OnHangupCompleted;
}
private Task OnIncomingCallReceived(IncomingCallEvent incomingCallEvent)
{
var id = Guid.NewGuid().ToString();
incomingCallEvent.ResultingWorkflow.Actions = new List<ActionBase>
{
new Answer { OperationId = id },
GetRecordForText("Welcome! How can I help you?")
};
return Task.FromResult(true);
}
private ActionBase GetRecordForText(string promptText)
{
PlayPrompt prompt;
if (string.IsNullOrEmpty(promptText))
prompt = null;
else
prompt = GetPromptForText(promptText);
var id = Guid.NewGuid().ToString();
return new Record()
{
OperationId = id,
PlayPrompt = prompt,
MaxDurationInSeconds = 10,
InitialSilenceTimeoutInSeconds = 5,
MaxSilenceTimeoutInSeconds = 2,
PlayBeep = false,
RecordingFormat = RecordingFormat.Wav,
StopTones = new List<char> { '#' }
};
}
private Task OnPlayPromptCompleted(PlayPromptOutcomeEvent playPromptOutcomeEvent)
{
if (response.Count > 0)
{
silenceTimes = 0;
var actionList = new List<ActionBase>();
foreach (var res in response)
{
Debug.WriteLine($"Response ----- {res}");
}
actionList.Add(GetPromptForText(response));
actionList.Add(GetRecordForText(string.Empty));
playPromptOutcomeEvent.ResultingWorkflow.Actions = actionList;
response.Clear();
}
else
{
if (sttFailed)
{
playPromptOutcomeEvent.ResultingWorkflow.Actions = new List<ActionBase>
{
GetRecordForText("I didn't catch that, would you kindly repeat?")
};
sttFailed = false;
silenceTimes = 0;
}
else if (silenceTimes > 2)
{
playPromptOutcomeEvent.ResultingWorkflow.Actions = new List<ActionBase>
{
GetPromptForText("Something went wrong. Call again later."),
new Hangup() { OperationId = Guid.NewGuid().ToString() }
};
playPromptOutcomeEvent.ResultingWorkflow.Links = null;
silenceTimes = 0;
}
else
{
silenceTimes++;
playPromptOutcomeEvent.ResultingWorkflow.Actions = new List<ActionBase>
{
GetSilencePrompt(2000)
};
}
}
return Task.CompletedTask;
}
private async Task OnRecordCompleted(RecordOutcomeEvent recordOutcomeEvent)
{
if (recordOutcomeEvent.RecordOutcome.Outcome == Outcome.Success)
{
var record = await recordOutcomeEvent.RecordedContent;
BingSpeech bs = new BingSpeech(recordOutcomeEvent.ConversationResult, t => response.Add(t), s => sttFailed = s);
bs.CreateDataRecoClient();
bs.SendAudioHelper(record);
recordOutcomeEvent.ResultingWorkflow.Actions = new List<ActionBase>
{
GetSilencePrompt()
};
}
else
{
if (silenceTimes > 1)
{
recordOutcomeEvent.ResultingWorkflow.Actions = new List<ActionBase>
{
GetPromptForText("Thank you for calling"),
new Hangup() { OperationId = Guid.NewGuid().ToString() }
};
recordOutcomeEvent.ResultingWorkflow.Links = null;
silenceTimes = 0;
}
else
{
silenceTimes++;
recordOutcomeEvent.ResultingWorkflow.Actions = new List<ActionBase>
{
GetRecordForText("I didn't catch that, would you kinly repeat?")
};
}
}
}
private Task OnHangupCompleted(HangupOutcomeEvent hangupOutcomeEvent)
{
hangupOutcomeEvent.ResultingWorkflow = null;
return Task.FromResult(true);
}
private static PlayPrompt GetPromptForText(string text)
{
var prompt = new Prompt { Value = text, Voice = VoiceGender.Female };
return new PlayPrompt { OperationId = Guid.NewGuid().ToString(), Prompts = new List<Prompt> { prompt } };
}
private static PlayPrompt GetPromptForText(List<string> text)
{
var prompts = new List<Prompt>();
foreach (var txt in text)
{
if (!string.IsNullOrEmpty(txt))
prompts.Add(new Prompt { Value = txt, Voice = VoiceGender.Female });
}
if (prompts.Count == 0)
return GetSilencePrompt(1000);
return new PlayPrompt { OperationId = Guid.NewGuid().ToString(), Prompts = prompts };
}
private static PlayPrompt GetSilencePrompt(uint silenceLengthInMilliseconds = 3000)
{
var prompt = new Prompt { Value = string.Empty, Voice = VoiceGender.Female, SilenceLengthInMilliseconds = silenceLengthInMilliseconds };
return new PlayPrompt { OperationId = Guid.NewGuid().ToString(), Prompts = new List<Prompt> { prompt } };
}
}
我完整的 BingSpeech class 如下
public class BingSpeech
{
private DataRecognitionClient dataClient;
private Action<string> _callback;
private ConversationResult conversationResult;
private Action<bool> _failedCallback;
public BingSpeech(ConversationResult conversationResult, Action<string> callback, Action<bool> failedCallback)
{
this.conversationResult = conversationResult;
_callback = callback;
_failedCallback = failedCallback;
}
public string DefaultLocale { get; } = "en-US";
public string SubscriptionKey { get; } = "Bing Speech API KEY"; //Bing Speech Recognition Key
public void CreateDataRecoClient()
{
this.dataClient = SpeechRecognitionServiceFactory.CreateDataClient(
SpeechRecognitionMode.ShortPhrase,
this.DefaultLocale,
this.SubscriptionKey);
this.dataClient.OnResponseReceived += this.OnDataShortPhraseResponseReceivedHandler;
}
public void SendAudioHelper(Stream recordedStream)
{
// Note for wave files, we can just send data from the file right to the server.
// In the case you are not an audio file in wave format, and instead you have just
// raw data (for example audio coming over bluetooth), then before sending up any
// audio data, you must first send up an SpeechAudioFormat descriptor to describe
// the layout and format of your raw audio data via DataRecognitionClient's sendAudioFormat() method.
int bytesRead = 0;
byte[] buffer = new byte[1024];
try
{
do
{
// Get more Audio data to send into byte buffer.
bytesRead = recordedStream.Read(buffer, 0, buffer.Length);
// Send of audio data to service.
this.dataClient.SendAudio(buffer, bytesRead);
}
while (bytesRead > 0);
}
catch (Exception ex)
{
WriteLine("Exception ------------ " + ex.Message);
}
finally
{
// We are done sending audio. Final recognition results will arrive in OnResponseReceived event call.
this.dataClient.EndAudio();
}
}
private async void OnDataShortPhraseResponseReceivedHandler(object sender, SpeechResponseEventArgs e)
{
this.WriteLine("--- OnDataShortPhraseResponseReceivedHandler ---");
this.WriteResponseResult(e);
// we got the final result, so it we can end the mic reco. No need to do this
// for dataReco, since we already called endAudio() on it as soon as we were done
// sending all the data.
// Send to bot
if (e.PhraseResponse.RecognitionStatus == RecognitionStatus.RecognitionSuccess)
{
await SendToBot(e.PhraseResponse.Results
.OrderBy(k => k.Confidence)
.FirstOrDefault());
}
else
{
_failedCallback(true);
}
}
private async Task SendToBot(RecognizedPhrase recognizedPhrase)
{
Activity activity = new Activity()
{
From = new ChannelAccount { Id = conversationResult.Id },
Conversation = new ConversationAccount { Id = conversationResult.Id },
Recipient = new ChannelAccount { Id = "Bot" },
ServiceUrl = "https://skype.botframework.com",
ChannelId = "skype",
};
activity.Text = recognizedPhrase.DisplayText;
using (var scope = Microsoft.Bot.Builder.Dialogs.Conversation
.Container.BeginLifetimeScope(DialogModule.LifetimeScopeTag, Configure))
{
scope.Resolve<IMessageActivity>
(TypedParameter.From((IMessageActivity)activity));
DialogModule_MakeRoot.Register
(scope, () => new LUISDialogClass());
var postToBot = scope.Resolve<IPostToBot>();
try
{
await postToBot.PostAsync(activity, CancellationToken.None);
}
catch (SerializationException ex)
{
Debug.WriteLine("Exception: " + ex.StackTrace);
}
}
}
private void Configure(ContainerBuilder builder)
{
builder.Register(c => new BotToUserSpeech(c.Resolve<IMessageActivity>(), _callback))
.As<IBotToUser>()
.InstancePerLifetimeScope();
}
private void WriteResponseResult(SpeechResponseEventArgs e)
{
if (e.PhraseResponse.Results.Length == 0)
{
this.WriteLine("No phrase response is available.");
}
else
{
this.WriteLine("********* Final n-BEST Results *********");
for (int i = 0; i < e.PhraseResponse.Results.Length; i++)
{
this.WriteLine(
"[{0}] Confidence={1}, Text=\"{2}\"",
i,
e.PhraseResponse.Results[i].Confidence,
e.PhraseResponse.Results[i].DisplayText);
}
this.WriteLine(string.Empty);
}
}
private void WriteLine(string format, params object[] args)
{
var formattedStr = string.Format(format, args);
Trace.WriteLine(formattedStr);
Debug.WriteLine(formattedStr);
}
}
流程如下: 呼叫到达 CallingController class,后者将其转发给 JoeCallingBot class,后者将其转发给 BingSpeech class,后者随后将其转发给 LUISDialog class
使用 Bot.Builder 版本 3.3.3 解决了这个问题。但是较新版本的 Bot Builder SDK 导致了这个问题。 Github 上有一个未解决的问题:
将 Bot Builder 升级到 3。9.x 解决了问题:)