Browse Source

feat: Introduce AI management for microservices

pull/1421/head
colin 1 week ago
parent
commit
ce7d9a6c12
  1. 53
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.DbMigrator/AIServiceDbMigratorHostedService.cs
  2. 13
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.DbMigrator/AIServiceDbMigratorModule.cs
  3. 3
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.DbMigrator/FodyWeavers.xml
  4. 40
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.DbMigrator/LINGYUN.Abp.MicroService.AIService.DbMigrator.csproj
  5. 43
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.DbMigrator/Program.cs
  6. 5
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.DbMigrator/appsettings.json
  7. 26
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/AIServiceDataSeeder.cs
  8. 44
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/AIServiceDbMigrationEventHandler.cs
  9. 36
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/AIServiceDbMigrationService.cs
  10. 32
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/AIServiceMigrationsDbContext.cs
  11. 28
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/AIServiceMigrationsDbContextFactory.cs
  12. 45
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/AIServiceMigrationsEntityFrameworkCoreModule.cs
  13. 3
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/FodyWeavers.xml
  14. 30
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/FodyWeavers.xsd
  15. 35
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore.csproj
  16. 303
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260127083027_Initial_AI_Service.Designer.cs
  17. 148
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260127083027_Initial_AI_Service.cs
  18. 300
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/AIServiceMigrationsDbContextModelSnapshot.cs
  19. 423
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/AIServiceModule.Configure.cs
  20. 103
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/AIServiceModule.cs
  21. 3
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/FodyWeavers.xml
  22. 71
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/LINGYUN.Abp.MicroService.AIService.csproj
  23. 99
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/Program.cs
  24. 12
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/Properties/launchSettings.json
  25. 35
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/TenantHeaderParamter.cs
  26. 116
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/appsettings.Development.json
  27. 91
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/appsettings.json
  28. 25
      aspnet-core/aspire/LINGYUN.Abp.MicroService.ApiGateway/yarp.json
  29. 12
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AppHost/AppHost.cs
  30. 2
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AppHost/LINGYUN.Abp.MicroService.AppHost.csproj

53
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.DbMigrator/AIServiceDbMigratorHostedService.cs

@ -0,0 +1,53 @@
using LINGYUN.Abp.MicroService.AIService.DbMigrator;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Data;
namespace LINGYUN.Abp.MicroService.AIService;
public class AIServiceDbMigratorHostedService : IHostedService
{
private readonly IHostApplicationLifetime _hostApplicationLifetime;
private readonly IConfiguration _configuration;
public AIServiceDbMigratorHostedService(
IHostApplicationLifetime hostApplicationLifetime,
IConfiguration configuration)
{
_hostApplicationLifetime = hostApplicationLifetime;
_configuration = configuration;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
using var application = await AbpApplicationFactory
.CreateAsync<AIServiceDbMigratorModule>(options =>
{
options.Services.ReplaceConfiguration(_configuration);
options.UseAutofac();
options.Services.AddLogging(c => c.AddSerilog());
options.AddDataMigrationEnvironment();
});
await application.InitializeAsync();
await application
.ServiceProvider
.GetRequiredService<AIServiceDbMigrationService>()
.CheckAndApplyDatabaseMigrationsAsync();
await application.ShutdownAsync();
_hostApplicationLifetime.StopApplication();
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}

13
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.DbMigrator/AIServiceDbMigratorModule.cs

@ -0,0 +1,13 @@
using Volo.Abp.Autofac;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.MicroService.AIService.DbMigrator;
[DependsOn(
typeof(AbpAutofacModule),
typeof(AIServiceMigrationsEntityFrameworkCoreModule)
)]
public class AIServiceDbMigratorModule : AbpModule
{
}

3
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.DbMigrator/FodyWeavers.xml

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

40
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.DbMigrator/LINGYUN.Abp.MicroService.AIService.DbMigrator.csproj

@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.secrets.props" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<RootNamespace>LINGYUN.Abp.MicroService.AIService</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Serilog.Extensions.Logging" />
<PackageReference Include="Serilog.Sinks.Async" />
<PackageReference Include="Serilog.Sinks.File" />
<PackageReference Include="Serilog.Sinks.Console" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="Volo.Abp.Autofac" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Logs\**" />
<Content Remove="Logs\**" />
<EmbeddedResource Remove="Logs\**" />
<None Remove="Logs\**" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore\LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

43
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.DbMigrator/Program.cs

@ -0,0 +1,43 @@
using LINGYUN.Abp.MicroService.AIService;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Events;
using System;
var defaultOutputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}";
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("Volo.Abp", LogEventLevel.Warning)
#if DEBUG
.MinimumLevel.Override("LINGYUN.Abp.MicroService.AIService", LogEventLevel.Debug)
#else
.MinimumLevel.Override("LINGYUN.Abp.MicroService.AIService", LogEventLevel.Information)
#endif
.Enrich.FromLogContext()
.WriteTo.Async(x => x.Console(outputTemplate: defaultOutputTemplate))
.WriteTo.Async(x => x.File("Logs/migrations.txt", outputTemplate: defaultOutputTemplate))
.CreateLogger();
try
{
var builder = Host.CreateDefaultBuilder(args)
.AddAppSettingsSecretsJson()
.ConfigureLogging((context, logging) => logging.ClearProviders())
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<AIServiceDbMigratorHostedService>();
});
await builder.RunConsoleAsync();
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly!");
}
finally
{
await Log.CloseAndFlushAsync();
}

5
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.DbMigrator/appsettings.json

@ -0,0 +1,5 @@
{
"ConnectionStrings": {
"Default": "Host=127.0.0.1;Database=abp;Username=postgres;Password=123456"
}
}

26
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/AIServiceDataSeeder.cs

@ -0,0 +1,26 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.MicroService.AIService;
public class AIServiceDataSeeder : ITransientDependency
{
protected ILogger<AIServiceDataSeeder> Logger { get; }
protected ICurrentTenant CurrentTenant { get; }
public AIServiceDataSeeder(
ICurrentTenant currentTenant)
{
CurrentTenant = currentTenant;
Logger = NullLogger<AIServiceDataSeeder>.Instance;
}
public virtual Task SeedAsync(DataSeedContext context)
{
return Task.CompletedTask;
}
}

44
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/AIServiceDbMigrationEventHandler.cs

