Browse Source

Merge pull request #1454 from colinin/ai

AI Integration
pull/1455/head
yx lin 5 months ago
committed by GitHub
parent
commit
c7a35b9c9b
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      Directory.Packages.props
  2. 1
      aspnet-core/LINGYUN.MicroService.Aspire.slnx
  3. 6
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/AIServiceModule.cs
  4. 2
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/LINGYUN.Abp.MicroService.AIService.csproj
  5. 16
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Agent/LINGYUN/Abp/AI/Agent/AbpAIAgentOptions.cs
  6. 21
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Agent/LINGYUN/Abp/AI/Agent/AgentFactory.cs
  7. 9
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/AbpAICoreOptions.cs
  8. 19
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Internal/OpenAIChatClientProvider.cs
  9. 16
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Internal/OpenAIKernelProvider.cs
  10. 11
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Tools/GlobalFunctions.cs
  11. 4
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/IWorkspaceDefinitionManager.cs
  12. 2
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/NullDynamicWorkspaceDefinitionStore.cs
  13. 3
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Ollama/FodyWeavers.xml
  14. 30
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Ollama/FodyWeavers.xsd
  15. 27
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Ollama/LINGYUN.Abp.AI.Ollama.csproj
  16. 17
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Ollama/LINGYUN/Abp/AI/Ollama/AbpAIOllamaModule.cs
  17. 51
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Ollama/LINGYUN/Abp/AI/Ollama/OllamaChatClientProvider.cs
  18. 39
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Ollama/LINGYUN/Abp/AI/Ollama/OllamaKernelProvider.cs
  19. 3
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/FodyWeavers.xml
  20. 30
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/FodyWeavers.xsd
  21. 26
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN.Abp.AI.Tools.csproj
  22. 55
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinition.cs
  23. 37
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionContext.cs
  24. 52
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionManager.cs
  25. 7
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionProvider.cs
  26. 55
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolFactory.cs
  27. 45
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolProviderManager.cs
  28. 80
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsModule.cs
  29. 13
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsOptions.cs
  30. 34
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/FunctionAIToolDefinitionExtenssions.cs
  31. 48
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/FunctionAIToolProvider.cs
  32. 41
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/GlobalAIToolDefinitionProvider.cs
  33. 11
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionContext.cs
  34. 16
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionManager.cs
  35. 5
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionProvider.cs
  36. 10
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolFactory.cs
  37. 9
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolProvider.cs
  38. 7
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolProviderManager.cs
  39. 13
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IDynamicAIToolDefinitionStore.cs
  40. 13
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IStaticAIToolDefinitionStore.cs
  41. 10
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Localization/Resources/en.json
  42. 10
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Localization/Resources/zh-Hans.json
  43. 32
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/NullDynamicAIToolDefinitionStore.cs
  44. 20
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Settings/GetSettingTool.cs
  45. 20
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Settings/GetSettingsTool.cs
  46. 80
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/StaticAIToolDefinitionStore.cs
  47. 19
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Timing/NowTimeTool.cs
  48. 21
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Users/CurrentUserTool.cs
  49. 79
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/README.md

2
Directory.Packages.props

@ -348,6 +348,8 @@
<PackageVersion Include="Elastic.Clients.Elasticsearch" Version="8.19.4" />
<PackageVersion Include="NRules" Version="0.9.2" />
<PackageVersion Include="Ocelot.Provider.Polly" Version="20.0.0" />
<PackageVersion Include="OllamaSharp" Version="5.4.20" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Ollama" Version="1.74.0-alpha" />
<PackageVersion Include="OpenIddict.Server.DataProtection" Version="7.2.0" />
<PackageVersion Include="OpenIddict.Validation.DataProtection" Version="7.2.0" />
<PackageVersion Include="Polly" Version="8.6.3" />

1
aspnet-core/LINGYUN.MicroService.Aspire.slnx

@ -284,6 +284,7 @@
<Folder Name="/modules/ai/">
<Project Path="modules/ai/LINGYUN.Abp.AI.Agent/LINGYUN.Abp.AI.Agent.csproj" />
<Project Path="modules/ai/LINGYUN.Abp.AI.Core/LINGYUN.Abp.AI.Core.csproj" />
<Project Path="modules/ai/LINGYUN.Abp.AI.Ollama/LINGYUN.Abp.AI.Ollama.csproj" Id="d59e459c-7ca2-4c5b-b981-685af7ad2848" />
<Project Path="modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN.Abp.AIManagement.Application.Contracts.csproj" />
<Project Path="modules/ai/LINGYUN.Abp.AIManagement.Application/LINGYUN.Abp.AIManagement.Application.csproj" />
<Project Path="modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN.Abp.AIManagement.Domain.Shared.csproj" />

6
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/AIServiceModule.cs

@ -1,4 +1,6 @@
using LINGYUN.Abp.AIManagement;
using LINGYUN.Abp.AI.Ollama;
using LINGYUN.Abp.AI.Tools;
using LINGYUN.Abp.AIManagement;
using LINGYUN.Abp.AspNetCore.HttpOverrides;
using LINGYUN.Abp.AspNetCore.Mvc.Localization;
using LINGYUN.Abp.AspNetCore.Mvc.Wrapper;
@ -46,6 +48,8 @@ namespace LINGYUN.Abp.MicroService.AIService;
typeof(AbpIdentitySessionAspNetCoreModule),
typeof(AbpAIOllamaModule),
typeof(AbpAIToolsModule),
typeof(AbpAIManagementApplicationModule),
typeof(AbpAIManagementHttpApiModule),
typeof(AIServiceMigrationsEntityFrameworkCoreModule),

