37 changed files with 1284 additions and 0 deletions
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,25 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0</TargetFrameworks> |
||||
|
<AssemblyName>LINGYUN.Abp.AI.Agent</AssemblyName> |
||||
|
<PackageId>LINGYUN.Abp.AI.Agent</PackageId> |
||||
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
||||
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
||||
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
||||
|
<Nullable>enable</Nullable> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.Agents.AI" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.AI.Core\LINGYUN.Abp.AI.Core.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Agent; |
||||
|
|
||||
|
[DependsOn(typeof(AbpAICoreModule))] |
||||
|
public class AbpAIAgentModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,80 @@ |
|||||
|
using LINGYUN.Abp.AI.Workspaces; |
||||
|
using Microsoft.Agents.AI; |
||||
|
using Microsoft.Extensions.AI; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using System.Collections.Concurrent; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.AI; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Agent; |
||||
|
public class ChatClientAgentFactory : IChatClientAgentFactory, ISingletonDependency |
||||
|
{ |
||||
|
private readonly static ConcurrentDictionary<string, ChatClientAgent> _chatClientAgentCache = new(); |
||||
|
|
||||
|
private readonly IChatClientFactory _chatClientFactory; |
||||
|
private readonly IStringLocalizerFactory _stringLocalizerFactory; |
||||
|
private readonly IWorkspaceDefinitionManager _workspaceDefinitionManager; |
||||
|
public ChatClientAgentFactory( |
||||
|
IChatClientFactory chatClientFactory, |
||||
|
IStringLocalizerFactory stringLocalizerFactory, |
||||
|
IWorkspaceDefinitionManager workspaceDefinitionManager) |
||||
|
{ |
||||
|
_chatClientFactory = chatClientFactory; |
||||
|
_stringLocalizerFactory = stringLocalizerFactory; |
||||
|
_workspaceDefinitionManager = workspaceDefinitionManager; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<ChatClientAgent> CreateAsync<TWorkspace>() |
||||
|
{ |
||||
|
var workspace = WorkspaceNameAttribute.GetWorkspaceName<TWorkspace>(); |
||||
|
if (_chatClientAgentCache.TryGetValue(workspace, out var chatClientAgent)) |
||||
|
{ |
||||
|
return chatClientAgent; |
||||
|
} |
||||
|
|
||||
|
var chatClient = await _chatClientFactory.CreateAsync<TWorkspace>(); |
||||
|
|
||||
|
var workspaceDefine = await _workspaceDefinitionManager.GetOrNullAsync(workspace); |
||||
|
|
||||
|
string? description = null; |
||||
|
if (workspaceDefine?.Description != null) |
||||
|
{ |
||||
|
description = workspaceDefine.Description.Localize(_stringLocalizerFactory); |
||||
|
} |
||||
|
|
||||
|
chatClientAgent = chatClient.CreateAIAgent( |
||||
|
instructions: workspaceDefine?.SystemPrompt, |
||||
|
name: workspaceDefine?.Name, |
||||
|
description: description); |
||||
|
|
||||
|
_chatClientAgentCache.TryAdd(workspace, chatClientAgent); |
||||
|
|
||||
|
return chatClientAgent; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<ChatClientAgent> CreateAsync(string workspace) |
||||
|
{ |
||||
|
if (_chatClientAgentCache.TryGetValue(workspace, out var chatClientAgent)) |
||||
|
{ |
||||
|
return chatClientAgent; |
||||
|
} |
||||
|
var workspaceDefine = await _workspaceDefinitionManager.GetAsync(workspace); |
||||
|
var chatClient = await _chatClientFactory.CreateAsync(workspace); |
||||
|
|
||||
|
string? description = null; |
||||
|
if (workspaceDefine.Description != null) |
||||
|
{ |
||||
|
description = workspaceDefine.Description.Localize(_stringLocalizerFactory); |
||||
|
} |
||||
|
|
||||
|
chatClientAgent = chatClient.CreateAIAgent( |
||||
|
instructions: workspaceDefine.SystemPrompt, |
||||
|
name: workspaceDefine.Name, |
||||
|
description: description); |
||||
|
|
||||
|
_chatClientAgentCache.TryAdd(workspace, chatClientAgent); |
||||
|
|
||||
|
return chatClientAgent; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Microsoft.Agents.AI; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Agent; |
||||
|
public interface IChatClientAgentFactory |
||||
|
{ |
||||
|
[NotNull] |
||||
|
Task<ChatClientAgent> CreateAsync<TWorkspace>(); |
||||
|
|
||||
|
[NotNull] |
||||
|
Task<ChatClientAgent> CreateAsync(string workspace); |
||||
|
} |
||||
@ -0,0 +1,98 @@ |
|||||
|
# LINGYUN.Abp.AI.Agent |
||||
|
|
||||
|
[Abp AI Module](https://abp.io/docs/latest/framework/infrastructure/artificial-intelligence) 扩展. |
||||
|
|
||||
|
## 功能特性 |
||||
|
|
||||
|
|
||||
|
## 模块引用 |
||||
|
|
||||
|
```csharp |
||||
|
[DependsOn(typeof(AbpAIAgentModule))] |
||||
|
public class YouProjectModule : AbpModule |
||||
|
{ |
||||
|
// other |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## 依赖模块 |
||||
|
|
||||
|
* [AbpAIModule](https://abp.io/docs/latest/framework/infrastructure/artificial-intelligence) |
||||
|
* [AbpLocalizationModule](https://abp.io/docs/latest/framework/fundamentals/localization) |
||||
|
|
||||
|
## 基本用法 |
||||
|
|
||||
|
> 兼容 `IKernelAccessor` 与 `IChatClientAccessor` 的语法. |
||||
|
|
||||
|
```csharp |
||||
|
using LINGYUN.Abp.AI; |
||||
|
using LINGYUN.Abp.AI.Agent; |
||||
|
using Microsoft.Extensions.AI; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.SemanticKernel; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
var application = await AbpApplicationFactory.CreateAsync<YouProjectModule>(options => |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
}); |
||||
|
|
||||
|
await application.InitializeAsync(); |
||||
|
|
||||
|
var chatClientAgentFactory = application.ServiceProvider.GetRequiredService<IChatClientAgentFactory>(); |
||||
|
|
||||
|
var agent = await chatClientAgentFactory.CreateAsync<YouWorkspace>(); |
||||
|
|
||||
|
var agentResponse = agent.RunStreamingAsync("解释一下线性代数"); |
||||
|
|
||||
|
await foreach (var item in agentResponse) |
||||
|
{ |
||||
|
Console.Write(item); |
||||
|
} |
||||
|
Console.WriteLine(); |
||||
|
|
||||
|
await application.ShutdownAsync(); |
||||
|
|
||||
|
Console.WriteLine(); |
||||
|
Console.WriteLine("AI Console completed!"); |
||||
|
|
||||
|
Console.ReadKey(); |
||||
|
``` |
||||
|
|
||||
|
> 支持动态工作区语法. |
||||
|
|
||||
|
```csharp |
||||
|
using LINGYUN.Abp.AI; |
||||
|
using LINGYUN.Abp.AI.Agent; |
||||
|
using Microsoft.Extensions.AI; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.SemanticKernel; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
var application = await AbpApplicationFactory.CreateAsync<YouProjectModule>(options => |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
}); |
||||
|
|
||||
|
await application.InitializeAsync(); |
||||
|
|
||||
|
var chatClientAgentFactory = application.ServiceProvider.GetRequiredService<IChatClientAgentFactory>(); |
||||
|
|
||||
|
var agent = await chatClientAgentFactory.CreateAsync("YouWorkspace"); |
||||
|
|
||||
|
var agentResponse = agent.RunStreamingAsync("解释一下线性代数"); |
||||
|
|
||||
|
await foreach (var item in agentResponse) |
||||
|
{ |
||||
|
Console.Write(item); |
||||
|
} |
||||
|
Console.WriteLine(); |
||||
|
|
||||
|
await application.ShutdownAsync(); |
||||
|
|
||||
|
Console.WriteLine(); |
||||
|
Console.WriteLine("AI Console completed!"); |
||||
|
|
||||
|
Console.ReadKey(); |
||||
|
|
||||
|
``` |
||||
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,22 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0</TargetFrameworks> |
||||
|
<AssemblyName>LINGYUN.Abp.AI.Core</AssemblyName> |
||||
|
<PackageId>LINGYUN.Abp.AI.Core</PackageId> |
||||
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
||||
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
||||
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
||||
|
<Nullable>enable</Nullable> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.AI" /> |
||||
|
<PackageReference Include="Volo.Abp.Localization" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,52 @@ |
|||||
|
using LINGYUN.Abp.AI.Localization; |
||||
|
using LINGYUN.Abp.AI.Workspaces; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp.AI; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI; |
||||
|
|
||||
|
[DependsOn( |
||||
|
typeof(AbpAIModule), |
||||
|
typeof(AbpLocalizationModule))] |
||||
|
public class AbpAICoreModule : AbpModule |
||||
|
{ |
||||
|
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
AutoAddDefinitionProviders(context.Services); |
||||
|
} |
||||
|
|
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources.Add<AbpAIResource>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpAICoreOptions>(options => |
||||
|
{ |
||||
|
options.ChatClientProviders.Add<OpenAIChatClientProvider>(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private static void AutoAddDefinitionProviders(IServiceCollection services) |
||||
|
{ |
||||
|
var definitionProviders = new List<Type>(); |
||||
|
|
||||
|
services.OnRegistered(context => |
||||
|
{ |
||||
|
if (typeof(IWorkspaceDefinitionProvider).IsAssignableFrom(context.ImplementationType)) |
||||
|
{ |
||||
|
definitionProviders.Add(context.ImplementationType); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
services.Configure<AbpAICoreOptions>(options => |
||||
|
{ |
||||
|
options.DefinitionProviders.AddIfNotContains(definitionProviders); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using LINGYUN.Abp.AI.Workspaces; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp.Collections; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI; |
||||
|
public class AbpAICoreOptions |
||||
|
{ |
||||
|
public ITypeList<IWorkspaceDefinitionProvider> DefinitionProviders { get; } |
||||
|
public ITypeList<IChatClientProvider> ChatClientProviders { get; } |
||||
|
public ITypeList<IKernelProvider> KernelProviders { get; } |
||||
|
|
||||
|
public HashSet<string> DeletedWorkspaces { get; } |
||||
|
|
||||
|
public AbpAICoreOptions() |
||||
|
{ |
||||
|
DefinitionProviders = new TypeList<IWorkspaceDefinitionProvider>(); |
||||
|
ChatClientProviders = new TypeList<IChatClientProvider>(); |
||||
|
KernelProviders = new TypeList<IKernelProvider>(); |
||||
|
|
||||
|
DeletedWorkspaces = new HashSet<string>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,82 @@ |
|||||
|
using LINGYUN.Abp.AI.Workspaces; |
||||
|
using Microsoft.Extensions.AI; |
||||
|
using System; |
||||
|
using System.Collections.Concurrent; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.AI; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI; |
||||
|
public class ChatClientFactory : IChatClientFactory, ISingletonDependency |
||||
|
{ |
||||
|
private readonly static ConcurrentDictionary<string, IChatClient> _chatClientCache = new(); |
||||
|
protected IWorkspaceDefinitionManager WorkspaceDefinitionManager { get; } |
||||
|
protected IChatClientProviderManager ChatClientProviderManager { get; } |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
|
||||
|
public ChatClientFactory( |
||||
|
IWorkspaceDefinitionManager workspaceDefinitionManager, |
||||
|
IChatClientProviderManager chatClientProviderManager, |
||||
|
IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
WorkspaceDefinitionManager = workspaceDefinitionManager; |
||||
|
ChatClientProviderManager = chatClientProviderManager; |
||||
|
ServiceProvider = serviceProvider; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<IChatClient> CreateAsync<TWorkspace>() |
||||
|
{ |
||||
|
var workspace = WorkspaceNameAttribute.GetWorkspaceName<TWorkspace>(); |
||||
|
if (_chatClientCache.TryGetValue(workspace, out var chatClient)) |
||||
|
{ |
||||
|
return chatClient; |
||||
|
} |
||||
|
|
||||
|
var chatClientAccessorType = typeof(IChatClientAccessor<>).MakeGenericType(typeof(TWorkspace)); |
||||
|
var chatClientAccessor = ServiceProvider.GetService(chatClientAccessorType); |
||||
|
if (chatClientAccessor != null && |
||||
|
chatClientAccessor is IChatClientAccessor accessor && |
||||
|
accessor.ChatClient != null) |
||||
|
{ |
||||
|
chatClient = accessor.ChatClient; |
||||
|
_chatClientCache.TryAdd(workspace, chatClient); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
chatClient = await CreateAsync(workspace); |
||||
|
} |
||||
|
return chatClient; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<IChatClient> CreateAsync(string workspace) |
||||
|
{ |
||||
|
if (_chatClientCache.TryGetValue(workspace, out var chatClient)) |
||||
|
{ |
||||
|
return chatClient; |
||||
|
} |
||||
|
|
||||
|
var workspaceDefine = await WorkspaceDefinitionManager.GetAsync(workspace); |
||||
|
|
||||
|
chatClient = await CreateChatClientAsync(workspaceDefine); |
||||
|
|
||||
|
_chatClientCache.TryAdd(workspace, chatClient); |
||||
|
|
||||
|
return chatClient; |
||||
|
} |
||||
|
|
||||
|
protected async virtual Task<IChatClient> CreateChatClientAsync(WorkspaceDefinition workspace) |
||||
|
{ |
||||
|
foreach (var provider in ChatClientProviderManager.Providers) |
||||
|
{ |
||||
|
if (!string.Equals(provider.Name, workspace.Provider)) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
return await provider.CreateAsync(workspace); |
||||
|
} |
||||
|
|
||||
|
throw new AbpException($"The ChatClient provider implementation named {workspace.Provider} was not found"); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
using LINGYUN.Abp.AI.Workspaces; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI; |
||||
|
public class ChatClientProviderManager : IChatClientProviderManager, ISingletonDependency |
||||
|
{ |
||||
|
public List<IChatClientProvider> Providers => _lazyProviders.Value; |
||||
|
|
||||
|
protected AbpAICoreOptions Options { get; } |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
private readonly Lazy<List<IChatClientProvider>> _lazyProviders; |
||||
|
|
||||
|
public ChatClientProviderManager( |
||||
|
IServiceProvider serviceProvider, |
||||
|
IOptions<AbpAICoreOptions> options) |
||||
|
{ |
||||
|
|
||||
|
Options = options.Value; |
||||
|
ServiceProvider = serviceProvider; |
||||
|
|
||||
|
_lazyProviders = new Lazy<List<IChatClientProvider>>(GetProviders, true); |
||||
|
} |
||||
|
|
||||
|
protected virtual List<IChatClientProvider> GetProviders() |
||||
|
{ |
||||
|
var providers = Options |
||||
|
.ChatClientProviders |
||||
|
.Select(type => (ServiceProvider.GetRequiredService(type) as IChatClientProvider)!) |
||||
|
.ToList(); |
||||
|
|
||||
|
var multipleProviders = providers.GroupBy(p => p.Name).FirstOrDefault(x => x.Count() > 1); |
||||
|
if (multipleProviders != null) |
||||
|
{ |
||||
|
throw new AbpException($"Duplicate ChatClient provider name detected: {multipleProviders.Key}. Providers:{Environment.NewLine}{multipleProviders.Select(p => p.GetType().FullName!).JoinAsString(Environment.NewLine)}"); |
||||
|
} |
||||
|
|
||||
|
return providers; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Microsoft.Extensions.AI; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI; |
||||
|
public interface IChatClientFactory |
||||
|
{ |
||||
|
[NotNull] |
||||
|
Task<IChatClient> CreateAsync<TWorkspace>(); |
||||
|
|
||||
|
[NotNull] |
||||
|
Task<IChatClient> CreateAsync(string workspace); |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using LINGYUN.Abp.AI.Workspaces; |
||||
|
using Microsoft.Extensions.AI; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI; |
||||
|
public interface IChatClientProvider |
||||
|
{ |
||||
|
string Name { get; } |
||||
|
|
||||
|
Task<IChatClient> CreateAsync(WorkspaceDefinition workspace); |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI; |
||||
|
public interface IChatClientProviderManager |
||||
|
{ |
||||
|
List<IChatClientProvider> Providers { get; } |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Microsoft.SemanticKernel; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI; |
||||
|
public interface IKernelFactory |
||||
|
{ |
||||
|
[NotNull] |
||||
|
Task<Kernel> CreateAsync<TWorkspace>(); |
||||
|
|
||||
|
[NotNull] |
||||
|
Task<Kernel> CreateAsync(string workspace); |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using LINGYUN.Abp.AI.Workspaces; |
||||
|
using Microsoft.SemanticKernel; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI; |
||||
|
public interface IKernelProvider |
||||
|
{ |
||||
|
string Name { get; } |
||||
|
|
||||
|
Task<Kernel> CreateAsync(WorkspaceDefinition workspace); |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI; |
||||
|
public interface IKernelProviderManager |
||||
|
{ |
||||
|
List<IKernelProvider> Providers { get; } |
||||
|
} |
||||
@ -0,0 +1,82 @@ |
|||||
|
using LINGYUN.Abp.AI.Workspaces; |
||||
|
using Microsoft.SemanticKernel; |
||||
|
using System; |
||||
|
using System.Collections.Concurrent; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.AI; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI; |
||||
|
public class KernelFactory : IKernelFactory, ISingletonDependency |
||||
|
{ |
||||
|
private readonly static ConcurrentDictionary<string, Kernel> _kernelCache = new(); |
||||
|
protected IWorkspaceDefinitionManager WorkspaceDefinitionManager { get; } |
||||
|
protected IKernelProviderManager KernelProviderManager { get; } |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
|
||||
|
public KernelFactory( |
||||
|
IWorkspaceDefinitionManager workspaceDefinitionManager, |
||||
|
IKernelProviderManager kernelProviderManager, |
||||
|
IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
WorkspaceDefinitionManager = workspaceDefinitionManager; |
||||
|
KernelProviderManager = kernelProviderManager; |
||||
|
ServiceProvider = serviceProvider; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<Kernel> CreateAsync<TWorkspace>() |
||||
|
{ |
||||
|
var workspace = WorkspaceNameAttribute.GetWorkspaceName<TWorkspace>(); |
||||
|
if (_kernelCache.TryGetValue(workspace, out var kernel)) |
||||
|
{ |
||||
|
return kernel; |
||||
|
} |
||||
|
|
||||
|
var kernelAccessorType = typeof(IKernelAccessor<>).MakeGenericType(typeof(TWorkspace)); |
||||
|
var kernelAccessor = ServiceProvider.GetService(kernelAccessorType); |
||||
|
if (kernelAccessor != null && |
||||
|
kernelAccessor is IKernelAccessor accessor |
||||
|
&& accessor.Kernel != null) |
||||
|
{ |
||||
|
kernel = accessor.Kernel; |
||||
|
_kernelCache.TryAdd(workspace, kernel); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
kernel = await CreateAsync(workspace); |
||||
|
} |
||||
|
return kernel; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<Kernel> CreateAsync(string workspace) |
||||
|
{ |
||||
|
if (_kernelCache.TryGetValue(workspace, out var kernel)) |
||||
|
{ |
||||
|
return kernel; |
||||
|
} |
||||
|
|
||||
|
var workspaceDefine = await WorkspaceDefinitionManager.GetAsync(workspace); |
||||
|
|
||||
|
kernel = await CreateKernelAsync(workspaceDefine); |
||||
|
|
||||
|
_kernelCache.TryAdd(workspace, kernel); |
||||
|
|
||||
|
return kernel; |
||||
|
} |
||||
|
|
||||
|
protected async virtual Task<Kernel> CreateKernelAsync(WorkspaceDefinition workspace) |
||||
|
{ |
||||
|
foreach (var provider in KernelProviderManager.Providers) |
||||
|
{ |
||||
|
if (!string.Equals(provider.Name, workspace.Provider)) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
return await provider.CreateAsync(workspace); |
||||
|
} |
||||
|
|
||||
|
throw new AbpException($"The Kernel provider implementation named {workspace.Provider} was not found"); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI; |
||||
|
public class KernelProviderManager : IKernelProviderManager, ISingletonDependency |
||||
|
{ |
||||
|
public List<IKernelProvider> Providers => _lazyProviders.Value; |
||||
|
|
||||
|
protected AbpAICoreOptions Options { get; } |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
private readonly Lazy<List<IKernelProvider>> _lazyProviders; |
||||
|
|
||||
|
public KernelProviderManager( |
||||
|
IServiceProvider serviceProvider, |
||||
|
IOptions<AbpAICoreOptions> options) |
||||
|
{ |
||||
|
|
||||
|
Options = options.Value; |
||||
|
ServiceProvider = serviceProvider; |
||||
|
|
||||
|
_lazyProviders = new Lazy<List<IKernelProvider>>(GetProviders, true); |
||||
|
} |
||||
|
|
||||
|
protected virtual List<IKernelProvider> GetProviders() |
||||
|
{ |
||||
|
var providers = Options |
||||
|
.ChatClientProviders |
||||
|
.Select(type => (ServiceProvider.GetRequiredService(type) as IKernelProvider)!) |
||||
|
.ToList(); |
||||
|
|
||||
|
var multipleProviders = providers.GroupBy(p => p.Name).FirstOrDefault(x => x.Count() > 1); |
||||
|
if (multipleProviders != null) |
||||
|
{ |
||||
|
throw new AbpException($"Duplicate Kernel provider name detected: {multipleProviders.Key}. Providers:{Environment.NewLine}{multipleProviders.Select(p => p.GetType().FullName!).JoinAsString(Environment.NewLine)}"); |
||||
|
} |
||||
|
|
||||
|
return providers; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Localization; |
||||
|
|
||||
|
[LocalizationResourceName("AbpAI")] |
||||
|
public class AbpAIResource |
||||
|
{ |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
using LINGYUN.Abp.AI.Workspaces; |
||||
|
using Microsoft.Extensions.AI; |
||||
|
using OpenAI; |
||||
|
using System; |
||||
|
using System.ClientModel; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI; |
||||
|
public class OpenAIChatClientProvider : IChatClientProvider, ITransientDependency |
||||
|
{ |
||||
|
private const string DefaultEndpoint = "https://api.openai.com/v1"; |
||||
|
public const string ProviderName = "OpenAI"; |
||||
|
|
||||
|
public virtual string Name => ProviderName; |
||||
|
|
||||
|
public virtual Task<IChatClient> CreateAsync(WorkspaceDefinition workspace) |
||||
|
{ |
||||
|
Check.NotNull(workspace, nameof(workspace)); |
||||
|
Check.NotNullOrWhiteSpace(workspace.ApiKey, nameof(WorkspaceDefinition.ApiKey)); |
||||
|
|
||||
|
var openAIClient = new OpenAIClient( |
||||
|
new ApiKeyCredential(workspace.ApiKey), |
||||
|
new OpenAIClientOptions |
||||
|
{ |
||||
|
Endpoint = new Uri(workspace.ApiBaseUrl ?? DefaultEndpoint), |
||||
|
}); |
||||
|
|
||||
|
var chatClient = openAIClient |
||||
|
.GetChatClient(workspace.ModelName) |
||||
|
.AsIChatClient(); |
||||
|
|
||||
|
return Task.FromResult(chatClient); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Workspaces; |
||||
|
public interface IDynamicWorkspaceDefinitionStore |
||||
|
{ |
||||
|
Task<WorkspaceDefinition> GetAsync([NotNull] string name); |
||||
|
|
||||
|
Task<IReadOnlyList<WorkspaceDefinition>> GetAllAsync(); |
||||
|
|
||||
|
Task<WorkspaceDefinition?> GetOrNullAsync([NotNull] string name); |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Workspaces; |
||||
|
public interface IStaticWorkspaceDefinitionStore |
||||
|
{ |
||||
|
Task<WorkspaceDefinition> GetAsync([NotNull] string name); |
||||
|
|
||||
|
Task<IReadOnlyList<WorkspaceDefinition>> GetAllAsync(); |
||||
|
|
||||
|
Task<WorkspaceDefinition?> GetOrNullAsync([NotNull] string name); |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Workspaces; |
||||
|
public interface IWorkspaceDefinitionContext |
||||
|
{ |
||||
|
WorkspaceDefinition? GetOrNull(string name); |
||||
|
|
||||
|
IReadOnlyList<WorkspaceDefinition> GetAll(); |
||||
|
|
||||
|
void Add(params WorkspaceDefinition[] definitions); |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Workspaces; |
||||
|
public interface IWorkspaceDefinitionManager |
||||
|
{ |
||||
|
[ItemNotNull] |
||||
|
Task<WorkspaceDefinition> GetAsync([NotNull] string name); |
||||
|
|
||||
|
[ItemNotNull] |
||||
|
Task<IReadOnlyList<WorkspaceDefinition>> GetAllAsync(); |
||||
|
|
||||
|
[ItemCanBeNull] |
||||
|
Task<WorkspaceDefinition?> GetOrNullAsync([NotNull] string name); |
||||
|
} |
||||
@ -0,0 +1,5 @@ |
|||||
|
namespace LINGYUN.Abp.AI.Workspaces; |
||||
|
public interface IWorkspaceDefinitionProvider |
||||
|
{ |
||||
|
void Define(IWorkspaceDefinitionContext context); |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.Immutable; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Workspaces; |
||||
|
public class NullDynamicWorkspaceDefinitionStore : IDynamicWorkspaceDefinitionStore, ISingletonDependency |
||||
|
{ |
||||
|
private readonly static Task<WorkspaceDefinition?> CachedNullableWorkspaceResult = Task.FromResult((WorkspaceDefinition?)null); |
||||
|
private readonly static Task<WorkspaceDefinition> CachedWorkspaceResult = Task.FromResult((WorkspaceDefinition)null!); |
||||
|
|
||||
|
private readonly static Task<IReadOnlyList<WorkspaceDefinition>> CachedWorkspacesResult = Task.FromResult( |
||||
|
(IReadOnlyList<WorkspaceDefinition>)Array.Empty<WorkspaceDefinition>().ToImmutableList()); |
||||
|
|
||||
|
public Task<WorkspaceDefinition> GetAsync(string name) |
||||
|
{ |
||||
|
return CachedWorkspaceResult; |
||||
|
} |
||||
|
|
||||
|
public Task<IReadOnlyList<WorkspaceDefinition>> GetAllAsync() |
||||
|
{ |
||||
|
return CachedWorkspacesResult; |
||||
|
} |
||||
|
|
||||
|
public Task<WorkspaceDefinition?> GetOrNullAsync(string name) |
||||
|
{ |
||||
|
return CachedNullableWorkspaceResult; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,79 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.Immutable; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.StaticDefinitions; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Workspaces; |
||||
|
public class StaticWorkspaceDefinitionStore : IStaticWorkspaceDefinitionStore, ISingletonDependency |
||||
|
{ |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
protected AbpAICoreOptions Options { get; } |
||||
|
protected IStaticDefinitionCache<WorkspaceDefinition, Dictionary<string, WorkspaceDefinition>> DefinitionCache { get; } |
||||
|
|
||||
|
public StaticWorkspaceDefinitionStore( |
||||
|
IServiceProvider serviceProvider, |
||||
|
IOptions<AbpAICoreOptions> options, |
||||
|
IStaticDefinitionCache<WorkspaceDefinition, Dictionary<string, WorkspaceDefinition>> definitionCache) |
||||
|
{ |
||||
|
ServiceProvider = serviceProvider; |
||||
|
Options = options.Value; |
||||
|
DefinitionCache = definitionCache; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<WorkspaceDefinition> GetAsync(string name) |
||||
|
{ |
||||
|
Check.NotNull(name, nameof(name)); |
||||
|
|
||||
|
var workspace = await GetOrNullAsync(name); |
||||
|
|
||||
|
if (workspace == null) |
||||
|
{ |
||||
|
throw new AbpException("Undefined workspace: " + name); |
||||
|
} |
||||
|
|
||||
|
return workspace; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<IReadOnlyList<WorkspaceDefinition>> GetAllAsync() |
||||
|
{ |
||||
|
var defs = await GetWorkspaceDefinitionsAsync(); |
||||
|
return defs.Values.ToImmutableList(); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<WorkspaceDefinition?> GetOrNullAsync(string name) |
||||
|
{ |
||||
|
var defs = await GetWorkspaceDefinitionsAsync(); |
||||
|
return defs.GetOrDefault(name); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<Dictionary<string, WorkspaceDefinition>> GetWorkspaceDefinitionsAsync() |
||||
|
{ |
||||
|
return await DefinitionCache.GetOrCreateAsync(CreateWorkspaceDefinitionsAsync); |
||||
|
} |
||||
|
|
||||
|
protected virtual Task<Dictionary<string, WorkspaceDefinition>> CreateWorkspaceDefinitionsAsync() |
||||
|
{ |
||||
|
var workspaces = new Dictionary<string, WorkspaceDefinition>(); |
||||
|
|
||||
|
using (var scope = ServiceProvider.CreateScope()) |
||||
|
{ |
||||
|
var providers = Options |
||||
|
.DefinitionProviders |
||||
|
.Select(p => scope.ServiceProvider.GetRequiredService(p) as IWorkspaceDefinitionProvider) |
||||
|
.ToList(); |
||||
|
|
||||
|
foreach (var provider in providers) |
||||
|
{ |
||||
|
provider?.Define(new WorkspaceDefinitionContext(workspaces)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return Task.FromResult(workspaces); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,104 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.SimpleStateChecking; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Workspaces; |
||||
|
/// <summary>
|
||||
|
/// 工作区定义
|
||||
|
/// </summary>
|
||||
|
public class WorkspaceDefinition : IHasSimpleStateCheckers<WorkspaceDefinition> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 名称
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
public string Name { get; } |
||||
|
/// <summary>
|
||||
|
/// AI提供者名称
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
public string Provider { get; } |
||||
|
/// <summary>
|
||||
|
/// 模型名称
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
public string ModelName { get; } |
||||
|
/// <summary>
|
||||
|
/// 显示名称
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
public ILocalizableString DisplayName { |
||||
|
get => _displayName; |
||||
|
set => _displayName = Check.NotNull(value, nameof(value)); |
||||
|
} |
||||
|
private ILocalizableString _displayName = default!; |
||||
|
/// <summary>
|
||||
|
/// 描述
|
||||
|
/// </summary>
|
||||
|
public ILocalizableString? Description { get; set; } |
||||
|
/// <summary>
|
||||
|
/// API 身份验证密钥
|
||||
|
/// </summary>
|
||||
|
public string? ApiKey { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 自定义端点 URL
|
||||
|
/// </summary>
|
||||
|
public string? ApiBaseUrl { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 系统提示词
|
||||
|
/// </summary>
|
||||
|
public string? SystemPrompt { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 启用/禁用工作区
|
||||
|
/// </summary>
|
||||
|
public bool IsEnabled { get; set; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public Dictionary<string, object> Properties { get; } |
||||
|
|
||||
|
public List<ISimpleStateChecker<WorkspaceDefinition>> StateCheckers { get; } |
||||
|
|
||||
|
public WorkspaceDefinition( |
||||
|
string name, |
||||
|
string provider, |
||||
|
string modelName, |
||||
|
ILocalizableString displayName, |
||||
|
ILocalizableString? description = null) |
||||
|
{ |
||||
|
Name = name; |
||||
|
Provider = provider; |
||||
|
ModelName = modelName; |
||||
|
_displayName = displayName; |
||||
|
_displayName = displayName; |
||||
|
Description = description; |
||||
|
|
||||
|
IsEnabled = true; |
||||
|
Properties = new Dictionary<string, object>(); |
||||
|
StateCheckers = new List<ISimpleStateChecker<WorkspaceDefinition>>(); |
||||
|
} |
||||
|
|
||||
|
public virtual WorkspaceDefinition WithApiBaseUrl(string apiBaseUrl) |
||||
|
{ |
||||
|
ApiBaseUrl = apiBaseUrl; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
public virtual WorkspaceDefinition WithApiKey(string apiKey) |
||||
|
{ |
||||
|
ApiKey = apiKey; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
public virtual WorkspaceDefinition WithProperty(string key, object value) |
||||
|
{ |
||||
|
Properties[key] = value; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
public override string ToString() |
||||
|
{ |
||||
|
return $"[{nameof(WorkspaceDefinition)} {Name}]"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.Immutable; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Workspaces; |
||||
|
public class WorkspaceDefinitionContext : IWorkspaceDefinitionContext |
||||
|
{ |
||||
|
protected Dictionary<string, WorkspaceDefinition> Workspaces { get; } |
||||
|
|
||||
|
public WorkspaceDefinitionContext(Dictionary<string, WorkspaceDefinition> workspaces) |
||||
|
{ |
||||
|
Workspaces = workspaces; |
||||
|
} |
||||
|
|
||||
|
public virtual WorkspaceDefinition? GetOrNull(string name) |
||||
|
{ |
||||
|
return Workspaces.GetOrDefault(name); |
||||
|
} |
||||
|
|
||||
|
public virtual IReadOnlyList<WorkspaceDefinition> GetAll() |
||||
|
{ |
||||
|
return Workspaces.Values.ToImmutableList(); |
||||
|
} |
||||
|
|
||||
|
public virtual void Add(params WorkspaceDefinition[] definitions) |
||||
|
{ |
||||
|
if (definitions.IsNullOrEmpty()) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
foreach (var definition in definitions) |
||||
|
{ |
||||
|
Workspaces[definition.Name] = definition; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,52 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.Immutable; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Workspaces; |
||||
|
public class WorkspaceDefinitionManager : IWorkspaceDefinitionManager, ISingletonDependency |
||||
|
{ |
||||
|
protected readonly IStaticWorkspaceDefinitionStore StaticStore; |
||||
|
protected readonly IDynamicWorkspaceDefinitionStore DynamicStore; |
||||
|
|
||||
|
public WorkspaceDefinitionManager( |
||||
|
IStaticWorkspaceDefinitionStore staticStore, |
||||
|
IDynamicWorkspaceDefinitionStore dynamicStore) |
||||
|
{ |
||||
|
StaticStore = staticStore; |
||||
|
DynamicStore = dynamicStore; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<WorkspaceDefinition> GetAsync(string name) |
||||
|
{ |
||||
|
var workspace = await GetOrNullAsync(name); |
||||
|
if (workspace == null) |
||||
|
{ |
||||
|
throw new AbpException("Undefined Workspace: " + name); |
||||
|
} |
||||
|
|
||||
|
return workspace; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<WorkspaceDefinition?> GetOrNullAsync(string name) |
||||
|
{ |
||||
|
Check.NotNull(name, nameof(name)); |
||||
|
|
||||
|
return await StaticStore.GetOrNullAsync(name) ?? await DynamicStore.GetOrNullAsync(name); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<IReadOnlyList<WorkspaceDefinition>> GetAllAsync() |
||||
|
{ |
||||
|
var staticWorkspaces = await StaticStore.GetAllAsync(); |
||||
|
var staticWorkspaceNames = staticWorkspaces |
||||
|
.Select(p => p.Name) |
||||
|
.ToImmutableHashSet(); |
||||
|
|
||||
|
var dynamicWorkspaces = await DynamicStore.GetAllAsync(); |
||||
|
|
||||
|
return staticWorkspaces.Concat(dynamicWorkspaces.Where(d => !staticWorkspaceNames.Contains(d.Name))) |
||||
|
.ToImmutableList(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Workspaces; |
||||
|
|
||||
|
public abstract class WorkspaceDefinitionProvider : IWorkspaceDefinitionProvider, ITransientDependency |
||||
|
{ |
||||
|
public abstract void Define(IWorkspaceDefinitionContext context); |
||||
|
} |
||||
@ -0,0 +1,164 @@ |
|||||
|
# LINGYUN.Abp.AI.Core |
||||
|
|
||||
|
[Abp AI Module](https://abp.io/docs/latest/framework/infrastructure/artificial-intelligence) 扩展. |
||||
|
|
||||
|
## 功能特性 |
||||
|
|
||||
|
|
||||
|
## 模块引用 |
||||
|
|
||||
|
```csharp |
||||
|
[DependsOn(typeof(AbpAICoreModule))] |
||||
|
public class YouProjectModule : AbpModule |
||||
|
{ |
||||
|
// other |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## 依赖模块 |
||||
|
|
||||
|
* [AbpAIModule](https://abp.io/docs/latest/framework/infrastructure/artificial-intelligence) |
||||
|
* [AbpLocalizationModule](https://abp.io/docs/latest/framework/fundamentals/localization) |
||||
|
|
||||
|
## 基本用法 |
||||
|
|
||||
|
> 定义系统工作区 |
||||
|
```csharp |
||||
|
[DependsOn(typeof(AbpAICoreModule))] |
||||
|
public class YouProjectModule : AbpModule |
||||
|
{ |
||||
|
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
PreConfigure<AbpAIWorkspaceOptions>(options => |
||||
|
{ |
||||
|
options.Workspaces.Configure<YouWorkspace>(workspace => |
||||
|
{ |
||||
|
workspace.ConfigureChatClient(config => |
||||
|
{ |
||||
|
config.Builder = new ChatClientBuilder( |
||||
|
sp => new OpenAIClient( |
||||
|
new ApiKeyCredential("YouApiKey"), |
||||
|
new OpenAIClientOptions |
||||
|
{ |
||||
|
Endpoint = new Uri("https://api.openai.com/v1"), |
||||
|
}).GetChatClient("GPT-4").AsIChatClient()); |
||||
|
}); |
||||
|
|
||||
|
workspace.ConfigureKernel(config => |
||||
|
{ |
||||
|
config.Builder = Kernel.CreateBuilder() |
||||
|
.AddOpenAIChatClient( |
||||
|
modelId: "GPT-4", |
||||
|
openAIClient: new OpenAIClient( |
||||
|
new ApiKeyCredential("YouApiKey"), |
||||
|
new OpenAIClientOptions |
||||
|
{ |
||||
|
Endpoint = new Uri("https://api.openai.com/v1"), |
||||
|
})); |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
> 兼容 `IKernelAccessor` 与 `IChatClientAccessor` 的语法. |
||||
|
```csharp |
||||
|
using LINGYUN.Abp.AI; |
||||
|
using LINGYUN.Abp.AI.Agent; |
||||
|
using Microsoft.Extensions.AI; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.SemanticKernel; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
var application = await AbpApplicationFactory.CreateAsync<YouProjectModule>(options => |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
}); |
||||
|
|
||||
|
await application.InitializeAsync(); |
||||
|
|
||||
|
// 使用 IKernelFactory |
||||
|
Console.WriteLine("Use Microsoft.SemanticKernel:"); |
||||
|
var kernelFactory = application.ServiceProvider.GetRequiredService<IKernelFactory>(); |
||||
|
|
||||
|
var kernel = await kernelFactory.CreateAsync<YouWorkspace>(); |
||||
|
var kernelResponse = kernel.InvokePromptStreamingAsync("如何优化 C# 代码性能?"); |
||||
|
await foreach (var item in kernelResponse) |
||||
|
{ |
||||
|
Console.Write(item); |
||||
|
} |
||||
|
Console.WriteLine(); |
||||
|
|
||||
|
// 使用 IKernelAccessor |
||||
|
var kernelWithAbp = application.ServiceProvider.GetRequiredService<IKernelAccessor<YouWorkspace>>(); |
||||
|
var kernelWithAbpResponse = kernelWithAbp.InvokePromptStreamingAsync("如何优化 C# 代码性能?"); |
||||
|
await foreach (var item in kernelWithAbpResponse) |
||||
|
{ |
||||
|
Console.Write(item); |
||||
|
} |
||||
|
Console.WriteLine(); |
||||
|
|
||||
|
await application.ShutdownAsync(); |
||||
|
|
||||
|
Console.WriteLine(); |
||||
|
Console.WriteLine("AI Console completed!"); |
||||
|
|
||||
|
Console.ReadKey(); |
||||
|
``` |
||||
|
|
||||
|
> 定义动态工作区 |
||||
|
```csharp |
||||
|
public class YouWorkspaceDefinitionProvider : WorkspaceDefinitionProvider |
||||
|
{ |
||||
|
public override void Define(IWorkspaceDefinitionContext context) |
||||
|
{ |
||||
|
context.Add( |
||||
|
new WorkspaceDefinition( |
||||
|
"YouWorkspace", |
||||
|
OpenAIChatClientProvider.ProviderName, |
||||
|
"GPT-4", |
||||
|
new FixedLocalizableString("YouWorkspace")) |
||||
|
.WithApiKey("YouApiKey") |
||||
|
.WithApiBaseUrl("https://api.openai.com/v1")); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
``` |
||||
|
|
||||
|
> 支持动态工作区语法. |
||||
|
```csharp |
||||
|
using LINGYUN.Abp.AI; |
||||
|
using LINGYUN.Abp.AI.Agent; |
||||
|
using Microsoft.Extensions.AI; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.SemanticKernel; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
var application = await AbpApplicationFactory.CreateAsync<YouProjectModule>(options => |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
}); |
||||
|
|
||||
|
await application.InitializeAsync(); |
||||
|
|
||||
|
// Microsoft.SemanticKernel |
||||
|
Console.WriteLine("Use Microsoft.SemanticKernel:"); |
||||
|
var kernelFactory = application.ServiceProvider.GetRequiredService<IKernelFactory>(); |
||||
|
|
||||
|
var kernel = await kernelFactory.CreateAsync("YouWorkspace"); |
||||
|
var kernelResponse = kernel.InvokePromptStreamingAsync("如何优化 C# 代码性能?"); |
||||
|
await foreach (var item in kernelResponse) |
||||
|
{ |
||||
|
Console.Write(item); |
||||
|
} |
||||
|
Console.WriteLine(); |
||||
|
|
||||
|
await application.ShutdownAsync(); |
||||
|
|
||||
|
Console.WriteLine(); |
||||
|
Console.WriteLine("AI Console completed!"); |
||||
|
|
||||
|
Console.ReadKey(); |
||||
|
|
||||
|
``` |
||||
Loading…
Reference in new issue