@ -0,0 +1,44 @@
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DistributedLocking;
using Volo.Abp.EntityFrameworkCore.Migrations;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow;
namespace LINGYUN.Abp.MicroService.AIService;
public class AIServiceDbMigrationEventHandler : EfCoreDatabaseMigrationEventHandlerBase<AIServiceMigrationsDbContext>
{
protected AIServiceDataSeeder DataSeeder { get; }
public AIServiceDbMigrationEventHandler(
ICurrentTenant currentTenant,
IUnitOfWorkManager unitOfWorkManager,
ITenantStore tenantStore,
IAbpDistributedLock abpDistributedLock,
IDistributedEventBus distributedEventBus,
ILoggerFactory loggerFactory,
AIServiceDataSeeder dataSeeder)
: base(
ConnectionStringNameAttribute.GetConnStringName<AIServiceMigrationsDbContext>(),
currentTenant, unitOfWorkManager, tenantStore, abpDistributedLock, distributedEventBus, loggerFactory)
{
DataSeeder = dataSeeder;
}
protected async override Task AfterTenantCreated(TenantCreatedEto eventData, bool schemaMigrated)
{
// 新租户数据种子
var context = new DataSeedContext(eventData.Id);
if (eventData.Properties != null)
{
foreach (var property in eventData.Properties)
{
context.WithProperty(property.Key, property.Value);
}
}
await DataSeeder.SeedAsync(context);
}
}

36
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/AIServiceDbMigrationService.cs

@ -0,0 +1,36 @@
using LINGYUN.Abp.Data.DbMigrator;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DistributedLocking;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow;
namespace LINGYUN.Abp.MicroService.AIService;
public class AIServiceDbMigrationService : EfCoreRuntimeDbMigratorBase<AIServiceMigrationsDbContext>, ITransientDependency
{
protected AIServiceDataSeeder DataSeeder { get; }
public AIServiceDbMigrationService(
ICurrentTenant currentTenant,
IUnitOfWorkManager unitOfWorkManager,
IServiceProvider serviceProvider,
IAbpDistributedLock abpDistributedLock,
IDistributedEventBus distributedEventBus,
ILoggerFactory loggerFactory,
AIServiceDataSeeder dataSeeder)
: base(
ConnectionStringNameAttribute.GetConnStringName<AIServiceMigrationsDbContext>(),
unitOfWorkManager, serviceProvider, currentTenant, abpDistributedLock, distributedEventBus, loggerFactory)
{
DataSeeder = dataSeeder;
}
protected async override Task SeedAsync()
{
// DbMigrator迁移数据种子
await DataSeeder.SeedAsync(new DataSeedContext());
}
}

32
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/AIServiceMigrationsDbContext.cs

@ -0,0 +1,32 @@
using LINGYUN.Abp.AIManagement.Chats;
using LINGYUN.Abp.AIManagement.EntityFrameworkCore;
using LINGYUN.Abp.AIManagement.Tokens;
using LINGYUN.Abp.AIManagement.Workspaces;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
namespace LINGYUN.Abp.MicroService.AIService;
[ConnectionStringName("Default")]
public class AIServiceMigrationsDbContext :
AbpDbContext<AIServiceMigrationsDbContext>,
IAIManagementDbContext
{
public DbSet<WorkspaceDefinitionRecord> WorkspaceDefinitions { get; set; }
public DbSet<TextChatMessageRecord> TextChatMessageRecords { get; set; }
public DbSet<ConversationRecord> ConversationRecords { get; set; }
public DbSet<TokenUsageRecord> TokenUsageRecords { get; set; }
public AIServiceMigrationsDbContext(
DbContextOptions<AIServiceMigrationsDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ConfigureAIManagement();
}
}

28
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/AIServiceMigrationsDbContextFactory.cs

@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using System.IO;
namespace LINGYUN.Abp.MicroService.AIService;
public class AIServiceMigrationsDbContextFactory : IDesignTimeDbContextFactory<AIServiceMigrationsDbContext>
{
public AIServiceMigrationsDbContext CreateDbContext(string[] args)
{
var configuration = BuildConfiguration();
var connectionString = configuration.GetConnectionString("Default");
var builder = new DbContextOptionsBuilder<AIServiceMigrationsDbContext>()
.UseNpgsql(connectionString);
return new AIServiceMigrationsDbContext(builder!.Options);
}
private static IConfigurationRoot BuildConfiguration()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../LINGYUN.Abp.MicroService.AIService.DbMigrator/"))
.AddJsonFile("appsettings.json", optional: false);
return builder.Build();
}
}

45
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/AIServiceMigrationsEntityFrameworkCoreModule.cs

@ -0,0 +1,45 @@
using LINGYUN.Abp.AIManagement.EntityFrameworkCore;
using LINGYUN.Abp.Data.DbMigrator;
using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore;
using LINGYUN.Abp.Saas.EntityFrameworkCore;
using LINGYUN.Abp.TextTemplating.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.PostgreSql;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Modularity;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
namespace LINGYUN.Abp.MicroService.AIService;
[DependsOn(
typeof(AbpAIManagementEntityFrameworkCoreModule),
typeof(AbpSaasEntityFrameworkCoreModule),
typeof(AbpSettingManagementEntityFrameworkCoreModule),
typeof(AbpPermissionManagementEntityFrameworkCoreModule),
typeof(AbpFeatureManagementEntityFrameworkCoreModule),
typeof(AbpLocalizationManagementEntityFrameworkCoreModule),
typeof(AbpTextTemplatingEntityFrameworkCoreModule),
typeof(AbpEntityFrameworkCorePostgreSqlModule),
typeof(AbpDataDbMigratorModule)
)]
public class AIServiceMigrationsEntityFrameworkCoreModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
// https://www.npgsql.org/efcore/release-notes/6.0.html#opting-out-of-the-new-timestamp-mapping-logic
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAbpDbContext<AIServiceMigrationsDbContext>();
Configure<AbpDbContextOptions>(options =>
{
options.UseNpgsql();
});
}
}

3
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/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/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/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>

35
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore.csproj