2
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/LINGYUN.Abp.MicroService.AIService.csproj

@ -56,6 +56,8 @@
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore\LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\modules\ai\LINGYUN.Abp.AI.Ollama\LINGYUN.Abp.AI.Ollama.csproj" />
<ProjectReference Include="..\..\modules\ai\LINGYUN.Abp.AI.Tools\LINGYUN.Abp.AI.Tools.csproj" />
<ProjectReference Include="..\..\modules\ai\LINGYUN.Abp.AIManagement.Application\LINGYUN.Abp.AIManagement.Application.csproj" />
<ProjectReference Include="..\..\modules\ai\LINGYUN.Abp.AIManagement.HttpApi\LINGYUN.Abp.AIManagement.HttpApi.csproj" />
<ProjectReference Include="..\..\modules\identity\LINGYUN.Abp.Identity.Session.AspNetCore\LINGYUN.Abp.Identity.Session.AspNetCore.csproj" />

16
aspnet-core/modules/ai/LINGYUN.Abp.AI.Agent/LINGYUN/Abp/AI/Agent/AbpAIAgentOptions.cs

@ -0,0 +1,16 @@
using LINGYUN.Abp.AI.Workspaces;
using Microsoft.Agents.AI;
using System;
using System.Collections.Generic;
namespace LINGYUN.Abp.AI.Agent;
public class AbpAIAgentOptions
{
public List<Action<WorkspaceDefinition?, AIAgentBuilder>> AgentBuildActions { get; }
public List<Action<WorkspaceDefinition?, ChatClientAgentOptions>> AgentOptionActions { get; }
public AbpAIAgentOptions()
{
AgentBuildActions = new List<Action<WorkspaceDefinition?, AIAgentBuilder>>();
AgentOptionActions = new List<Action<WorkspaceDefinition?, ChatClientAgentOptions>>();
}
}

21
aspnet-core/modules/ai/LINGYUN.Abp.AI.Agent/LINGYUN/Abp/AI/Agent/AgentFactory.cs

@ -2,6 +2,7 @@
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using Volo.Abp.AI;
@ -12,6 +13,7 @@ namespace LINGYUN.Abp.AI.Agent;
public class AgentFactory : IAgentFactory, IScopedDependency
{
protected IServiceProvider ServiceProvider { get; }
protected AbpAIAgentOptions AgentOptions { get; }
protected IChatClientFactory ChatClientFactory { get; }
protected IStringLocalizerFactory StringLocalizerFactory { get; }
protected IWorkspaceDefinitionManager WorkspaceDefinitionManager { get; }
@ -19,10 +21,12 @@ public class AgentFactory : IAgentFactory, IScopedDependency
public AgentFactory(
IServiceProvider serviceProvider,
IChatClientFactory chatClientFactory,
IOptions<AbpAIAgentOptions> agentOptions,
IStringLocalizerFactory stringLocalizerFactory,
IWorkspaceDefinitionManager workspaceDefinitionManager,
ISimpleStateCheckerManager<WorkspaceDefinition> stateCheckerManager)
{
AgentOptions = agentOptions.Value;
ServiceProvider = serviceProvider;
ChatClientFactory = chatClientFactory;
StringLocalizerFactory = stringLocalizerFactory;
@ -75,8 +79,21 @@ public class AgentFactory : IAgentFactory, IScopedDependency
Description = description,
};
var aiAgent = chatClient.CreateAIAgent(clientAgentOptions)
.AsBuilder()
foreach (var handlerAction in AgentOptions.AgentOptionActions)
{
handlerAction(workspace, clientAgentOptions);
}
var aiAgentBuilder = chatClient
.CreateAIAgent(clientAgentOptions)
.AsBuilder();
foreach (var handlerAction in AgentOptions.AgentBuildActions)
{
handlerAction(workspace, aiAgentBuilder);
}
var aiAgent = aiAgentBuilder
.UseLogging()
.UseOpenTelemetry()
.Build(ServiceProvider);

9
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/AbpAICoreOptions.cs

@ -1,5 +1,9 @@
using LINGYUN.Abp.AI.Workspaces;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Collections;
namespace LINGYUN.Abp.AI;
@ -9,6 +13,9 @@ public class AbpAICoreOptions
public ITypeList<IChatClientProvider> ChatClientProviders { get; }
public ITypeList<IKernelProvider> KernelProviders { get; }
public List<Action<WorkspaceDefinition, IKernelBuilder>> KernelBuildActions { get; }
public List<Func<WorkspaceDefinition, IServiceProvider, ChatClientBuilder, Task>> ChatClientBuildActions { get; }
public HashSet<string> DeletedWorkspaces { get; }
public AbpAICoreOptions()
@ -18,5 +25,7 @@ public class AbpAICoreOptions
KernelProviders = new TypeList<IKernelProvider>();
DeletedWorkspaces = new HashSet<string>();
KernelBuildActions = new List<Action<WorkspaceDefinition, IKernelBuilder>>();
ChatClientBuildActions = new List<Func<WorkspaceDefinition, IServiceProvider, ChatClientBuilder, Task>>();
}
}

