Skip to content

Commit 70eadbd

Browse files
author
Haiping Chen
committed
IRealtimeHook
1 parent 253be7c commit 70eadbd

File tree

8 files changed

+50
-18
lines changed

8 files changed

+50
-18
lines changed

src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,7 @@ public virtual Task OnBreakpointUpdated(string conversationId, bool resetStates)
7878

7979
public virtual Task OnNotificationGenerated(RoleDialogModel message)
8080
=> Task.CompletedTask;
81+
82+
public Task OnUserDisconnected(Conversation conversation)
83+
=> Task.CompletedTask;
8184
}

src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ public interface IConversationHook
2525
/// <returns></returns>
2626
Task OnUserAgentConnectedInitially(Conversation conversation);
2727

28+
/// <summary>
29+
/// Triggered when user disconnects with agent.
30+
/// </summary>
31+
/// <param name="conversation"></param>
32+
/// <returns></returns>
33+
Task OnUserDisconnected(Conversation conversation);
34+
2835
/// <summary>
2936
/// Triggered once for every new conversation.
3037
/// </summary>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace BotSharp.Abstraction.Realtime;
2+
3+
public interface IRealtimeHook
4+
{
5+
string[] OnModelTranscriptPrompt(Agent agent);
6+
}

src/Infrastructure/BotSharp.Core.Realtime/BotSharp.Core.Realtime.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
<ItemGroup>
1010
<ProjectReference Include="..\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
11+
<ProjectReference Include="..\BotSharp.Core\BotSharp.Core.csproj" />
1112
</ItemGroup>
1213

1314
</Project>

src/Infrastructure/BotSharp.Core.Realtime/Services/RealtimeHub.cs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using BotSharp.Abstraction.Utilities;
2+
using BotSharp.Core.Infrastructures;
3+
using Microsoft.AspNetCore.Cors.Infrastructure;
24

35
namespace BotSharp.Core.Realtime.Services;
46

@@ -86,11 +88,14 @@ private async Task ConnectToModel(WebSocket userWebSocket)
8688
var routing = _services.GetRequiredService<IRoutingService>();
8789
routing.Context.Push(agent.Id);
8890

91+
var storage = _services.GetRequiredService<IConversationStorage>();
8992
var dialogs = convService.GetDialogHistory();
9093
if (dialogs.Count == 0)
9194
{
9295
dialogs.Add(new RoleDialogModel(AgentRole.User, "Hi"));
96+
storage.Append(_conn.ConversationId, dialogs.First());
9397
}
98+
9499
routing.Context.SetDialogs(dialogs);
95100