@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<IsPackable>false</IsPackable>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>LINGYUN.Abp.MicroService.AIService</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Volo.Abp.EntityFrameworkCore.PostgreSql" />
<PackageReference Include="Volo.Abp.FeatureManagement.EntityFrameworkCore" />
<PackageReference Include="Volo.Abp.SettingManagement.EntityFrameworkCore" />
<PackageReference Include="Volo.Abp.PermissionManagement.EntityFrameworkCore" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\modules\ai\LINGYUN.Abp.AIManagement.EntityFrameworkCore\LINGYUN.Abp.AIManagement.EntityFrameworkCore.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\framework\common\LINGYUN.Abp.Data.DbMigrator\LINGYUN.Abp.Data.DbMigrator.csproj" />
<ProjectReference Include="..\..\modules\localization-management\LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore\LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\modules\saas\LINGYUN.Abp.Saas.EntityFrameworkCore\LINGYUN.Abp.Saas.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\modules\text-templating\LINGYUN.Abp.TextTemplating.EntityFrameworkCore\LINGYUN.Abp.TextTemplating.EntityFrameworkCore.csproj" />
</ItemGroup>
</Project>

303
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260127083027_Initial_AI_Service.Designer.cs

@ -0,0 +1,303 @@
// <auto-generated />
using System;
using LINGYUN.Abp.MicroService.AIService;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Volo.Abp.EntityFrameworkCore;
#nullable disable
namespace LINGYUN.Abp.MicroService.AIService.Migrations
{
[DbContext(typeof(AIServiceMigrationsDbContext))]
[Migration("20260127083027_Initial_AI_Service")]
partial class Initial_AI_Service
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql)
.HasAnnotation("ProductVersion", "10.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.ConversationRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<DateTime>("ExpiredAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<DateTime?>("UpdateAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.ToTable("AbpAIConversations", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.TextChatMessageRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<string>("Content")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<Guid?>("ConversationId")
.HasColumnType("uuid");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<DateTime?>("ReplyAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("ReplyMessage")
.HasColumnType("text");
b.Property<string>("Role")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.Property<string>("Workspace")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.HasKey("Id");
b.HasIndex("TenantId", "ConversationId");
b.ToTable("AbpAITextChatMessages", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Tokens.TokenUsageRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<long?>("CachedInputTokenCount")
.HasColumnType("bigint");
b.Property<Guid?>("ConversationId")
.HasColumnType("uuid");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<long?>("InputTokenCount")
.HasColumnType("bigint");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<Guid?>("MessageId")
.HasColumnType("uuid");
b.Property<long?>("OutputTokenCount")
.HasColumnType("bigint");
b.Property<long?>("ReasoningTokenCount")
.HasColumnType("bigint");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<long?>("TotalTokenCount")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("TenantId", "ConversationId");
b.ToTable("AbpAITokenUsages", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Workspaces.WorkspaceDefinitionRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("ApiBaseUrl")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ApiKey")
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("Description")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<float?>("FrequencyPenalty")
.HasColumnType("real");
b.Property<string>("Instructions")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<bool>("IsEnabled")
.HasColumnType("boolean");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<int?>("MaxOutputTokens")
.HasColumnType("integer");
b.Property<string>("ModelName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<float?>("PresencePenalty")
.HasColumnType("real");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("StateCheckers")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("SystemPrompt")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<float?>("Temperature")
.HasColumnType("real");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("AbpAIWorkspaceDefinitions", (string)null);
});
#pragma warning restore 612, 618
}
}
}

148
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260127083027_Initial_AI_Service.cs

@ -0,0 +1,148 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LINGYUN.Abp.MicroService.AIService.Migrations
{
/// <inheritdoc />
public partial class Initial_AI_Service : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AbpAIConversations",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
TenantId = table.Column<Guid>(type: "uuid", nullable: true),
Name = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
ExpiredAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
UpdateAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
CreationTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
CreatorId = table.Column<Guid>(type: "uuid", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
LastModifierId = table.Column<Guid>(type: "uuid", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpAIConversations", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpAITextChatMessages",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Content = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
ExtraProperties = table.Column<string>(type: "text", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "character varying(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
CreatorId = table.Column<Guid>(type: "uuid", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
LastModifierId = table.Column<Guid>(type: "uuid", nullable: true),
TenantId = table.Column<Guid>(type: "uuid", nullable: true),
Workspace = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
Role = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: true),
ConversationId = table.Column<Guid>(type: "uuid", nullable: true),
ReplyMessage = table.Column<string>(type: "text", nullable: true),
ReplyAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpAITextChatMessages", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpAITokenUsages",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
TenantId = table.Column<Guid>(type: "uuid", nullable: true),
MessageId = table.Column<Guid>(type: "uuid", nullable: true),
ConversationId = table.Column<Guid>(type: "uuid", nullable: true),
InputTokenCount = table.Column<long>(type: "bigint", nullable: true),
OutputTokenCount = table.Column<long>(type: "bigint", nullable: true),
TotalTokenCount = table.Column<long>(type: "bigint", nullable: true),
CachedInputTokenCount = table.Column<long>(type: "bigint", nullable: true),
ReasoningTokenCount = table.Column<long>(type: "bigint", nullable: true),
CreationTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
CreatorId = table.Column<Guid>(type: "uuid", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
LastModifierId = table.Column<Guid>(type: "uuid", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpAITokenUsages", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpAIWorkspaceDefinitions",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
Provider = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
ModelName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
DisplayName = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
Description = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
ApiKey = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
ApiBaseUrl = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
SystemPrompt = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true),
Instructions = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true),
Temperature = table.Column<float>(type: "real", nullable: true),
MaxOutputTokens = table.Column<int>(type: "integer", nullable: true),
FrequencyPenalty = table.Column<float>(type: "real", nullable: true),
PresencePenalty = table.Column<float>(type: "real", nullable: true),
IsEnabled = table.Column<bool>(type: "boolean", nullable: false),
StateCheckers = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
ExtraProperties = table.Column<string>(type: "text", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "character varying(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
CreatorId = table.Column<Guid>(type: "uuid", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
LastModifierId = table.Column<Guid>(type: "uuid", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpAIWorkspaceDefinitions", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_AbpAITextChatMessages_TenantId_ConversationId",
table: "AbpAITextChatMessages",
columns: new[] { "TenantId", "ConversationId" });
migrationBuilder.CreateIndex(
name: "IX_AbpAITokenUsages_TenantId_ConversationId",
table: "AbpAITokenUsages",
columns: new[] { "TenantId", "ConversationId" });
migrationBuilder.CreateIndex(
name: "IX_AbpAIWorkspaceDefinitions_Name",
table: "AbpAIWorkspaceDefinitions",
column: "Name",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AbpAIConversations");
migrationBuilder.DropTable(
name: "AbpAITextChatMessages");
migrationBuilder.DropTable(
name: "AbpAITokenUsages");
migrationBuilder.DropTable(
name: "AbpAIWorkspaceDefinitions");
}
}
}

300
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/AIServiceMigrationsDbContextModelSnapshot.cs

@ -0,0 +1,300 @@
// <auto-generated />
using System;
using LINGYUN.Abp.MicroService.AIService;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Volo.Abp.EntityFrameworkCore;
#nullable disable
namespace LINGYUN.Abp.MicroService.AIService.Migrations
{
[DbContext(typeof(AIServiceMigrationsDbContext))]
partial class AIServiceMigrationsDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql)
.HasAnnotation("ProductVersion", "10.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.ConversationRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<DateTime>("ExpiredAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<DateTime?>("UpdateAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.ToTable("AbpAIConversations", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.TextChatMessageRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<string>("Content")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<Guid?>("ConversationId")
.HasColumnType("uuid");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<DateTime?>("ReplyAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("ReplyMessage")
.HasColumnType("text");
b.Property<string>("Role")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.Property<string>("Workspace")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.HasKey("Id");
b.HasIndex("TenantId", "ConversationId");
b.ToTable("AbpAITextChatMessages", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Tokens.TokenUsageRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<long?>("CachedInputTokenCount")
.HasColumnType("bigint");
b.Property<Guid?>("ConversationId")
.HasColumnType("uuid");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<long?>("InputTokenCount")
.HasColumnType("bigint");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<Guid?>("MessageId")
.HasColumnType("uuid");
b.Property<long?>("OutputTokenCount")
.HasColumnType("bigint");
b.Property<long?>("ReasoningTokenCount")
.HasColumnType("bigint");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<long?>("TotalTokenCount")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("TenantId", "ConversationId");
b.ToTable("AbpAITokenUsages", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Workspaces.WorkspaceDefinitionRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("ApiBaseUrl")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ApiKey")
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("Description")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<float?>("FrequencyPenalty")
.HasColumnType("real");
b.Property<string>("Instructions")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<bool>("IsEnabled")
.HasColumnType("boolean");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<int?>("MaxOutputTokens")
.HasColumnType("integer");
b.Property<string>("ModelName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<float?>("PresencePenalty")
.HasColumnType("real");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("StateCheckers")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("SystemPrompt")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<float?>("Temperature")
.HasColumnType("real");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("AbpAIWorkspaceDefinitions", (string)null);
});
#pragma warning restore 612, 618
}
}
}

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

@ -0,0 +1,423 @@
using DotNetCore.CAP;
using LINGYUN.Abp.AIManagement;
using LINGYUN.Abp.AIManagement.Chats;
using LINGYUN.Abp.Localization.CultureMap;
using LINGYUN.Abp.LocalizationManagement;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
using LINGYUN.Abp.TextTemplating;
using LINGYUN.Abp.Wrapper;
using Medallion.Threading;
using Medallion.Threading.Redis;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Caching.StackExchangeRedis;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using StackExchange.Redis;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.AntiForgery;
using Volo.Abp.Auditing;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.FeatureManagement;
using Volo.Abp.GlobalFeatures;
using Volo.Abp.Http.Client;
using Volo.Abp.Identity.Localization;
using Volo.Abp.Json;
using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
using Volo.Abp.PermissionManagement;
using Volo.Abp.Security.Claims;
using Volo.Abp.SettingManagement;
using Volo.Abp.Threading;
using Volo.Abp.Timing;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.MicroService.AIService;
public partial class AIServiceModule
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
private void PreConfigureFeature()
{
OneTimeRunner.Run(() =>
{
GlobalFeatureManager.Instance.Modules.Editions().EnableAll();
});
}
private void PreConfigureApp(IConfiguration configuration)
{
PreConfigure<AbpSerilogEnrichersUniqueIdOptions>(options =>
{
// 以开放端口区别,应在0-31之间
options.SnowflakeIdOptions.WorkerId = 19;
options.SnowflakeIdOptions.WorkerIdBits = 5;
options.SnowflakeIdOptions.DatacenterId = 1;
});
if (configuration.GetValue<bool>("App:ShowPii"))
{
IdentityModelEventSource.ShowPII = true;
}
}
private void PreConfigureCAP(IConfiguration configuration)
{
PreConfigure<CapOptions>(options =>
{
options
.UsePostgreSql(mySqlOptions =>
{
configuration.GetSection("CAP:PostgreSql").Bind(mySqlOptions);
})
.UseRabbitMQ(rabbitMQOptions =>
{
configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions);
})
.UseDashboard();
});
}
private void ConfigureTextTemplating()
{
Configure<AbpTextTemplatingCachingOptions>(options =>
{
options.IsDynamicTemplateDefinitionStoreEnabled = true;
});
}
private void ConfigureFeatureManagement()
{
Configure<FeatureManagementOptions>(options =>
{
options.IsDynamicFeatureStoreEnabled = true;
});
}
private void ConfigureJsonSerializer(IConfiguration configuration)
{
// 统一时间日期格式
Configure<AbpJsonOptions>(options =>
{
var jsonConfiguration = configuration.GetSection("Json");
if (jsonConfiguration.Exists())
{
jsonConfiguration.Bind(options);
}
});
// 中文序列化的编码问题
Configure<AbpSystemTextJsonSerializerOptions>(options =>
{
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
});
}
private void ConfigureAIManagement()
{
Configure<AIManagementOptions>(options =>
{
options.IsDynamicWorkspaceStoreEnabled = true;
options.SaveStaticWorkspacesToDatabase = true;
});
}
private void ConfigurePermissionManagement()
{
Configure<PermissionManagementOptions>(options =>
{
options.IsDynamicPermissionStoreEnabled = true;
});
}
private void ConfigureSettingManagement()
{
Configure<SettingManagementOptions>(options =>
{
options.IsDynamicSettingStoreEnabled = true;
});
}
private void ConfigureTiming(IConfiguration configuration)
{
Configure<AbpClockOptions>(options =>
{
configuration.GetSection("Clock").Bind(options);
});
}
private void ConfigureCaching(IConfiguration configuration)
{
Configure<AbpDistributedCacheOptions>(options =>
{
configuration.GetSection("DistributedCache").Bind(options);
});
Configure<AbpDistributedEntityEventOptions>(options =>
{
options.AutoEventSelectors.AddNamespace("Volo.Abp.TenantManagement");
});
Configure<RedisCacheOptions>(options =>
{
var redisConfig = ConfigurationOptions.Parse(options.Configuration!);
options.ConfigurationOptions = redisConfig;
options.InstanceName = configuration["Redis:InstanceName"];
});
}
private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration)
{
var distributedLockEnabled = configuration["DistributedLock:IsEnabled"];
if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled))
{
services.AddSingleton<IDistributedLockProvider>(sp =>
{
var connectionMultiplexer = sp.GetRequiredService<IConnectionMultiplexer>();
return new RedisDistributedSynchronizationProvider(connectionMultiplexer.GetDatabase());
});
}
}
private void ConfigureMvc(IServiceCollection services, IConfiguration configuration)
{
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ExposeIntegrationServices = true;
});
}
private void ConfigureVirtualFileSystem()
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AIServiceModule>("LINGYUN.Abp.MicroService.AIService");
});
}
private void ConfigureMultiTenancy(IConfiguration configuration)
{
// 多租户
Configure<AbpMultiTenancyOptions>(options =>
{
options.IsEnabled = true;
});
var tenantResolveCfg = configuration.GetSection("App:Domains");
if (tenantResolveCfg.Exists())
{
Configure<AbpTenantResolveOptions>(options =>
{
var domains = tenantResolveCfg.Get<string[]>() ?? [];
foreach (var domain in domains)
{
options.AddDomainTenantResolver(domain);
}
});
}
}
private void ConfigureIdentity(IConfiguration configuration)
{
Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
options.IsDynamicClaimsEnabled = true;
options.RemoteRefreshUrl = configuration["App:RefreshClaimsUrl"] + options.RemoteRefreshUrl;
});
}
private void ConfigureAuditing(IConfiguration configuration)
{
Configure<AbpAuditingOptions>(options =>
{
// 是否启用实体变更记录
var allEntitiesSelectorIsEnabled = configuration["Auditing:AllEntitiesSelector"];
if (allEntitiesSelectorIsEnabled.IsNullOrWhiteSpace() ||
(bool.TryParse(allEntitiesSelectorIsEnabled, out var enabled) && enabled))
{
options.EntityHistorySelectors.AddAllEntities();
}
});
}
private void ConfigureSwagger(IServiceCollection services, IConfiguration configuration)
{
// Swagger
services.AddAbpSwaggerGenWithOAuth(
configuration["AuthServer:Authority"]!,
new Dictionary<string, string>
{
{ "AIService", "AI Service API"}
},
options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "AI Service API", Version = "v1",
Contact = new OpenApiContact
{
Name = "colin",
Email = "colin.in@foxmail.com",
Url = new Uri("https://github.com/colinin")
},
License = new OpenApiLicense
{
Name = "MIT",
Url = new Uri("https://github.com/colinin/abp-next-admin/blob/master/LICENSE")
}
});
options.DocInclusionPredicate((docName, description) => true);
options.CustomSchemaIds(type => type.FullName);
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Scheme = "bearer",
Type = SecuritySchemeType.Http,
BearerFormat = "JWT"
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
},
new string[] { }
}
});
options.OperationFilter<TenantHeaderParamter>();
});
}
private void ConfigureLocalization()
{
// 支持本地化语言类型
Configure<AbpLocalizationOptions>(options =>
{
options.Languages.Add(new LanguageInfo("en", "en", "English"));
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
options.Resources
.Get<IdentityResource>()
.AddVirtualJson("/Localization/Resources");
});
Configure<AbpLocalizationCultureMapOptions>(options =>
{
var zhHansCultureMapInfo = new CultureMapInfo
{
TargetCulture = "zh-Hans",
SourceCultures = new string[] { "zh", "zh_CN", "zh-CN" }
};
options.CulturesMaps.Add(zhHansCultureMapInfo);
options.UiCulturesMaps.Add(zhHansCultureMapInfo);
});
Configure<AbpLocalizationManagementOptions>(options =>
{
options.SaveStaticLocalizationsToDatabase = true;
});
}
private void ConfigureCors(IServiceCollection services, IConfiguration configuration)
{
services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
var corsOrigins = configuration.GetSection("App:CorsOrigins").Get<List<string>>();
if (corsOrigins == null || corsOrigins.Count == 0)
{
corsOrigins = configuration["App:CorsOrigins"]?
.Split(",", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.RemovePostFix("/"))
.ToList() ?? new List<string>();
}
builder
.WithOrigins(corsOrigins
.Select(o => o.RemovePostFix("/"))
.ToArray()
)
.WithAbpExposedHeaders()
.WithAbpWrapExposedHeaders()
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
}
private void ConfigureSecurity(IServiceCollection services, IConfiguration configuration, bool isDevelopment = false)
{
Configure<AbpAntiForgeryOptions>(options =>
{
options.TokenCookie.HttpOnly = false;
options.TokenCookie.SameSite = SameSiteMode.Lax;
});
services.AddAlwaysAllowAuthorization();
services.AddAlwaysAllowSession();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddAbpJwtBearer(options =>
{
configuration.GetSection("AuthServer").Bind(options);
var validIssuers = configuration.GetSection("AuthServer:ValidIssuers").Get<List<string>>();
if (validIssuers?.Count > 0)
{
options.TokenValidationParameters.ValidIssuers = validIssuers;
options.TokenValidationParameters.IssuerValidator = TokenWildcardIssuerValidator.IssuerValidator;
}
var validAudiences = configuration.GetSection("AuthServer:ValidAudiences").Get<List<string>>();
if (validAudiences?.Count > 0)
{
options.TokenValidationParameters.ValidAudiences = validAudiences;
}
});
services
.AddDataProtection()
.SetApplicationName("LINGYUN.Abp.Application")
.PersistKeysToStackExchangeRedis(() =>
{
var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!);
return redis.GetDatabase();
},
"LINGYUN.Abp.Application:DataProtection:Protection-Keys");
}
private void ConfigureWrapper()
{
Configure<AbpWrapperOptions>(options =>
{
options.IsEnabled = true;
options.IgnoreControllers.Add<ChatController>();
});
}
private void PreConfigureWrapper()
{
// 服务间调用不包装
PreConfigure<AbpHttpClientBuilderOptions>(options =>
{
options.ProxyClientActions.Add(
(_, _, client) =>
{
client.DefaultRequestHeaders.TryAddWithoutValidation(AbpHttpWrapConsts.AbpDontWrapResult, "true");
});
});
}
}

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