19
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Internal/OpenAIChatClientProvider.cs

@ -1,6 +1,8 @@
using LINGYUN.Abp.AI.Models;
using LINGYUN.Abp.AI.Workspaces;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenAI;
using System;
using System.ClientModel;
@ -31,7 +33,7 @@ public class OpenAIChatClientProvider : ChatClientProvider
];
}
public override Task<IChatClient> CreateAsync(WorkspaceDefinition workspace)
public override async Task<IChatClient> CreateAsync(WorkspaceDefinition workspace)
{
Check.NotNull(workspace, nameof(workspace));
Check.NotNullOrWhiteSpace(workspace.ApiKey, nameof(WorkspaceDefinition.ApiKey));
@ -43,16 +45,23 @@ public class OpenAIChatClientProvider : ChatClientProvider
Endpoint = new Uri(workspace.ApiBaseUrl ?? DefaultEndpoint),
});
var chatClient = openAIClient
var options = ServiceProvider.GetRequiredService<IOptions<AbpAICoreOptions>>().Value;
var chatClientBuilder = openAIClient
.GetChatClient(workspace.ModelName)
.AsIChatClient()
.AsBuilder()
.AsBuilder();
foreach (var handlerAction in options.ChatClientBuildActions)
{
await handlerAction(workspace, ServiceProvider, chatClientBuilder);
}
return chatClientBuilder
.UseLogging()
.UseOpenTelemetry()
.UseFunctionInvocation()
.UseDistributedCache()
.Build(ServiceProvider);
return Task.FromResult(chatClient);
}
}

16
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Internal/OpenAIKernelProvider.cs

@ -1,4 +1,6 @@
using LINGYUN.Abp.AI.Workspaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.SemanticKernel;
using OpenAI;
using System;
@ -23,6 +25,8 @@ public class OpenAIKernelProvider : KernelProvider
Check.NotNull(workspace, nameof(workspace));
Check.NotNullOrWhiteSpace(workspace.ApiKey, nameof(WorkspaceDefinition.ApiKey));
var options = ServiceProvider.GetRequiredService<IOptions<AbpAICoreOptions>>().Value;
var openAIClient = new OpenAIClient(
new ApiKeyCredential(workspace.ApiKey),
new OpenAIClientOptions
@ -30,10 +34,14 @@ public class OpenAIKernelProvider : KernelProvider
Endpoint = new Uri(workspace.ApiBaseUrl ?? DefaultEndpoint),
});
var kernel = Kernel.CreateBuilder()
.AddOpenAIChatClient(workspace.ModelName, openAIClient)
.Build();
var kernelBuilder = Kernel.CreateBuilder()
.AddOpenAIChatClient(workspace.ModelName, openAIClient);
foreach (var handlerAction in options.KernelBuildActions)
{
handlerAction(workspace, kernelBuilder);
}
return Task.FromResult(kernel);
return Task.FromResult(kernelBuilder.Build());
}
}

11
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Tools/GlobalFunctions.cs

@ -1,11 +0,0 @@
using Microsoft.Extensions.AI;
using System;
namespace LINGYUN.Abp.AI.Tools;
public static class GlobalFunctions
{
public static AITool Now => AIFunctionFactory.Create(
() => DateTime.Now,
nameof(Now),
"Get now time");
}

4
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/IWorkspaceDefinitionManager.cs

@ -5,12 +5,12 @@ using System.Threading.Tasks;
namespace LINGYUN.Abp.AI.Workspaces;
public interface IWorkspaceDefinitionManager
{
[ItemNotNull]
[NotNull]
Task<WorkspaceDefinition> GetAsync([NotNull] string name);
[ItemNotNull]
Task<IReadOnlyList<WorkspaceDefinition>> GetAllAsync();
[ItemCanBeNull]
[CanBeNull]
Task<WorkspaceDefinition?> GetOrNullAsync([NotNull] string name);
}

2
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Workspaces/NullDynamicWorkspaceDefinitionStore.cs

@ -5,6 +5,8 @@ using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.AI.Workspaces;
[Dependency(TryRegister = true)]
public class NullDynamicWorkspaceDefinitionStore : IDynamicWorkspaceDefinitionStore, ISingletonDependency
{
private readonly static Task<WorkspaceDefinition?> CachedNullableWorkspaceResult = Task.FromResult((WorkspaceDefinition?)null);

3
aspnet-core/modules/ai/LINGYUN.Abp.AI.Ollama/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/ai/LINGYUN.Abp.AI.Ollama/FodyWeavers.xsd

@ -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>

27
aspnet-core/modules/ai/LINGYUN.Abp.AI.Ollama/LINGYUN.Abp.AI.Ollama.csproj

@ -0,0 +1,27 @@
<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.Ollama</AssemblyName>
<PackageId>LINGYUN.Abp.AI.Ollama</PackageId>
<NoWarn>$(NoWarn);SKEXP0001,SKEXP0010,SKEXP0070</NoWarn>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OllamaSharp" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Ollama" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.AI.Core\LINGYUN.Abp.AI.Core.csproj" />
</ItemGroup>
</Project>

17
aspnet-core/modules/ai/LINGYUN.Abp.AI.Ollama/LINGYUN/Abp/AI/Ollama/AbpAIOllamaModule.cs

@ -0,0 +1,17 @@
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.AI.Ollama;
[DependsOn(typeof(AbpAICoreModule))]
public class AbpAIOllamaModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAICoreOptions>(options =>
{
options.ChatClientProviders.Add<OllamaChatClientProvider>();
options.KernelProviders.Add<OllamaKernelProvider>();
});
}
}

51
aspnet-core/modules/ai/LINGYUN.Abp.AI.Ollama/LINGYUN/Abp/AI/Ollama/OllamaChatClientProvider.cs

@ -0,0 +1,51 @@
using LINGYUN.Abp.AI.Models;
using LINGYUN.Abp.AI.Workspaces;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OllamaSharp;
using System;
using System.Threading.Tasks;
using Volo.Abp;
namespace LINGYUN.Abp.AI.Ollama;
public class OllamaChatClientProvider : ChatClientProvider
{
public const string DefaultEndpoint = "http://localhost:11434";
public const string ProviderName = "Ollama";
public override string Name => ProviderName;
public OllamaChatClientProvider(
IServiceProvider serviceProvider) : base(serviceProvider)
{
}
public async override Task<IChatClient> CreateAsync(WorkspaceDefinition workspace)
{
Check.NotNull(workspace, nameof(workspace));
var options = ServiceProvider.GetRequiredService<IOptions<AbpAICoreOptions>>().Value;
var ollamaApiClient = new OllamaApiClient(workspace.ApiBaseUrl ?? DefaultEndpoint);
var chatClientBuilder = ChatClientBuilderChatClientExtensions.AsBuilder(ollamaApiClient);
foreach (var handlerAction in options.ChatClientBuildActions)
{
await handlerAction(workspace, ServiceProvider, chatClientBuilder);
}
return chatClientBuilder
.UseLogging()
.UseOpenTelemetry()
.UseFunctionInvocation()
.UseDistributedCache()
.Build(ServiceProvider);
}
public override ChatModel[] GetModels()
{
return [];
}
}

39
aspnet-core/modules/ai/LINGYUN.Abp.AI.Ollama/LINGYUN/Abp/AI/Ollama/OllamaKernelProvider.cs

@ -0,0 +1,39 @@
using LINGYUN.Abp.AI.Workspaces;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.SemanticKernel;
using OllamaSharp;
using System;
using System.Threading.Tasks;
using Volo.Abp;
namespace LINGYUN.Abp.AI.Ollama;
public class OllamaKernelProvider : KernelProvider
{
public const string ProviderName = "Ollama";
public override string Name => ProviderName;
public OllamaKernelProvider(IServiceProvider serviceProvider) : base(serviceProvider)
{
}
public override Task<Kernel> CreateAsync(WorkspaceDefinition workspace)
{
Check.NotNull(workspace, nameof(workspace));
var options = ServiceProvider.GetRequiredService<IOptions<AbpAICoreOptions>>().Value;
var ollamaApiClient = new OllamaApiClient(workspace.ApiBaseUrl ?? OllamaChatClientProvider.DefaultEndpoint);
var kernelBuilder = Kernel.CreateBuilder()
.AddOllamaChatClient(ollamaApiClient);
foreach (var handlerAction in options.KernelBuildActions)
{
handlerAction(workspace, kernelBuilder);
}
return Task.FromResult(kernelBuilder.Build());
}
}

3
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/FodyWeavers.xsd

@ -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>

26
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN.Abp.AI.Tools.csproj

@ -0,0 +1,26 @@
<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.Tools</AssemblyName>
<PackageId>LINGYUN.Abp.AI.Tools</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<None Remove="LINGYUN\Abp\AI\Tools\Localization\Resources\*.json" />
<EmbeddedResource Include="LINGYUN\Abp\AI\Tools\Localization\Resources\*.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.AI.Core\LINGYUN.Abp.AI.Core.csproj" />
</ItemGroup>
</Project>

55
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinition.cs

@ -0,0 +1,55 @@
using JetBrains.Annotations;
using System.Collections.Generic;
using Volo.Abp.Localization;
using Volo.Abp.SimpleStateChecking;
namespace LINGYUN.Abp.AI.Tools;
public class AIToolDefinition : IHasSimpleStateCheckers<AIToolDefinition>
{
/// <summary>
/// 名称
/// </summary>
[NotNull]
public string Name { get; }
/// <summary>
/// 提供者
/// </summary>
[NotNull]
public string Provider { get; }
/// <summary>
/// 描述
/// </summary>
public ILocalizableString? Description { get; set; }
/// <summary>
/// 属性
/// </summary>
[NotNull]
public Dictionary<string, object?> Properties { get; }
public List<ISimpleStateChecker<AIToolDefinition>> StateCheckers { get; }
public AIToolDefinition(
[NotNull] string name,
[NotNull] string provider,
ILocalizableString? description = null)
{
Name = name;
Provider = provider;
Description = description;
Properties = new Dictionary<string, object?>();
StateCheckers = new List<ISimpleStateChecker<AIToolDefinition>>();
}
public virtual AIToolDefinition WithProperty(string key, object? value)
{
Properties[key] = value;
return this;
}
public override string ToString()
{
return $"[{nameof(AIToolDefinition)} {Name}]";
}
}

