diff --git a/HuanMengProject.sln b/HuanMengProject.sln index c11cebb..2ea6513 100644 --- a/HuanMengProject.sln +++ b/HuanMengProject.sln @@ -19,6 +19,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "9-test", "9-test", "{8D39E8 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuanMeng.DotNetCore", "src\0-core\HuanMeng.DotNetCore\HuanMeng.DotNetCore.csproj", "{B9014C9B-B47D-4900-9EA7-4FE8998C30BE}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4-abstractions", "4-abstractions", "{6C2243B0-58DA-4D59-A163-7DDDA7DB01C4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuanMeng.StableDiffusion.Abstractions", "src\4-abstractions\HuanMeng.StableDiffusion.Abstractions\HuanMeng.StableDiffusion.Abstractions.csproj", "{2A7E25DE-A3B8-4F47-9282-64B8EB2D9953}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuanMeng.StableDiffusion.WebSocket", "src\0-core\HuanMeng.StableDiffusion.WebSocket\HuanMeng.StableDiffusion.WebSocket.csproj", "{1B659309-ACDB-49FD-8AE0-2097A1BC6D17}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuanMeng.StableDiffusion.TextGeneration", "src\0-core\HuanMeng.StableDiffusion.TextGeneration\HuanMeng.StableDiffusion.TextGeneration.csproj", "{CFE784F8-3889-4698-8719-55BAB1724486}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuanMeng.StableDiffusion.TextGenerationTests", "src\9-test\HuanMeng.StableDiffusion.TextGenerationTests\HuanMeng.StableDiffusion.TextGenerationTests.csproj", "{054AFFF5-D25E-4EC7-A135-050EEE7F7FA0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TextGenerationApi", "src\2-api\TextGenerationApi\TextGenerationApi.csproj", "{A9C5939E-D239-4AB8-9380-7E76166326D9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -29,6 +41,26 @@ Global {B9014C9B-B47D-4900-9EA7-4FE8998C30BE}.Debug|Any CPU.Build.0 = Debug|Any CPU {B9014C9B-B47D-4900-9EA7-4FE8998C30BE}.Release|Any CPU.ActiveCfg = Release|Any CPU {B9014C9B-B47D-4900-9EA7-4FE8998C30BE}.Release|Any CPU.Build.0 = Release|Any CPU + {2A7E25DE-A3B8-4F47-9282-64B8EB2D9953}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A7E25DE-A3B8-4F47-9282-64B8EB2D9953}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A7E25DE-A3B8-4F47-9282-64B8EB2D9953}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A7E25DE-A3B8-4F47-9282-64B8EB2D9953}.Release|Any CPU.Build.0 = Release|Any CPU + {1B659309-ACDB-49FD-8AE0-2097A1BC6D17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B659309-ACDB-49FD-8AE0-2097A1BC6D17}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B659309-ACDB-49FD-8AE0-2097A1BC6D17}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B659309-ACDB-49FD-8AE0-2097A1BC6D17}.Release|Any CPU.Build.0 = Release|Any CPU + {CFE784F8-3889-4698-8719-55BAB1724486}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CFE784F8-3889-4698-8719-55BAB1724486}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CFE784F8-3889-4698-8719-55BAB1724486}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CFE784F8-3889-4698-8719-55BAB1724486}.Release|Any CPU.Build.0 = Release|Any CPU + {054AFFF5-D25E-4EC7-A135-050EEE7F7FA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {054AFFF5-D25E-4EC7-A135-050EEE7F7FA0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {054AFFF5-D25E-4EC7-A135-050EEE7F7FA0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {054AFFF5-D25E-4EC7-A135-050EEE7F7FA0}.Release|Any CPU.Build.0 = Release|Any CPU + {A9C5939E-D239-4AB8-9380-7E76166326D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A9C5939E-D239-4AB8-9380-7E76166326D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A9C5939E-D239-4AB8-9380-7E76166326D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A9C5939E-D239-4AB8-9380-7E76166326D9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -41,6 +73,12 @@ Global {F34C5BC4-8810-4D6A-B003-AFE12D7ED4BA} = {443B77DF-BB15-4DF7-8F45-C54FE6F51AB9} {8D39E84B-2810-41D7-AFE6-0A58E09E34C3} = {443B77DF-BB15-4DF7-8F45-C54FE6F51AB9} {B9014C9B-B47D-4900-9EA7-4FE8998C30BE} = {DD14191F-22CE-48D8-A944-B8A41C97ACD4} + {6C2243B0-58DA-4D59-A163-7DDDA7DB01C4} = {443B77DF-BB15-4DF7-8F45-C54FE6F51AB9} + {2A7E25DE-A3B8-4F47-9282-64B8EB2D9953} = {6C2243B0-58DA-4D59-A163-7DDDA7DB01C4} + {1B659309-ACDB-49FD-8AE0-2097A1BC6D17} = {DD14191F-22CE-48D8-A944-B8A41C97ACD4} + {CFE784F8-3889-4698-8719-55BAB1724486} = {DD14191F-22CE-48D8-A944-B8A41C97ACD4} + {054AFFF5-D25E-4EC7-A135-050EEE7F7FA0} = {8D39E84B-2810-41D7-AFE6-0A58E09E34C3} + {A9C5939E-D239-4AB8-9380-7E76166326D9} = {0C0B6EB5-E41D-46D9-9F60-90D320A2EEF3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4A1DC406-AFAA-4884-859C-51B9B26E37FC} diff --git a/src/0-core/HuanMeng.DotNetCore/Base/BaseResponse.cs b/src/0-core/HuanMeng.DotNetCore/Base/BaseResponse.cs index 3908154..972f554 100644 --- a/src/0-core/HuanMeng.DotNetCore/Base/BaseResponse.cs +++ b/src/0-core/HuanMeng.DotNetCore/Base/BaseResponse.cs @@ -35,7 +35,7 @@ namespace HuanMeng.DotNetCore.Base /// 数据 /// [DataMember] - public T Data { get; set; } + public T? Data { get; set; } /// /// 构造函数 @@ -60,7 +60,7 @@ namespace HuanMeng.DotNetCore.Base /// /// 构造函数 /// - public BaseResponse(int code, string message, T data) + public BaseResponse(int code, string message, T? data) { Code = code; Message = message; @@ -70,7 +70,7 @@ namespace HuanMeng.DotNetCore.Base /// /// 构造函数 /// - public BaseResponse(ResonseCode code, string message, T data) + public BaseResponse(ResonseCode code, string message, T? data) { Code = (int)code; Message = message; diff --git a/src/0-core/HuanMeng.StableDiffusion.TextGeneration/Abstractions/TextGenerationRequestAbstract.cs b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/Abstractions/TextGenerationRequestAbstract.cs new file mode 100644 index 0000000..247718f --- /dev/null +++ b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/Abstractions/TextGenerationRequestAbstract.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HuanMeng.StableDiffusion.TextGeneration.Abstractions +{ + /// + /// 文本聊天请求类 + /// + public abstract class TextGenerationRequestAbstract + { + + /// + /// 发送数据 + /// + /// + public abstract IAsyncEnumerable SendMessageAsync(); + } +} diff --git a/src/0-core/HuanMeng.StableDiffusion.TextGeneration/BLL/TextGenerationBLL.cs b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/BLL/TextGenerationBLL.cs new file mode 100644 index 0000000..ce38fc2 --- /dev/null +++ b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/BLL/TextGenerationBLL.cs @@ -0,0 +1,94 @@ +using HuanMeng.StableDiffusion.TextGeneration.api; +using HuanMeng.StableDiffusion.TextGeneration.Models; + +using Microsoft.EntityFrameworkCore; + +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HuanMeng.StableDiffusion.TextGeneration.BLL +{ + /// + /// ai聊天 + /// + /// + public class TextGenerationBLL(TextGenerationTestContext textGenerationTestContext) + { + /// + /// + /// + /// + /// + /// + public async IAsyncEnumerable Chat(string sessionId, string message) + { + if (string.IsNullOrEmpty(sessionId)) + { + sessionId = Guid.NewGuid().ToString(); + } + var x = textGenerationTestContext.TextGenerationSessionDetails.Where(it => it.SessionId == sessionId).OrderBy(it => it.TimeStamp).ToList(); + List textGenerationRequestHttpApiModels = new List(); + if (textGenerationRequestHttpApiModels != null) + { + foreach (var item in x) + { + textGenerationRequestHttpApiModels.Add(new TextGenerationRequestHttpApiModel + { + Role = item.Role, + Content = item.Message + }); + } + } + textGenerationRequestHttpApiModels.Add(new TextGenerationRequestHttpApiModel + { + Role = "user", + Content = message + }); + var messageStr = JsonConvert.SerializeObject(textGenerationRequestHttpApiModels, Formatting.None, new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver(), + Formatting = Formatting.Indented // 这个选项是用于美化输出,便于阅读 + }); + TextGenerationSessionDetail d = new TextGenerationSessionDetail() + { + CreateDateTime = DateTime.Now, + Message = message, + Role = "user", + Model = "", + SessionId = sessionId, + TimeStamp = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds(), + TextGenerationSessionId = 0 + }; + textGenerationTestContext.TextGenerationSessionDetails.Add(d); + string json = $@" +{{ + ""messages"": {messageStr}, + ""stream"": true +}} +"; + TextGenerationRequestHttpApi textGenerationRequestHttpApi = new TextGenerationRequestHttpApi(json); + await foreach (var item in textGenerationRequestHttpApi.SendMessageAsync()) + { + yield return item; + } + TextGenerationSessionDetail d1 = new TextGenerationSessionDetail() + { + CreateDateTime = DateTime.Now, + Message = textGenerationRequestHttpApi?.textGenerationRequestHttpModel?.Choices?[0]?.Delta?.Content ?? "", + Role = textGenerationRequestHttpApi?.textGenerationRequestHttpModel?.Choices?[0]?.Delta?.Role ?? "", + Model = textGenerationRequestHttpApi?.textGenerationRequestHttpModel?.Model ?? "", + SessionId = sessionId, + TimeStamp = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds(), + TextGenerationSessionId = 0 + }; + textGenerationTestContext.TextGenerationSessionDetails.Add(d1); + await textGenerationTestContext.SaveChangesAsync(); + } + } +} diff --git a/src/0-core/HuanMeng.StableDiffusion.TextGeneration/CodeTemplates/EFCore/DbContext.t4 b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/CodeTemplates/EFCore/DbContext.t4 new file mode 100644 index 0000000..1351902 --- /dev/null +++ b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/CodeTemplates/EFCore/DbContext.t4 @@ -0,0 +1,355 @@ +<#@ template hostSpecific="true" #> +<#@ assembly name="Microsoft.EntityFrameworkCore" #> +<#@ assembly name="Microsoft.EntityFrameworkCore.Design" #> +<#@ assembly name="Microsoft.EntityFrameworkCore.Relational" #> +<#@ assembly name="Microsoft.Extensions.DependencyInjection.Abstractions" #> +<#@ parameter name="Model" type="Microsoft.EntityFrameworkCore.Metadata.IModel" #> +<#@ parameter name="Options" type="Microsoft.EntityFrameworkCore.Scaffolding.ModelCodeGenerationOptions" #> +<#@ parameter name="NamespaceHint" type="System.String" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="Microsoft.EntityFrameworkCore" #> +<#@ import namespace="Microsoft.EntityFrameworkCore.Design" #> +<#@ import namespace="Microsoft.EntityFrameworkCore.Infrastructure" #> +<#@ import namespace="Microsoft.EntityFrameworkCore.Scaffolding" #> +<#@ import namespace="Microsoft.Extensions.DependencyInjection" #> +<# + if (!ProductInfo.GetVersion().StartsWith("8.0")) + { + Warning("Your templates were created using an older version of Entity Framework. Additional features and bug fixes may be available. See https://aka.ms/efcore-docs-updating-templates for more information."); + } + + var services = (IServiceProvider)Host; + var providerCode = services.GetRequiredService(); + var annotationCodeGenerator = services.GetRequiredService(); + var code = services.GetRequiredService(); + + var usings = new List + { + "System", + "System.Collections.Generic", + "Microsoft.EntityFrameworkCore" + }; + + if (NamespaceHint != Options.ModelNamespace + && !string.IsNullOrEmpty(Options.ModelNamespace)) + { + usings.Add(Options.ModelNamespace); + } + + if (!string.IsNullOrEmpty(NamespaceHint)) + { +#> +namespace <#= NamespaceHint #>; + +<# + } +#> +public partial class <#= Options.ContextName #> : DbContext +{ +<# + if (!Options.SuppressOnConfiguring) + { +#> + public <#= Options.ContextName #>() + { + } + +<# + } +#> + public <#= Options.ContextName #>(DbContextOptions<<#= Options.ContextName #>> options) + : base(options) + { + } + +<# + foreach (var entityType in Model.GetEntityTypes().Where(e => !e.IsSimpleManyToManyJoinEntityType())) + { +#> + public virtual DbSet<<#= entityType.Name #>> <#= entityType.GetDbSetName() #> { get; set; } + +<# + } + + if (!Options.SuppressOnConfiguring) + { +#> + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) +<# + if (!Options.SuppressConnectionStringWarning) + { +#> +#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263. +<# + } + + var useProviderCall = providerCode.GenerateUseProvider(Options.ConnectionString); + usings.AddRange(useProviderCall.GetRequiredUsings()); +#> + => optionsBuilder<#= code.Fragment(useProviderCall, indent: 3) #>; + +<# + } + +#> + protected override void OnModelCreating(ModelBuilder modelBuilder) + { +<# + var anyConfiguration = false; + + var modelFluentApiCalls = Model.GetFluentApiCalls(annotationCodeGenerator); + if (modelFluentApiCalls != null) + { + usings.AddRange(modelFluentApiCalls.GetRequiredUsings()); +#> + modelBuilder<#= code.Fragment(modelFluentApiCalls, indent: 3) #>; +<# + anyConfiguration = true; + } + + StringBuilder mainEnvironment; + foreach (var entityType in Model.GetEntityTypes().Where(e => !e.IsSimpleManyToManyJoinEntityType())) + { + // Save all previously generated code, and start generating into a new temporary environment + mainEnvironment = GenerationEnvironment; + GenerationEnvironment = new StringBuilder(); + + if (anyConfiguration) + { + WriteLine(""); + } + + var anyEntityTypeConfiguration = false; +#> + modelBuilder.Entity<<#= entityType.Name #>>(entity => + { +<# + var key = entityType.FindPrimaryKey(); + if (key != null) + { + var keyFluentApiCalls = key.GetFluentApiCalls(annotationCodeGenerator); + if (keyFluentApiCalls != null + || (!key.IsHandledByConvention() && !Options.UseDataAnnotations)) + { + if (keyFluentApiCalls != null) + { + usings.AddRange(keyFluentApiCalls.GetRequiredUsings()); + } +#> + entity.HasKey(<#= code.Lambda(key.Properties, "e") #>)<#= code.Fragment(keyFluentApiCalls, indent: 4) #>; +<# + anyEntityTypeConfiguration = true; + } + } + + var entityTypeFluentApiCalls = entityType.GetFluentApiCalls(annotationCodeGenerator) + ?.FilterChain(c => !(Options.UseDataAnnotations && c.IsHandledByDataAnnotations)); + if (entityTypeFluentApiCalls != null) + { + usings.AddRange(entityTypeFluentApiCalls.GetRequiredUsings()); + + if (anyEntityTypeConfiguration) + { + WriteLine(""); + } +#> + entity<#= code.Fragment(entityTypeFluentApiCalls, indent: 4) #>; +<# + anyEntityTypeConfiguration = true; + } + + foreach (var index in entityType.GetIndexes() + .Where(i => !(Options.UseDataAnnotations && i.IsHandledByDataAnnotations(annotationCodeGenerator)))) + { + if (anyEntityTypeConfiguration) + { + WriteLine(""); + } + + var indexFluentApiCalls = index.GetFluentApiCalls(annotationCodeGenerator); + if (indexFluentApiCalls != null) + { + usings.AddRange(indexFluentApiCalls.GetRequiredUsings()); + } +#> + entity.HasIndex(<#= code.Lambda(index.Properties, "e") #>, <#= code.Literal(index.GetDatabaseName()) #>)<#= code.Fragment(indexFluentApiCalls, indent: 4) #>; +<# + anyEntityTypeConfiguration = true; + } + + var firstProperty = true; + foreach (var property in entityType.GetProperties()) + { + var propertyFluentApiCalls = property.GetFluentApiCalls(annotationCodeGenerator) + ?.FilterChain(c => !(Options.UseDataAnnotations && c.IsHandledByDataAnnotations) + && !(c.Method == "IsRequired" && Options.UseNullableReferenceTypes && !property.ClrType.IsValueType)); + if (propertyFluentApiCalls == null) + { + continue; + } + + usings.AddRange(propertyFluentApiCalls.GetRequiredUsings()); + + if (anyEntityTypeConfiguration && firstProperty) + { + WriteLine(""); + } +#> + entity.Property(e => e.<#= property.Name #>)<#= code.Fragment(propertyFluentApiCalls, indent: 4) #>; +<# + anyEntityTypeConfiguration = true; + firstProperty = false; + } + + foreach (var foreignKey in entityType.GetForeignKeys()) + { + var foreignKeyFluentApiCalls = foreignKey.GetFluentApiCalls(annotationCodeGenerator) + ?.FilterChain(c => !(Options.UseDataAnnotations && c.IsHandledByDataAnnotations)); + if (foreignKeyFluentApiCalls == null) + { + continue; + } + + usings.AddRange(foreignKeyFluentApiCalls.GetRequiredUsings()); + + if (anyEntityTypeConfiguration) + { + WriteLine(""); + } +#> + entity.HasOne(d => d.<#= foreignKey.DependentToPrincipal.Name #>).<#= foreignKey.IsUnique ? "WithOne" : "WithMany" #>(<#= foreignKey.PrincipalToDependent != null ? $"p => p.{foreignKey.PrincipalToDependent.Name}" : "" #>)<#= code.Fragment(foreignKeyFluentApiCalls, indent: 4) #>; +<# + anyEntityTypeConfiguration = true; + } + + foreach (var skipNavigation in entityType.GetSkipNavigations().Where(n => n.IsLeftNavigation())) + { + if (anyEntityTypeConfiguration) + { + WriteLine(""); + } + + var left = skipNavigation.ForeignKey; + var leftFluentApiCalls = left.GetFluentApiCalls(annotationCodeGenerator, useStrings: true); + var right = skipNavigation.Inverse.ForeignKey; + var rightFluentApiCalls = right.GetFluentApiCalls(annotationCodeGenerator, useStrings: true); + var joinEntityType = skipNavigation.JoinEntityType; + + if (leftFluentApiCalls != null) + { + usings.AddRange(leftFluentApiCalls.GetRequiredUsings()); + } + + if (rightFluentApiCalls != null) + { + usings.AddRange(rightFluentApiCalls.GetRequiredUsings()); + } +#> + entity.HasMany(d => d.<#= skipNavigation.Name #>).WithMany(p => p.<#= skipNavigation.Inverse.Name #>) + .UsingEntity>( + <#= code.Literal(joinEntityType.Name) #>, + r => r.HasOne<<#= right.PrincipalEntityType.Name #>>().WithMany()<#= code.Fragment(rightFluentApiCalls, indent: 6) #>, + l => l.HasOne<<#= left.PrincipalEntityType.Name #>>().WithMany()<#= code.Fragment(leftFluentApiCalls, indent: 6) #>, + j => + { +<# + var joinKey = joinEntityType.FindPrimaryKey(); + var joinKeyFluentApiCalls = joinKey.GetFluentApiCalls(annotationCodeGenerator); + + if (joinKeyFluentApiCalls != null) + { + usings.AddRange(joinKeyFluentApiCalls.GetRequiredUsings()); + } +#> + j.HasKey(<#= code.Arguments(joinKey.Properties.Select(e => e.Name)) #>)<#= code.Fragment(joinKeyFluentApiCalls, indent: 7) #>; +<# + var joinEntityTypeFluentApiCalls = joinEntityType.GetFluentApiCalls(annotationCodeGenerator); + if (joinEntityTypeFluentApiCalls != null) + { + usings.AddRange(joinEntityTypeFluentApiCalls.GetRequiredUsings()); +#> + j<#= code.Fragment(joinEntityTypeFluentApiCalls, indent: 7) #>; +<# + } + + foreach (var index in joinEntityType.GetIndexes()) + { + var indexFluentApiCalls = index.GetFluentApiCalls(annotationCodeGenerator); + if (indexFluentApiCalls != null) + { + usings.AddRange(indexFluentApiCalls.GetRequiredUsings()); + } +#> + j.HasIndex(<#= code.Literal(index.Properties.Select(e => e.Name).ToArray()) #>, <#= code.Literal(index.GetDatabaseName()) #>)<#= code.Fragment(indexFluentApiCalls, indent: 7) #>; +<# + } + + foreach (var property in joinEntityType.GetProperties()) + { + var propertyFluentApiCalls = property.GetFluentApiCalls(annotationCodeGenerator); + if (propertyFluentApiCalls == null) + { + continue; + } + + usings.AddRange(propertyFluentApiCalls.GetRequiredUsings()); +#> + j.IndexerProperty<<#= code.Reference(property.ClrType) #>>(<#= code.Literal(property.Name) #>)<#= code.Fragment(propertyFluentApiCalls, indent: 7) #>; +<# + } +#> + }); +<# + anyEntityTypeConfiguration = true; + } +#> + }); +<# + // If any signicant code was generated, append it to the main environment + if (anyEntityTypeConfiguration) + { + mainEnvironment.Append(GenerationEnvironment); + anyConfiguration = true; + } + + // Resume generating code into the main environment + GenerationEnvironment = mainEnvironment; + } + + foreach (var sequence in Model.GetSequences()) + { + var needsType = sequence.Type != typeof(long); + var needsSchema = !string.IsNullOrEmpty(sequence.Schema) && sequence.Schema != sequence.Model.GetDefaultSchema(); + var sequenceFluentApiCalls = sequence.GetFluentApiCalls(annotationCodeGenerator); +#> + modelBuilder.HasSequence<#= needsType ? $"<{code.Reference(sequence.Type)}>" : "" #>(<#= code.Literal(sequence.Name) #><#= needsSchema ? $", {code.Literal(sequence.Schema)}" : "" #>)<#= code.Fragment(sequenceFluentApiCalls, indent: 3) #>; +<# + } + + if (anyConfiguration) + { + WriteLine(""); + } +#> + OnModelCreatingPartial(modelBuilder); + } + + partial void OnModelCreatingPartial(ModelBuilder modelBuilder); +} +<# + mainEnvironment = GenerationEnvironment; + GenerationEnvironment = new StringBuilder(); + + foreach (var ns in usings.Distinct().OrderBy(x => x, new NamespaceComparer())) + { +#> +using <#= ns #>; +<# + } + + WriteLine(""); + + GenerationEnvironment.Append(mainEnvironment); +#> diff --git a/src/0-core/HuanMeng.StableDiffusion.TextGeneration/CodeTemplates/EFCore/EntityType.t4 b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/CodeTemplates/EFCore/EntityType.t4 new file mode 100644 index 0000000..6c6c708 --- /dev/null +++ b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/CodeTemplates/EFCore/EntityType.t4 @@ -0,0 +1,173 @@ +<#@ template hostSpecific="true" #> +<#@ assembly name="Microsoft.EntityFrameworkCore" #> +<#@ assembly name="Microsoft.EntityFrameworkCore.Design" #> +<#@ assembly name="Microsoft.EntityFrameworkCore.Relational" #> +<#@ assembly name="Microsoft.Extensions.DependencyInjection.Abstractions" #> +<#@ parameter name="EntityType" type="Microsoft.EntityFrameworkCore.Metadata.IEntityType" #> +<#@ parameter name="Options" type="Microsoft.EntityFrameworkCore.Scaffolding.ModelCodeGenerationOptions" #> +<#@ parameter name="NamespaceHint" type="System.String" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.ComponentModel.DataAnnotations" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="Microsoft.EntityFrameworkCore" #> +<#@ import namespace="Microsoft.EntityFrameworkCore.Design" #> +<#@ import namespace="Microsoft.Extensions.DependencyInjection" #> +<# + if (EntityType.IsSimpleManyToManyJoinEntityType()) + { + // Don't scaffold these + return ""; + } + + var services = (IServiceProvider)Host; + var annotationCodeGenerator = services.GetRequiredService(); + var code = services.GetRequiredService(); + + var usings = new List + { + "System", + "System.Collections.Generic" + }; + + if (Options.UseDataAnnotations) + { + usings.Add("System.ComponentModel.DataAnnotations"); + usings.Add("System.ComponentModel.DataAnnotations.Schema"); + usings.Add("Microsoft.EntityFrameworkCore"); + } + + if (!string.IsNullOrEmpty(NamespaceHint)) + { +#> +namespace <#= NamespaceHint #>; + +<# + } + + if (!string.IsNullOrEmpty(EntityType.GetComment())) + { +#> +/// +/// <#= code.XmlComment(EntityType.GetComment()) #> +/// +<# + } + + if (Options.UseDataAnnotations) + { + foreach (var dataAnnotation in EntityType.GetDataAnnotations(annotationCodeGenerator)) + { +#> +<#= code.Fragment(dataAnnotation) #> +<# + } + } +#> +public partial class <#= EntityType.Name #> +{ +<# + var firstProperty = true; + foreach (var property in EntityType.GetProperties().OrderBy(p => p.GetColumnOrder() ?? -1)) + { + if (!firstProperty) + { + WriteLine(""); + } + + if (!string.IsNullOrEmpty(property.GetComment())) + { +#> + /// + /// <#= code.XmlComment(property.GetComment(), indent: 1) #> + /// +<# + } + + if (Options.UseDataAnnotations) + { + var dataAnnotations = property.GetDataAnnotations(annotationCodeGenerator) + .Where(a => !(a.Type == typeof(RequiredAttribute) && Options.UseNullableReferenceTypes && !property.ClrType.IsValueType)); + foreach (var dataAnnotation in dataAnnotations) + { +#> + <#= code.Fragment(dataAnnotation) #> +<# + } + } + + usings.AddRange(code.GetRequiredUsings(property.ClrType)); + + var needsNullable = Options.UseNullableReferenceTypes && property.IsNullable && !property.ClrType.IsValueType; + var needsInitializer = Options.UseNullableReferenceTypes && !property.IsNullable && !property.ClrType.IsValueType; +#> + public <#= code.Reference(property.ClrType) #><#= needsNullable ? "?" : "" #> <#= property.Name #> { get; set; }<#= needsInitializer ? " = null!;" : "" #> +<# + firstProperty = false; + } + + foreach (var navigation in EntityType.GetNavigations()) + { + WriteLine(""); + + if (Options.UseDataAnnotations) + { + foreach (var dataAnnotation in navigation.GetDataAnnotations(annotationCodeGenerator)) + { +#> + <#= code.Fragment(dataAnnotation) #> +<# + } + } + + var targetType = navigation.TargetEntityType.Name; + if (navigation.IsCollection) + { +#> + public virtual ICollection<<#= targetType #>> <#= navigation.Name #> { get; set; } = new List<<#= targetType #>>(); +<# + } + else + { + var needsNullable = Options.UseNullableReferenceTypes && !(navigation.ForeignKey.IsRequired && navigation.IsOnDependent); + var needsInitializer = Options.UseNullableReferenceTypes && navigation.ForeignKey.IsRequired && navigation.IsOnDependent; +#> + public virtual <#= targetType #><#= needsNullable ? "?" : "" #> <#= navigation.Name #> { get; set; }<#= needsInitializer ? " = null!;" : "" #> +<# + } + } + + foreach (var skipNavigation in EntityType.GetSkipNavigations()) + { + WriteLine(""); + + if (Options.UseDataAnnotations) + { + foreach (var dataAnnotation in skipNavigation.GetDataAnnotations(annotationCodeGenerator)) + { +#> + <#= code.Fragment(dataAnnotation) #> +<# + } + } +#> + public virtual ICollection<<#= skipNavigation.TargetEntityType.Name #>> <#= skipNavigation.Name #> { get; set; } = new List<<#= skipNavigation.TargetEntityType.Name #>>(); +<# + } +#> +} +<# + var previousOutput = GenerationEnvironment; + GenerationEnvironment = new StringBuilder(); + + foreach (var ns in usings.Distinct().OrderBy(x => x, new NamespaceComparer())) + { +#> +using <#= ns #>; +<# + } + + WriteLine(""); + + GenerationEnvironment.Append(previousOutput); +#> diff --git a/src/0-core/HuanMeng.StableDiffusion.TextGeneration/HuanMeng.StableDiffusion.TextGeneration.csproj b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/HuanMeng.StableDiffusion.TextGeneration.csproj new file mode 100644 index 0000000..eca4b97 --- /dev/null +++ b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/HuanMeng.StableDiffusion.TextGeneration.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + diff --git a/src/0-core/HuanMeng.StableDiffusion.TextGeneration/Models/TextGenerationSession.cs b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/Models/TextGenerationSession.cs new file mode 100644 index 0000000..980ec29 --- /dev/null +++ b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/Models/TextGenerationSession.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; + +namespace HuanMeng.StableDiffusion.TextGeneration.Models; + +public partial class TextGenerationSession +{ + /// + /// 主键 + /// + public int Id { get; set; } + + /// + /// 用户Id + /// + public string UserId { get; set; } = null!; + + /// + /// 绘画Id + /// + public string SessionId { get; set; } = null!; + + /// + /// 绘画名称 + /// + public string SessionName { get; set; } = null!; + + /// + /// 创建时间 + /// + public DateTime CreateDateTime { get; set; } + + /// + /// 最后一次请求时间 + /// + public DateTime LastDateTime { get; set; } +} diff --git a/src/0-core/HuanMeng.StableDiffusion.TextGeneration/Models/TextGenerationSessionDetail.cs b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/Models/TextGenerationSessionDetail.cs new file mode 100644 index 0000000..a782f92 --- /dev/null +++ b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/Models/TextGenerationSessionDetail.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; + +namespace HuanMeng.StableDiffusion.TextGeneration.Models; + +public partial class TextGenerationSessionDetail +{ + public int Id { get; set; } + + /// + /// 会话id + /// + public int TextGenerationSessionId { get; set; } + + /// + /// 会话Id + /// + public string SessionId { get; set; } = null!; + + /// + /// 角色 + /// + public string Role { get; set; } = null!; + + /// + /// 消息内容 + /// + public string? Message { get; set; } + + /// + /// 模型 + /// + public string? Model { get; set; } + + /// + /// 时间戳 + /// + public long TimeStamp { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreateDateTime { get; set; } +} diff --git a/src/0-core/HuanMeng.StableDiffusion.TextGeneration/Models/TextGenerationTestContext.cs b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/Models/TextGenerationTestContext.cs new file mode 100644 index 0000000..53a119d --- /dev/null +++ b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/Models/TextGenerationTestContext.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; + +namespace HuanMeng.StableDiffusion.TextGeneration.Models; + +public partial class TextGenerationTestContext : DbContext +{ + public TextGenerationTestContext() + { + } + + public TextGenerationTestContext(DbContextOptions options) + : base(options) + { + } + + public virtual DbSet TextGenerationSessions { get; set; } + + public virtual DbSet TextGenerationSessionDetails { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) +#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263. + => optionsBuilder.UseSqlServer("Server=172.27.27.12;Database=TextGenerationTest;User Id=zpc;Password=zpc;TrustServerCertificate=true;"); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK_TextGenerationSession'"); + + entity.ToTable("TextGenerationSession"); + + entity.Property(e => e.Id).HasComment("主键"); + entity.Property(e => e.CreateDateTime) + .HasComment("创建时间") + .HasColumnType("datetime"); + entity.Property(e => e.LastDateTime) + .HasComment("最后一次请求时间") + .HasColumnType("datetime"); + entity.Property(e => e.SessionId) + .HasMaxLength(32) + .IsUnicode(false) + .HasComment("绘画Id"); + entity.Property(e => e.SessionName) + .HasMaxLength(100) + .HasComment("绘画名称"); + entity.Property(e => e.UserId) + .HasMaxLength(32) + .IsUnicode(false) + .HasComment("用户Id"); + }); + + modelBuilder.Entity(entity => + { + entity.Property(e => e.CreateDateTime) + .HasComment("创建时间") + .HasColumnType("datetime"); + entity.Property(e => e.Message) + .HasMaxLength(1000) + .HasComment("消息内容"); + entity.Property(e => e.Model) + .HasMaxLength(100) + .HasComment("模型"); + entity.Property(e => e.Role) + .HasMaxLength(50) + .HasComment("角色"); + entity.Property(e => e.SessionId) + .HasMaxLength(32) + .IsUnicode(false) + .HasComment("会话Id"); + entity.Property(e => e.TextGenerationSessionId).HasComment("会话id"); + entity.Property(e => e.TimeStamp).HasComment("时间戳"); + }); + + OnModelCreatingPartial(modelBuilder); + } + + partial void OnModelCreatingPartial(ModelBuilder modelBuilder); +} diff --git a/src/0-core/HuanMeng.StableDiffusion.TextGeneration/api/TextGenerationRequestHttpApi.cs b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/api/TextGenerationRequestHttpApi.cs new file mode 100644 index 0000000..d8a199e --- /dev/null +++ b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/api/TextGenerationRequestHttpApi.cs @@ -0,0 +1,104 @@ +using HuanMeng.StableDiffusion.TextGeneration.Abstractions; + +using Newtonsoft.Json; + +using System; +using System.Net.Http.Headers; + +using System.Text; +using System.Text.Json.Serialization; +using System.Text.RegularExpressions; + + +namespace HuanMeng.StableDiffusion.TextGeneration.api +{ + /// + /// + /// + public class TextGenerationRequestHttpApi : TextGenerationRequestAbstract + { + public string Url = "http://117.50.182.144:5000/v1/chat/completions"; + string jsonContent = "{\"messages\":[{\"role\":\"user\",\"content\":\"你好?\"}],\"stream\":true}"; + string analysisStr = "data:"; + /// + /// 请求内容 + /// + public TextGenerationRequestHttpModel textGenerationRequestHttpModel { get; set; } + public TextGenerationRequestHttpApi(string jsonContent) + { + this.jsonContent = jsonContent; + } + public override async IAsyncEnumerable SendMessageAsync() + { + using (var httpClient = new HttpClient()) + { + // 设置请求头 + httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + //httpClient.DefaultRequestHeaders.Add("Content-Type", "application/json"); + + var content = new StringContent(jsonContent, Encoding.UTF8, "application/json"); + // 发送请求 + using (var response = await httpClient.PostAsync(Url, content)) + { + if (response.IsSuccessStatusCode) + { + // 获取响应流 + using (var stream = await response.Content.ReadAsStreamAsync()) + using (var reader = new System.IO.StreamReader(stream)) + { + string textContent = ""; + // 持续读取流中的事件 + while (!reader.EndOfStream) + { + var line = await reader.ReadLineAsync(); + if (!string.IsNullOrEmpty(line)) + { + var index = line.IndexOf(analysisStr); + if (index > -1) + { + line = line.Substring(index + analysisStr.Length).Trim(); + } + if (!string.IsNullOrEmpty(line)) + { + var linex = JsonConvert.DeserializeObject(line); + if (linex != null) + { + textGenerationRequestHttpModel = linex; + textContent += linex?.Choices?[0].Delta?.Content ?? ""; + yield return linex?.Choices?[0].Delta?.Content ?? ""; + } + } + //yield return line; + } + } + if (textGenerationRequestHttpModel != null) + { + if (textGenerationRequestHttpModel?.Choices?.Length == 0) + { + textGenerationRequestHttpModel.Choices = new Choice[1] { new Choice() { Delta = new Delta() } }; + } + textGenerationRequestHttpModel.Choices[0].Delta.Content = textContent; + } + } + } + + } + } + + } + + /// + /// 解析 + /// + /// + /// + public string DecodeUnicodeString(string input) + { + // 使用正则表达式匹配 \u 后面跟随的 4 个十六进制数字 + return Regex.Replace(input, @"\\u([0-9A-Fa-f]{4})", m => + { + return ((char)Convert.ToInt32(m.Groups[1].Value, 16)).ToString(); + }); + } + } +} diff --git a/src/0-core/HuanMeng.StableDiffusion.TextGeneration/api/TextGenerationRequestHttpApiModel.cs b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/api/TextGenerationRequestHttpApiModel.cs new file mode 100644 index 0000000..9fc0dc7 --- /dev/null +++ b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/api/TextGenerationRequestHttpApiModel.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HuanMeng.StableDiffusion.TextGeneration.api +{ + /// + /// 消息内容 + /// + public class TextGenerationRequestHttpApiModel + { + /// + /// 角色 + /// + public string Role { get; set; } + + /// + /// 控制器 + /// + public string Content { get; set; } + } + +} diff --git a/src/0-core/HuanMeng.StableDiffusion.TextGeneration/api/TextGenerationRequestHttpModel.cs b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/api/TextGenerationRequestHttpModel.cs new file mode 100644 index 0000000..9cc8c27 --- /dev/null +++ b/src/0-core/HuanMeng.StableDiffusion.TextGeneration/api/TextGenerationRequestHttpModel.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace HuanMeng.StableDiffusion.TextGeneration.api +{ + + /// + /// 返回内容 + /// + public class TextGenerationRequestHttpModel + { + /// + /// 文本生成请求的唯一标识符。 + /// + [JsonPropertyName("id")] + public string? Id { get; set; } + + /// + /// 返回的对象类型(例如,"text_completion")。 + /// + [JsonPropertyName("object")] + public string? Object { get; set; } + + /// + /// 请求创建的时间戳。 + /// + [JsonPropertyName("created")] + public long? Created { get; set; } + + /// + /// 用于文本生成的模型。 + /// + [JsonPropertyName("model")] + public string? Model { get; set; } + + /// + /// 包含生成文本和相关信息的选项数组。 + /// + [JsonPropertyName("choices")] + public Choice[]? Choices { get; set; } + + /// + /// 请求的使用统计信息,包括令牌计数。 + /// + [JsonPropertyName("usage")] + public Usage? Usage { get; set; } + } + + public class Usage + { + /// + /// 提示中使用的令牌数。 + /// + [JsonPropertyName("prompt_tokens")] + public int? PromptTokens { get; set; } + + /// + /// 生成的完成内容中的令牌数。 + /// + [JsonPropertyName("completion_tokens")] + public int? CompletionTokens { get; set; } + + /// + /// 使用的令牌总数(提示 + 完成)。 + /// + [JsonPropertyName("total_tokens")] + public int? TotalTokens { get; set; } + } + /// + /// 消息内容 + /// + public class Choice + { + /// + /// 返回列表中选项的索引。 + /// + [JsonPropertyName("index")] + public int? Index { get; set; } + + /// + /// 完成的原因(例如,"length"、"stop")。 + /// + [JsonPropertyName("finish_reason")] + public string? FinishReason { get; set; } + + /// + /// 包含生成文本的角色和内容的 delta 对象。 + /// + [JsonPropertyName("delta")] + public Delta? Delta { get; set; } + } + + public class Delta + { + /// + /// 消息发送者的角色(例如,"user"、"system")。 + /// + [JsonPropertyName("role")] + public string? Role { get; set; } + + /// + /// 生成的内容。 + /// + [JsonPropertyName("content")] + public string? Content { get; set; } + } + +} diff --git a/src/0-core/HuanMeng.StableDiffusion.WebSocket/Class1.cs b/src/0-core/HuanMeng.StableDiffusion.WebSocket/Class1.cs new file mode 100644 index 0000000..58d7c1c --- /dev/null +++ b/src/0-core/HuanMeng.StableDiffusion.WebSocket/Class1.cs @@ -0,0 +1,7 @@ +namespace HuanMeng.StableDiffusion.WebSocket +{ + public class Class1 + { + + } +} diff --git a/src/0-core/HuanMeng.StableDiffusion.WebSocket/HuanMeng.StableDiffusion.WebSocket.csproj b/src/0-core/HuanMeng.StableDiffusion.WebSocket/HuanMeng.StableDiffusion.WebSocket.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/src/0-core/HuanMeng.StableDiffusion.WebSocket/HuanMeng.StableDiffusion.WebSocket.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/src/1-service/HuanMeng.StableDiffusion.WebSocket/HuanMeng.StableDiffusion.WebSocket.csproj b/src/1-service/HuanMeng.StableDiffusion.WebSocket/HuanMeng.StableDiffusion.WebSocket.csproj new file mode 100644 index 0000000..f8a132c --- /dev/null +++ b/src/1-service/HuanMeng.StableDiffusion.WebSocket/HuanMeng.StableDiffusion.WebSocket.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + enable + enable + + + + + + + + diff --git a/src/1-service/HuanMeng.StableDiffusion.WebSocket/HuanMeng.StableDiffusion.WebSocket.http b/src/1-service/HuanMeng.StableDiffusion.WebSocket/HuanMeng.StableDiffusion.WebSocket.http new file mode 100644 index 0000000..c42d09d --- /dev/null +++ b/src/1-service/HuanMeng.StableDiffusion.WebSocket/HuanMeng.StableDiffusion.WebSocket.http @@ -0,0 +1,6 @@ +@HuanMeng.StableDiffusion.WebSocket_HostAddress = http://localhost:5077 + +GET {{HuanMeng.StableDiffusion.WebSocket_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/src/1-service/HuanMeng.StableDiffusion.WebSocket/Program.cs b/src/1-service/HuanMeng.StableDiffusion.WebSocket/Program.cs new file mode 100644 index 0000000..040bb65 --- /dev/null +++ b/src/1-service/HuanMeng.StableDiffusion.WebSocket/Program.cs @@ -0,0 +1,39 @@ + +namespace HuanMeng.StableDiffusion.WebSocket +{ + public class Program + { + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + // Add services to the container. + builder.Services.AddAuthorization(); + + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + } + + app.UseAuthorization(); + + + app.MapGet("/", (HttpContext httpContext) => + { + return "请求成功"; + }) + .WithName("GetWeatherForecast") + .WithOpenApi(); + + app.Run(); + } + } +} diff --git a/src/1-service/HuanMeng.StableDiffusion.WebSocket/Properties/launchSettings.json b/src/1-service/HuanMeng.StableDiffusion.WebSocket/Properties/launchSettings.json new file mode 100644 index 0000000..8961392 --- /dev/null +++ b/src/1-service/HuanMeng.StableDiffusion.WebSocket/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:19623", + "sslPort": 0 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5077", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/1-service/HuanMeng.StableDiffusion.WebSocket/WeatherForecast.cs b/src/1-service/HuanMeng.StableDiffusion.WebSocket/WeatherForecast.cs new file mode 100644 index 0000000..89dc862 --- /dev/null +++ b/src/1-service/HuanMeng.StableDiffusion.WebSocket/WeatherForecast.cs @@ -0,0 +1,13 @@ +namespace HuanMeng.StableDiffusion.WebSocket +{ + public class WeatherForecast + { + public DateOnly Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } + } +} diff --git a/src/1-service/HuanMeng.StableDiffusion.WebSocket/appsettings.Development.json b/src/1-service/HuanMeng.StableDiffusion.WebSocket/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/src/1-service/HuanMeng.StableDiffusion.WebSocket/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/1-service/HuanMeng.StableDiffusion.WebSocket/appsettings.json b/src/1-service/HuanMeng.StableDiffusion.WebSocket/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/src/1-service/HuanMeng.StableDiffusion.WebSocket/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/src/2-api/TextGenerationApi/Controllers/TextGenerationApiController.cs b/src/2-api/TextGenerationApi/Controllers/TextGenerationApiController.cs new file mode 100644 index 0000000..2ca033e --- /dev/null +++ b/src/2-api/TextGenerationApi/Controllers/TextGenerationApiController.cs @@ -0,0 +1,38 @@ +using HuanMeng.StableDiffusion.TextGeneration.BLL; +using HuanMeng.StableDiffusion.TextGeneration.Models; + +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +using System.Collections.Generic; +using System.Text; + +namespace TextGenerationApi.Controllers +{ + [Route("api/[controller]/[action]")] + [ApiController] + public class TextGenerationApiController(TextGenerationTestContext textGenerationTestContext) : ControllerBase + { + [HttpPost] + /// + /// 聊天接口 + /// + /// + /// + /// + public async Task Chat(string sessionId, string message) + { + var outputStream = this.Response.Body; + TextGenerationBLL textGenerationBLL = new TextGenerationBLL(textGenerationTestContext); + await foreach (var item in textGenerationBLL.Chat(sessionId, message)) + { + if (item == null) + { + continue; + } + await outputStream.WriteAsync(Encoding.UTF8.GetBytes(item)); + await outputStream.FlushAsync(); + } + } + } +} diff --git a/src/2-api/TextGenerationApi/Controllers/WeatherForecastController.cs b/src/2-api/TextGenerationApi/Controllers/WeatherForecastController.cs new file mode 100644 index 0000000..54968ec --- /dev/null +++ b/src/2-api/TextGenerationApi/Controllers/WeatherForecastController.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; + +namespace TextGenerationApi.Controllers +{ + [ApiController] + [Route("[controller]")] + public class WeatherForecastController : ControllerBase + { + private static readonly string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + private readonly ILogger _logger; + + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } + + [HttpGet(Name = "GetWeatherForecast")] + public IEnumerable Get() + { + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray(); + } + } +} diff --git a/src/2-api/TextGenerationApi/Program.cs b/src/2-api/TextGenerationApi/Program.cs new file mode 100644 index 0000000..4de4235 --- /dev/null +++ b/src/2-api/TextGenerationApi/Program.cs @@ -0,0 +1,60 @@ +using HuanMeng.StableDiffusion.TextGeneration.Models; + +using Microsoft.EntityFrameworkCore; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +builder.Services.AddHttpContextAccessor(); //添加httpContext注入访问 +builder.Services.AddControllers(); + +//注入数据库 +builder.Services.AddDbContext((options) => +{ + options.UseSqlServer(builder.Configuration.GetConnectionString("TextGenerationTest")); +}); + +//添加跨域设置 +var _myAllowSpecificOrigins = "_myAllowSpecificOrigins"; + +builder.Services.AddCors(options => +options.AddPolicy(_myAllowSpecificOrigins, +builder => +{ + + builder.AllowAnyHeader() + .AllowAnyMethod() + .AllowAnyOrigin();// 许来自任意源的跨域请求 +})); + +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(c => + { + + c.EnableDeepLinking(); + c.DefaultModelsExpandDepth(3); + c.DefaultModelExpandDepth(3); + c.EnableFilter("true"); + //c.RoutePrefix = "swagger"; + //c.SwaggerEndpoint("/swagger/v1/swagger.json", "Your API V1"); + }); + //} +} + +//app.UseHttpsRedirection(); +//使用跨域 +app.UseCors(_myAllowSpecificOrigins); +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/src/2-api/TextGenerationApi/Properties/launchSettings.json b/src/2-api/TextGenerationApi/Properties/launchSettings.json new file mode 100644 index 0000000..2b2d638 --- /dev/null +++ b/src/2-api/TextGenerationApi/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:54212", + "sslPort": 44383 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5210", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7095;http://localhost:5210", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/2-api/TextGenerationApi/TextGenerationApi.csproj b/src/2-api/TextGenerationApi/TextGenerationApi.csproj new file mode 100644 index 0000000..76cc23b --- /dev/null +++ b/src/2-api/TextGenerationApi/TextGenerationApi.csproj @@ -0,0 +1,32 @@ + + + + net8.0 + enable + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/src/2-api/TextGenerationApi/TextGenerationApi.http b/src/2-api/TextGenerationApi/TextGenerationApi.http new file mode 100644 index 0000000..905edac --- /dev/null +++ b/src/2-api/TextGenerationApi/TextGenerationApi.http @@ -0,0 +1,6 @@ +@TextGenerationApi_HostAddress = http://localhost:5210 + +GET {{TextGenerationApi_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/src/2-api/TextGenerationApi/WeatherForecast.cs b/src/2-api/TextGenerationApi/WeatherForecast.cs new file mode 100644 index 0000000..0765a1f --- /dev/null +++ b/src/2-api/TextGenerationApi/WeatherForecast.cs @@ -0,0 +1,13 @@ +namespace TextGenerationApi +{ + public class WeatherForecast + { + public DateOnly Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } + } +} diff --git a/src/2-api/TextGenerationApi/appsettings.Development.json b/src/2-api/TextGenerationApi/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/src/2-api/TextGenerationApi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/2-api/TextGenerationApi/appsettings.json b/src/2-api/TextGenerationApi/appsettings.json new file mode 100644 index 0000000..9e246b7 --- /dev/null +++ b/src/2-api/TextGenerationApi/appsettings.json @@ -0,0 +1,32 @@ +{ + "ConnectionStrings": { + "TextGenerationTest": "Server=172.27.27.12;Database=TextGenerationTest;User Id=zpc;Password=zpc;TrustServerCertificate=true;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=True;" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "Kestrel": { + "Endpoints": { + "Http": { + "Url": "http://*:800" + } + //"HttpsInlineCertFile": { + // "Url": "https://*:443", + // "Certificate": { + // "Path": "", //证书地址 + // "Password": "" //证书密码 + // } + //} + } + //"Certificates": { + // "Default": { + // "Path": "", //证书地址 + // "Password": "" //证书密码 + // } + //} + } +} diff --git a/src/4-abstractions/HuanMeng.StableDiffusion.Abstractions/HuanMeng.StableDiffusion.Abstractions.csproj b/src/4-abstractions/HuanMeng.StableDiffusion.Abstractions/HuanMeng.StableDiffusion.Abstractions.csproj new file mode 100644 index 0000000..b4b43f4 --- /dev/null +++ b/src/4-abstractions/HuanMeng.StableDiffusion.Abstractions/HuanMeng.StableDiffusion.Abstractions.csproj @@ -0,0 +1,8 @@ + + + + netstandard2.1 + enable + + + diff --git a/src/4-abstractions/HuanMeng.StableDiffusion.Abstractions/PlugIn/IStableDiffusionGenerateImage.cs b/src/4-abstractions/HuanMeng.StableDiffusion.Abstractions/PlugIn/IStableDiffusionGenerateImage.cs new file mode 100644 index 0000000..19db581 --- /dev/null +++ b/src/4-abstractions/HuanMeng.StableDiffusion.Abstractions/PlugIn/IStableDiffusionGenerateImage.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace HuanMeng.StableDiffusion.Abstractions.PlugIn +{ + public interface IStableDiffusionGenerateImage + { + /// + /// 文生图 + /// + public Task TextToImage(); + + /// + /// 图生图 + /// + /// + public Task ImageToImage(); + } +} diff --git a/src/4-abstractions/HuanMeng.StableDiffusion.Abstractions/StableDiffusionRequestAbstract.cs b/src/4-abstractions/HuanMeng.StableDiffusion.Abstractions/StableDiffusionRequestAbstract.cs new file mode 100644 index 0000000..e36e130 --- /dev/null +++ b/src/4-abstractions/HuanMeng.StableDiffusion.Abstractions/StableDiffusionRequestAbstract.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace HuanMeng.StableDiffusion.Abstractions +{ + /// + /// StableDiffusion请求类 + /// + public abstract class StableDiffusionRequestAbstract + { + /// + /// 会话标识 + /// + protected string SessionHash { get; set; } + + /// + /// + /// + public StableDiffusionRequestAbstract() + { + this.SessionHash = Guid.NewGuid().ToString(); + } + + /// + /// StableDiffusion请求类 + /// + /// + public StableDiffusionRequestAbstract(string sessionHash) + { + this.SessionHash = sessionHash; + } + + /// + /// 发送消息 + /// + /// 请求地址 + /// 编号 + /// 数据 + /// session编号 + /// + public abstract Task SendMessageAsync(string requestUrl, int fn_index, List data); + + /// + /// 发送自定义消息 + /// + /// + /// + /// + public abstract Task SendMessageAsync(string requestUrl, string jsonData); + } +} diff --git a/src/9-test/HuanMeng.StableDiffusion.TextGenerationTests/HuanMeng.StableDiffusion.TextGenerationTests.csproj b/src/9-test/HuanMeng.StableDiffusion.TextGenerationTests/HuanMeng.StableDiffusion.TextGenerationTests.csproj new file mode 100644 index 0000000..4d14c94 --- /dev/null +++ b/src/9-test/HuanMeng.StableDiffusion.TextGenerationTests/HuanMeng.StableDiffusion.TextGenerationTests.csproj @@ -0,0 +1,27 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + diff --git a/src/9-test/HuanMeng.StableDiffusion.TextGenerationTests/api/TextGenerationRequestHttpApiTests.cs b/src/9-test/HuanMeng.StableDiffusion.TextGenerationTests/api/TextGenerationRequestHttpApiTests.cs new file mode 100644 index 0000000..07feda1 --- /dev/null +++ b/src/9-test/HuanMeng.StableDiffusion.TextGenerationTests/api/TextGenerationRequestHttpApiTests.cs @@ -0,0 +1,25 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HuanMeng.StableDiffusion.TextGeneration.api.Tests +{ + [TestClass()] + public class TextGenerationRequestHttpApiTests + { + [TestMethod()] + public async Task SendMessageAsyncTest() + { + TextGenerationRequestHttpApi textGenerationRequestHttpApi = new TextGenerationRequestHttpApi(); + await foreach (var item in textGenerationRequestHttpApi.SendMessageAsync()) + { + Console.WriteLine(item); + } + Console.WriteLine(textGenerationRequestHttpApi.textGenerationRequestHttpModel.Choices[0].Delta.Content); + } + } +} \ No newline at end of file