From 437c1e01838651e26138de5f3c6f08f7157d08a2 Mon Sep 17 00:00:00 2001 From: arthuridea w <2337583+arthuridea@users.noreply.github.com> Date: Tue, 5 Mar 2024 16:54:16 +0800 Subject: [PATCH] feat:add db persistance.(on development). --- NetCore.AIGC.sln | 14 ++ .../ChatDbContextFactory.cs | 81 ++++++ .../LLMService.DataProvider.Migrator.csproj | 32 +++ .../README.md | 52 ++++ .../appsettings.json | 9 + .../Data/ChatDbContext.cs | 230 ++++++++++++++++++ .../Data/DbExtensions.cs | 139 +++++++++++ .../Entity/ChatFolder.cs | 72 ++++++ .../Entity/ChatMessage.cs | 124 ++++++++++ .../Entity/Conversation.cs | 75 ++++++ .../Entity/EntityConsts.cs | 50 ++++ .../Entity/ICreatedUtcTime.cs | 22 ++ .../LLMService.DataProvider.Relational.csproj | 35 +++ .../Provider/ChatDataRelationalDbProvider.cs | 71 ++++++ .../Provider/ChatStorage.cs | 48 ++++ .../Provider/IChatStorage.cs | 14 ++ 16 files changed, 1068 insertions(+) create mode 100644 src/LLMService.DataProvider.Migrator/ChatDbContextFactory.cs create mode 100644 src/LLMService.DataProvider.Migrator/LLMService.DataProvider.Migrator.csproj create mode 100644 src/LLMService.DataProvider.Migrator/README.md create mode 100644 src/LLMService.DataProvider.Migrator/appsettings.json create mode 100644 src/LLMService.DataProvider.Relational/Data/ChatDbContext.cs create mode 100644 src/LLMService.DataProvider.Relational/Data/DbExtensions.cs create mode 100644 src/LLMService.DataProvider.Relational/Entity/ChatFolder.cs create mode 100644 src/LLMService.DataProvider.Relational/Entity/ChatMessage.cs create mode 100644 src/LLMService.DataProvider.Relational/Entity/Conversation.cs create mode 100644 src/LLMService.DataProvider.Relational/Entity/EntityConsts.cs create mode 100644 src/LLMService.DataProvider.Relational/Entity/ICreatedUtcTime.cs create mode 100644 src/LLMService.DataProvider.Relational/LLMService.DataProvider.Relational.csproj create mode 100644 src/LLMService.DataProvider.Relational/Provider/ChatDataRelationalDbProvider.cs create mode 100644 src/LLMService.DataProvider.Relational/Provider/ChatStorage.cs create mode 100644 src/LLMService.DataProvider.Relational/Provider/IChatStorage.cs diff --git a/NetCore.AIGC.sln b/NetCore.AIGC.sln index 430b9bc..6e512c3 100644 --- a/NetCore.AIGC.sln +++ b/NetCore.AIGC.sln @@ -34,6 +34,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LLMService.OpenAI.ChatGPT", EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "02.Sample", "02.Sample", "{0B000384-47E8-4013-A1CE-59A465017EF2}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LLMService.DataProvider.Relational", "src\LLMService.DataProvider.Relational\LLMService.DataProvider.Relational.csproj", "{3B8B2207-56F2-4D98-858F-7BAB3858CD74}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LLMService.DataProvider.Migrator", "src\LLMService.DataProvider.Migrator\LLMService.DataProvider.Migrator.csproj", "{E2CC4393-ABF1-400F-A9B2-A56F99A2285E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -60,6 +64,14 @@ Global {09322116-1405-47CE-BBB5-35E02167905D}.Debug|Any CPU.Build.0 = Debug|Any CPU {09322116-1405-47CE-BBB5-35E02167905D}.Release|Any CPU.ActiveCfg = Release|Any CPU {09322116-1405-47CE-BBB5-35E02167905D}.Release|Any CPU.Build.0 = Release|Any CPU + {3B8B2207-56F2-4D98-858F-7BAB3858CD74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B8B2207-56F2-4D98-858F-7BAB3858CD74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B8B2207-56F2-4D98-858F-7BAB3858CD74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B8B2207-56F2-4D98-858F-7BAB3858CD74}.Release|Any CPU.Build.0 = Release|Any CPU + {E2CC4393-ABF1-400F-A9B2-A56F99A2285E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2CC4393-ABF1-400F-A9B2-A56F99A2285E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2CC4393-ABF1-400F-A9B2-A56F99A2285E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2CC4393-ABF1-400F-A9B2-A56F99A2285E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -70,6 +82,8 @@ Global {E73CB18F-26D3-4A6C-8AA2-E89FF17B65C5} = {01705FE5-59E6-4B65-B545-5DFD3AFB1F16} {E3AE89E4-31A0-4EDA-9154-2D089E1FD8A4} = {01705FE5-59E6-4B65-B545-5DFD3AFB1F16} {09322116-1405-47CE-BBB5-35E02167905D} = {01705FE5-59E6-4B65-B545-5DFD3AFB1F16} + {3B8B2207-56F2-4D98-858F-7BAB3858CD74} = {01705FE5-59E6-4B65-B545-5DFD3AFB1F16} + {E2CC4393-ABF1-400F-A9B2-A56F99A2285E} = {01705FE5-59E6-4B65-B545-5DFD3AFB1F16} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4FD3BE39-36D7-4A01-8EEC-39063ED813B4} diff --git a/src/LLMService.DataProvider.Migrator/ChatDbContextFactory.cs b/src/LLMService.DataProvider.Migrator/ChatDbContextFactory.cs new file mode 100644 index 0000000..0d15a67 --- /dev/null +++ b/src/LLMService.DataProvider.Migrator/ChatDbContextFactory.cs @@ -0,0 +1,81 @@ +using LLMService.DataProvider.Relational.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.Extensions.Configuration; +using Org.BouncyCastle.Tls; + +namespace LLMService.DataProvider.Migrator +{ + /// + /// + /// + internal class ChatDbContextFactory : ChatDbContextFactoryGeneric + { + } + + /// + /// + /// + /// + internal class ChatDbContextFactoryGeneric : IDesignTimeDbContextFactory + where TContext : DbContext + { + const string connectionKey = "DbConnection"; + const string assemblyName = "LLMService.DataProvider.Migrator"; + + /// + /// Creates a new instance of a derived context. + /// + /// Arguments provided by the design-time service. + /// + /// An instance of . + /// + public TContext CreateDbContext(string[] args) + { + // + var configuration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json") + .AddCommandLine(args) + .Build(); + var dbContextBuilder = new DbContextOptionsBuilder(); + var connectionString = configuration.GetConnectionString(connectionKey); + + string migrationDbProvider = configuration["DbProvider"] ?? "SqlServer"; + //string contextTypeName = configuration["contextType"] ?? nameof(TContext); + /* + * Sample DI code goes here: + services.AddDbContext( + options => _ = provider switch + { + "Sqlite" => options.UseSqlite( + configuration.GetConnectionString("SqliteConnection"), + x => x.MigrationsAssembly("SqliteMigrations")), + + "SqlServer" => options.UseSqlServer( + configuration.GetConnectionString("SqlServerConnection"), + x => x.MigrationsAssembly("SqlServerMigrations")), + + _ => throw new Exception($"Unsupported provider: {provider}") + }); + * + */ + + if (migrationDbProvider.Contains("SqlServer", StringComparison.InvariantCultureIgnoreCase)){ + dbContextBuilder.UseSqlServer(connectionString, action => action.MigrationsAssembly(assemblyName)); + } + else if(migrationDbProvider.Contains("MySql", StringComparison.InvariantCultureIgnoreCase)) + { + dbContextBuilder.UseMySQL(connectionString, action => action.MigrationsAssembly(assemblyName)); + } + else + { + throw new InvalidOperationException("Invalid DbProvider"); + } + + var dbContextInstance = (TContext)Activator.CreateInstance(typeof(TContext), dbContextBuilder.Options); + + return dbContextInstance; + } + } +} diff --git a/src/LLMService.DataProvider.Migrator/LLMService.DataProvider.Migrator.csproj b/src/LLMService.DataProvider.Migrator/LLMService.DataProvider.Migrator.csproj new file mode 100644 index 0000000..f815156 --- /dev/null +++ b/src/LLMService.DataProvider.Migrator/LLMService.DataProvider.Migrator.csproj @@ -0,0 +1,32 @@ + + + + net8.0 + enable + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + diff --git a/src/LLMService.DataProvider.Migrator/README.md b/src/LLMService.DataProvider.Migrator/README.md new file mode 100644 index 0000000..ab61898 --- /dev/null +++ b/src/LLMService.DataProvider.Migrator/README.md @@ -0,0 +1,52 @@ +# 项目说明 + +本项目为独立的数据库迁移项目,支持在`appsettings.json`中配置数据库提供程序,目前支持`SqlServer`和`MySql`. + +## 目录结构 + +例如,有3次迁移Migration1,Migration2,Migration3,文件结构大致如下: + +``` +. +├── Migrations /*迁移文件夹*/ +│ ├── 时间戳1_Migration1.cs /*第1次迁移*/ +│ ├── 时间戳2_Migration2.cs /*第2次迁移*/ +│ ├── 时间戳3_Migration3.cs /*第3次迁移*/ +│ ├── ChatDbContextModelSnapshot.cs /*迁移快照文件*/ +│ └── Scripts /*迁移脚本文件夹*/ +│ ├── Migration1.sql /*第1次迁移脚本*/ +│ ├── Migration2.sql /*第2次迁移脚本*/ +│ └── Migration3.sql /*第3次迁移脚本*/ +├── ChatDbContextFactory.cs /*迁移配置程序*/ +└── README.md /*说明文件*/ + +``` + +#### 创建迁移 + +以`NewMigration`为迁移名称 + +##### VisualStudio 包管理器命令行 +``` +add-migration -c ChatDbContext NewMigration +``` + +#### 创建迁移脚本 + +`NewMigration`为本次迁移名称,`LastMigration`为上次迁移名称(可选),加入`-from` 参数创建`LastMigration`之后所做的增量脚本 + +##### VisualStudio 包管理器命令行 + +需要注意当前命令行执行的目录. + ++ 仅创建迁移增量脚本 +``` +script-migration -o .\src\LLMService.DataProvider.Migrator\Migrations\Scripts\NewMigration.sql -Idempotent -from LastMigration +``` + ++ 创建整个数据库的建库脚本 + +`DbProvider`参数可选值:SqlServer,MySql +``` +script-dbcontext -c ChatDbContext -Args "--DbProvider SqlServer" +``` diff --git a/src/LLMService.DataProvider.Migrator/appsettings.json b/src/LLMService.DataProvider.Migrator/appsettings.json new file mode 100644 index 0000000..2fe7645 --- /dev/null +++ b/src/LLMService.DataProvider.Migrator/appsettings.json @@ -0,0 +1,9 @@ +{ + "ConnectionStrings": { + "DbConnection": "Data Source=(localdb)\\mssqllocaldb;Database=LLMServiceHub_Db;Trusted_Connection=True;MultipleActiveResultSets=true" + //"DbConnection": "Server=.,3306;Database=LLMServiceHub_Db;Uid=sa;Pwd=pass;" + }, + //database provider,optional values:SqlServer|MySql + "DbProvider": "SqlServer" +} + diff --git a/src/LLMService.DataProvider.Relational/Data/ChatDbContext.cs b/src/LLMService.DataProvider.Relational/Data/ChatDbContext.cs new file mode 100644 index 0000000..c81ed3d --- /dev/null +++ b/src/LLMService.DataProvider.Relational/Data/ChatDbContext.cs @@ -0,0 +1,230 @@ +using LLMService.DataProvider.Relational.Entity; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace LLMService.DataProvider.Relational.Data +{ + /// + /// + /// + public class ChatDbContext : ChatDbContext + { + /// + /// Initializes a new instance of the class. + /// + /// + /// See DbContext lifetime, configuration, and initialization + /// for more information. + /// + public ChatDbContext() + { + } + /// + /// Initializes a new instance of the class. + /// + /// The options for this context. + /// + /// See DbContext lifetime, configuration, and initialization and + /// Using DbContextOptions for more information. + /// + public ChatDbContext(DbContextOptions options) + : base(options) + { + } + + internal override void OnModelCreatingFinishing(ModelBuilder modelBuilder) + { + base.OnModelCreatingFinishing(modelBuilder); + + modelBuilder.Entity() + .Property(x => x.TenantId) + .HasMaxLength(128); + modelBuilder.Entity() + .Property(x => x.UserId) + .HasMaxLength(128); + modelBuilder.Entity() + .Property(x => x.TenantId) + .HasMaxLength(128); + modelBuilder.Entity() + .Property(x => x.UserId) + .HasMaxLength(128); + modelBuilder.Entity() + .Property(x => x.TenantId) + .HasMaxLength(128); + modelBuilder.Entity() + .Property(x => x.UserId) + .HasMaxLength(128); + + } + } + + /// + /// + /// + /// The type of the chat folder. + /// The type of the conversation. + /// The type of the chat message. + /// The type of the tenant key. + /// The type of the user key. + /// The type of the conversation key. + /// The type of the message key. + public class ChatDbContext: DbContext + where TUserKey : IEquatable + where TTenantKey : IEquatable + where TMessageKey : IEquatable + where TConversationKey : IEquatable + where TChatFolder: ChatFolder + where TConversation: Conversation + where TMessage: ChatMessage + { + #region Entities + /// + /// Gets or sets the chat folders. + /// + /// + /// The chat folders. + /// + public virtual DbSet ChatFolders { get; set; } + /// + /// Gets or sets the conversations. + /// + /// + /// The conversations. + /// + public virtual DbSet Conversations { get; set; } + /// + /// Gets or sets the chat messages. + /// + /// + /// The chat messages. + /// + public virtual DbSet ChatMessages { get; set; } + #endregion + + #region ctor + /// + /// Initializes a new instance of the class. + /// + /// + /// See DbContext lifetime, configuration, and initialization + /// for more information. + /// + public ChatDbContext() + { + + } + /// + /// Initializes a new instance of the class. + /// + /// The options for this context. + /// + /// See DbContext lifetime, configuration, and initialization and + /// Using DbContextOptions for more information. + /// + public ChatDbContext(DbContextOptions options) + :base(options) + { + + } + #endregion + + #region FluentAPI config + + /// + /// Override this method to further configure the model that was discovered by convention from the entity types + /// exposed in properties on your derived context. The resulting model may be cached + /// and re-used for subsequent instances of your derived context. + /// + /// The builder being used to construct the model for this context. Databases (and other extensions) typically + /// define extension methods on this object that allow you to configure aspects of the model that are specific + /// to a given database. + /// + /// + /// If a model is explicitly set on the options for this context (via ) + /// then this method will not be run. + /// + /// + /// See Modeling entity types and relationships for more information. + /// + /// + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + // overriding configurations + modelBuilder.Entity(_configureChatFolder); + modelBuilder.Entity(_configureConversation); + modelBuilder.Entity(_configureChatMessage); + + modelBuilder.ConfigEntitiesThatImplementedFromIDomainEntity(this); + + OnModelCreatingFinishing(modelBuilder); + } + + /// + /// Called when [model creating internal]. + /// This method is called after all default model initialization. + /// + /// The model builder. + internal virtual void OnModelCreatingFinishing(ModelBuilder modelBuilder) + { + // override in derrived class. + } + + /// + /// Configures the chat folder. + /// + /// The builder. + /// + private void _configureChatFolder(EntityTypeBuilder builder) + { + builder.ToTable("ChatFolder"); + builder.HasKey(x => x.Id); + + builder.Property(x => x.Name) + .HasMaxLength(512); + + builder.HasMany() + .WithOne() + .HasForeignKey(x => x.ParentId) + .IsRequired(false); + + } + /// + /// Configures the conversation. + /// + /// The builder. + /// + private void _configureConversation(EntityTypeBuilder builder) + { + builder.ToTable("Conversation"); + builder.HasKey(x => x.Id); + + // one to many + builder.HasMany() + .WithOne() + .HasForeignKey(x => x.ConversationId) + .IsRequired(false); + + } + /// + /// Configures the chat message. + /// + /// The builder. + /// + private void _configureChatMessage(EntityTypeBuilder builder) + { + builder.ToTable("ChatMessage"); + builder.HasKey(x => x.Id); + + builder.Property(x => x.Role) + .HasMaxLength(256); + + } + + + + #endregion + } +} diff --git a/src/LLMService.DataProvider.Relational/Data/DbExtensions.cs b/src/LLMService.DataProvider.Relational/Data/DbExtensions.cs new file mode 100644 index 0000000..5e1eaa2 --- /dev/null +++ b/src/LLMService.DataProvider.Relational/Data/DbExtensions.cs @@ -0,0 +1,139 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LLMService.DataProvider.Relational.Entity; + +namespace LLMService.DataProvider.Relational.Data +{ + /// + /// + /// + public static class DbExtensions + { + + /// + /// Configurations the entities that implemented from i domain entity. + /// + /// The model builder. + /// The database context. + /// + public static ModelBuilder ConfigEntitiesThatImplementedFromIDomainEntity(this ModelBuilder modelBuilder, DbContext dbContext) + { + foreach (Type domain in from e in modelBuilder.Model.GetEntityTypes() + where !e.IsOwned() + select e.ClrType) + { + modelBuilder.Entity(domain, delegate (EntityTypeBuilder b) + { + + if (domain.IsDerivedFrom(typeof(ICreatedUtcTime))) + { + string defaultDateSql = ""; + if (dbContext.Database.IsSqlServer()) + { + defaultDateSql = "getutcdate()"; + } + else if(dbContext.Database.IsMysql()) + { + defaultDateSql = "UTC_DATE()"; + } + else + { + throw new Exception($"DbType {dbContext.Database.ProviderName} not supported"); + } + + b.Property("CreatedUtcTime").HasDefaultValueSql(defaultDateSql); + } + + }); + } + + return modelBuilder; + } + + /// + /// Determines whether [is derived from] [the specified pattern]. + /// + /// The type. + /// The pattern. + /// + /// true if [is derived from] [the specified pattern]; otherwise, false. + /// + /// + /// type + /// or + /// pattern + /// + public static bool IsDerivedFrom(this Type type, Type pattern) + { + if (type == null) + { + throw new ArgumentNullException("type"); + } + + if (pattern == null) + { + throw new ArgumentNullException("pattern"); + } + + if (type.IsSubclassOf(pattern)) + { + return true; + } + + if (pattern.IsAssignableFrom(type)) + { + return true; + } + + if (type.GetInterfaces().Any(IsTheRawGenericType)) + { + return true; + } + + while (type != null && type != typeof(object)) + { + if (IsTheRawGenericType(type)) + { + return true; + } + + type = type.BaseType; + } + + return false; + bool IsTheRawGenericType(Type test) + { + return pattern == (test.IsGenericType ? test.GetGenericTypeDefinition() : test); + } + } + + /// + /// Determines whether [is SQL server]. + /// + /// The database. + /// + /// true if [is SQL server] [the specified database]; otherwise, false. + /// + public static bool IsSqlServer(this DatabaseFacade database) + { + return database.ProviderName.Equals("Microsoft.EntityFrameworkCore.SqlServer", StringComparison.InvariantCultureIgnoreCase); + } + /// + /// Determines whether this instance is mysql. + /// + /// The database. + /// + /// true if the specified database is mysql; otherwise, false. + /// + public static bool IsMysql(this DatabaseFacade database) + { + return database.ProviderName.Contains("Mysql", StringComparison.InvariantCultureIgnoreCase); + } + } +} diff --git a/src/LLMService.DataProvider.Relational/Entity/ChatFolder.cs b/src/LLMService.DataProvider.Relational/Entity/ChatFolder.cs new file mode 100644 index 0000000..84c5072 --- /dev/null +++ b/src/LLMService.DataProvider.Relational/Entity/ChatFolder.cs @@ -0,0 +1,72 @@ +using System.ComponentModel.DataAnnotations; + +namespace LLMService.DataProvider.Relational.Entity +{ + /// + /// + /// + public class ChatFolder : ChatFolder + { + } + + /// + /// + /// + /// The type of the user key. + /// The type of the tenant key. + public class ChatFolder : ICreatedUtcTime + where TUserKey : IEquatable + where TTenantKey : IEquatable + { + /// + /// Gets or sets the identifier. + /// + /// + /// The identifier. + /// + public Guid Id { get; set; } + /// + /// Gets or sets the parent identifier. + /// + /// + /// The parent identifier. + /// + public Guid? ParentId { get; set; } + /// + /// Gets or sets the user identifier. + /// + /// + /// The user identifier. + /// + public virtual TUserKey UserId { get; set; } + /// + /// Gets or sets the tenant identifier. + /// + /// + /// The tenant identifier. + /// + public virtual TTenantKey TenantId { get; set; } + /// + /// Gets or sets the name. + /// + /// + /// The name. + /// + public string Name { get; set; } + /// + /// Gets or sets the created UTC time. + /// + /// + /// The created UTC time. + /// + public DateTime CreatedUtcTime { get; set; } = DateTime.UtcNow; + /// + /// Gets or sets a value indicating whether this instance is deleted. + /// + /// + /// true if this instance is deleted; otherwise, false. + /// + public bool IsDeleted { get; set; } = false; + + } +} diff --git a/src/LLMService.DataProvider.Relational/Entity/ChatMessage.cs b/src/LLMService.DataProvider.Relational/Entity/ChatMessage.cs new file mode 100644 index 0000000..150cfdf --- /dev/null +++ b/src/LLMService.DataProvider.Relational/Entity/ChatMessage.cs @@ -0,0 +1,124 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using static LLMService.DataProvider.Relational.Entity.EntityConsts; +using static LLMService.Shared.Models.LLMApiDefaults; + +namespace LLMService.DataProvider.Relational.Entity +{ +#nullable enable + /// + /// + /// + public class ChatMessage: ChatMessage + { + } + + /// + /// + /// + /// The type of the tenant key. + /// The type of the message key. + /// The type of the conversation key. + /// The type of the user key. + public class ChatMessage: ICreatedUtcTime + where TTenantKey : IEquatable + where TMessageKey : IEquatable + where TConversationKey : IEquatable + where TUserKey : IEquatable + { + /// + /// Gets or sets the identifier. + /// + /// + /// The identifier. + /// + public TMessageKey Id { get; set; } + /// + /// Gets or sets the conversation identifier. + /// + /// + /// The conversation identifier. + /// + public TConversationKey? ConversationId { get; set; } + /// + /// Gets or sets the tenant identifier. + /// + /// + /// The tenant identifier. + /// + public virtual TTenantKey TenantId { get; set; } + /// + /// Gets or sets the user identifier. + /// + /// + /// The user identifier. + /// + public virtual TUserKey UserId { get; set; } + /// + /// Gets or sets the role. + /// + /// + /// The role. + /// + public string Role { get; set; } = "user"; + /// + /// Gets or sets the content. + /// + /// + /// The content. + /// + public string Content { get; set; } = ""; + /// + /// Gets or sets the display content. + /// + /// + /// The display content. + /// + public string DisplayContent { get; set; } = ""; + /// + /// Gets or sets a value indicating whether [use display content]. + /// + /// + /// true if [use display content]; otherwise, false. + /// + public bool UseDisplayContent { get; set; } = false; + /// + /// Gets or sets the type of the model. + /// + /// + /// The type of the model. + /// + public LLM_ModelType ModelType { get; set; } + /// + /// Gets or sets the type of the content. + /// + /// + /// The type of the content. + /// + public MessageDataType DataType { get; set; } = MessageDataType.PlainText; + /// + /// Gets or sets the type of the content. + /// + /// + /// The type of the content. + /// + public MessageContentType ContentType { get; set; } = MessageContentType.Text; + /// + /// Gets or sets the created UTC time. + /// + /// + /// The created UTC time. + /// + public DateTime CreatedUtcTime { get; set; } = DateTime.UtcNow; + /// + /// Gets or sets a value indicating whether this instance is deleted. + /// + /// + /// true if this instance is deleted; otherwise, false. + /// + public bool IsDeleted { get; set; } = false; + + + } +#nullable disable +} diff --git a/src/LLMService.DataProvider.Relational/Entity/Conversation.cs b/src/LLMService.DataProvider.Relational/Entity/Conversation.cs new file mode 100644 index 0000000..c3ab796 --- /dev/null +++ b/src/LLMService.DataProvider.Relational/Entity/Conversation.cs @@ -0,0 +1,75 @@ +using System.ComponentModel.DataAnnotations; + +namespace LLMService.DataProvider.Relational.Entity +{ + /// + /// + /// + public class Conversation : Conversation + { + } + + + /// + /// + /// + /// The type of the conversation key. + /// The type of the tenant key. + /// The type of the user key. + public class Conversation: ICreatedUtcTime + where TConversationKey : IEquatable + where TTenantKey : IEquatable + where TUserKey : IEquatable + { + /// + /// Gets or sets the identifier. + /// + /// + /// The identifier. + /// + public virtual TConversationKey Id { get; set; } + /// + /// Gets or sets the tenant identifier. + /// + /// + /// The tenant identifier. + /// + public virtual TTenantKey TenantId { get; set; } + /// + /// Gets or sets the user identifier. + /// + /// + /// The user identifier. + /// + public virtual TUserKey UserId { get; set; } + /// + /// Gets or sets the folder identifier. + /// + /// + /// The folder identifier. + /// + public Guid? FolderId { get; set; } + /// + /// Gets or sets the topic. + /// + /// + /// The topic. + /// + public string Topic { get; set; } = ""; + /// + /// Gets or sets the created UTC time. + /// + /// + /// The created UTC time. + /// + public DateTime CreatedUtcTime { get; set; } = DateTime.UtcNow; + /// + /// Gets or sets a value indicating whether this instance is deleted. + /// + /// + /// true if this instance is deleted; otherwise, false. + /// + public bool IsDeleted { get; set; } = false; + + } +} diff --git a/src/LLMService.DataProvider.Relational/Entity/EntityConsts.cs b/src/LLMService.DataProvider.Relational/Entity/EntityConsts.cs new file mode 100644 index 0000000..6d6a3d7 --- /dev/null +++ b/src/LLMService.DataProvider.Relational/Entity/EntityConsts.cs @@ -0,0 +1,50 @@ +namespace LLMService.DataProvider.Relational.Entity +{ + /// + /// + /// + public static class EntityConsts + { + /// + /// + /// + public enum MessageDataType + { + /// + /// The plain text + /// + PlainText = 0, + /// + /// The HTML + /// + Html = 1, + /// + /// The json + /// + Json = 2, + } + + /// + /// + /// + public enum MessageContentType + { + /// + /// The text + /// + Text = 0, + /// + /// The image + /// + Image = 1, + /// + /// The audio + /// + Audio = 2, + /// + /// The video + /// + Video = 3 + } + } +} diff --git a/src/LLMService.DataProvider.Relational/Entity/ICreatedUtcTime.cs b/src/LLMService.DataProvider.Relational/Entity/ICreatedUtcTime.cs new file mode 100644 index 0000000..b9cf122 --- /dev/null +++ b/src/LLMService.DataProvider.Relational/Entity/ICreatedUtcTime.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LLMService.DataProvider.Relational.Entity +{ + /// + /// + /// + public interface ICreatedUtcTime + { + /// + /// Gets or sets the created UTC time. + /// + /// + /// The created UTC time. + /// + DateTime CreatedUtcTime { get; set; } + } +} diff --git a/src/LLMService.DataProvider.Relational/LLMService.DataProvider.Relational.csproj b/src/LLMService.DataProvider.Relational/LLMService.DataProvider.Relational.csproj new file mode 100644 index 0000000..ed500d9 --- /dev/null +++ b/src/LLMService.DataProvider.Relational/LLMService.DataProvider.Relational.csproj @@ -0,0 +1,35 @@ + + + + net6.0;net8.0 + enable + + + + + + + + + + + + + + 6.0.0 + + + + + + + + 8.0.0 + + + + diff --git a/src/LLMService.DataProvider.Relational/Provider/ChatDataRelationalDbProvider.cs b/src/LLMService.DataProvider.Relational/Provider/ChatDataRelationalDbProvider.cs new file mode 100644 index 0000000..ef886b1 --- /dev/null +++ b/src/LLMService.DataProvider.Relational/Provider/ChatDataRelationalDbProvider.cs @@ -0,0 +1,71 @@ +using LLMService.Shared.Models; +using LLMService.Shared.ServiceInterfaces; + +namespace LLMService.DataProvider.Relational.Provider +{ + /// + /// + /// + /// The type of the chat message. + /// The type of the message content. + /// + public class ChatDataRelationalDbProvider : IChatDataProvider + where TChatMessage : IChatMessage, new() + { + /// + /// Initializes a new instance of the class. + /// + public ChatDataRelationalDbProvider() + { + + } + + /// + /// Adds the chat message. + /// not write to cache. + /// + /// The conversation. + /// The message. + /// The role. + /// + /// + public Task> AddChatMessage(List conversation, TMessageContent message, string role = "user") + { + throw new NotImplementedException(); + } + + /// + /// Gets the conversation. + /// + /// The conversation identifier. + /// + /// + public Task> GetConversationHistory(string conversationId) + { + throw new NotImplementedException(); + } + + /// + /// Resets the session. + /// + /// The conversation identifier. + /// + /// + public bool ResetSession(string conversationId) + { + throw new NotImplementedException(); + } + + /// + /// Saves the chat. + /// + /// The conversation identifier. + /// + /// + /// + public Task SaveChat(string conversationId, IEnumerable conversation) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/LLMService.DataProvider.Relational/Provider/ChatStorage.cs b/src/LLMService.DataProvider.Relational/Provider/ChatStorage.cs new file mode 100644 index 0000000..dfb80c9 --- /dev/null +++ b/src/LLMService.DataProvider.Relational/Provider/ChatStorage.cs @@ -0,0 +1,48 @@ +using LLMService.DataProvider.Relational.Entity; +using LLMService.Shared.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LLMService.DataProvider.Relational.Provider +{ + /// + /// + /// + /// The type of the chat message. + /// The type of the message content. + /// The type of the chat database context. + public class ChatStorage : IChatStorage + where TChatMessage : IChatMessage, new() + { + + } + + /// + /// + /// + /// The type of the chat message. + /// The type of the message content. + /// The type of the chat folder. + /// The type of the conversation. + /// The type of the message. + /// The type of the tenant key. + /// The type of the user key. + /// The type of the conversation key. + /// The type of the message key. + /// + public class ChatStorage : IChatStorage + where TChatMessage : IChatMessage, new() + where TUserKey : IEquatable + where TTenantKey : IEquatable + where TMessageKey : IEquatable + where TConversationKey : IEquatable + where TChatFolder : ChatFolder + where TConversation : Conversation + where TMessage : ChatMessage + { + } +} diff --git a/src/LLMService.DataProvider.Relational/Provider/IChatStorage.cs b/src/LLMService.DataProvider.Relational/Provider/IChatStorage.cs new file mode 100644 index 0000000..8ccbebd --- /dev/null +++ b/src/LLMService.DataProvider.Relational/Provider/IChatStorage.cs @@ -0,0 +1,14 @@ +using LLMService.Shared.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LLMService.DataProvider.Relational.Provider +{ + internal interface IChatStorage + where TChatMessage : IChatMessage, new() + { + } +}