37
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionContext.cs

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
namespace LINGYUN.Abp.AI.Tools;
public class AIToolDefinitionContext : IAIToolDefinitionContext
{
protected Dictionary<string, AIToolDefinition> Tools { get; }
public AIToolDefinitionContext(Dictionary<string, AIToolDefinition> tools)
{
Tools = tools;
}
public virtual AIToolDefinition? GetOrNull(string name)
{
return Tools.GetOrDefault(name);
}
public virtual IReadOnlyList<AIToolDefinition> GetAll()
{
return Tools.Values.ToImmutableList();
}
public virtual void Add(params AIToolDefinition[] definitions)
{
if (definitions.IsNullOrEmpty())
{
return;
}
foreach (var definition in definitions)
{
Tools[definition.Name] = definition;
}
}
}

52
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionManager.cs

@ -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.Tools;
public class AIToolDefinitionManager : IAIToolDefinitionManager, ISingletonDependency
{
protected readonly IStaticAIToolDefinitionStore StaticStore;
protected readonly IDynamicAIToolDefinitionStore DynamicStore;
public AIToolDefinitionManager(
IStaticAIToolDefinitionStore staticStore,
IDynamicAIToolDefinitionStore dynamicStore)
{
StaticStore = staticStore;
DynamicStore = dynamicStore;
}
public virtual async Task<AIToolDefinition> GetAsync(string name)
{
var workspace = await GetOrNullAsync(name);
if (workspace == null)
{
throw new AbpException("Undefined AITool: " + name);
}
return workspace;
}
public virtual async Task<AIToolDefinition?> GetOrNullAsync(string name)
{
Check.NotNull(name, nameof(name));
return await StaticStore.GetOrNullAsync(name) ?? await DynamicStore.GetOrNullAsync(name);
}
public virtual async Task<IReadOnlyList<AIToolDefinition>> GetAllAsync()
{
var staticAITools = await StaticStore.GetAllAsync();
var staticAIToolNames = staticAITools
.Select(p => p.Name)
.ToImmutableHashSet();
var dynamicAITools = await DynamicStore.GetAllAsync();
return staticAITools.Concat(dynamicAITools.Where(d => !staticAIToolNames.Contains(d.Name)))
.ToImmutableList();
}
}

7
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionProvider.cs

@ -0,0 +1,7 @@
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.AI.Tools;
public abstract class AIToolDefinitionProvider : IAIToolDefinitionProvider, ITransientDependency
{
public abstract void Define(IAIToolDefinitionContext context);
}

55
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolFactory.cs

@ -0,0 +1,55 @@
using Microsoft.Extensions.AI;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.SimpleStateChecking;
namespace LINGYUN.Abp.AI.Tools;
public class AIToolFactory : IAIToolFactory, ITransientDependency
{
protected ISimpleStateCheckerManager<AIToolDefinition> StateCheckerManager { get; }
protected IAIToolDefinitionManager AIToolDefinitionManager { get; }
protected IAIToolProviderManager AIToolProviderManager { get; }
public AIToolFactory(
ISimpleStateCheckerManager<AIToolDefinition> stateCheckerManager,
IAIToolDefinitionManager aIToolDefinitionManager,
IAIToolProviderManager aIToolProviderManager)
{
StateCheckerManager = stateCheckerManager;
AIToolDefinitionManager = aIToolDefinitionManager;
AIToolProviderManager = aIToolProviderManager;
}
public virtual AITool CreateTool(AIToolDefinition definition)
{
foreach (var provider in AIToolProviderManager.Providers)
{
if (!string.Equals(provider.Name, definition.Provider))
{
continue;
}
return provider.CreateTool(definition);
}
throw new AbpException($"The AITool provider implementation named {definition.Provider} was not found!");
}
public async virtual Task<AITool[]> CreateAllTools()
{
var aiTools = new List<AITool>();
var toolDefines = await AIToolDefinitionManager.GetAllAsync();
foreach (var toolDefine in toolDefines)
{
if (await StateCheckerManager.IsEnabledAsync(toolDefine))
{
aiTools.Add(CreateTool(toolDefine));
}
}
return aiTools.ToArray();
}
}

45
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolProviderManager.cs

@ -0,0 +1,45 @@
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.Tools;
public class AIToolProviderManager : IAIToolProviderManager, ISingletonDependency
{
public List<IAIToolProvider> Providers => _lazyProviders.Value;
protected AbpAIToolsOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }
private readonly Lazy<List<IAIToolProvider>> _lazyProviders;
public AIToolProviderManager(
IServiceProvider serviceProvider,
IOptions<AbpAIToolsOptions> options)
{
Options = options.Value;
ServiceProvider = serviceProvider;
_lazyProviders = new Lazy<List<IAIToolProvider>>(GetProviders, true);
}
protected virtual List<IAIToolProvider> GetProviders()
{
var providers = Options
.AIToolProviders
.Select(type => (ServiceProvider.GetRequiredService(type) as IAIToolProvider)!)
.ToList();
var multipleProviders = providers.GroupBy(p => p.Name).FirstOrDefault(x => x.Count() > 1);
if (multipleProviders != null)
{
throw new AbpException($"Duplicate AITool provider name detected: {multipleProviders.Key}. Providers:{Environment.NewLine}{multipleProviders.Select(p => p.GetType().FullName!).JoinAsString(Environment.NewLine)}");
}
return providers;
}
}

80
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsModule.cs