@ -0,0 +1,103 @@
using LINGYUN.Abp.AIManagement;
using LINGYUN.Abp.AspNetCore.HttpOverrides;
using LINGYUN.Abp.AspNetCore.Mvc.Localization;
using LINGYUN.Abp.AspNetCore.Mvc.Wrapper;
using LINGYUN.Abp.AuditLogging.Elasticsearch;
using LINGYUN.Abp.Claims.Mapping;
using LINGYUN.Abp.Data.DbMigrator;
using LINGYUN.Abp.Emailing.Platform;
using LINGYUN.Abp.EventBus.CAP;
using LINGYUN.Abp.ExceptionHandling.Emailing;
using LINGYUN.Abp.Identity.Session.AspNetCore;
using LINGYUN.Abp.Localization.CultureMap;
using LINGYUN.Abp.Logging.Serilog.Elasticsearch;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
using LINGYUN.Abp.Sms.Platform;
using LINGYUN.Abp.TextTemplating.Scriban;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Autofac;
using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
using Volo.Abp.PermissionManagement.Identity;
using Volo.Abp.PermissionManagement.OpenIddict;
using Volo.Abp.Swashbuckle;
namespace LINGYUN.Abp.MicroService.AIService;
[DependsOn(
typeof(AbpCAPEventBusModule),
typeof(AbpSerilogEnrichersApplicationModule),
typeof(AbpSerilogEnrichersUniqueIdModule),
typeof(AbpAspNetCoreSerilogModule),
typeof(AbpLoggingSerilogElasticsearchModule),
typeof(AbpAuditLoggingElasticsearchModule),
typeof(AbpAspNetCoreMvcUiMultiTenancyModule),
typeof(AbpAspNetCoreMvcLocalizationModule),
typeof(AbpPermissionManagementDomainIdentityModule),
typeof(AbpPermissionManagementDomainOpenIddictModule),
// 重写模板引擎支持外部本地化
typeof(AbpTextTemplatingScribanModule),
typeof(AbpIdentitySessionAspNetCoreModule),
typeof(AbpAIManagementApplicationModule),
typeof(AbpAIManagementHttpApiModule),
typeof(AIServiceMigrationsEntityFrameworkCoreModule),
typeof(AbpDataDbMigratorModule),
typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
typeof(AbpEmailingExceptionHandlingModule),
typeof(AbpHttpClientModule),
typeof(AbpSmsPlatformModule),
typeof(AbpEmailingPlatformModule),
typeof(AbpCachingStackExchangeRedisModule),
typeof(AbpLocalizationCultureMapModule),
typeof(AbpAspNetCoreMvcWrapperModule),
typeof(AbpAspNetCoreHttpOverridesModule),
typeof(AbpClaimsMappingModule),
typeof(AbpSwashbuckleModule),
typeof(AbpAutofacModule)
)]
public partial class AIServiceModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
PreConfigureWrapper();
PreConfigureFeature();
PreConfigureApp(configuration);
PreConfigureCAP(configuration);
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();
ConfigureWrapper();
ConfigureLocalization();
ConfigureVirtualFileSystem();
ConfigureTextTemplating();
ConfigureAIManagement();
ConfigureSettingManagement();
ConfigureFeatureManagement();
ConfigurePermissionManagement();
ConfigureIdentity(configuration);
ConfigureTiming(configuration);
ConfigureCaching(configuration);
ConfigureAuditing(configuration);
ConfigureMultiTenancy(configuration);
ConfigureJsonSerializer(configuration);
ConfigureMvc(context.Services, configuration);
ConfigureCors(context.Services, configuration);
ConfigureSwagger(context.Services, configuration);
ConfigureDistributedLocking(context.Services, configuration);
ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment());
}
}

