2024-10-17 23:17:38 +00:00
|
|
|
using BotSharp.Abstraction.Instructs.Models;
|
2025-01-02 21:29:30 +00:00
|
|
|
using BotSharp.Abstraction.Options;
|
2024-10-17 23:17:38 +00:00
|
|
|
using BotSharp.Abstraction.Templating;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
|
|
|
|
namespace BotSharp.Core.Instructs;
|
|
|
|
|
|
|
|
|
|
public partial class InstructService
|
|
|
|
|
{
|
2025-03-31 20:16:46 +00:00
|
|
|
public async Task<T?> Instruct<T>(string text, InstructOptions? options = null) where T : class
|
2024-10-17 23:17:38 +00:00
|
|
|
{
|
2025-03-31 20:16:46 +00:00
|
|
|
var agent = await BuildInnerAgent(options);
|
|
|
|
|
var response = await GetAiResponse(text, agent, options);
|
2024-10-17 23:17:38 +00:00
|
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(response.Content)) return null;
|
|
|
|
|
|
|
|
|
|
var type = typeof(T);
|
|
|
|
|
T? result = null;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2025-01-02 21:29:30 +00:00
|
|
|
var botsharpOptions = _services.GetRequiredService<BotSharpOptions>();
|
|
|
|
|
|
2024-10-17 23:17:38 +00:00
|
|
|
if (IsStringType(type))
|
|
|
|
|
{
|
|
|
|
|
result = response.Content as T;
|
|
|
|
|
}
|
|
|
|
|
else if (IsListType(type))
|
|
|
|
|
{
|
2025-03-31 20:16:46 +00:00
|
|
|
var content = response.Content.JsonArrayContent();
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(content))
|
2024-10-17 23:17:38 +00:00
|
|
|
{
|
2025-03-31 20:16:46 +00:00
|
|
|
result = JsonSerializer.Deserialize<T>(content, botsharpOptions.JsonSerializerOptions);
|
2024-10-17 23:17:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-03-31 20:16:46 +00:00
|
|
|
var content = response.Content.JsonContent();
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(content))
|
2024-10-17 23:17:38 +00:00
|
|
|
{
|
2025-03-31 20:16:46 +00:00
|
|
|
result = JsonSerializer.Deserialize<T>(content, botsharpOptions.JsonSerializerOptions);
|
2024-10-17 23:17:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogWarning($"Error when getting ai response, {ex.Message}\r\n{ex.InnerException}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-31 20:16:46 +00:00
|
|
|
private async Task<Agent> BuildInnerAgent(InstructOptions? options)
|
2024-10-17 23:17:38 +00:00
|
|
|
{
|
2025-03-31 20:16:46 +00:00
|
|
|
Agent? agent = null;
|
|
|
|
|
string? instruction = null;
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(options?.AgentId))
|
|
|
|
|
{
|
|
|
|
|
var agentService = _services.GetRequiredService<IAgentService>();
|
|
|
|
|
agent = await agentService.GetAgent(options.AgentId);
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(options?.TemplateName))
|
|
|
|
|
{
|
|
|
|
|
var template = agent?.Templates?.FirstOrDefault(x => x.Name == options.TemplateName)?.Content ?? string.Empty;
|
|
|
|
|
instruction = BuildInstruction(template, options?.Data ?? []);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-10-17 23:17:38 +00:00
|
|
|
|
2025-03-31 20:16:46 +00:00
|
|
|
return new Agent
|
|
|
|
|
{
|
|
|
|
|
Id = agent?.Id ?? Guid.Empty.ToString(),
|
|
|
|
|
Name = agent?.Name ?? "Unknown",
|
|
|
|
|
Instruction = instruction,
|
|
|
|
|
LlmConfig = agent?.LlmConfig ?? new()
|
|
|
|
|
};
|
2024-10-17 23:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-31 20:16:46 +00:00
|
|
|
private string BuildInstruction(string instruction, Dictionary<string, object> data)
|
2024-10-17 23:17:38 +00:00
|
|
|
{
|
2025-03-31 20:16:46 +00:00
|
|
|
var render = _services.GetRequiredService<ITemplateRender>();
|
2024-10-17 23:17:38 +00:00
|
|
|
|
2025-03-31 20:16:46 +00:00
|
|
|
return render.Render(instruction, data ?? new Dictionary<string, object>());
|
|
|
|
|
}
|
2024-10-17 23:17:38 +00:00
|
|
|
|
2025-03-31 20:16:46 +00:00
|
|
|
private async Task<RoleDialogModel> GetAiResponse(string text, Agent agent, InstructOptions? options)
|
|
|
|
|
{
|
|
|
|
|
var dialogs = BuildDialogs(text, options);
|
|
|
|
|
var provider = options?.Provider ?? agent?.LlmConfig?.Provider ?? "openai";
|
|
|
|
|
var model = options?.Model ?? agent?.LlmConfig?.Model ?? "gpt-4o";
|
2024-10-22 17:30:53 +00:00
|
|
|
var completion = CompletionProvider.GetChatCompletion(_services, provider: provider, model: model);
|
2025-03-31 20:16:46 +00:00
|
|
|
return await completion.GetChatCompletions(agent, dialogs);
|
2024-10-17 23:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-31 20:16:46 +00:00
|
|
|
private List<RoleDialogModel> BuildDialogs(string text, InstructOptions? options)
|
2024-10-17 23:17:38 +00:00
|
|
|
{
|
|
|
|
|
var messages = new List<RoleDialogModel>();
|
|
|
|
|
|
2025-03-31 20:16:46 +00:00
|
|
|
if (!string.IsNullOrWhiteSpace(options?.ConversationId))
|
2024-10-17 23:17:38 +00:00
|
|
|
{
|
|
|
|
|
var conv = _services.GetRequiredService<IConversationService>();
|
|
|
|
|
var dialogs = conv.GetDialogHistory();
|
|
|
|
|
messages.AddRange(dialogs);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-31 20:16:46 +00:00
|
|
|
if (!string.IsNullOrWhiteSpace(text))
|
2024-10-17 23:17:38 +00:00
|
|
|
{
|
2025-03-31 20:16:46 +00:00
|
|
|
messages.Add(new RoleDialogModel(AgentRole.User, text));
|
2024-10-17 23:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return messages;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool IsStringType(Type? type)
|
|
|
|
|
{
|
|
|
|
|
if (type == null) return false;
|
|
|
|
|
|
|
|
|
|
return type == typeof(string);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool IsListType(Type? type)
|
|
|
|
|
{
|
|
|
|
|
if (type == null) return false;
|
|
|
|
|
|
|
|
|
|
var interfaces = type.GetTypeInfo().ImplementedInterfaces;
|
|
|
|
|
return type.IsArray || interfaces.Any(x => x.Name == typeof(IEnumerable).Name);
|
|
|
|
|
}
|
|
|
|
|
}
|