@ -0,0 +1,80 @@
using LINGYUN.Abp.AI.Localization;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.AI.Tools;
[DependsOn(typeof(AbpAICoreModule))]
public class AbpAIToolsModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
AutoAddDefinitionProviders(context.Services);
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpAIToolsModule>();
});
Configure<AbpAIToolsOptions>(options =>
{
// 自定义函数工具
options.AIToolProviders.Add<FunctionAIToolProvider>();
});
Configure<AbpAICoreOptions>(options =>
{
options.ChatClientBuildActions.Add(async (_, sp, builder) =>
{
var aiToolFactory = sp.GetRequiredService<IAIToolFactory>();
var aiTools = await aiToolFactory.CreateAllTools();
builder.ConfigureOptions(ai =>
{
ai.ToolMode = ChatToolMode.Auto;
ai.AllowMultipleToolCalls = true;
ai.Tools ??= [];
foreach (var aiTool in aiTools)
{
ai.Tools.Add(aiTool);
}
});
});
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<AbpAIResource>()
.AddVirtualJson("/LINGYUN/Abp/AI/Tools/Localization/Resources");
});
}
private static void AutoAddDefinitionProviders(IServiceCollection services)
{
var definitionProviders = new List<Type>();
services.OnRegistered(context =>
{
if (typeof(IAIToolDefinitionProvider).IsAssignableFrom(context.ImplementationType))
{
definitionProviders.Add(context.ImplementationType);
}
});
services.Configure<AbpAIToolsOptions>(options =>
{
options.DefinitionProviders.AddIfNotContains(definitionProviders);
});
}
}

13
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsOptions.cs

@ -0,0 +1,13 @@
using Volo.Abp.Collections;
namespace LINGYUN.Abp.AI.Tools;
public class AbpAIToolsOptions
{
public ITypeList<IAIToolDefinitionProvider> DefinitionProviders { get; }
public ITypeList<IAIToolProvider> AIToolProviders { get; }
public AbpAIToolsOptions()
{
DefinitionProviders = new TypeList<IAIToolDefinitionProvider>();
AIToolProviders = new TypeList<IAIToolProvider>();
}
}

34
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/FunctionAIToolDefinitionExtenssions.cs

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using Volo.Abp;
namespace LINGYUN.Abp.AI.Tools;
public static class FunctionAIToolDefinitionExtenssions
{
private const string FunctionType = "Function";
public static AIToolDefinition WithFunction<TFunc>(this AIToolDefinition definition)
{
return definition.WithFunction(typeof(TFunc));
}
public static AIToolDefinition WithFunction(this AIToolDefinition definition, Type funcType)
{
Check.NotNull(funcType, nameof(funcType));
definition.WithProperty(FunctionType, funcType);
return definition;
}
public static Type GetFunction(this AIToolDefinition definition)
{
var funcTypeSet = definition.Properties.GetOrDefault(FunctionType);
Check.NotNull(funcTypeSet, nameof(FunctionType));
var funcType = Type.GetType(funcTypeSet.ToString()!);
Check.NotNull(funcType, nameof(funcType));
return funcType;
}
}

48
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/FunctionAIToolProvider.cs

@ -0,0 +1,48 @@
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using System;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.AI.Tools;
public class FunctionAIToolProvider : IAIToolProvider, ITransientDependency
{
public const string ProviderName = "Function";
public string Name => ProviderName;
protected IServiceProvider ServiceProvider { get; }
public FunctionAIToolProvider(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
}
public virtual AITool CreateTool(AIToolDefinition definition)
{
var aiToolType = definition.GetFunction();
// 框架约定, 自定义Tool只需要定义同步方法(Invoke)或异步方法(InvokeAsync)即可
var aiToolMethodInfo = aiToolType.GetMethod("Invoke") ?? aiToolType.GetMethod("InvokeAsync");
Check.NotNull(aiToolMethodInfo, nameof(aiToolMethodInfo));
string? description = null;
if (definition.Description != null)
{
var localizerFactory = ServiceProvider.GetRequiredService<IStringLocalizerFactory>();
description = definition.Description.Localize(localizerFactory)?.Value;
}
return AIFunctionFactory.Create(
method: aiToolMethodInfo,
createInstanceFunc: (AIFunctionArguments args) =>
{
return ActivatorUtilities.CreateInstance(args.Services ?? ServiceProvider, aiToolType);
},
options: new AIFunctionFactoryOptions
{
Name = definition.Name,
Description = description,
AdditionalProperties = definition.Properties,
});
}
}

41
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/GlobalAIToolDefinitionProvider.cs

@ -0,0 +1,41 @@
using LINGYUN.Abp.AI.Localization;
using LINGYUN.Abp.AI.Tools.Settings;
using LINGYUN.Abp.AI.Tools.Timing;
using LINGYUN.Abp.AI.Tools.Users;
using Volo.Abp.Localization;
namespace LINGYUN.Abp.AI.Tools;
public class GlobalAIToolDefinitionProvider : AIToolDefinitionProvider
{
public override void Define(IAIToolDefinitionContext context)
{
context.Add(
new AIToolDefinition(
NowTimeTool.Name,
FunctionAIToolProvider.ProviderName,
L("Tools:GetNowTime"))
.WithFunction<NowTimeTool>(),
new AIToolDefinition(
CurrentUserTool.Name,
FunctionAIToolProvider.ProviderName,
L("Tools:GetUserInfo"))
.WithFunction<CurrentUserTool>(),
new AIToolDefinition(
GetSettingTool.Name,
FunctionAIToolProvider.ProviderName,
L("Tools:GetSetting"))
.WithFunction<GetSettingTool>(),
new AIToolDefinition(
GetSettingsTool.Name,
FunctionAIToolProvider.ProviderName,
L("Tools:GetSettings"))
.WithFunction<GetSettingsTool>());
}
private static LocalizableString L(string name)
{
return LocalizableString.Create<AbpAIResource>(name);
}
}