96101
await _completer.Connect(_conn,
@@ -155,6 +160,7 @@ await _completer.Connect(_conn,
155160
{
156161
// append output audio transcript to conversation
157162
dialogs.Add(message);
163+
storage.Append(_conn.ConversationId, message);
158164

159165
foreach (var hook in hookProvider.HooksOrderByPriority)
160166
{
@@ -174,6 +180,7 @@ await _completer.Connect(_conn,
174180
{
175181
// append input audio transcript to conversation
176182
dialogs.Add(message);
183+
storage.Append(_conn.ConversationId, message);
177184

178185
foreach (var hook in hookProvider.HooksOrderByPriority)
179186
{
@@ -224,6 +231,9 @@ private async Task HandleUserDtmfReceived()
224231
};
225232
dialogs.Add(message);
226233

234+
var storage = _services.GetRequiredService<IConversationStorage>();
235+
storage.Append(_conn.ConversationId, message);
236+
227237
foreach (var hook in hookProvider.HooksOrderByPriority)
228238
{
229239
hook.SetAgent(agent)
@@ -239,14 +249,9 @@ private async Task HandleUserDtmfReceived()
239249

240250
private async Task HandleUserDisconnected()
241251
{
242-
// Save dialog history
243-
var routing = _services.GetRequiredService<IRoutingService>();
244-
var storage = _services.GetRequiredService<IConversationStorage>();
245-
var dialogs = routing.Context.GetDialogs();
246-
foreach (var item in dialogs)
247-
{
248-
storage.Append(_conn.ConversationId, item);
249-
}
252+
var convService = _services.GetRequiredService<IConversationService>();
253+
var conversation = await convService.GetConversation(_conn.ConversationId);
254+
await HookEmitter.Emit<IConversationHook>(_services, x => x.OnUserDisconnected(conversation));
250255
}
251256

252257
private async Task SendEventToUser(WebSocket webSocket, object message)

src/Plugins/BotSharp.Plugin.OpenAI/Models/Realtime/RealtimeSessionBody.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,6 @@ public class InputAudioTranscription
7777
public string Language { get; set; } = "en";
7878

7979
[JsonPropertyName("prompt")]
80-
public string Prompt { get; set; }
80+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
81+
public string? Prompt { get; set; }
8182
}

src/Plugins/BotSharp.Plugin.OpenAI/Providers/Realtime/RealTimeCompletionProvider.cs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
using BotSharp.Abstraction.Files.Utilities;
33
using BotSharp.Abstraction.Functions.Models;
44
using BotSharp.Abstraction.Options;
5+
using BotSharp.Abstraction.Realtime;
56
using BotSharp.Abstraction.Realtime.Models;
7+
using BotSharp.Abstraction.Routing;
68
using BotSharp.Core.Infrastructures;
79
using BotSharp.Plugin.OpenAI.Models.Realtime;
810
using OpenAI.Chat;
@@ -42,7 +44,7 @@ public async Task Connect(RealtimeHubConnection conn,
4244
Action onModelReady,
4345
Action<string,string> onModelAudioDeltaReceived,
4446
Action onModelAudioResponseDone,
45-
Action<string> onAudioTranscriptDone,
47+
Action<string> onModelAudioTranscriptDone,
4648
Action<List<RoleDialogModel>> onModelResponseDone,
4749
Action<string> onConversationItemCreated,
4850
Action<RoleDialogModel> onInputAudioTranscriptionCompleted,
@@ -64,7 +66,7 @@ public async Task Connect(RealtimeHubConnection conn,
6466
onModelReady,
6567
onModelAudioDeltaReceived,
6668
onModelAudioResponseDone,
67-
onAudioTranscriptDone,
69+
onModelAudioTranscriptDone,
6870
onModelResponseDone,
6971
onConversationItemCreated,
7072
onInputAudioTranscriptionCompleted,
@@ -125,10 +127,10 @@ private async Task ReceiveMessage(RealtimeHubConnection conn,
125127
Action onModelReady,
126128
Action<string,string> onModelAudioDeltaReceived,
127129
Action onModelAudioResponseDone,
128-
Action<string> onAudioTranscriptDone,
130+
Action<string> onModelAudioTranscriptDone,
129131
Action<List<RoleDialogModel>> onModelResponseDone,
130132
Action<string> onConversationItemCreated,
131-
Action<RoleDialogModel> onInputAudioTranscriptionCompleted,
133+
Action<RoleDialogModel> onUserAudioTranscriptionCompleted,
132134
Action onUserInterrupted)
133135
{
134136
var buffer = new byte[1024 * 32];
@@ -171,7 +173,7 @@ private async Task ReceiveMessage(RealtimeHubConnection conn,
171173
_logger.LogInformation($"{response.Type}: {receivedText}");
172174
var data = JsonSerializer.Deserialize<ResponseAudioTranscript>(receivedText);
173175
await Task.Delay(1000);
174-
onAudioTranscriptDone(data.Transcript);
176+
onModelAudioTranscriptDone(data.Transcript);
175177
}
176178
else if (response.Type == "response.audio.delta")
177179
{
@@ -201,8 +203,11 @@ private async Task ReceiveMessage(RealtimeHubConnection conn,
201203
else if (response.Type == "conversation.item.input_audio_transcription.completed")
202204
{
203205
_logger.LogInformation($"{response.Type}: {receivedText}");
204-
var message = await OnInputAudioTranscriptionCompleted(conn, receivedText);
205-
onInputAudioTranscriptionCompleted(message);
206+
var message = await OnUserAudioTranscriptionCompleted(conn, receivedText);
207+
if (!string.IsNullOrEmpty(message.Content))
208+
{
209+
onUserAudioTranscriptionCompleted(message);
210+
}
206211
}
207212
else if (response.Type == "input_audio_buffer.speech_started")
208213
{
@@ -309,6 +314,9 @@ public async Task<string> UpdateSession(RealtimeHubConnection conn, bool turnDet
309314
return fn;
310315
}).ToArray();
311316

317+
var words = new List<string>();
318+
HookEmitter.Emit<IRealtimeHook>(_services, hook => words.AddRange(hook.OnModelTranscriptPrompt(agent)));
319+
312320
var sessionUpdate = new
313321
{
314322
type = "session.update",
@@ -320,6 +328,7 @@ public async Task<string> UpdateSession(RealtimeHubConnection conn, bool turnDet
320328
{
321329
Model = "whisper-1",
322330
Language = "en",
331+
Prompt = string.Join(", ", words.Select(x => x.ToLower().Trim()).Distinct()).SubstringMax(1024)
323332
},
324333
Voice = "alloy",
325334
Instructions = instruction,
@@ -663,7 +672,7 @@ await hook.AfterGenerated(new RoleDialogModel(AgentRole.Assistant, "response.don
663672
return outputs;
664673
}
665674

666-
public async Task<RoleDialogModel> OnInputAudioTranscriptionCompleted(RealtimeHubConnection conn, string response)
675+
public async Task<RoleDialogModel> OnUserAudioTranscriptionCompleted(RealtimeHubConnection conn, string response)
667676
{
668677
var data = JsonSerializer.Deserialize<ResponseAudioTranscript>(response);
669678
return new RoleDialogModel(AgentRole.User, data.Transcript)

src/Plugins/BotSharp.Plugin.Twilio/OutboundPhoneCallHandler/Functions/HangupPhoneCallFn.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public async Task<bool> Execute(RoleDialogModel message)
4545
pathSid: callSid
4646
);
4747

48-
message.Content = "The call has ended.";
48+
message.Content = "The call has been ended.";
4949
message.StopCompletion = true;
5050
});
5151

0 commit comments

Comments
 (0)