3
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/FodyWeavers.xml

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

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

@ -0,0 +1,71 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>LINGYUN.Abp.MicroService.AIService</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AgileConfig.Client" />
<PackageReference Include="DotNetCore.CAP.Dashboard" />
<PackageReference Include="DotNetCore.CAP.PostgreSql" />
<PackageReference Include="DotNetCore.CAP.RabbitMQ" />
<PackageReference Include="DistributedLock.Redis" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" />
<PackageReference Include="Serilog.AspNetCore" />
<PackageReference Include="Serilog.Enrichers.Environment" />
<PackageReference Include="Serilog.Enrichers.Assembly" />
<PackageReference Include="Serilog.Enrichers.Process" />
<PackageReference Include="Serilog.Enrichers.Thread" />
<PackageReference Include="Serilog.Settings.Configuration" />
<PackageReference Include="Serilog.Sinks.Async" />
<PackageReference Include="Serilog.Sinks.Elasticsearch" />
<PackageReference Include="Serilog.Sinks.File" />
<PackageReference Include="Volo.Abp.Caching.StackExchangeRedis" />
<PackageReference Include="Volo.Abp.AspNetCore.Serilog" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy" />
<PackageReference Include="Volo.Abp.AspNetCore.Authentication.JwtBearer" />
<PackageReference Include="Volo.Abp.Autofac" />
<PackageReference Include="Volo.Abp.FeatureManagement.Application" />
<PackageReference Include="Volo.Abp.FeatureManagement.HttpApi" />
<PackageReference Include="Volo.Abp.Http.Client" />
<PackageReference Include="Volo.Abp.PermissionManagement.Application" />
<PackageReference Include="Volo.Abp.PermissionManagement.Domain.Identity" />
<PackageReference Include="Volo.Abp.PermissionManagement.Domain.OpenIddict" />
<PackageReference Include="Volo.Abp.PermissionManagement.HttpApi" />
<PackageReference Include="Volo.Abp.Swashbuckle" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\framework\auditing\LINGYUN.Abp.AuditLogging.Elasticsearch\LINGYUN.Abp.AuditLogging.Elasticsearch.csproj" />
<ProjectReference Include="..\..\framework\common\LINGYUN.Abp.AspNetCore.HttpOverrides\LINGYUN.Abp.AspNetCore.HttpOverrides.csproj" />
<ProjectReference Include="..\..\framework\common\LINGYUN.Abp.Data.DbMigrator\LINGYUN.Abp.Data.DbMigrator.csproj" />
<ProjectReference Include="..\..\framework\common\LINGYUN.Abp.EventBus.CAP\LINGYUN.Abp.EventBus.CAP.csproj" />
<ProjectReference Include="..\..\framework\common\LINGYUN.Abp.ExceptionHandling.Emailing\LINGYUN.Abp.ExceptionHandling.Emailing.csproj" />
<ProjectReference Include="..\..\framework\features\LINGYUN.Abp.FeatureManagement.Client\LINGYUN.Abp.FeatureManagement.Client.csproj" />
<ProjectReference Include="..\..\framework\localization\LINGYUN.Abp.AspNetCore.Mvc.Localization\LINGYUN.Abp.AspNetCore.Mvc.Localization.csproj" />
<ProjectReference Include="..\..\framework\localization\LINGYUN.Abp.Localization.CultureMap\LINGYUN.Abp.Localization.CultureMap.csproj" />
<ProjectReference Include="..\..\framework\logging\LINGYUN.Abp.Logging.Serilog.Elasticsearch\LINGYUN.Abp.Logging.Serilog.Elasticsearch.csproj" />
<ProjectReference Include="..\..\framework\logging\LINGYUN.Abp.Serilog.Enrichers.Application\LINGYUN.Abp.Serilog.Enrichers.Application.csproj" />
<ProjectReference Include="..\..\framework\logging\LINGYUN.Abp.Serilog.Enrichers.UniqueId\LINGYUN.Abp.Serilog.Enrichers.UniqueId.csproj" />
<ProjectReference Include="..\..\framework\mvc\LINGYUN.Abp.AspNetCore.Mvc.Wrapper\LINGYUN.Abp.AspNetCore.Mvc.Wrapper.csproj" />
<ProjectReference Include="..\..\framework\security\LINGYUN.Abp.Claims.Mapping\LINGYUN.Abp.Claims.Mapping.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore\LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore.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" />
<ProjectReference Include="..\..\modules\platform\LINGYUN.Abp.Emailing.Platform\LINGYUN.Abp.Emailing.Platform.csproj" />
<ProjectReference Include="..\..\modules\platform\LINGYUN.Abp.Sms.Platform\LINGYUN.Abp.Sms.Platform.csproj" />
<ProjectReference Include="..\..\modules\text-templating\LINGYUN.Abp.TextTemplating.Scriban\LINGYUN.Abp.TextTemplating.Scriban.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.MicroService.ServiceDefaults\LINGYUN.Abp.MicroService.ServiceDefaults.csproj" />
</ItemGroup>
</Project>