11
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionContext.cs

@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace LINGYUN.Abp.AI.Tools;
public interface IAIToolDefinitionContext
{
AIToolDefinition? GetOrNull(string name);
IReadOnlyList<AIToolDefinition> GetAll();
void Add(params AIToolDefinition[] definitions);
}

16
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionManager.cs

@ -0,0 +1,16 @@
using JetBrains.Annotations;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.AI.Tools;
public interface IAIToolDefinitionManager
{
[NotNull]
Task<AIToolDefinition> GetAsync([NotNull] string name);
[ItemNotNull]
Task<IReadOnlyList<AIToolDefinition>> GetAllAsync();
[CanBeNull]
Task<AIToolDefinition?> GetOrNullAsync([NotNull] string name);
}

5
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionProvider.cs

@ -0,0 +1,5 @@
namespace LINGYUN.Abp.AI.Tools;
public interface IAIToolDefinitionProvider
{
void Define(IAIToolDefinitionContext context);
}

10
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolFactory.cs

@ -0,0 +1,10 @@
using Microsoft.Extensions.AI;
using System.Threading.Tasks;
namespace LINGYUN.Abp.AI.Tools;
public interface IAIToolFactory
{
AITool CreateTool(AIToolDefinition definition);
Task<AITool[]> CreateAllTools();
}

9
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolProvider.cs

@ -0,0 +1,9 @@
using Microsoft.Extensions.AI;
namespace LINGYUN.Abp.AI.Tools;
public interface IAIToolProvider
{
string Name { get; }
AITool CreateTool(AIToolDefinition definition);
}

7
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolProviderManager.cs

@ -0,0 +1,7 @@
using System.Collections.Generic;
namespace LINGYUN.Abp.AI.Tools;
public interface IAIToolProviderManager
{
List<IAIToolProvider> Providers { get; }
}

13
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IDynamicAIToolDefinitionStore.cs

@ -0,0 +1,13 @@
using JetBrains.Annotations;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.AI.Tools;
public interface IDynamicAIToolDefinitionStore
{
Task<AIToolDefinition> GetAsync([NotNull] string name);
Task<IReadOnlyList<AIToolDefinition>> GetAllAsync();
Task<AIToolDefinition?> GetOrNullAsync([NotNull] string name);
}

13
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IStaticAIToolDefinitionStore.cs

@ -0,0 +1,13 @@
using JetBrains.Annotations;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.AI.Tools;
public interface IStaticAIToolDefinitionStore
{
Task<AIToolDefinition> GetAsync([NotNull] string name);
Task<IReadOnlyList<AIToolDefinition>> GetAllAsync();
Task<AIToolDefinition?> GetOrNullAsync([NotNull] string name);
}

10
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Localization/Resources/en.json

@ -0,0 +1,10 @@
{
"culture": "en",
"texts": {
"Tools": "Tools",
"Tools:GetNowTime": "Get now time",
"Tools:GetUserInfo": "Get the current user information",
"Tools:GetSetting": "Get setting value",
"Tools:GetSettings": "Get all settings"
}
}

10
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Localization/Resources/zh-Hans.json

@ -0,0 +1,10 @@
{
"culture": "zh-Hans",
"texts": {
"Tools": "工具列表",
"Tools:GetNowTime": "获取当前时间",
"Tools:GetUserInfo": "获取当前用户信息",
"Tools:GetSetting": "获取设置值",
"Tools:GetSettings": "获取所有设置"
}
}

32
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/NullDynamicAIToolDefinitionStore.cs

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.AI.Tools;
[Dependency(TryRegister = true)]
public class NullDynamicAIToolDefinitionStore : IDynamicAIToolDefinitionStore, ISingletonDependency
{
private readonly static Task<AIToolDefinition?> CachedNullableAIToolResult = Task.FromResult((AIToolDefinition?)null);
private readonly static Task<AIToolDefinition> CachedAIToolResult = Task.FromResult((AIToolDefinition)null!);
private readonly static Task<IReadOnlyList<AIToolDefinition>> CachedAIToolsResult = Task.FromResult(
(IReadOnlyList<AIToolDefinition>)Array.Empty<AIToolDefinition>().ToImmutableList());
public Task<AIToolDefinition> GetAsync(string name)
{
return CachedAIToolResult;
}
public Task<IReadOnlyList<AIToolDefinition>> GetAllAsync()
{
return CachedAIToolsResult;
}
public Task<AIToolDefinition?> GetOrNullAsync(string name)
{
return CachedNullableAIToolResult;
}
}

20
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Settings/GetSettingTool.cs

@ -0,0 +1,20 @@
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
namespace LINGYUN.Abp.AI.Tools.Settings;
public class GetSettingTool : ITransientDependency
{
public const string Name = "GetSetting";
private readonly ISettingProvider _settingProvider;
public GetSettingTool(ISettingProvider settingProvider)
{
_settingProvider = settingProvider;
}
public async Task<object?> InvokeAsync(string name)
{
return await _settingProvider.GetOrNullAsync(name);
}
}

20
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Settings/GetSettingsTool.cs

