merge with master
This commit is contained in:
commit
a84f58af78
|
|
@ -0,0 +1,9 @@
|
|||
using BotSharp.Abstraction.Instructs.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Instructs;
|
||||
|
||||
public interface IInstructHook
|
||||
{
|
||||
Task BeforeCompletion(RoleDialogModel message);
|
||||
Task AfterCompletion(InstructResult result);
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
using BotSharp.Abstraction.Instructs.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Instructs;
|
||||
|
||||
public interface IInstructService
|
||||
{
|
||||
Task<bool> ExecuteInstructionRecursively(Agent agent,
|
||||
List<RoleDialogModel> wholeDialogs,
|
||||
Task<InstructResult> ExecuteInstruction(Agent agent,
|
||||
RoleDialogModel message,
|
||||
Func<RoleDialogModel, Task> onMessageReceived,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuting,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuted);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
using BotSharp.Abstraction.Instructs.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Instructs;
|
||||
|
||||
public class InstructHookBase : IInstructHook
|
||||
{
|
||||
public virtual async Task AfterCompletion(InstructResult result)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public virtual async Task BeforeCompletion(RoleDialogModel message)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,9 @@ namespace BotSharp.Core.Agents.Services;
|
|||
|
||||
public partial class AgentService
|
||||
{
|
||||
#if !DEBUG
|
||||
[MemoryCache(10 * 60)]
|
||||
#endif
|
||||
public async Task<Agent> LoadAgent(string id)
|
||||
{
|
||||
var hooks = _services.GetServices<IAgentHook>();
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aspects.Cache" Version="2.0.3" />
|
||||
<PackageReference Include="EntityFrameworkCore.BootKit" Version="6.2.1" />
|
||||
<PackageReference Include="Fluid.Core" Version="2.4.0" />
|
||||
<PackageReference Include="TensorFlow.Keras" Version="0.11.2" />
|
||||
|
|
|
|||
|
|
@ -59,6 +59,21 @@ public partial class ConversationService
|
|||
}, onMessageReceived);
|
||||
return;
|
||||
}
|
||||
else if (fn.StopCompletion)
|
||||
{
|
||||
var message = new RoleDialogModel(AgentRole.Assistant, fn.Content)
|
||||
{
|
||||
CurrentAgentId = fn.CurrentAgentId,
|
||||
Channel = fn.Channel,
|
||||
ExecutionData = fn.ExecutionData,
|
||||
ExecutionResult = fn.ExecutionResult
|
||||
};
|
||||
|
||||
await HandleAssistantMessage(message, onMessageReceived);
|
||||
|
||||
_storage.Append(_conversationId, agent.Id, message);
|
||||
return;
|
||||
}
|
||||
|
||||
fn.Content = fn.FunctionArgs.Replace("\r", " ").Replace("\n", " ").Trim() + " => " + fn.ExecutionResult;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
using BotSharp.Abstraction.Agents.Enums;
|
||||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Instructs;
|
||||
using BotSharp.Abstraction.Instructs.Models;
|
||||
using BotSharp.Abstraction.MLTasks;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
using System.IO;
|
||||
|
||||
namespace BotSharp.Core.Instructs;
|
||||
|
||||
|
|
@ -17,7 +19,53 @@ public partial class InstructService : IInstructService
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<bool> ExecuteInstructionRecursively(Agent agent,
|
||||
public async Task<InstructResult> ExecuteInstruction(Agent agent,
|
||||
RoleDialogModel message,
|
||||
Func<RoleDialogModel, Task> onMessageReceived,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuting,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuted)
|
||||
{
|
||||
var response = new InstructResult();
|
||||
|
||||
var wholeDialogs = new List<RoleDialogModel>
|
||||
{
|
||||
new RoleDialogModel("user", message.Content)
|
||||
};
|
||||
|
||||
// Trigger before completion hooks
|
||||
var hooks = _services.GetServices<IInstructHook>();
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
await hook.BeforeCompletion(message);
|
||||
}
|
||||
|
||||
await ExecuteInstructionRecursively(agent,
|
||||
wholeDialogs,
|
||||
async msg =>
|
||||
{
|
||||
response.Text = msg.Content;
|
||||
await onMessageReceived(msg);
|
||||
},
|
||||
async fn =>
|
||||
{
|
||||
response.Function = fn.FunctionName;
|
||||
await onFunctionExecuting(fn);
|
||||
},
|
||||
async fn =>
|
||||
{
|
||||
response.Data = fn.ExecutionData;
|
||||
await onFunctionExecuted(fn);
|
||||
});
|
||||
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
await hook.AfterCompletion(response);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private async Task<bool> ExecuteInstructionRecursively(Agent agent,
|
||||
List<RoleDialogModel> wholeDialogs,
|
||||
Func<RoleDialogModel, Task> onMessageReceived,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuting,
|
||||
|
|
@ -28,6 +76,8 @@ public partial class InstructService : IInstructService
|
|||
var result = await chatCompletion.GetChatCompletionsAsync(agent, wholeDialogs, async msg =>
|
||||
{
|
||||
await onMessageReceived(msg);
|
||||
|
||||
wholeDialogs.Add(msg);
|
||||
}, async fn =>
|
||||
{
|
||||
var preAgentId = agent.Id;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using Aspects.Cache;
|
||||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Repositories;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
|
|
@ -29,7 +30,8 @@ public class Router : IAgentRouting
|
|||
return await agentService.LoadAgent(AgentId);
|
||||
}
|
||||
|
||||
public RoutingItem[] GetRoutingRecords()
|
||||
[MemoryCache(10 * 60)]
|
||||
public RoutingRecord[] GetRoutingRecords()
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
|
||||
|
|
|
|||
|
|
@ -20,4 +20,5 @@ global using BotSharp.Core.Repository;
|
|||
global using BotSharp.Core.Agents.Services;
|
||||
global using BotSharp.Core.Conversations.Services;
|
||||
global using BotSharp.Core.Infrastructures;
|
||||
global using BotSharp.Core.Users.Services;
|
||||
global using BotSharp.Core.Users.Services;
|
||||
global using Aspects.Cache;
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
using BotSharp.Abstraction.Agents.Enums;
|
||||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.ApiAdapters;
|
||||
using BotSharp.Abstraction.Conversations.Models;
|
||||
using BotSharp.Abstraction.Instructs;
|
||||
using BotSharp.Abstraction.Instructs.Models;
|
||||
using BotSharp.OpenAPI.ViewModels.Conversations;
|
||||
using BotSharp.OpenAPI.ViewModels.Instructs;
|
||||
|
||||
namespace BotSharp.OpenAPI.Controllers;
|
||||
|
||||
|
|
@ -12,43 +13,32 @@ namespace BotSharp.OpenAPI.Controllers;
|
|||
public class InstructModeController : ControllerBase, IApiAdapter
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly IUserIdentity _user;
|
||||
|
||||
public InstructModeController(IServiceProvider services,
|
||||
IUserIdentity user)
|
||||
public InstructModeController(IServiceProvider services)
|
||||
{
|
||||
_services = services;
|
||||
_user = user;
|
||||
}
|
||||
|
||||
[HttpPost("/instruct/{agentId}")]
|
||||
public async Task<InstructResult> NewConversation([FromRoute] string agentId,
|
||||
[FromBody] NewMessageModel input)
|
||||
[FromBody] InstructMessageModel input)
|
||||
{
|
||||
var response = new InstructResult();
|
||||
var instructor = _services.GetRequiredService<IInstructService>();
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
Agent agent = await agentService.LoadAgent(agentId);
|
||||
|
||||
await instructor.ExecuteInstructionRecursively(agent,
|
||||
new List<RoleDialogModel>
|
||||
{
|
||||
new RoleDialogModel("user", input.Text)
|
||||
},
|
||||
async msg =>
|
||||
{
|
||||
response.Text = msg.Content;
|
||||
},
|
||||
async fnExecuting =>
|
||||
{
|
||||
// switch to different instruction template
|
||||
if (!string.IsNullOrEmpty(input.TemplateName))
|
||||
{
|
||||
var agentSettings = _services.GetRequiredService<AgentSettings>();
|
||||
var filePath = Path.Combine(agentService.GetAgentDataDir(agentId), $"{input.TemplateName}.{agentSettings.TemplateFormat}");
|
||||
agent.Instruction = System.IO.File.ReadAllText(filePath);
|
||||
}
|
||||
|
||||
},
|
||||
async fnExecuted =>
|
||||
{
|
||||
response.Function = fnExecuted.FunctionName;
|
||||
response.Data = fnExecuted.ExecutionData;
|
||||
});
|
||||
|
||||
return response;
|
||||
return await instructor.ExecuteInstruction(agent,
|
||||
new RoleDialogModel(AgentRole.User, input.Text),
|
||||
fn => Task.CompletedTask,
|
||||
fn => Task.CompletedTask,
|
||||
fn => Task.CompletedTask);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
using BotSharp.OpenAPI.ViewModels.Conversations;
|
||||
|
||||
namespace BotSharp.OpenAPI.ViewModels.Instructs;
|
||||
|
||||
public class InstructMessageModel : NewMessageModel
|
||||
{
|
||||
public string? TemplateName { get; set; }
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@ using Tensorflow.Keras.Engine;
|
|||
using Tensorflow.NumPy;
|
||||
using static Tensorflow.Binding;
|
||||
using Tensorflow.Keras.Callbacks;
|
||||
using System.Text.RegularExpressions;
|
||||
using BotSharp.Plugin.RoutingSpeeder.Settings;
|
||||
using BotSharp.Abstraction.MLTasks;
|
||||
using BotSharp.Abstraction.Knowledges.Settings;
|
||||
|
|
@ -151,11 +150,11 @@ public class IntentClassifier
|
|||
.ServiceProvider
|
||||
.GetRequiredService<IAgentService>();
|
||||
string rootDirectory = Path.Combine(
|
||||
agentService.GetDataDir(),
|
||||
agentService.GetDataDir(),
|
||||
_settings.RAW_DATA_DIR);
|
||||
string saveLabelDirectory = Path.Combine(
|
||||
agentService.GetDataDir(),
|
||||
_settings.MODEL_DIR,
|
||||
agentService.GetDataDir(),
|
||||
_settings.MODEL_DIR,
|
||||
_settings.LABEL_FILE_NAME);
|
||||
|
||||
if (!Directory.Exists(rootDirectory))
|
||||
|
|
@ -170,18 +169,15 @@ public class IntentClassifier
|
|||
|
||||
foreach (var filePath in GetFiles())
|
||||
{
|
||||
var texts = File.ReadAllLines(filePath, Encoding.UTF8)
|
||||
.Select(x => TextClean(x))
|
||||
.ToList();
|
||||
var texts = File.ReadAllLines(filePath, Encoding.UTF8).ToList();
|
||||
|
||||
vectorList.AddRange(vector.GetVectors(texts));
|
||||
string fileName = Path.GetFileNameWithoutExtension(filePath);
|
||||
labelList.AddRange(Enumerable.Repeat(fileName, texts.Count).ToList());
|
||||
}
|
||||
|
||||
// Write label into local file
|
||||
// Sort label to keep the same order
|
||||
var uniqueLabelList = labelList.Distinct().OrderBy(x => x).ToArray();
|
||||
File.WriteAllLines(saveLabelDirectory, uniqueLabelList);
|
||||
|
||||
var x = np.zeros((vectorList.Count, vector.Dimension), dtype: np.float32);
|
||||
var y = np.zeros((vectorList.Count, 1), dtype: np.float32);
|
||||
|
|
@ -195,13 +191,20 @@ public class IntentClassifier
|
|||
return (x, y);
|
||||
}
|
||||
|
||||
public string[] GetFiles(string prefix = "intent")
|
||||
public string[] GetFiles(string prefix = "")
|
||||
{
|
||||
var agentService = _services.CreateScope()
|
||||
.ServiceProvider
|
||||
.GetRequiredService<IAgentService>();
|
||||
string rootDirectory = Path.Combine(agentService.GetDataDir(), _settings.RAW_DATA_DIR);
|
||||
|
||||
if (string.IsNullOrEmpty(prefix))
|
||||
{
|
||||
return Directory.GetFiles(rootDirectory)
|
||||
.OrderBy(x => Path.GetFileName(x).Split(".")[^2])
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
return Directory.GetFiles(rootDirectory)
|
||||
.Where(x => Path.GetFileNameWithoutExtension(x)
|
||||
.StartsWith(prefix))
|
||||
|
|
@ -216,32 +219,24 @@ public class IntentClassifier
|
|||
var agentService = _services.CreateScope()
|
||||
.ServiceProvider
|
||||
.GetRequiredService<IAgentService>();
|
||||
string rootDirectory = Path.Combine(
|
||||
agentService.GetDataDir(),
|
||||
|
||||
string[] labels = GetFiles()
|
||||
.Select(x => Path.GetFileName(x).Split(".")[^2])
|
||||
.ToArray();
|
||||
|
||||
string writePath = Path.Combine(
|
||||
agentService.GetDataDir(),
|
||||
_settings.MODEL_DIR,
|
||||
_settings.LABEL_FILE_NAME
|
||||
);
|
||||
_settings.LABEL_FILE_NAME);
|
||||
|
||||
var labelText = File.ReadAllLines(rootDirectory);
|
||||
_labels = labelText.OrderBy(x => x).ToArray();
|
||||
_labels = labels.OrderBy(x => x).ToArray();
|
||||
|
||||
// Write labels into the local txt file
|
||||
File.WriteAllLines(writePath, _labels);
|
||||
}
|
||||
|
||||
return _labels;
|
||||
}
|
||||
|
||||
public string TextClean(string text)
|
||||
{
|
||||
// Remove punctuation
|
||||
// Remove digits
|
||||
// To lowercase
|
||||
var processedText = Regex.Replace(text, "[AB0-9]", " ");
|
||||
var replacedTextList = processedText.Select(c => char.IsPunctuation(c) ? ' ' : c).ToList();
|
||||
|
||||
return string.Join("", replacedTextList)
|
||||
.Replace(" ", " ")
|
||||
.ToLower();
|
||||
}
|
||||
|
||||
public string Predict(NDArray vector, float confidenceScore = 0.9f)
|
||||
{
|
||||
if (!_isModelReady)
|
||||
|
|
@ -260,7 +255,6 @@ public class IntentClassifier
|
|||
}
|
||||
|
||||
var labelIndex = probLabel[0];
|
||||
|
||||
return _labels[labelIndex];
|
||||
}
|
||||
public void InitClassifer(bool inference = true)
|
||||
|
|
|
|||
Loading…
Reference in a new issue