99
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/Program.cs

@ -0,0 +1,99 @@
using LINGYUN.Abp.Identity.Session.AspNetCore;
using LINGYUN.Abp.MicroService.AIService;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using Serilog;
using Volo.Abp.IO;
using Volo.Abp.Modularity.PlugIns;
Log.Information("Starting AIService Host...");
try
{
var builder = WebApplication.CreateBuilder(args);
builder.Host.AddAppSettingsSecretsJson()
.UseAutofac()
.ConfigureAppConfiguration((context, config) =>
{
if (context.Configuration.GetValue("AgileConfig:IsEnabled", false))
{
config.AddAgileConfig(new AgileConfig.Client.ConfigClient(context.Configuration));
}
})
.UseSerilog((context, provider, config) =>
{
config.ReadFrom.Configuration(context.Configuration);
});
builder.AddServiceDefaults();
await builder.AddApplicationAsync<AIServiceModule>(options =>
{
var applicationName = Environment.GetEnvironmentVariable("APPLICATION_NAME") ?? "AIService";
options.ApplicationName = applicationName;
AbpSerilogEnrichersConsts.ApplicationName = applicationName;
var pluginFolder = Path.Combine(Directory.GetCurrentDirectory(), "Modules");
DirectoryHelper.CreateIfNotExists(pluginFolder);
options.PlugInSources.AddFolder(pluginFolder, SearchOption.AllDirectories);
});
var app = builder.Build();
await app.InitializeApplicationAsync();
app.MapDefaultEndpoints();
app.UseForwardedHeaders();
// 本地化
app.UseMapRequestLocalization();
// http调用链
app.UseCorrelationId();
// 文件系统
app.MapAbpStaticAssets();
// 路由
app.UseRouting();
// 跨域
app.UseCors();
// 认证
app.UseAuthentication();
app.UseJwtTokenMiddleware();
// 多租户
app.UseMultiTenancy();
// 会话
app.UseAbpSession();
// jwt
app.UseDynamicClaims();
// 授权
app.UseAuthorization();
// Swagger
app.UseSwagger();
// Swagger可视化界面
app.UseAbpSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support AI Service API");
var configuration = app.Configuration;
options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);
options.OAuthScopes(configuration["AuthServer:Audience"]);
});
// 审计日志
app.UseAuditing();
app.UseAbpSerilogEnrichers();
// 路由
app.UseConfiguredEndpoints();
await app.RunAsync();
}
catch (Exception ex)
{
if (ex is HostAbortedException)
{
throw;
}
Log.Fatal(ex, "Host terminated unexpectedly!");
}
finally
{
await Log.CloseAndFlushAsync();
}