@ -0,0 +1,20 @@
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
namespace LINGYUN.Abp.AI.Tools.Settings;
public class GetSettingsTool : ITransientDependency
{
public const string Name = "GetSettings";
private readonly ISettingProvider _settingProvider;
public GetSettingsTool(ISettingProvider settingProvider)
{
_settingProvider = settingProvider;
}
public async Task<object?> InvokeAsync()
{
return await _settingProvider.GetAllAsync();
}
}

80
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/StaticAIToolDefinitionStore.cs

@ -0,0 +1,80 @@
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.Tools;
public class StaticAIToolDefinitionStore : IStaticAIToolDefinitionStore, ISingletonDependency
{
protected IServiceProvider ServiceProvider { get; }
protected AbpAIToolsOptions Options { get; }
protected IStaticDefinitionCache<AIToolDefinition, Dictionary<string, AIToolDefinition>> DefinitionCache { get; }
public StaticAIToolDefinitionStore(
IServiceProvider serviceProvider,
IOptions<AbpAIToolsOptions> options,
IStaticDefinitionCache<AIToolDefinition, Dictionary<string, AIToolDefinition>> definitionCache)
{
ServiceProvider = serviceProvider;
Options = options.Value;
DefinitionCache = definitionCache;
}
public virtual async Task<AIToolDefinition> GetAsync(string name)
{
Check.NotNull(name, nameof(name));
var workspace = await GetOrNullAsync(name);
if (workspace == null)
{
throw new AbpException("Undefined AITool: " + name);
}
return workspace;
}
public virtual async Task<IReadOnlyList<AIToolDefinition>> GetAllAsync()
{
var defs = await GetAIToolDefinitionsAsync();
return defs.Values.ToImmutableList();
}
public virtual async Task<AIToolDefinition?> GetOrNullAsync(string name)
{
var defs = await GetAIToolDefinitionsAsync();
return defs.GetOrDefault(name);
}
protected virtual async Task<Dictionary<string, AIToolDefinition>> GetAIToolDefinitionsAsync()
{
return await DefinitionCache.GetOrCreateAsync(CreateAIToolDefinitionsAsync);
}
protected virtual Task<Dictionary<string, AIToolDefinition>> CreateAIToolDefinitionsAsync()
{
var workspaces = new Dictionary<string, AIToolDefinition>();
using (var scope = ServiceProvider.CreateScope())
{
var providers = Options
.DefinitionProviders
.Select(p => scope.ServiceProvider.GetRequiredService(p) as IAIToolDefinitionProvider)
.ToList();
foreach (var provider in providers)
{
provider?.Define(new AIToolDefinitionContext(workspaces));
}
}
return Task.FromResult(workspaces);
}
}

19
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Timing/NowTimeTool.cs

@ -0,0 +1,19 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;
namespace LINGYUN.Abp.AI.Tools.Timing;
public class NowTimeTool : ITransientDependency
{
public const string Name = "GetNowTime";
private readonly IClock _clock;
public NowTimeTool(IClock clock)
{
_clock = clock;
}
public object? Invoke()
{
return _clock.Now;
}
}

21
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Users/CurrentUserTool.cs

@ -0,0 +1,21 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.Users;
namespace LINGYUN.Abp.AI.Tools.Users;
public class CurrentUserTool : ITransientDependency
{
public const string Name = "GetUserInfo";
private readonly ICurrentUser _currentUser;
public CurrentUserTool(ICurrentUser currentUser)
{
_currentUser = currentUser;
}
public object? Invoke()
{
return _currentUser;
}
}

79
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/README.md

@ -0,0 +1,79 @@
# LINGYUN.Abp.AI.Tools
AI 工具模块.
参考: [AI 工具调用](https://learn.microsoft.com/zh-cn/dotnet/ai/conceptual/ai-tools)
## 功能特性
## 模块引用
```csharp
[DependsOn(typeof(AbpAIToolsModule))]
public class YouProjectModule : AbpModule
{
// other
}
```
## 依赖模块
* [AbpAICoreModule](../LINGYUN.Abp.AI.Core)
## 自定义函数
> 注意: 自定义函数遵循一个约定: 同步工具需要定义一个名为 `Invoke` 的函数; 异步工具需要定义一个名为 `InvokeAsync` 的函数, 如需使用DI容器, 需要将工具注入到容器
```csharp
public class NowTimeTool : ITransientDependency
{
private readonly IClock _clock;
public NowTimeTool(IClock clock)
{
_clock = clock;
}
public object? Invoke()
{
return _clock.Now;
}
}
public class NowTimeAIToolDefinitionProvider : AIToolDefinitionProvider
{
context.Add(
new AIToolDefinition(
"GetNowTime",
FunctionAIToolProvider.ProviderName)
.WithFunction<NowTimeTool>());
}
```
## 扩展
实现 `IAIToolProvider` 接口, 以增加其他工具调用
实现 `IDynamicAIToolDefinitionStore` 接口, 以增加动态AI工具管理
```csharp
public class McpAIToolProvider : IAIToolProvider, ITransientDependency
{
public virtual AITool CreateTool(AIToolDefinition definition)
{
// 你的具体实现
}
}
[DependsOn(typeof(AbpAIToolsModule))]
public class YouProjectModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAIToolsOptions>(options =>
{
options.AIToolProviders.Add<McpAIToolProvider>();
});
}
}
```
Loading…
Cancel
Save