Skip to content

Commit c544ddd

Browse files
authored
Merge pull request #510 from iceljc/features/add-image-generation
add image generation
2 parents fecae62 + fa9e0bf commit c544ddd

File tree

37 files changed

+439
-79
lines changed

37 files changed

+439
-79
lines changed

src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ public enum AgentField
1616
Template,
1717
Response,
1818
Sample,
19-
LlmConfig
19+
LlmConfig,
20+
Tool
2021
}
2122

2223
public enum AgentTaskField
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace BotSharp.Abstraction.Agents.Enums;
2+
3+
public class AgentTool
4+
{
5+
public const string FileAnalyzer = "file-analyzer";
6+
public const string ImageGenerator = "image-generator";
7+
public const string HttpHandler = "http-handler";
8+
}

src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,6 @@ public interface IAgentService
5151
List<Agent> GetAgentsByUser(string userId);
5252

5353
PluginDef GetPlugin(string agentId);
54+
55+
IEnumerable<string> GetAgentTools();
5456
}

src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ public class Agent
9090
public List<string> Profiles { get; set; }
9191
= new List<string>();
9292

93+
/// <summary>
94+
/// Useful tools
95+
/// </summary>
96+
public List<string> Tools { get; set; }
97+
= new List<string>();
98+
9399
/// <summary>
94100
/// Inherit from agent
95101
/// </summary>
@@ -121,6 +127,7 @@ public static Agent Clone(Agent agent)
121127
Functions = agent.Functions,
122128
Responses = agent.Responses,
123129
Samples = agent.Samples,
130+
Tools = agent.Tools,
124131
Knowledges = agent.Knowledges,
125132
IsPublic = agent.IsPublic,
126133
Disabled = agent.Disabled,
@@ -162,6 +169,12 @@ public Agent SetSamples(List<string> samples)
162169
return this;
163170
}
164171

172+
public Agent SetTools(List<string> tools)
173+
{
174+
Tools = tools ?? new List<string>();
175+
return this;
176+
}
177+
165178
public Agent SetResponses(List<AgentResponse> responses)
166179
{
167180
Responses = responses ?? new List<AgentResponse>(); ;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,6 @@ Task<bool> SendMessage(string agentId,
5858
Task<string> GetConversationSummary(IEnumerable<string> conversationId);
5959

6060
Task<Conversation> GetConversationRecordOrCreateNew(string agentId);
61+
62+
bool IsConversationMode();
6163
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace BotSharp.Abstraction.MLTasks;
2+
3+
public interface IImageGeneration
4+
{
5+
/// <summary>
6+
/// The LLM provider like Microsoft Azure, OpenAI, ClaudAI
7+
/// </summary>
8+
string Provider { get; }
9+
10+
/// <summary>
11+
/// Set model name, one provider can consume different model or version(s)
12+
/// </summary>
13+
/// <param name="model">deployment name</param>
14+
void SetModelName(string model);
15+
16+
Task<RoleDialogModel> GetImageGeneration(Agent agent, List<RoleDialogModel> conversations);
17+
}

src/Infrastructure/BotSharp.Abstraction/MLTasks/ILlmProviderService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ public interface ILlmProviderService
66
{
77
LlmModelSetting GetSetting(string provider, string model);
88
List<string> GetProviders();
9-
LlmModelSetting GetProviderModel(string provider, string id, bool? multiModal = null);
9+
LlmModelSetting GetProviderModel(string provider, string id, bool? multiModal = null, bool imageGenerate = false);
1010
List<LlmModelSetting> GetProviderModels(string provider);
1111
}

src/Infrastructure/BotSharp.Abstraction/MLTasks/Settings/LlmModelSetting.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ public class LlmModelSetting
3232
/// </summary>
3333
public bool MultiModal { get; set; }
3434

35+
/// <summary>
36+
/// If true, allow generating images
37+
/// </summary>
38+
public bool ImageGeneration { get; set; }
39+
3540
/// <summary>
3641
/// Prompt cost per 1K token
3742
/// </summary>
@@ -51,5 +56,6 @@ public override string ToString()
5156
public enum LlmModelType
5257
{
5358
Text = 1,
54-
Chat = 2
59+
Chat = 2,
60+
Image = 3
5561
}

src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ public partial class AgentService
77
[MemoryCache(10 * 60, perInstanceCache: true)]
88
public async Task<Agent> LoadAgent(string id)
99
{
10-
if (string.IsNullOrEmpty(id) || id == Guid.Empty.ToString())
10+
if (string.IsNullOrEmpty(id))
1111
{
1212
return null;
1313
}
@@ -28,7 +28,7 @@ public async Task<Agent> LoadAgent(string id)
2828
var agent = await GetAgent(id);
2929
if (agent == null)
3030
{
31-
throw new Exception($"Can't load agent by id: {id}");
31+
return null;
3232
}
3333

3434
if (agent.InheritAgentId != null)

src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
using BotSharp.Abstraction.Agents;
21
using BotSharp.Abstraction.Repositories.Enums;
32
using BotSharp.Abstraction.Routing.Models;
43
using BotSharp.Abstraction.Users.Enums;
5-
using Microsoft.EntityFrameworkCore.Metadata;
64
using System.IO;
75

86
namespace BotSharp.Core.Agents.Services;
@@ -34,6 +32,7 @@ public async Task UpdateAgent(Agent agent, AgentField updateField)
3432
record.Templates = agent.Templates ?? new List<AgentTemplate>();
3533
record.Responses = agent.Responses ?? new List<AgentResponse>();
3634
record.Samples = agent.Samples ?? new List<string>();
35+
record.Tools = agent.Tools ?? new List<string>();
3736
if (agent.LlmConfig != null && !agent.LlmConfig.IsInherit)
3837
{
3938
record.LlmConfig = agent.LlmConfig;
@@ -95,6 +94,7 @@ public async Task<string> UpdateAgentFromFile(string id)
9594
.SetFunctions(foundAgent.Functions)
9695
.SetResponses(foundAgent.Responses)
9796
.SetSamples(foundAgent.Samples)
97+
.SetTools(foundAgent.Tools)
9898
.SetLlmConfig(foundAgent.LlmConfig);
9999

100100
_db.UpdateAgent(clonedAgent, AgentField.All);

src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.IO;
2+
using System.Reflection;
23

34
namespace BotSharp.Core.Agents.Services;
45

@@ -53,4 +54,14 @@ public List<Agent> GetAgentsByUser(string userId)
5354
var agents = _db.GetAgentsByUser(userId);
5455
return agents;
5556
}
57+
58+
public IEnumerable<string> GetAgentTools()
59+
{
60+
var tools = typeof(AgentTool).GetFields(BindingFlags.Public | BindingFlags.Static)
61+
.Where(f => f.IsLiteral && f.FieldType == typeof(string))
62+
.Select(x => x.GetRawConstantValue()?.ToString())
63+
.ToList();
64+
65+
return tools;
66+
}
5667
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@
4646
</PropertyGroup>
4747

4848
<ItemGroup>
49+
<None Remove="data\agents\00000000-0000-0000-0000-000000000000\agent.json" />
50+
<None Remove="data\agents\00000000-0000-0000-0000-000000000000\instruction.liquid" />
51+
<None Remove="data\agents\00000000-0000-0000-0000-000000000000\functions.json" />
52+
<None Remove="data\agents\00000000-0000-0000-0000-000000000000\templates\load_attachment_prompt.liquid" />
4953
<None Remove="data\agents\01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b\agent.json" />
5054
<None Remove="data\agents\01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b\functions.json" />
5155
<None Remove="data\agents\01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b\instruction.liquid" />
@@ -146,6 +150,18 @@
146150
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\conversation.summary.liquid">
147151
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
148152
</Content>
153+
<Content Include="data\agents\00000000-0000-0000-0000-000000000000\agent.json">
154+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
155+
</Content>
156+
<Content Include="data\agents\00000000-0000-0000-0000-000000000000\instruction.liquid">
157+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
158+
</Content>
159+
<Content Include="data\agents\00000000-0000-0000-0000-000000000000\functions.json">
160+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
161+
</Content>
162+
<Content Include="data\agents\00000000-0000-0000-0000-000000000000\templates\load_attachment_prompt.liquid">
163+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
164+
</Content>
149165
<Content Include="data\plugins\config.json">
150166
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
151167
</Content>

src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,4 +161,9 @@ public async Task<Conversation> GetConversationRecordOrCreateNew(string agentId)
161161

162162
return converation;
163163
}
164+
165+
public bool IsConversationMode()
166+
{
167+
return !string.IsNullOrWhiteSpace(_conversationId);
168+
}
164169
}

src/Infrastructure/BotSharp.Core/Files/Functions/LoadAttachmentFn.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ public class LoadAttachmentFn : IFunctionCallback
1010

1111
private readonly IServiceProvider _services;
1212
private readonly ILogger<LoadAttachmentFn> _logger;
13-
private const string AIAssistant = "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a";
1413
private readonly IEnumerable<string> _imageTypes = new List<string> { "image", "images", "png", "jpg", "jpeg" };
1514
private readonly IEnumerable<string> _pdfTypes = new List<string> { "pdf" };
15+
private static string TOOL_ASSISTANT = Guid.Empty.ToString();
1616

1717
public LoadAttachmentFn(
1818
IServiceProvider services,
@@ -29,13 +29,13 @@ public async Task<bool> Execute(RoleDialogModel message)
2929
var agentService = _services.GetRequiredService<IAgentService>();
3030

3131
var wholeDialogs = conv.GetDialogHistory();
32-
var fileTypes = args?.FileTypes?.Split(",")?.ToList() ?? new List<string>();
32+
var fileTypes = args?.FileTypes?.Split(",", StringSplitOptions.RemoveEmptyEntries)?.ToList() ?? new List<string>();
3333
var dialogs = await AssembleFiles(conv.ConversationId, wholeDialogs, fileTypes);
34-
var agent = await agentService.LoadAgent(!string.IsNullOrEmpty(message.CurrentAgentId) ? message.CurrentAgentId : AIAssistant);
34+
var agent = await agentService.LoadAgent(TOOL_ASSISTANT);
3535
var fileAgent = new Agent
3636
{
37-
Id = agent.Id,
38-
Name = agent.Name,
37+
Id = agent?.Id ?? Guid.Empty.ToString(),
38+
Name = agent?.Name ?? "Unkown",
3939
Instruction = !string.IsNullOrWhiteSpace(args?.UserRequest) ? args.UserRequest : "Please describe the files.",
4040
TemplateDict = new Dictionary<string, object>()
4141
};
Lines changed: 27 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,53 @@
1-
2-
using Microsoft.EntityFrameworkCore;
3-
41
namespace BotSharp.Core.Files.Hooks;
52

63
public class AttachmentProcessingHook : AgentHookBase
74
{
8-
private readonly IServiceProvider _services;
5+
private static string TOOL_ASSISTANT = Guid.Empty.ToString();
96

107
public override string SelfId => string.Empty;
118

129
public AttachmentProcessingHook(IServiceProvider services, AgentSettings settings)
1310
: base(services, settings)
1411
{
15-
_services = services;
1612
}
1713

1814
public override void OnAgentLoaded(Agent agent)
1915
{
20-
var fileService = _services.GetRequiredService<IBotSharpFileService>();
2116
var conv = _services.GetRequiredService<IConversationService>();
22-
var hasConvFiles = fileService.HasConversationUserFiles(conv.ConversationId);
17+
var isConvMode = conv.IsConversationMode();
18+
var isEnabled = !agent.Tools.IsNullOrEmpty() && agent.Tools.Contains(AgentTool.FileAnalyzer);
2319

24-
if (hasConvFiles)
20+
if (isConvMode && isEnabled)
2521
{
26-
agent.Instruction += "\r\n\r\nPlease call load_attachment if user wants to describe files, such as images, pdf.\r\n\r\n";
27-
28-
if (agent.Functions != null)
22+
var (prompt, loadAttachmentFn) = GetLoadAttachmentFn();
23+
if (loadAttachmentFn != null)
2924
{
30-
var json = JsonSerializer.Serialize(new
25+
if (!string.IsNullOrWhiteSpace(prompt))
26+
{
27+
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
28+
}
29+
30+
if (agent.Functions == null)
3131
{
32-
user_request = new
33-
{
34-
type = "string",
35-
description = "The request posted by user, which is related to analyzing requested files. User can request for multiple files to process at one time."
36-
},
37-
file_types = new
38-
{
39-
type = "string",
40-
description = "The file types requested by user to analyze, such as image, png, jpeg, and pdf. There can be multiple file types in a single request. An example output is, 'image,pdf'"
41-
}
42-
});
43-
44-
agent.Functions.Add(new FunctionDef
32+
agent.Functions = new List<FunctionDef> { loadAttachmentFn };
33+
}
34+
else
4535
{
46-
Name = "load_attachment",
47-
Description = "If the user's request is related to analyzing files and/or images, you can call this function to analyze files and images.",
48-
Parameters =
49-
{
50-
Properties = JsonSerializer.Deserialize<JsonDocument>(json),
51-
Required = new List<string>
52-
{
53-
"user_request",
54-
"file_types"
55-
}
56-
}
57-
});
36+
agent.Functions.Add(loadAttachmentFn);
37+
}
5838
}
5939
}
6040

6141
base.OnAgentLoaded(agent);
6242
}
43+
44+
private (string, FunctionDef?) GetLoadAttachmentFn()
45+
{
46+
var fnName = "load_attachment";
47+
var db = _services.GetRequiredService<IBotSharpRepository>();
48+
var agent = db.GetAgent(TOOL_ASSISTANT);
49+
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo($"{fnName}_prompt"))?.Content ?? string.Empty;
50+
var loadAttachmentFn = agent?.Functions?.FirstOrDefault(x => x.Name.IsEqualTo(fnName));
51+
return (prompt, loadAttachmentFn);
52+
}
6353
}

0 commit comments

Comments
 (0)