12
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/Properties/launchSettings.json

@ -0,0 +1,12 @@
{
"profiles": {
"LINGYUN.Abp.MicroService.AIService": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:49787;http://localhost:49788"
}
}
}

35
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/TenantHeaderParamter.cs

@ -0,0 +1,35 @@
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.MicroService.AIService;
public class TenantHeaderParamter : IOperationFilter
{
private readonly AbpMultiTenancyOptions _multiTenancyOptions;
private readonly AbpAspNetCoreMultiTenancyOptions _aspNetCoreMultiTenancyOptions;
public TenantHeaderParamter(
IOptions<AbpMultiTenancyOptions> multiTenancyOptions,
IOptions<AbpAspNetCoreMultiTenancyOptions> aspNetCoreMultiTenancyOptions)
{
_multiTenancyOptions = multiTenancyOptions.Value;
_aspNetCoreMultiTenancyOptions = aspNetCoreMultiTenancyOptions.Value;
}
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (_multiTenancyOptions.IsEnabled)
{
operation.Parameters = operation.Parameters ?? new List<OpenApiParameter>();
operation.Parameters.Add(new OpenApiParameter
{
Name = _aspNetCoreMultiTenancyOptions.TenantKey,
In = ParameterLocation.Header,
Description = "Tenant Id in http header",
Required = false
});
}
}
}

116
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/appsettings.Development.json

