18 changed files with 608 additions and 1 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,31 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks> |
||||
|
<AssemblyName>LINGYUN.Abp.AI.Tools.Http</AssemblyName> |
||||
|
<PackageId>LINGYUN.Abp.AI.Tools.Http</PackageId> |
||||
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
||||
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
||||
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
||||
|
<Nullable>enable</Nullable> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<None Remove="LINGYUN\Abp\AI\Tools\Http\Localization\Resources\*.json" /> |
||||
|
<EmbeddedResource Include="LINGYUN\Abp\AI\Tools\Http\Localization\Resources\*.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Http.Client" /> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.Contracts" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.AI.Tools\LINGYUN.Abp.AI.Tools.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,42 @@ |
|||||
|
using LINGYUN.Abp.AI.Localization; |
||||
|
using LINGYUN.Abp.AI.Tools.Http.ApplicationConfigurations; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
using Volo.Abp.Http.Client; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Tools.Http; |
||||
|
|
||||
|
[DependsOn( |
||||
|
typeof(AbpAIToolsModule), |
||||
|
typeof(AbpHttpClientModule), |
||||
|
typeof(AbpAspNetCoreMvcContractsModule))] |
||||
|
public class AbpAIToolsHttpModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpAIToolsApplicationConfigurationOptions>(context.Configuration.GetSection("AITools:Http:ApplicationConfiguration")); |
||||
|
|
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpAIToolsHttpModule>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpAIToolsOptions>(options => |
||||
|
{ |
||||
|
// Http工具
|
||||
|
options.AIToolProviders.Add<HttpAIToolProvider>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources |
||||
|
.Get<AbpAIResource>() |
||||
|
.AddVirtualJson("/LINGYUN/Abp/AI/Tools/Http/Localization/Resources"); |
||||
|
}); |
||||
|
|
||||
|
context.Services.AddHttpAIToolClient(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Net.Http; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Tools.Http; |
||||
|
public class AbpAIToolsHttpOptiions |
||||
|
{ |
||||
|
public List<Action<IHttpClientBuilder>> ClientBuildActions { get; } |
||||
|
|
||||
|
public List<Action<IServiceProvider, HttpClient>> ClientActions { get; } |
||||
|
|
||||
|
public List<Action<IServiceProvider, HttpClientHandler>> ClientHandlerActions { get; } |
||||
|
/// <summary>
|
||||
|
/// 自定义Http请求响应处理
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 参数1: HttpAITool工具名称
|
||||
|
/// 参数2: IServiceProvider
|
||||
|
/// 参数3: 请求响应
|
||||
|
/// </remarks>
|
||||
|
public IDictionary<string, Func<IServiceProvider, HttpResponseMessage, Task<object>>> HttpResponseActions { get; } |
||||
|
public AbpAIToolsHttpOptiions() |
||||
|
{ |
||||
|
ClientBuildActions = new List<Action<IHttpClientBuilder>>(); |
||||
|
ClientActions = new List<Action<IServiceProvider, HttpClient>>(); |
||||
|
ClientHandlerActions = new List<Action<IServiceProvider, HttpClientHandler>>(); |
||||
|
HttpResponseActions = new Dictionary<string, Func<IServiceProvider, HttpResponseMessage, Task<object>>>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
namespace LINGYUN.Abp.AI.Tools.Http.ApplicationConfigurations; |
||||
|
public class AbpAIToolsApplicationConfigurationOptions |
||||
|
{ |
||||
|
public bool IsEnabled { get; set; } |
||||
|
public string EndPoint { get; set; } |
||||
|
public AbpAIToolsApplicationConfigurationOptions() |
||||
|
{ |
||||
|
IsEnabled = false; |
||||
|
EndPoint = "http://localhost:8080/api/abp/application-configuration"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
using LINGYUN.Abp.AI.Localization; |
||||
|
using LINGYUN.Abp.AI.Tools.Http.ApplicationConfigurations; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System.Net.Http; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Tools.Http; |
||||
|
public class GlobalHttpAIToolDefinitionProvider : AIToolDefinitionProvider |
||||
|
{ |
||||
|
protected AbpAIToolsApplicationConfigurationOptions Options { get; } |
||||
|
public GlobalHttpAIToolDefinitionProvider(IOptions<AbpAIToolsApplicationConfigurationOptions> options) |
||||
|
{ |
||||
|
Options = options.Value; |
||||
|
} |
||||
|
|
||||
|
public override void Define(IAIToolDefinitionContext context) |
||||
|
{ |
||||
|
if (Options.IsEnabled) |
||||
|
{ |
||||
|
context.Add( |
||||
|
new AIToolDefinition( |
||||
|
"GetApplicationConfiguration", |
||||
|
HttpAIToolProvider.ProviderName, |
||||
|
L("Tools:GetApplicationConfiguration")) |
||||
|
.WithHttpEndpoint(Options.EndPoint) |
||||
|
.WithHttpMethod(HttpMethod.Get) |
||||
|
.WithHttpHeaders("_AbpDontWrapResult", "true")// 无需包装结果
|
||||
|
.UseHttpCurrentAccessToken()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static LocalizableString L(string name) |
||||
|
{ |
||||
|
return LocalizableString.Create<AbpAIResource>(name); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,136 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.Globalization; |
||||
|
using System.Net.Http; |
||||
|
using System.Net.Http.Headers; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Http.Client.Authentication; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using Volo.Abp.Timing; |
||||
|
using Volo.Abp.Tracing; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Tools.Http; |
||||
|
public class HttpAITool |
||||
|
{ |
||||
|
protected HttpAIToolInvokeContext Context { get; } |
||||
|
|
||||
|
public HttpAITool(HttpAIToolInvokeContext context) |
||||
|
{ |
||||
|
Context = context; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<object?> InvokeAsync() |
||||
|
{ |
||||
|
// Abp远程服务适配
|
||||
|
//var remoteService = Context.ToolDefinition.GetRemoteServiceOrNull();
|
||||
|
//var remoteMethod = Context.ToolDefinition.GetRemoteMethodOrNull();
|
||||
|
//if (!remoteService.IsNullOrWhiteSpace() && !remoteMethod.IsNullOrWhiteSpace())
|
||||
|
//{
|
||||
|
// var abpHttpClientOptions = Context.ServiceProvider.GetRequiredService<IOptions<AbpHttpClientOptions>>().Value;
|
||||
|
// HttpClientProxyConfig? clientProxyConfig = null;
|
||||
|
|
||||
|
// foreach (var httpClientProxyConfig in abpHttpClientOptions.HttpClientProxies.Values)
|
||||
|
// {
|
||||
|
// if (httpClientProxyConfig.RemoteServiceName.Equals(remoteService))
|
||||
|
// {
|
||||
|
// clientProxyConfig = httpClientProxyConfig;
|
||||
|
// continue;
|
||||
|
// }
|
||||
|
// }
|
||||
|
|
||||
|
// if (clientProxyConfig != null)
|
||||
|
// {
|
||||
|
// // var serviceType = clientProxyConfig.Type.GetProperty(nameof(IHttpClientProxy<object>.Service));
|
||||
|
// var serviceMethod = clientProxyConfig.Type.GetMethod(remoteMethod);
|
||||
|
// if (serviceMethod != null)
|
||||
|
// {
|
||||
|
// var httpClientProxyType = typeof(IHttpClientProxy<>).MakeGenericType(clientProxyConfig.Type);
|
||||
|
// var httpClientProxy = Context.ServiceProvider.GetRequiredService(httpClientProxyType);
|
||||
|
// var service = httpClientProxyType.GetProperty(nameof(IHttpClientProxy<object>.Service))!.GetValue(httpClientProxy);
|
||||
|
// // TODO: 暂不支持有参远程服务调用
|
||||
|
// var task = (Task)serviceMethod.Invoke(service, null)!;
|
||||
|
// await task;
|
||||
|
// // TODO: 必须为Task<XXX>返回结构
|
||||
|
// return typeof(Task<>).MakeGenericType(serviceMethod.ReturnType.GenericTypeArguments[0])
|
||||
|
// .GetProperty(nameof(Task<object>.Result), BindingFlags.Public | BindingFlags.Instance)!
|
||||
|
// .GetValue(task);
|
||||
|
// }
|
||||
|
// }
|
||||
|
//}
|
||||
|
|
||||
|
var options = Context.ServiceProvider.GetRequiredService<IOptions<AbpAIToolsHttpOptiions>>().Value; |
||||
|
var httpClientFactory = Context.ServiceProvider.GetRequiredService<IHttpClientFactory>(); |
||||
|
var httpClient = httpClientFactory.GetHttpAIToolClient(); |
||||
|
|
||||
|
var httpRequestMessage = new HttpRequestMessage( |
||||
|
Context.ToolDefinition.GetHttpMethod(), |
||||
|
Context.ToolDefinition.GetHttpEndpoint()); |
||||
|
|
||||
|
var headers = Context.ToolDefinition.GetHttpHeaders(); |
||||
|
foreach (var header in headers) |
||||
|
{ |
||||
|
httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value); |
||||
|
} |
||||
|
|
||||
|
if (Context.ToolDefinition.IsUseHttpCurrentAccessToken()) |
||||
|
{ |
||||
|
var accessTokenProvider = Context.ServiceProvider.GetRequiredService<IAbpAccessTokenProvider>(); |
||||
|
|
||||
|
var token = await accessTokenProvider.GetTokenAsync(); |
||||
|
if (!token.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
AddDefaultHeaders(httpRequestMessage); |
||||
|
|
||||
|
var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage); |
||||
|
|
||||
|
if (options.HttpResponseActions.TryGetValue(Context.ToolDefinition.Name, out var customHandler)) |
||||
|
{ |
||||
|
return await customHandler(Context.ServiceProvider, httpResponseMessage); |
||||
|
} |
||||
|
|
||||
|
return await httpResponseMessage.Content.ReadAsStringAsync(); |
||||
|
} |
||||
|
|
||||
|
protected virtual void AddDefaultHeaders(HttpRequestMessage requestMessage) |
||||
|
{ |
||||
|
//CorrelationId
|
||||
|
var correlationIdProvider = Context.ServiceProvider.GetRequiredService<ICorrelationIdProvider>(); |
||||
|
var correlationId = correlationIdProvider.Get(); |
||||
|
if (correlationId != null) |
||||
|
{ |
||||
|
var correlationIdOptions = Context.ServiceProvider.GetRequiredService<IOptions<AbpCorrelationIdOptions>>(); |
||||
|
requestMessage.Headers.Add(correlationIdOptions.Value.HttpHeaderName, correlationId); |
||||
|
} |
||||
|
|
||||
|
//TenantId
|
||||
|
var currentTenant = Context.ServiceProvider.GetRequiredService<ICurrentTenant>(); |
||||
|
if (currentTenant.Id.HasValue) |
||||
|
{ |
||||
|
//TODO: Use AbpAspNetCoreMultiTenancyOptions to get the key
|
||||
|
requestMessage.Headers.Add(TenantResolverConsts.DefaultTenantKey, currentTenant.Id.Value.ToString()); |
||||
|
} |
||||
|
|
||||
|
//Culture
|
||||
|
//TODO: Is that the way we want? Couldn't send the culture (not ui culture)
|
||||
|
var currentCulture = CultureInfo.CurrentUICulture.Name ?? CultureInfo.CurrentCulture.Name; |
||||
|
if (!currentCulture.IsNullOrEmpty()) |
||||
|
{ |
||||
|
requestMessage.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(currentCulture)); |
||||
|
} |
||||
|
|
||||
|
//X-Requested-With
|
||||
|
requestMessage.Headers.Add("X-Requested-With", "XMLHttpRequest"); |
||||
|
|
||||
|
//Timezone
|
||||
|
var currentTimezoneProvider = Context.ServiceProvider.GetRequiredService<ICurrentTimezoneProvider>(); |
||||
|
if (!currentTimezoneProvider.TimeZone.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
requestMessage.Headers.Add(TimeZoneConsts.DefaultTimeZoneKey, currentTimezoneProvider.TimeZone); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,150 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Net.Http; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Tools.Http; |
||||
|
public static class HttpAIToolDefinitionExtenssions |
||||
|
{ |
||||
|
private const string RemoteService = "RemoteService"; |
||||
|
private const string RemoteController = "RemoteController"; |
||||
|
private const string RemoteMethod = "RemoteMethod"; |
||||
|
|
||||
|
private const string Endpoint = "HttpEndpoint"; |
||||
|
private const string Method = "HttpMethod"; |
||||
|
private const string Headers = "HttpHeaders"; |
||||
|
|
||||
|
private const string CurrentAccessToken = "UseHttpCurrentAccessToken"; |
||||
|
|
||||
|
public static AIToolDefinition UseHttpCurrentAccessToken(this AIToolDefinition definition, bool useCurrentAccessToken = true) |
||||
|
{ |
||||
|
definition.WithProperty(CurrentAccessToken, useCurrentAccessToken); |
||||
|
|
||||
|
return definition; |
||||
|
} |
||||
|
|
||||
|
public static AIToolDefinition WithRemoteService(this AIToolDefinition definition, string service, string controllerName, string uniqueMethodName) |
||||
|
{ |
||||
|
Check.NotNullOrWhiteSpace(service, nameof(service)); |
||||
|
Check.NotNullOrWhiteSpace(controllerName, nameof(controllerName)); |
||||
|
Check.NotNullOrWhiteSpace(uniqueMethodName, nameof(uniqueMethodName)); |
||||
|
|
||||
|
definition.WithProperty(RemoteService, service); |
||||
|
definition.WithProperty(RemoteController, controllerName); |
||||
|
definition.WithProperty(RemoteMethod, uniqueMethodName); |
||||
|
|
||||
|
return definition; |
||||
|
} |
||||
|
|
||||
|
public static AIToolDefinition WithHttpEndpoint(this AIToolDefinition definition, string endPoint) |
||||
|
{ |
||||
|
Check.NotNullOrWhiteSpace(endPoint, nameof(endPoint)); |
||||
|
|
||||
|
definition.WithProperty(Endpoint, endPoint); |
||||
|
|
||||
|
return definition; |
||||
|
} |
||||
|
|
||||
|
public static AIToolDefinition WithHttpMethod(this AIToolDefinition definition, HttpMethod method) |
||||
|
{ |
||||
|
Check.NotNull(method, nameof(method)); |
||||
|
|
||||
|
definition.WithProperty(Method, method.Method); |
||||
|
|
||||
|
return definition; |
||||
|
} |
||||
|
|
||||
|
public static AIToolDefinition WithHttpHeaders(this AIToolDefinition definition, IDictionary<string, string> headers) |
||||
|
{ |
||||
|
Check.NotNullOrEmpty(headers, nameof(headers)); |
||||
|
|
||||
|
var currentHeaders = definition.GetHttpHeaders(); |
||||
|
|
||||
|
currentHeaders.AddIfNotContains(headers); |
||||
|
|
||||
|
definition.WithProperty(Headers, currentHeaders); |
||||
|
|
||||
|
return definition; |
||||
|
} |
||||
|
|
||||
|
public static AIToolDefinition WithHttpHeaders(this AIToolDefinition definition, string key, string value) |
||||
|
{ |
||||
|
Check.NotNullOrEmpty(key, nameof(key)); |
||||
|
Check.NotNullOrEmpty(value, nameof(value)); |
||||
|
|
||||
|
var currentHeaders = definition.GetHttpHeaders(); |
||||
|
|
||||
|
currentHeaders.TryAdd(key, value); |
||||
|
|
||||
|
definition.WithProperty(Headers, currentHeaders); |
||||
|
|
||||
|
return definition; |
||||
|
} |
||||
|
|
||||
|
public static bool IsUseHttpCurrentAccessToken(this AIToolDefinition definition) |
||||
|
{ |
||||
|
if (definition.Properties.TryGetValue(CurrentAccessToken, out var useCurrentAccessTokenObj) && useCurrentAccessTokenObj != null |
||||
|
&& bool.TryParse(useCurrentAccessTokenObj.ToString(), out var useCurrentAccessToken)) |
||||
|
{ |
||||
|
return useCurrentAccessToken; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public static string? GetRemoteServiceOrNull(this AIToolDefinition definition) |
||||
|
{ |
||||
|
definition.Properties.TryGetValue(RemoteService, out var remoteServiceObj); |
||||
|
|
||||
|
return remoteServiceObj?.ToString(); |
||||
|
} |
||||
|
|
||||
|
public static string? GetRemoteControllerOrNull(this AIToolDefinition definition) |
||||
|
{ |
||||
|
definition.Properties.TryGetValue(RemoteController, out var remoteControllerObj); |
||||
|
|
||||
|
return remoteControllerObj?.ToString(); |
||||
|
} |
||||
|
|
||||
|
public static string? GetRemoteMethodOrNull(this AIToolDefinition definition) |
||||
|
{ |
||||
|
definition.Properties.TryGetValue(RemoteMethod, out var remoteMethodObj); |
||||
|
|
||||
|
return remoteMethodObj?.ToString(); |
||||
|
} |
||||
|
|
||||
|
public static string GetHttpEndpoint(this AIToolDefinition definition) |
||||
|
{ |
||||
|
definition.Properties.TryGetValue(Endpoint, out var endpointObj); |
||||
|
|
||||
|
Check.NotNull(endpointObj, nameof(Endpoint)); |
||||
|
|
||||
|
return endpointObj.ToString()!; |
||||
|
} |
||||
|
|
||||
|
public static HttpMethod GetHttpMethod(this AIToolDefinition definition) |
||||
|
{ |
||||
|
if (definition.Properties.TryGetValue(Method, out var methodObj) && methodObj != null) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
return HttpMethod.Parse(methodObj.ToString()); |
||||
|
} |
||||
|
catch { } |
||||
|
} |
||||
|
|
||||
|
return HttpMethod.Get; |
||||
|
} |
||||
|
|
||||
|
public static IDictionary<string, string> GetHttpHeaders(this AIToolDefinition definition) |
||||
|
{ |
||||
|
if (definition.Properties.TryGetValue(Headers, out var headersObj) && headersObj != null) |
||||
|
{ |
||||
|
if (headersObj is IDictionary<string, string> h) |
||||
|
{ |
||||
|
return h; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return new Dictionary<string, string>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Tools.Http; |
||||
|
public class HttpAIToolInvokeContext |
||||
|
{ |
||||
|
public IServiceProvider ServiceProvider { get; } |
||||
|
public AIToolDefinition ToolDefinition { get; } |
||||
|
public HttpAIToolInvokeContext( |
||||
|
IServiceProvider serviceProvider, |
||||
|
AIToolDefinition toolDefinition) |
||||
|
{ |
||||
|
ServiceProvider = serviceProvider; |
||||
|
ToolDefinition = toolDefinition; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
using Microsoft.Extensions.AI; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AI.Tools.Http; |
||||
|
public class HttpAIToolProvider : IAIToolProvider, ITransientDependency |
||||
|
{ |
||||
|
public const string ProviderName = "Http"; |
||||
|
public string Name => ProviderName; |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
public HttpAIToolProvider(IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
ServiceProvider = serviceProvider; |
||||
|
} |
||||
|
|
||||
|
public virtual Task<AITool[]> CreateToolsAsync(AIToolDefinition definition) |
||||
|
{ |
||||
|
string? description = null; |
||||
|
if (definition.Description != null) |
||||
|
{ |
||||
|
var localizerFactory = ServiceProvider.GetRequiredService<IStringLocalizerFactory>(); |
||||
|
description = definition.Description.Localize(localizerFactory)?.Value; |
||||
|
} |
||||
|
|
||||
|
var httpAITool = AIFunctionFactory.Create( |
||||
|
method: typeof(HttpAITool).GetMethod(nameof(HttpAITool.InvokeAsync))!, |
||||
|
createInstanceFunc: (AIFunctionArguments args) => |
||||
|
{ |
||||
|
var context = new HttpAIToolInvokeContext( |
||||
|
args.Services ?? ServiceProvider, |
||||
|
definition); |
||||
|
|
||||
|
return new HttpAITool(context); |
||||
|
}, |
||||
|
options: new AIFunctionFactoryOptions |
||||
|
{ |
||||
|
Name = definition.Name, |
||||
|
Description = description, |
||||
|
AdditionalProperties = definition.Properties, |
||||
|
}); |
||||
|
|
||||
|
return Task.FromResult<AITool[]>([httpAITool]); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "en", |
||||
|
"texts": { |
||||
|
"Tools:GetApplicationConfiguration": "Get Application Configuration" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hans", |
||||
|
"texts": { |
||||
|
"Tools:GetApplicationConfiguration": "获取应用程序配置" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,48 @@ |
|||||
|
using LINGYUN.Abp.AI.Tools.Http; |
||||
|
using System.Net.Http; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace Microsoft.Extensions.DependencyInjection; |
||||
|
internal static class HttpClientHttpAIToolExtenssions |
||||
|
{ |
||||
|
private const string HttpAIToolClient = "__AbpAIHttpToolClient"; |
||||
|
public static IServiceCollection AddHttpAIToolClient(this IServiceCollection services) |
||||
|
{ |
||||
|
var preOptions = services.ExecutePreConfiguredActions<AbpAIToolsHttpOptiions>(); |
||||
|
|
||||
|
var clientBuilder = services.AddHttpClient(HttpAIToolClient, (provider, client) => |
||||
|
{ |
||||
|
foreach (var clientBuildAction in preOptions.ClientActions) |
||||
|
{ |
||||
|
clientBuildAction(provider, client); |
||||
|
} |
||||
|
}).ConfigurePrimaryHttpMessageHandler(provider => |
||||
|
{ |
||||
|
var handler = new HttpClientHandler(); |
||||
|
|
||||
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"))) |
||||
|
{ |
||||
|
handler.UseCookies = false; |
||||
|
} |
||||
|
|
||||
|
foreach (var handlerAction in preOptions.ClientHandlerActions) |
||||
|
{ |
||||
|
handlerAction(provider, handler); |
||||
|
} |
||||
|
|
||||
|
return handler; |
||||
|
}); |
||||
|
|
||||
|
foreach (var clientBuildAction in preOptions.ClientBuildActions) |
||||
|
{ |
||||
|
clientBuildAction(clientBuilder); |
||||
|
} |
||||
|
|
||||
|
return services; |
||||
|
} |
||||
|
|
||||
|
public static HttpClient GetHttpAIToolClient(this IHttpClientFactory httpClientFactory) |
||||
|
{ |
||||
|
return httpClientFactory.CreateClient(HttpAIToolClient); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue