Merge branch 'SciSharp:master' into master
This commit is contained in:
commit
a0935627a6
|
|
@ -1,6 +0,0 @@
|
|||
namespace BotSharp.Abstraction.Agents;
|
||||
|
||||
public interface IAgentRuleHook
|
||||
{
|
||||
void AddRules(List<AgentRule> rules);
|
||||
}
|
||||
|
|
@ -5,8 +5,9 @@ public class ConversationChannel
|
|||
public const string WebChat = "webchat";
|
||||
public const string OpenAPI = "openapi";
|
||||
public const string Phone = "phone";
|
||||
public const string SMS = "sms";
|
||||
public const string Messenger = "messenger";
|
||||
public const string Email = "email";
|
||||
public const string Cron = "cron";
|
||||
public const string Crontab = "crontab";
|
||||
public const string Database = "database";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ public class RoleDialogModel : ITrackableMessage
|
|||
FunctionArgs = source.FunctionArgs,
|
||||
FunctionName = source.FunctionName,
|
||||
ToolCallId = source.ToolCallId,
|
||||
Indication = source.Indication,
|
||||
PostbackFunctionName = source.PostbackFunctionName,
|
||||
RichContent = source.RichContent,
|
||||
Payload = source.Payload,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ public class CrontabItem : ScheduleTaskArgs
|
|||
[JsonPropertyName("expire_seconds")]
|
||||
public int ExpireSeconds { get; set; } = 60;
|
||||
|
||||
[JsonPropertyName("last_execution_time")]
|
||||
public DateTime? LastExecutionTime { get; set; }
|
||||
|
||||
[JsonPropertyName("created_time")]
|
||||
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ public interface IFunctionCallback
|
|||
/// </summary>
|
||||
string Indication => string.Empty;
|
||||
|
||||
Task<string> GetIndication(RoleDialogModel message) => Task.FromResult(Indication);
|
||||
Task<string> GetIndication(RoleDialogModel message) => Task.FromResult(message.Indication ?? Indication);
|
||||
|
||||
Task<bool> Execute(RoleDialogModel message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,5 +2,12 @@ namespace BotSharp.Core.Crontab.Abstraction;
|
|||
|
||||
public interface ICrontabHook
|
||||
{
|
||||
Task OnCronTriggered(CrontabItem item);
|
||||
Task OnCronTriggered(CrontabItem item)
|
||||
=> Task.CompletedTask;
|
||||
|
||||
Task OnTaskExecuting(CrontabItem item)
|
||||
=> Task.CompletedTask;
|
||||
|
||||
Task OnTaskExecuted(CrontabItem item)
|
||||
=> Task.CompletedTask;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
namespace BotSharp.Core.Crontab.Abstraction;
|
||||
|
||||
/// <summary>
|
||||
/// Provide a cron source for the crontab service.
|
||||
/// </summary>
|
||||
public interface ICrontabSource
|
||||
{
|
||||
CrontabItem GetCrontabItem();
|
||||
}
|
||||
|
|
@ -39,7 +39,17 @@ public class CrontabService : ICrontabService
|
|||
{
|
||||
var repo = _services.GetRequiredService<IBotSharpRepository>();
|
||||
var crontable = repo.GetCrontabItems(CrontabItemFilter.Empty());
|
||||
return crontable.Items.ToList();
|
||||
|
||||
// Add fixed crontab items from cronsources
|
||||
var fixedCrantabItems = crontable.Items.ToList();
|
||||
var cronsources = _services.GetServices<ICrontabSource>();
|
||||
foreach (var source in cronsources)
|
||||
{
|
||||
var item = source.GetCrontabItem();
|
||||
fixedCrantabItems.Add(source.GetCrontabItem());
|
||||
}
|
||||
|
||||
return fixedCrantabItems;
|
||||
}
|
||||
|
||||
public async Task ScheduledTimeArrived(CrontabItem item)
|
||||
|
|
@ -47,8 +57,10 @@ public class CrontabService : ICrontabService
|
|||
_logger.LogDebug($"ScheduledTimeArrived {item}");
|
||||
|
||||
await HookEmitter.Emit<ICrontabHook>(_services, async hook =>
|
||||
await hook.OnCronTriggered(item)
|
||||
);
|
||||
await Task.Delay(1000 * 10);
|
||||
{
|
||||
await hook.OnTaskExecuting(item);
|
||||
await hook.OnCronTriggered(item);
|
||||
await hook.OnTaskExecuted(item);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ public class CrontabWatcher : BackgroundService
|
|||
{
|
||||
var locker = scope.ServiceProvider.GetRequiredService<IDistributedLocker>();
|
||||
|
||||
/*while (!stoppingToken.IsCancellationRequested)
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
var delay = Task.Delay(1000, stoppingToken);
|
||||
var delay = Task.Delay(1000 * 10, stoppingToken);
|
||||
|
||||
await locker.LockAsync("CrontabWatcher", async () =>
|
||||
{
|
||||
|
|
@ -34,7 +34,7 @@ public class CrontabWatcher : BackgroundService
|
|||
});
|
||||
|
||||
await delay;
|
||||
}*/
|
||||
}
|
||||
|
||||
_logger.LogWarning("Crontab Watcher background service is stopped.");
|
||||
}
|
||||
|
|
@ -58,10 +58,24 @@ public class CrontabWatcher : BackgroundService
|
|||
// Get the current time
|
||||
var currentTime = DateTime.UtcNow;
|
||||
|
||||
// Get the last occurrence from the schedule
|
||||
var lastOccurrence = GetLastOccurrence(schedule);
|
||||
|
||||
// Get the next occurrence from the schedule
|
||||
var nextOccurrence = schedule.GetNextOccurrence(currentTime.AddSeconds(-1));
|
||||
|
||||
// Check if the current time matches the schedule
|
||||
// Get the previous occurrence from the execution log
|
||||
var previousOccurrence = item.LastExecutionTime;
|
||||
|
||||
// First check if this occurrence was already triggered
|
||||
if (previousOccurrence.HasValue &&
|
||||
previousOccurrence.Value >= lastOccurrence &&
|
||||
previousOccurrence.Value < nextOccurrence.AddSeconds(1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Then check if the current time matches the schedule
|
||||
bool matches = currentTime >= nextOccurrence && currentTime < nextOccurrence.AddSeconds(1);
|
||||
|
||||
if (matches)
|
||||
|
|
@ -72,9 +86,21 @@ public class CrontabWatcher : BackgroundService
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning($"Error when running cron task ({item.ConversationId}, {item.Title}, {item.Cron}): {ex.Message}\r\n{ex.InnerException}");
|
||||
_logger.LogError($"Error when running cron task ({item.Title}, {item.Cron}): {ex.Message}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime GetLastOccurrence(CrontabSchedule schedule)
|
||||
{
|
||||
var nextOccurrence = schedule.GetNextOccurrence(DateTime.UtcNow);
|
||||
var afterNextOccurrence = schedule.GetNextOccurrence(nextOccurrence);
|
||||
var interval = afterNextOccurrence - nextOccurrence;
|
||||
if (interval.TotalMinutes < 10)
|
||||
{
|
||||
throw new ArgumentException("The minimum interval must be at least 10 minutes.");
|
||||
}
|
||||
return nextOccurrence - interval;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ public class RuleEngine : IRuleEngine
|
|||
{
|
||||
var conv = await convService.NewConversation(new Conversation
|
||||
{
|
||||
Channel = trigger.Channel,
|
||||
Title = data,
|
||||
AgentId = agent.Id
|
||||
});
|
||||
|
||||
|
|
@ -52,7 +54,7 @@ public class RuleEngine : IRuleEngine
|
|||
|
||||
var states = new List<MessageState>
|
||||
{
|
||||
new("channel", ConversationChannel.Database),
|
||||
new("channel", trigger.Channel),
|
||||
new("channel_id", trigger.EntityId)
|
||||
};
|
||||
convService.SetConversationId(conv.Id, states);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
namespace BotSharp.Core.Rules.Triggers;
|
||||
|
||||
public interface IRuleConfig
|
||||
{
|
||||
}
|
||||
|
|
@ -111,7 +111,7 @@ public partial class AgentService
|
|||
|
||||
parameterDef.Properties = JsonSerializer.Deserialize<JsonDocument>(clonedRoot.ToString());
|
||||
parameterDef.Required = required;
|
||||
return parameterDef; ;
|
||||
return parameterDef;
|
||||
}
|
||||
|
||||
public string RenderedTemplate(Agent agent, string templateName)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ public partial class RoutingService
|
|||
message.ToolCallId = response.ToolCallId;
|
||||
message.FunctionName = response.FunctionName;
|
||||
message.FunctionArgs = response.FunctionArgs;
|
||||
message.Indication = response.Indication;
|
||||
message.CurrentAgentId = agent.Id;
|
||||
|
||||
await InvokeFunction(message, dialogs);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public class RateLimitConversationHook : ConversationHookBase
|
|||
var channel = states.GetState("channel");
|
||||
|
||||
// Check the number of conversations
|
||||
if (channel != ConversationChannel.Phone && channel != ConversationChannel.Email)
|
||||
if (channel != ConversationChannel.Phone && channel != ConversationChannel.Email && channel != ConversationChannel.Database)
|
||||
{
|
||||
var user = _services.GetRequiredService<IUserIdentity>();
|
||||
var convService = _services.GetRequiredService<IConversationService>();
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ public class VerboseLogHook : IContentGeneratingHook
|
|||
var agent = await agentService.LoadAgent(message.CurrentAgentId);
|
||||
|
||||
var log = message.Role == AgentRole.Function ?
|
||||
$"[{agent?.Name}]: {message.FunctionName}({message.FunctionArgs})" :
|
||||
$"[{agent?.Name}]: {message.Indication} {message.FunctionName}({message.FunctionArgs})" :
|
||||
$"[{agent?.Name}]: {message.Content}" + $" <== [msg_id: {message.MessageId}]";
|
||||
|
||||
_logger.LogInformation(tokenStats.Prompt);
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BotSharp.Core.Rules\BotSharp.Core.Rules.csproj" />
|
||||
<ProjectReference Include="..\BotSharp.Core\BotSharp.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -160,16 +160,4 @@ public class AgentController : ControllerBase
|
|||
}
|
||||
return utilities.Where(x => !string.IsNullOrWhiteSpace(x.Name)).OrderBy(x => x.Name).ToList();
|
||||
}
|
||||
|
||||
[HttpGet("/agent/rule/options")]
|
||||
public IEnumerable<AgentRule> GetAgentRuleOptions()
|
||||
{
|
||||
var rules = new List<AgentRule>();
|
||||
var hooks = _services.GetServices<IAgentRuleHook>();
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
hook.AddRules(rules);
|
||||
}
|
||||
return rules.Where(x => !string.IsNullOrWhiteSpace(x.TriggerName)).OrderBy(x => x.TriggerName).ToList();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Core.Rules.Triggers;
|
||||
|
||||
namespace BotSharp.OpenAPI.Controllers;
|
||||
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
public class RulesController
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
public RulesController(
|
||||
IServiceProvider services)
|
||||
{
|
||||
_services = services;
|
||||
}
|
||||
|
||||
[HttpGet("/rule/triggers")]
|
||||
public IEnumerable<AgentRule> GetRuleTriggers()
|
||||
{
|
||||
var triggers = _services.GetServices<IRuleTrigger>();
|
||||
return triggers.Select(x => new AgentRule
|
||||
{
|
||||
TriggerName = x.GetType().Name
|
||||
}).OrderBy(x => x.TriggerName).ToList();
|
||||
}
|
||||
|
||||
[HttpGet("/rule/formalization")]
|
||||
public async Task<string> GetFormalizedRuleDefinition([FromBody] AgentRule rule)
|
||||
{
|
||||
return "{}";
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Anthropic.SDK" Version="4.3.0" />
|
||||
<PackageReference Include="Anthropic.SDK" Version="4.4.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using Anthropic.SDK.Common;
|
||||
using BotSharp.Abstraction.Conversations;
|
||||
using BotSharp.Abstraction.MLTasks.Settings;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
|
|
@ -48,15 +47,16 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
|
||||
if (response.StopReason == "tool_use")
|
||||
{
|
||||
var content = response.Content.OfType<TextContent>().FirstOrDefault();
|
||||
var toolResult = response.Content.OfType<ToolUseContent>().First();
|
||||
|
||||
responseMessage = new RoleDialogModel(AgentRole.Function, response.FirstMessage?.Text ?? string.Empty)
|
||||
responseMessage = new RoleDialogModel(AgentRole.Function, content?.Text ?? string.Empty)
|
||||
{
|
||||
CurrentAgentId = agent.Id,
|
||||
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
|
||||
ToolCallId = toolResult.Id,
|
||||
FunctionName = toolResult.Name,
|
||||
FunctionArgs = JsonSerializer.Serialize(toolResult.Input)
|
||||
FunctionArgs = JsonSerializer.Serialize(toolResult.Input),
|
||||
};
|
||||
}
|
||||
else
|
||||
|
|
@ -161,7 +161,7 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
new ToolResultContent()
|
||||
{
|
||||
ToolUseId = conv.ToolCallId,
|
||||
Content = conv.Content
|
||||
Content = [new TextContent() { Text = conv.Content }]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.AI.OpenAI" Version="2.0.0" />
|
||||
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
var funcContextIn = new RoleDialogModel(AgentRole.Function, text)
|
||||
{
|
||||
CurrentAgentId = agent.Id,
|
||||
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
|
||||
FunctionName = toolCall?.FunctionName,
|
||||
FunctionArgs = toolCall?.FunctionArguments?.ToString()
|
||||
};
|
||||
|
|
|
|||
|
|
@ -116,7 +116,8 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
|
|||
var agent = await _agentService.LoadAgent(message.CurrentAgentId);
|
||||
message.FunctionArgs = message.FunctionArgs ?? "{}";
|
||||
var args = message.FunctionArgs.FormatJson();
|
||||
var log = $"{message.FunctionName} <u>executing</u>\r\n```json\r\n{args}\r\n```";
|
||||
var log = $"*{message.Indication.Replace("\r", string.Empty).Replace("\n", string.Empty)}* \r\n\r\n **{message.FunctionName}**()";
|
||||
log += args.Length > 5 ? $" \r\n```json\r\n{args}\r\n```" : string.Empty;
|
||||
|
||||
var input = new ContentLogInputModel(conversationId, message)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "util-file-read_image",
|
||||
"description": "If the user's request is related to analyzing images, you can call this function to analyze images.",
|
||||
"description": "If the user's request is related to describing or analyzing images, you can call this function to analyze images.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
},
|
||||
"image_urls": {
|
||||
"type": "array",
|
||||
"description": "The image, photo or picture urls that user requests for analysis. They typically start with 'http' or 'https'. If user doesn't include any url, then leave this array empty. Please remove any duplicated urls",
|
||||
"description": "The image, photo or picture urls that user requests for analysis. They typically start with 'http' or 'https'. If user doesn't include any url, then leave this array empty. Please remove any duplicated urls. Do not make up any urls.",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "The image, photo or picture url that user requests for analysis. It typically starts with http or https."
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
Please call function util-file-read_image if user wants to describe an image or images.
|
||||
Please call function util-file-read_image if user wants to describe an image or images.
|
||||
You can also call function util-file-read_image to access the image or images that user uploaded.
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
using BotSharp.Abstraction.Agents;
|
||||
using BotSharp.Abstraction.Agents.Enums;
|
||||
using BotSharp.Abstraction.Loggers;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
|
|
@ -125,17 +126,19 @@ public class GeminiChatCompletionProvider : IChatCompletion
|
|||
if (!agentService.RenderFunction(agent, function)) continue;
|
||||
|
||||
var def = agentService.RenderFunctionProperty(agent, function);
|
||||
var props = JsonSerializer.Serialize(def?.Properties);
|
||||
var parameters = !string.IsNullOrWhiteSpace(props) && props != "{}" ? new Schema()
|
||||
{
|
||||
Type = ParameterType.Object,
|
||||
Properties = JsonSerializer.Deserialize<dynamic>(props),
|
||||
Required = def?.Required ?? []
|
||||
} : null;
|
||||
|
||||
funcDeclarations.Add(new FunctionDeclaration
|
||||
{
|
||||
Name = function.Name,
|
||||
Description = function.Description,
|
||||
Parameters = new()
|
||||
{
|
||||
Type = ParameterType.Object,
|
||||
Properties = def.Properties,
|
||||
Required = def.Required
|
||||
}
|
||||
Parameters = parameters
|
||||
});
|
||||
|
||||
funcPrompts.Add($"{function.Name}: {function.Description} {def}");
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ public class CrontabItemDocument : MongoBase
|
|||
public int ExecutionCount { get; set; }
|
||||
public int MaxExecutionCount { get; set; }
|
||||
public int ExpireSeconds { get; set; }
|
||||
public DateTime? LastExecutionTime { get; set; }
|
||||
public bool LessThan60Seconds { get; set; } = false;
|
||||
public IEnumerable<CronTaskMongoElement> Tasks { get; set; } = [];
|
||||
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
|
||||
|
||||
|
|
@ -31,6 +33,8 @@ public class CrontabItemDocument : MongoBase
|
|||
ExecutionCount = item.ExecutionCount,
|
||||
MaxExecutionCount = item.MaxExecutionCount,
|
||||
ExpireSeconds = item.ExpireSeconds,
|
||||
LastExecutionTime = item.LastExecutionTime,
|
||||
LessThan60Seconds = item.LessThan60Seconds,
|
||||
Tasks = item.Tasks?.Select(x => CronTaskMongoElement.ToDomainElement(x))?.ToArray() ?? [],
|
||||
CreatedTime = item.CreatedTime
|
||||
};
|
||||
|
|
@ -50,6 +54,8 @@ public class CrontabItemDocument : MongoBase
|
|||
ExecutionCount = item.ExecutionCount,
|
||||
MaxExecutionCount = item.MaxExecutionCount,
|
||||
ExpireSeconds = item.ExpireSeconds,
|
||||
LastExecutionTime = item.LastExecutionTime,
|
||||
LessThan60Seconds = item.LessThan60Seconds,
|
||||
Tasks = item.Tasks?.Select(x => CronTaskMongoElement.ToMongoElement(x))?.ToList() ?? [],
|
||||
CreatedTime = item.CreatedTime
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OpenAI" Version="2.0.0" />
|
||||
<PackageReference Include="OpenAI" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
var funcContextIn = new RoleDialogModel(AgentRole.Function, text)
|
||||
{
|
||||
CurrentAgentId = agent.Id,
|
||||
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
|
||||
ToolCallId = toolCall?.Id,
|
||||
FunctionName = toolCall?.FunctionName,
|
||||
FunctionArgs = toolCall?.FunctionArguments?.ToString()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using BotSharp.Abstraction.Files;
|
||||
using BotSharp.Abstraction.Infrastructures;
|
||||
using BotSharp.Abstraction.Repositories;
|
||||
using BotSharp.Core.Infrastructures;
|
||||
using BotSharp.Plugin.Twilio.Interfaces;
|
||||
using BotSharp.Plugin.Twilio.Models;
|
||||
|
|
@ -126,9 +127,11 @@ public class TwilioVoiceController : TwilioController
|
|||
SeqNumber = request.SeqNum,
|
||||
Content = messageContent,
|
||||
Digits = request.Digits,
|
||||
From = request.From,
|
||||
From = string.Equals(request.Direction, "inbound") ? request.From : request.To,
|
||||
States = ParseStates(request.States)
|
||||
};
|
||||
callerMessage.RequestHeaders = new KeyValuePair<string, Microsoft.Extensions.Primitives.StringValues>[Request.Headers.Count];
|
||||
Request.Headers.CopyTo(callerMessage.RequestHeaders, 0);
|
||||
await messageQueue.EnqueueAsync(callerMessage);
|
||||
|
||||
response = new VoiceResponse();
|
||||
|
|
@ -387,6 +390,9 @@ public class TwilioVoiceController : TwilioController
|
|||
$"twilio/voice/speeches/{conversationId}/intial.mp3"
|
||||
}
|
||||
};
|
||||
string tag = $"twilio:{Request.Form["AnsweredBy"]}";
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
db.AppendConversationTags(conversationId, new List<string> { tag });
|
||||
var twilio = _services.GetRequiredService<TwilioService>();
|
||||
var response = twilio.ReturnNoninterruptedInstructions(instruction);
|
||||
return TwiML(response);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace BotSharp.Plugin.Twilio.Models
|
||||
{
|
||||
public class CallerMessage
|
||||
|
|
@ -8,6 +10,7 @@ namespace BotSharp.Plugin.Twilio.Models
|
|||
public string Digits { get; set; }
|
||||
public string From { get; set; }
|
||||
public Dictionary<string, string> States { get; set; } = new();
|
||||
public KeyValuePair<string, StringValues>[] RequestHeaders { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -64,13 +64,16 @@ namespace BotSharp.Plugin.Twilio.OutboundPhoneCallHandler.Functions
|
|||
Channel = ConversationChannel.Phone
|
||||
});
|
||||
var conversationId = newConv.Id;
|
||||
convStorage.Append(conversationId, new RoleDialogModel(AgentRole.User, "Hi, I'm calling to check my work order quote status, please help me locate my work order number and let me know what to do next.")
|
||||
convStorage.Append(conversationId, new List<RoleDialogModel>
|
||||
{
|
||||
CurrentAgentId = entryAgentId
|
||||
});
|
||||
convStorage.Append(conversationId, new RoleDialogModel(AgentRole.Assistant, args.InitialMessage)
|
||||
{
|
||||
CurrentAgentId = entryAgentId
|
||||
new RoleDialogModel(AgentRole.User, "Hi, I'm calling to check my work order quote status, please help me locate my work order number and let me know what to do next.")
|
||||
{
|
||||
CurrentAgentId = entryAgentId
|
||||
},
|
||||
new RoleDialogModel(AgentRole.Assistant, args.InitialMessage)
|
||||
{
|
||||
CurrentAgentId = entryAgentId
|
||||
}
|
||||
});
|
||||
|
||||
// Generate audio
|
||||
|
|
@ -89,7 +92,9 @@ namespace BotSharp.Plugin.Twilio.OutboundPhoneCallHandler.Functions
|
|||
var call = await CallResource.CreateAsync(
|
||||
url: new Uri($"{_twilioSetting.CallbackHost}/twilio/voice/init-call?conversationId={conversationId}"),
|
||||
to: new PhoneNumber(args.PhoneNumber),
|
||||
from: new PhoneNumber(_twilioSetting.PhoneNumber));
|
||||
from: new PhoneNumber(_twilioSetting.PhoneNumber),
|
||||
asyncAmd: "true",
|
||||
machineDetection: "DetectMessageEnd");
|
||||
|
||||
message.Content = $"The generated phone message: {args.InitialMessage}. \r\n[Conversation ID: {conversationId}]" ?? message.Content;
|
||||
message.StopCompletion = true;
|
||||
|
|
|
|||
|
|
@ -65,6 +65,10 @@ namespace BotSharp.Plugin.Twilio.Services
|
|||
var httpContext = sp.GetRequiredService<IHttpContextAccessor>();
|
||||
httpContext.HttpContext = new DefaultHttpContext();
|
||||
httpContext.HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
foreach (var header in message.RequestHeaders)
|
||||
{
|
||||
httpContext.HttpContext.Request.Headers[header.Key] = header.Value;
|
||||
}
|
||||
httpContext.HttpContext.Request.Headers["X-Twilio-BotSharp"] = "LOST";
|
||||
|
||||
AssistantMessage reply = null;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,10 @@ public class TwilioService
|
|||
Gather.InputEnum.Speech,
|
||||
Gather.InputEnum.Dtmf
|
||||
},
|
||||
Action = new Uri($"{_settings.CallbackHost}/twilio/voice/{twilioSetting.AgentId}")
|
||||
Action = new Uri($"{_settings.CallbackHost}/twilio/voice/{twilioSetting.AgentId}"),
|
||||
Enhanced = true,
|
||||
SpeechModel = Gather.SpeechModelEnum.PhoneCall,
|
||||
SpeechTimeout = "auto"
|
||||
};
|
||||
|
||||
gather.Say(message);
|
||||
|
|
@ -78,6 +81,7 @@ public class TwilioService
|
|||
Gather.InputEnum.Dtmf
|
||||
},
|
||||
Action = new Uri($"{_settings.CallbackHost}/{conversationalVoiceResponse.CallbackPath}"),
|
||||
Enhanced = true,
|
||||
SpeechModel = Gather.SpeechModelEnum.PhoneCall,
|
||||
SpeechTimeout = "auto", // timeout > 0 ? timeout.ToString() : "3",
|
||||
Timeout = conversationalVoiceResponse.Timeout > 0 ? conversationalVoiceResponse.Timeout : 3,
|
||||
|
|
@ -115,6 +119,7 @@ public class TwilioService
|
|||
Gather.InputEnum.Dtmf
|
||||
},
|
||||
Action = new Uri($"{_settings.CallbackHost}/{conversationalVoiceResponse.CallbackPath}"),
|
||||
Enhanced = true,
|
||||
SpeechModel = Gather.SpeechModelEnum.PhoneCall,
|
||||
SpeechTimeout = "auto", // conversationalVoiceResponse.Timeout > 0 ? conversationalVoiceResponse.Timeout.ToString() : "3",
|
||||
Timeout = conversationalVoiceResponse.Timeout > 0 ? conversationalVoiceResponse.Timeout : 3,
|
||||
|
|
|
|||
Loading…
Reference in a new issue