@ -0,0 +1,116 @@
{
"App": {
"ShowPii": true,
"CorsOrigins": [ "http://localhost:5666", "http://localhost:30000" ],
"RefreshClaimsUrl": "http://localhost:30015"
},
"Auditing": {
"AllEntitiesSelector": true
},
"DistributedCache": {
"HideErrors": true,
"KeyPrefix": "LINGYUN.Abp.Application",
"GlobalCacheEntryOptions": {
"SlidingExpiration": "30:00:00",
"AbsoluteExpirationRelativeToNow": "60:00:00"
}
},
"ConnectionStrings": {
"Default": "Host=127.0.0.1;Database=abp;Username=postgres;Password=123456"
},
"CAP": {
"EventBus": {
"DefaultGroupName": "AIService",
"Version": "v1",
"FailedRetryInterval": 300,
"FailedRetryCount": 10,
"CollectorCleaningInterval": 3600000
},
"PostgreSql": {
"TableNamePrefix": "admin",
"ConnectionString": "Host=127.0.0.1;Database=abp;Username=postgres;Password=123456"
},
"RabbitMQ": {
"HostName": "localhost",
"Port": 5672,
"UserName": "admin",
"Password": "123456",
"ExchangeName": "LINGYUN.Abp.Application",
"VirtualHost": "/"
}
},
"DistributedLock": {
"IsEnabled": true,
"Redis": {
"Configuration": "localhost,defaultDatabase=13"
}
},
"Redis": {
"Configuration": "localhost,defaultDatabase=10",
"InstanceName": "LINGYUN.Abp.Application"
},
"AuthServer": {
"Authority": "http://localhost:44385/",
"Audience": "admin-service",
"ValidAudiences": [ "lingyun-abp-application" ],
"MapInboundClaims": false,
"RequireHttpsMetadata": false,
"SwaggerClientId": "vue-oauth-client"
},
"RemoteServices": {
"Platform": {
"BaseUrl": "http://localhost:30025",
"UseCurrentAccessToken": false
}
},
"Logging": {
"Serilog": {
"Elasticsearch": {
"IndexFormat": "abp.dev.logging-{0:yyyy.MM.dd}"
}
}
},
"AuditLogging": {
"Elasticsearch": {
"IndexPrefix": "abp.dev.auditing"
}
},
"Elasticsearch": {
"NodeUris": "http://elasticsearch"
},
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"System": "Warning",
"Microsoft": "Warning",
"DotNetCore": "Debug"
}
},
"WriteTo": [
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "Console",
"Args": {
"restrictedToMinimumLevel": "Debug",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}"
}
},
{
"Name": "Elasticsearch",
"Args": {
"nodeUris": "http://elasticsearch",
"indexFormat": "abp.dev.logging-{0:yyyy.MM.dd}",
"autoRegisterTemplate": true,
"autoRegisterTemplateVersion": "ESv7"
}
}
]
}
}
]
}
}

91
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/appsettings.json

@ -0,0 +1,91 @@
{
"Clock": {
"Kind": "Local"
},
"Forwarded": {
"ForwardedHeaders": "XForwardedFor,XForwardedProto"
},
"StringEncryption": {
"DefaultPassPhrase": "s46c5q55nxpeS8Ra",
"InitVectorBytes": "s83ng0abvd02js84",
"DefaultSalt": "sf&5)s3#"
},
"Json": {
"InputDateTimeFormats": [
"yyyy-MM-dd HH:mm:ss",
"yyyy-MM-ddTHH:mm:ss"
]
},
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"System": "Warning",
"Microsoft": "Warning",
"DotNetCore": "Information"
}
},
"Enrich": [ "FromLogContext", "WithProcessId", "WithThreadId", "WithEnvironmentName", "WithMachineName", "WithApplicationName", "WithUniqueId" ],
"WriteTo": [
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "Console",
"Args": {
"restrictedToMinimumLevel": "Debug",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "Logs/Debug-.log",
"restrictedToMinimumLevel": "Debug",
"rollingInterval": "Day",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "Logs/Info-.log",
"restrictedToMinimumLevel": "Information",
"rollingInterval": "Day",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "Logs/Warn-.log",
"restrictedToMinimumLevel": "Warning",
"rollingInterval": "Day",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "Logs/Error-.log",
"restrictedToMinimumLevel": "Error",
"rollingInterval": "Day",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "Logs/Fatal-.log",
"restrictedToMinimumLevel": "Fatal",
"rollingInterval": "Day",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}"
}
}
]
}
}
]
}
}

25
aspnet-core/aspire/LINGYUN.Abp.MicroService.ApiGateway/yarp.json

@ -1,6 +1,21 @@
{
"ReverseProxy": {
"Routes": {
"ai-management-route": {
"ClusterId": "ai-management-cluster",
"Match": {
"Path": "/api/ai-management/{**everything}"
},
"Transforms": [
{
"HeaderPrefix": "X-Forwarded-",
"X-Forwarded": "Append"
},
{
"ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat"
}
]
},
"abp-route": {
"ClusterId": "admin-service-cluster",
"Match": {
@ -451,6 +466,16 @@
}
},
"Clusters": {
"ai-management-cluster": {
"Destinations": {
"destination1": {
"Address": "http://localhost:30070",
"Metadata": {
"SwaggerEndpoint": "http://localhost:30070"
}
}
}
},
"auth-server-cluster": {
"Destinations": {
"destination1": {

12
aspnet-core/aspire/LINGYUN.Abp.MicroService.AppHost/AppHost.cs

@ -215,6 +215,18 @@ builder.AddProject<Projects.LINGYUN_Abp_MicroService_WorkflowService>("WorkflowS
.WaitFor(rabbitmq)
.WaitFor(taskService);
// AIService
AddDotNetProject<
Projects.LINGYUN_Abp_MicroService_AIService_DbMigrator,
Projects.LINGYUN_Abp_MicroService_AIService>(
builder: builder,
servicePrefix: "AI",
serviceSuffix: "Service",
migratorSuffix: "Migrator",
port: 30070,
portName: "ai",
waitProject: localizationService);
// ApiGateway
var apigateway = builder.AddProject<Projects.LINGYUN_Abp_MicroService_ApiGateway>("ApiGateway")
.WithHttpEndpoint(port: 30000, name: "gateway")

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

@ -17,6 +17,8 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.MicroService.AIService.DbMigrator\LINGYUN.Abp.MicroService.AIService.DbMigrator.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.MicroService.AIService\LINGYUN.Abp.MicroService.AIService.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.MicroService.AdminService.DbMigrator\LINGYUN.Abp.MicroService.AdminService.DbMigrator.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.MicroService.AdminService\LINGYUN.Abp.MicroService.AdminService.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.MicroService.AuthServer.DbMigrator\LINGYUN.Abp.MicroService.AuthServer.DbMigrator.csproj" />

Loading…
Cancel
Save