😎1、代码清理及格式化 2、升级依赖

This commit is contained in:
zuohuaijun 2025-06-19 01:42:57 +08:00
parent 4cdb10b2bb
commit dbcd1236a1
68 changed files with 1955 additions and 1758 deletions

View File

@ -34,7 +34,7 @@
}, },
"TableSettings": { "TableSettings": {
"EnableInitTable": true, // "EnableInitTable": true, //
"EnableIncreTable": true // [IncreTable] "EnableIncreTable": false // [IncreTable]
}, },
"SeedSettings": { "SeedSettings": {
"EnableInitSeed": true, // "EnableInitSeed": true, //

View File

@ -16,6 +16,7 @@ global using Mapster;
global using Microsoft.AspNetCore.Authorization; global using Microsoft.AspNetCore.Authorization;
global using Microsoft.AspNetCore.Mvc; global using Microsoft.AspNetCore.Mvc;
global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.SemanticKernel;
global using SqlSugar; global using SqlSugar;
global using System; global using System;
global using System.Collections.Generic; global using System.Collections.Generic;
@ -23,6 +24,3 @@ global using System.ComponentModel;
global using System.ComponentModel.DataAnnotations; global using System.ComponentModel.DataAnnotations;
global using System.Threading.Tasks; global using System.Threading.Tasks;
global using System.Linq; global using System.Linq;
global using Microsoft.SemanticKernel;
global using Microsoft.SemanticKernel.PromptTemplates.Handlebars;

View File

@ -1,5 +1,8 @@
using Admin.NET.Core.Ai.Interface; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
using Admin.NET.Core.Ai.Models; //
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Application.Service.LLM; namespace Admin.NET.Application.Service.LLM;
@ -7,10 +10,12 @@ namespace Admin.NET.Application.Service.LLM;
public class LLMChangeModelTestService : IDynamicApiController, ITransient public class LLMChangeModelTestService : IDynamicApiController, ITransient
{ {
private readonly ILLMFactory _llmFactory; private readonly ILLMFactory _llmFactory;
public LLMChangeModelTestService(ILLMFactory llmFactory) public LLMChangeModelTestService(ILLMFactory llmFactory)
{ {
_llmFactory = llmFactory; _llmFactory = llmFactory;
} }
/// <summary> /// <summary>
/// 演示大模型的使用,可以切换模型。 /// 演示大模型的使用,可以切换模型。
/// 例如可以切换到不同的模型OpenAI、Azure OpenAI、Google Gemini等。 /// 例如可以切换到不同的模型OpenAI、Azure OpenAI、Google Gemini等。
@ -26,4 +31,3 @@ public class LLMChangeModelTestService : IDynamicApiController, ITransient
return result.ToString(); return result.ToString();
} }
} }

View File

@ -1,5 +1,8 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
using Microsoft.SemanticKernel.ChatCompletion; //
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Application.Service.LLM; namespace Admin.NET.Application.Service.LLM;
@ -7,6 +10,7 @@ namespace Admin.NET.Application.Service.LLM;
public class LLMTestService : IDynamicApiController, ITransient public class LLMTestService : IDynamicApiController, ITransient
{ {
private readonly Kernel _kernel; private readonly Kernel _kernel;
public LLMTestService(Kernel kernel) public LLMTestService(Kernel kernel)
{ {
_kernel = kernel; _kernel = kernel;

View File

@ -28,9 +28,9 @@
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" /> <PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.1" Aliases="BouncyCastleV2" /> <PackageReference Include="BouncyCastle.Cryptography" Version="2.6.1" Aliases="BouncyCastleV2" />
<PackageReference Include="Elastic.Clients.Elasticsearch" Version="9.0.6" /> <PackageReference Include="Elastic.Clients.Elasticsearch" Version="9.0.6" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.87" /> <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.88" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.87" /> <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.88" />
<PackageReference Include="Furion.Pure" Version="4.9.7.87" /> <PackageReference Include="Furion.Pure" Version="4.9.7.88" />
<PackageReference Include="Hardware.Info" Version="101.0.1.1" /> <PackageReference Include="Hardware.Info" Version="101.0.1.1" />
<PackageReference Include="Hashids.net" Version="1.7.0" /> <PackageReference Include="Hashids.net" Version="1.7.0" />
<PackageReference Include="IPTools.China" Version="1.6.0" /> <PackageReference Include="IPTools.China" Version="1.6.0" />
@ -59,15 +59,15 @@
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1259" /> <PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1259" />
<PackageReference Include="UAParser" Version="3.1.47" /> <PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" /> <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
<PackageReference Include="microsoft.semantickernel" Version="1.54.0" /> <PackageReference Include="microsoft.semantickernel" Version="1.57.0" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.Core" Version="1.54.0" /> <PackageReference Include="Microsoft.SemanticKernel.Agents.Core" Version="1.57.0" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Amazon" Version="1.56.0-alpha" /> <PackageReference Include="Microsoft.SemanticKernel.Connectors.Amazon" Version="1.56.0-alpha" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Google" Version="1.54.0-alpha" /> <PackageReference Include="Microsoft.SemanticKernel.Connectors.Google" Version="1.54.0-alpha" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.HuggingFace" Version="1.56.0-preview" /> <PackageReference Include="Microsoft.SemanticKernel.Connectors.HuggingFace" Version="1.56.0-preview" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Ollama" Version="1.54.0-alpha" /> <PackageReference Include="Microsoft.SemanticKernel.Connectors.Ollama" Version="1.54.0-alpha" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Qdrant" Version="1.54.0-preview" /> <PackageReference Include="Microsoft.SemanticKernel.Connectors.Qdrant" Version="1.54.0-preview" />
<PackageReference Include="Microsoft.SemanticKernel.PromptTemplates.Handlebars" Version="1.54.0" /> <PackageReference Include="Microsoft.SemanticKernel.PromptTemplates.Handlebars" Version="1.57.0" />
<PackageReference Include="Microsoft.SemanticKernel.Yaml" Version="1.54.0" /> <PackageReference Include="Microsoft.SemanticKernel.Yaml" Version="1.57.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' "> <ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">

View File

@ -1,12 +1,17 @@
namespace Admin.NET.Core.Ai.Entitys; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary> /// <summary>
/// 聊天历史 /// 聊天历史
/// </summary> /// </summary>
[SugarTable("LLMChatHistory")] [SugarTable(null, "AI聊天历史表")]
[IncreTable] [SugarIndex("i_{table}_u", nameof(UserId), OrderByType.Asc)]
[SugarIndex("index_UserId_{table}", nameof(UserId), OrderByType.Asc)] [SugarIndex("i_{table}_s", nameof(SummaryId), OrderByType.Asc)]
[SugarIndex("index_SummaryId_{table}", nameof(SummaryId), OrderByType.Asc)]
public class LLMChatHistory : EntityBaseId public class LLMChatHistory : EntityBaseId
{ {
/// <summary> /// <summary>

View File

@ -0,0 +1,46 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary>
/// 聊天摘要历史表
/// </summary>
[SugarTable(null, "AI聊天摘要历史表")]
[SugarIndex("i_{table}_us", nameof(UserId), OrderByType.Asc)]
[SugarIndex("i_{table}_un", nameof(UniqueToken), OrderByType.Asc)]
public class LLMChatSummaryHistory : EntityBaseId
{
/// <summary>
/// 用户ID
/// </summary>
[SugarColumn(ColumnDescription = "用户ID")]
public long UserId { get; set; }
/// <summary>
/// 唯一标识
/// </summary>
[SugarColumn(ColumnDescription = "唯一标识")]
public string UniqueToken { get; set; }
/// <summary>
/// 摘要
/// </summary>
[SugarColumn(ColumnDescription = "摘要", Length = 4000)]
public string? Summary { get; set; }
/// <summary>
/// 创建时间
/// </summary>
[SugarColumn(ColumnDescription = "创建时间")]
public long UtcCreateTime { get; set; } = DateTime.UtcNow.ToLong();
/// <summary>
/// 聊天历史
/// </summary>
[Navigate(NavigateType.OneToMany, nameof(LLMChatHistory.SummaryId))]
public List<LLMChatHistory>? Histories { get; set; }
}

View File

@ -1,40 +0,0 @@
namespace Admin.NET.Core.Ai.Entitys;
/// <summary>
/// 聊天摘要历史
/// </summary>
[SugarTable("LLMChatSummaryHistory")]
[IncreTable]
[SugarIndex("index_UserId_{table}", nameof(UserId), OrderByType.Asc)]
[SugarIndex("index_UniqueToken_{table}", nameof(UniqueToken), OrderByType.Asc)]
public class LLMChatSummaryHistory:EntityBaseId
{
/// <summary>
/// 用户ID
/// </summary>
[SugarColumn(ColumnDescription = "用户ID")]
public long UserId { get; set; }
/// <summary>
/// 唯一标识
/// </summary>
[SugarColumn(ColumnDescription = "唯一标识")]
public string UniqueToken {get;set;}
/// <summary>
/// 摘要
/// </summary>
[SugarColumn(ColumnDescription = "摘要",Length = 4000)]
public string? Summary { get; set; }
/// <summary>
/// 创建时间
/// </summary>
[SugarColumn(ColumnDescription = "创建时间")]
public long UtcCreateTime {get;set;} = DateTime.UtcNow.ToLong();
/// <summary>
/// 聊天历史
/// </summary>
[Navigate(NavigateType.OneToMany, nameof(LLMChatHistory.SummaryId))]
public List<LLMChatHistory>? Histories { get; set; }
}

View File

@ -0,0 +1,43 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary>
/// 保存数据库的动作枚举
/// </summary>
public enum ChatActionEnum
{
/// <summary>
/// 无
/// </summary>
None = 0,
/// <summary>
/// 追加
/// </summary>
Append,
/// <summary>
/// 追加明细
/// </summary>
AppendItem,
/// <summary>
/// 删除所有
/// </summary>
DeleteAll,
/// <summary>
/// 删除指定明细
/// </summary>
DeleteItem,
/// <summary>
/// 重命名摘要
/// </summary>
RenameSummary,
}

View File

@ -1,32 +0,0 @@
namespace Admin.NET.Core.Ai.Enums;
/// <summary>
/// 保存数据库的动作枚举
/// </summary>
public enum ChatActionEnums
{
/// <summary>
/// 无
/// </summary>
None = 0,
/// <summary>
/// 追加
/// </summary>
Append,
/// <summary>
/// 追加明细
/// </summary>
AppendItem,
/// <summary>
/// 删除所有
/// </summary>
DeleteAll,
/// <summary>
/// 删除指定明细
/// </summary>
DeleteItem,
/// <summary>
/// 重命名摘要
/// </summary>
RenameSummary,
}

View File

@ -0,0 +1,23 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Admin.NET.Core.Ai.Service;
namespace Admin.NET.Core;
public static class LLMFactoryExtention
{
/// <summary>
/// 注册LLM模型工厂
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddLLMFactory(this IServiceCollection services)
{
services.AddTransient<ILLMFactory, ChangeModelFactory>();
return services;
}
}

View File

@ -1,20 +1,10 @@
using Microsoft.SemanticKernel; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
using Microsoft.SemanticKernel.Connectors.Google; //
using Microsoft.SemanticKernel.Connectors.AzureOpenAI; // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
using Microsoft.SemanticKernel.Connectors.OpenAI; //
using Microsoft.SemanticKernel.Connectors.HuggingFace; // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Microsoft.SemanticKernel.Connectors.Ollama;
using Microsoft.SemanticKernel.Connectors.Qdrant;
using Admin.NET.Core.Ai.Option;
using System.Net;
using Admin.NET.Core.Ai.Handlers;
using OllamaSharp;
using Admin.NET.Core.Ai.Interface;
using Admin.NET.Core.Ai.Models;
namespace Admin.NET.Core.Ai.Extentions;
namespace Admin.NET.Core;
/// <summary> /// <summary>
/// LLM注册扩展类 /// LLM注册扩展类

View File

@ -1,21 +0,0 @@
using Admin.NET.Core.Ai.Interface;
using Admin.NET.Core.Ai.Services;
using Admin.NET.Core.Ai.Services.Infrastructure;
namespace Admin.NET.Core.Ai.Extentions;
public static class LLMFactoryExtention
{
/// <summary>
/// 注册LLM模型工厂
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddLLMFactory(this IServiceCollection services)
{
services.AddTransient<ILLMFactory, ChangeModelFactory>();
return services;
}
}

View File

@ -0,0 +1,26 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using System.Net.Http.Headers;
namespace Admin.NET.Core;
public class LLMDelegatingHandler : DelegatingHandler
{
private readonly LLMCustomOptions _options;
public LLMDelegatingHandler(IOptions<LLMCustomOptions> options)
{
_options = options.Value;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
//设置header
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _options.ApiKey);
return await base.SendAsync(request, cancellationToken);
}
}

View File

@ -1,14 +1,18 @@
using System.Text.Json; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
using System.Text.RegularExpressions; //
using System.Text; // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
using System.Text.Encodings.Web; //
using System.Text.Json.Serialization; // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Handlers; using System.Text.Encodings.Web;
using System.Text.Json;
namespace Admin.NET.Core;
public class LoggingHandler : DelegatingHandler public class LoggingHandler : DelegatingHandler
{ {
private readonly ILogger<LoggingHandler> _logger; private readonly ILogger<LoggingHandler> _logger;
public LoggingHandler(HttpMessageHandler innerHandler) public LoggingHandler(HttpMessageHandler innerHandler)
{ {
InnerHandler = innerHandler ?? new HttpClientHandler(); InnerHandler = innerHandler ?? new HttpClientHandler();
@ -143,6 +147,7 @@ public class LoggingStream : Stream
public override bool CanSeek => _innerStream.CanSeek; public override bool CanSeek => _innerStream.CanSeek;
public override bool CanWrite => _innerStream.CanWrite; public override bool CanWrite => _innerStream.CanWrite;
public override long Length => _innerStream.Length; public override long Length => _innerStream.Length;
public override long Position public override long Position
{ {
get => _innerStream.Position; get => _innerStream.Position;
@ -188,8 +193,11 @@ public class LoggingStream : Stream
} }
public override void Flush() => _innerStream.Flush(); public override void Flush() => _innerStream.Flush();
public override long Seek(long offset, SeekOrigin origin) => _innerStream.Seek(offset, origin); public override long Seek(long offset, SeekOrigin origin) => _innerStream.Seek(offset, origin);
public override void SetLength(long value) => _innerStream.SetLength(value); public override void SetLength(long value) => _innerStream.SetLength(value);
public override void Write(byte[] buffer, int offset, int count) => _innerStream.Write(buffer, offset, count); public override void Write(byte[] buffer, int offset, int count) => _innerStream.Write(buffer, offset, count);
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)

View File

@ -1,23 +0,0 @@
using System.Net.Http.Headers;
using Admin.NET.Core.Ai.Option;
namespace Admin.NET.Core.Ai.Handlers;
public class LLMDelegatingHandler: DelegatingHandler
{
private readonly LLMCustomOptions _options;
public LLMDelegatingHandler(IOptions<LLMCustomOptions> options)
{
_options = options.Value;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
//设置header
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _options.ApiKey);
return await base.SendAsync(request, cancellationToken);
}
}

View File

@ -1,6 +1,10 @@
using Admin.NET.Core.Ai.Models; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Interface; namespace Admin.NET.Core;
/// <summary> /// <summary>
/// LLM工厂接口 /// LLM工厂接口
@ -14,4 +18,3 @@ public interface ILLMFactory
/// <returns></returns> /// <returns></returns>
Kernel CreateKernel(LLMModelInput modelInput); Kernel CreateKernel(LLMModelInput modelInput);
} }

View File

@ -1,6 +1,12 @@
// 1. 定义接口 // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using System.Threading.Channels; using System.Threading.Channels;
namespace Admin.NET.Core.Ai.Interface;
namespace Admin.NET.Core;
/// <summary> /// <summary>
/// SSE通道管理接口 /// SSE通道管理接口
@ -11,11 +17,13 @@ public interface ISseChannelManager
/// 注册 /// 注册
/// </summary> /// </summary>
ChannelReader<string> Register(long userId); ChannelReader<string> Register(long userId);
/// <summary> /// <summary>
/// 注销 /// 注销
/// </summary> /// </summary>
/// <param name="userId"></param> /// <param name="userId"></param>
void Unregister(long userId); void Unregister(long userId);
/// <summary> /// <summary>
/// 发送消息 /// 发送消息
/// </summary> /// </summary>

View File

@ -0,0 +1,32 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary>
/// LLM请求体
/// </summary>
public class LLMInputBody
{
public string Model { get; set; }
public List<LLMInputMessage> Messages { get; set; }
}
/// <summary>
/// LLM请求体消息
/// </summary>
public class LLMInputMessage
{
/// <summary>
/// 角色system、user、assistant
/// </summary>
public string Role { get; set; }
/// <summary>
/// 内容
/// </summary>
public string Content { get; set; }
}

View File

@ -0,0 +1,24 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary>
/// LLM模型输入
/// 用途:切换模型
/// </summary>
public class LLMModelInput
{
/// <summary>
/// 产品名称
/// </summary>
public string ProductName { get; set; }
/// <summary>
/// 模型ID
/// </summary>
public string ModelId { get; set; }
}

View File

@ -1,11 +1,18 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Admin.NET.Core.Ai.Models; namespace Admin.NET.Core;
/// <summary> /// <summary>
/// LLM输出 /// LLM输出
/// </summary> /// </summary>
public class LLMOutput { public class LLMOutput
{
public string Id { get; set; } public string Id { get; set; }
public string Provider { get; set; } public string Provider { get; set; }
public string Model { get; set; } public string Model { get; set; }
@ -18,9 +25,11 @@ public class LLMOutput {
/// <summary> /// <summary>
/// LLM输出机会 /// LLM输出机会
/// </summary> /// </summary>
public class ChoicesItem { public class ChoicesItem
{
[JsonProperty("logprobs")] [JsonProperty("logprobs")]
public string? Logprobs { get; set; } public string? Logprobs { get; set; }
public string? FinishReason { get; set; } public string? FinishReason { get; set; }
public string? NativeFinishReason { get; set; } public string? NativeFinishReason { get; set; }
public int Index { get; set; } public int Index { get; set; }
@ -30,10 +39,12 @@ public class ChoicesItem {
/// <summary> /// <summary>
/// LLM输出消息 /// LLM输出消息
/// </summary> /// </summary>
public class OutPutMessage { public class OutPutMessage
{
public string Role { get; set; } public string Role { get; set; }
public string Content { get; set; } public string Content { get; set; }
public Object Refusal { get; set; } public Object Refusal { get; set; }
[JsonProperty("reasoning")] [JsonProperty("reasoning")]
public string? Reasoning { get; set; } public string? Reasoning { get; set; }
} }
@ -41,10 +52,9 @@ public class OutPutMessage {
/// <summary> /// <summary>
/// LLM的消耗 /// LLM的消耗
/// </summary> /// </summary>
public class Usage { public class Usage
{
public int PromptTokens { get; set; } public int PromptTokens { get; set; }
public int CompletionTokens { get; set; } public int CompletionTokens { get; set; }
public int TotalTokens { get; set; } public int TotalTokens { get; set; }
} }

View File

@ -1,25 +0,0 @@
namespace Admin.NET.Core.Ai.Models;
/// <summary>
/// LLM请求体
/// </summary>
public class LLMInputBody {
public string Model { get; set; }
public List<LLMInputMessage> Messages { get; set; }
}
/// <summary>
/// LLM请求体消息
/// </summary>
public class LLMInputMessage {
/// <summary>
/// 角色system、user、assistant
/// </summary>
public string Role { get; set; }
/// <summary>
/// 内容
/// </summary>
public string Content { get; set; }
}

View File

@ -1,18 +0,0 @@
namespace Admin.NET.Core.Ai.Models;
/// <summary>
/// LLM模型输入
/// 用途:切换模型
/// </summary>
public class LLMModelInput
{
/// <summary>
/// 产品名称
/// </summary>
public string ProductName { get; set; }
/// <summary>
/// 模型ID
/// </summary>
public string ModelId { get; set; }
}

View File

@ -1,9 +1,15 @@
namespace Admin.NET.Core.Ai.Option; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary> /// <summary>
/// 手动实现LLM接口配置选项 /// 手动实现LLM接口配置选项
/// </summary> /// </summary>
public class LLMCustomOptions: IConfigurableOptions public class LLMCustomOptions : IConfigurableOptions
{ {
public string LLMType { get; set; } = "openrouter"; public string LLMType { get; set; } = "openrouter";
public string ApiKey { get; set; } public string ApiKey { get; set; }

View File

@ -1,4 +1,10 @@
namespace Admin.NET.Core.Ai.Option; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary> /// <summary>
/// LLM配置选项 /// LLM配置选项
@ -49,4 +55,3 @@ public class EmbeddingOptions
public string ModelId { get; set; } public string ModelId { get; set; }
public List<string> SupportModelIds { get; set; } public List<string> SupportModelIds { get; set; }
} }

View File

@ -1,4 +1,10 @@
namespace Admin.NET.Core.Ai.Services.Chat.Dto; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Service;
public class ChatInput public class ChatInput
{ {
@ -6,14 +12,17 @@ public class ChatInput
/// 摘要id /// 摘要id
/// </summary> /// </summary>
public long SummaryId { get; set; } public long SummaryId { get; set; }
/// <summary> /// <summary>
/// 摘要 /// 摘要
/// </summary> /// </summary>
public string? Summary { get; set; } public string? Summary { get; set; }
/// <summary> /// <summary>
/// 摘要唯一标识 /// 摘要唯一标识
/// </summary> /// </summary>
public string? UniqueToken { get; set; } = ""; public string? UniqueToken { get; set; } = "";
/// <summary> /// <summary>
/// 消息 /// 消息
/// </summary> /// </summary>
@ -24,14 +33,13 @@ public class ChatInput
/// </summary> /// </summary>
public string ProviderName { get; set; } public string ProviderName { get; set; }
/// <summary> /// <summary>
/// 模型id /// 模型id
/// </summary> /// </summary>
public string ModelId { get; set; } public string ModelId { get; set; }
/// <summary> /// <summary>
/// 深度思考 /// 深度思考
/// </summary> /// </summary>
public bool DeepThinking { get; set; } = false; public bool DeepThinking { get; set; } = false;
} }

View File

@ -0,0 +1,11 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Service;
public class ChatListInput : BasePageInput
{
}

View File

@ -0,0 +1,14 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Service;
/// <summary>
/// 聊天列表输出
/// </summary>
public class ChatListOutput : LLMChatSummaryHistory
{
}

View File

@ -0,0 +1,35 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Service;
public class ChatOutput
{
/// <summary>
/// 唯一标识
/// </summary>
public string? UniqueToken { get; set; }
/// <summary>
/// 备注
/// </summary>
public string? Note { get; set; }
/// <summary>
/// 状态
/// </summary>
public bool State { get; set; } = true;
/// <summary>
/// 摘要
/// </summary>
public string? Summary { get; set; } = "";
/// <summary>
/// 摘要ID
/// </summary>
public long? SummaryId { get; set; }
}

View File

@ -0,0 +1,11 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Service;
public class ModelListChangeInput : ModelListOutputItem
{
}

View File

@ -1,4 +1,10 @@
namespace Admin.NET.Core.Ai.Services.Chat.Dto; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Service;
/// <summary> /// <summary>
/// 模型列表输出 /// 模型列表输出
@ -33,11 +39,8 @@ public class ModelListOutputItem
/// </summary> /// </summary>
public string ProviderName { get; set; } public string ProviderName { get; set; }
/// <summary> /// <summary>
/// 模型名称 /// 模型名称
/// </summary> /// </summary>
public string ModelName { get; set; } public string ModelName { get; set; }
} }

View File

@ -1,17 +1,13 @@
using Admin.NET.Core.Ai.Enums; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
using Admin.NET.Core.Ai.Option; //
using Admin.NET.Core.Ai.Services.Chat.Dto; // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
using Admin.NET.Core.Ai.Services.DataBase; //
using Admin.NET.Core.Ai.Services.DataBase.Dto; // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Microsoft.SemanticKernel.ChatCompletion;
using Admin.NET.Core.Ai.Services.SSE; using Microsoft.SemanticKernel.ChatCompletion;
using LLMChatHistory = Admin.NET.Core.Ai.Entitys.LLMChatHistory;
using LLMChatSummaryHistory = Admin.NET.Core.Ai.Entitys.LLMChatSummaryHistory; namespace Admin.NET.Core.Ai.Service;
using Admin.NET.Core.Ai.Interface;
using Admin.NET.Core.Ai.Models;
using NewLife.Reflection;
namespace Admin.NET.Core.Ai.Services.Chat;
/// <summary> /// <summary>
/// 聊天补全核心服务 /// 聊天补全核心服务
/// </summary> /// </summary>
@ -19,8 +15,10 @@ public class LLMChatCoreService : ITransient
{ {
private readonly ILogger<LLMChatCoreService> _logger; private readonly ILogger<LLMChatCoreService> _logger;
private readonly IChatHistoryReducer _chatHistoryTruncationReducer; //截取器 private readonly IChatHistoryReducer _chatHistoryTruncationReducer; //截取器
// private readonly IChatHistoryReducer _chatHistorySummarizationReducer; //摘要器 // private readonly IChatHistoryReducer _chatHistorySummarizationReducer; //摘要器
private readonly ILLMFactory _llmFactory; private readonly ILLMFactory _llmFactory;
private readonly SseChannelManager _sseChannelManager; //给sse服务发送消息 private readonly SseChannelManager _sseChannelManager; //给sse服务发送消息
private readonly SseDeepThinkingChannelManager _sseDeepThinkingChannelManager; //给sse服务发送深度思考消息 private readonly SseDeepThinkingChannelManager _sseDeepThinkingChannelManager; //给sse服务发送深度思考消息
private readonly ChatChannelManager _dbAction; //操作数据库 private readonly ChatChannelManager _dbAction; //操作数据库
@ -29,6 +27,7 @@ public class LLMChatCoreService : ITransient
private readonly UserManager _userManager; private readonly UserManager _userManager;
private Kernel _kernel; private Kernel _kernel;
private readonly SysCacheService _sysCacheService; private readonly SysCacheService _sysCacheService;
public LLMChatCoreService(ILogger<LLMChatCoreService> logger, public LLMChatCoreService(ILogger<LLMChatCoreService> logger,
ILLMFactory llmFactory, ILLMFactory llmFactory,
SseChannelManager sseChannelManager, SseChannelManager sseChannelManager,
@ -75,6 +74,7 @@ public class LLMChatCoreService : ITransient
} }
#region #region
/// <summary> /// <summary>
/// 新聊天 /// 新聊天
/// </summary> /// </summary>
@ -93,6 +93,7 @@ public class LLMChatCoreService : ITransient
return await NormalNewChatCore(input, kernel, cancellationToken); return await NormalNewChatCore(input, kernel, cancellationToken);
} }
} }
/// <summary> /// <summary>
/// 深度思考新聊天 /// 深度思考新聊天
/// </summary> /// </summary>
@ -103,7 +104,9 @@ public class LLMChatCoreService : ITransient
private async Task<ChatOutput> DeepThinkingNewChatCore(ChatInput input, Kernel kernel, CancellationToken cancellationToken) private async Task<ChatOutput> DeepThinkingNewChatCore(ChatInput input, Kernel kernel, CancellationToken cancellationToken)
{ {
ChatHistory chatHistory = []; ChatHistory chatHistory = [];
#region #region
var deepThinkingPrompt = $""" var deepThinkingPrompt = $"""
AI助手, AI助手,
``` ```
@ -131,7 +134,9 @@ public class LLMChatCoreService : ITransient
await _sseDeepThinkingChannelManager.SendMessageAsync(_userManager.UserId, streamInput, cancellationToken); await _sseDeepThinkingChannelManager.SendMessageAsync(_userManager.UserId, streamInput, cancellationToken);
} }
await _sseDeepThinkingChannelManager.SendMessageAsync(_userManager.UserId, "[DONE]", cancellationToken); await _sseDeepThinkingChannelManager.SendMessageAsync(_userManager.UserId, "[DONE]", cancellationToken);
#endregion
#endregion
//生成最终答案 //生成最终答案
return await NormalNewChatCore(input, kernel, cancellationToken, thinkingMessage); return await NormalNewChatCore(input, kernel, cancellationToken, thinkingMessage);
} }
@ -215,7 +220,7 @@ public class LLMChatCoreService : ITransient
}; };
DataActionInput dataActionInput = new DataActionInput DataActionInput dataActionInput = new DataActionInput
{ {
ActionType = ChatActionEnums.Append, ActionType = ChatActionEnum.Append,
Item = chatSummaryHistory Item = chatSummaryHistory
}; };
await _dbAction.ActionWriter.WriteAsync(dataActionInput); await _dbAction.ActionWriter.WriteAsync(dataActionInput);
@ -227,7 +232,8 @@ public class LLMChatCoreService : ITransient
Summary = "New Chat" Summary = "New Chat"
}; };
} }
#endregion
#endregion
#region #region
@ -251,6 +257,7 @@ public class LLMChatCoreService : ITransient
return await NormalContinueChatCoreAsync(input, kernel, uniqueToken, chatHistory, cancellationToken); return await NormalContinueChatCoreAsync(input, kernel, uniqueToken, chatHistory, cancellationToken);
} }
} }
/// <summary> /// <summary>
/// 深度思考续聊 /// 深度思考续聊
/// </summary> /// </summary>
@ -263,6 +270,7 @@ public class LLMChatCoreService : ITransient
private async Task<ChatOutput> DeepThinkingContinueChatCoreAsync(ChatInput input, Kernel kernel, string uniqueToken, ChatHistory chatHistory, CancellationToken cancellationToken) private async Task<ChatOutput> DeepThinkingContinueChatCoreAsync(ChatInput input, Kernel kernel, string uniqueToken, ChatHistory chatHistory, CancellationToken cancellationToken)
{ {
#region #region
var deepThinkChatHistory = new ChatHistory(chatHistory); var deepThinkChatHistory = new ChatHistory(chatHistory);
var deepThinkingPrompt = $""" var deepThinkingPrompt = $"""
AI助手,emoji表达人类情感**** AI助手,emoji表达人类情感****
@ -288,10 +296,12 @@ public class LLMChatCoreService : ITransient
} }
await _sseDeepThinkingChannelManager.SendMessageAsync(_userManager.UserId, "[DONE]", cancellationToken); await _sseDeepThinkingChannelManager.SendMessageAsync(_userManager.UserId, "[DONE]", cancellationToken);
#endregion #endregion
//生成最终答案 //生成最终答案
return await NormalContinueChatCoreAsync(input, kernel, uniqueToken, chatHistory, cancellationToken, thinkingMessage); return await NormalContinueChatCoreAsync(input, kernel, uniqueToken, chatHistory, cancellationToken, thinkingMessage);
} }
/// <summary> /// <summary>
/// 普通续聊 /// 普通续聊
/// </summary> /// </summary>
@ -368,6 +378,7 @@ public class LLMChatCoreService : ITransient
} }
input.SummaryId = chatSummaryHistory.Id; input.SummaryId = chatSummaryHistory.Id;
} }
private async Task _UpdateSummaryToDatabase(string summary, ChatInput input) private async Task _UpdateSummaryToDatabase(string summary, ChatInput input)
{ {
//更新摘要至数据库 //更新摘要至数据库
@ -375,7 +386,7 @@ public class LLMChatCoreService : ITransient
{ {
await _dbAction.ActionWriter.WriteAsync(new DataActionInput await _dbAction.ActionWriter.WriteAsync(new DataActionInput
{ {
ActionType = ChatActionEnums.RenameSummary, ActionType = ChatActionEnum.RenameSummary,
Item = new LLMChatSummaryHistory Item = new LLMChatSummaryHistory
{ {
Id = input.SummaryId, Id = input.SummaryId,
@ -410,6 +421,7 @@ public class LLMChatCoreService : ITransient
); );
return result.Content ?? ""; return result.Content ?? "";
} }
/// <summary> /// <summary>
/// 获取聊天历史,并截取 /// 获取聊天历史,并截取
/// </summary> /// </summary>
@ -432,12 +444,15 @@ public class LLMChatCoreService : ITransient
case "user": case "user":
chatHistory.AddUserMessage(history.Content); chatHistory.AddUserMessage(history.Content);
break; break;
case "assistant": case "assistant":
chatHistory.AddAssistantMessage(history.Content); chatHistory.AddAssistantMessage(history.Content);
break; break;
case "system": case "system":
chatHistory.AddSystemMessage(history.Content); chatHistory.AddSystemMessage(history.Content);
break; break;
default: default:
break; break;
} }
@ -453,6 +468,7 @@ public class LLMChatCoreService : ITransient
} }
return chatHistory; return chatHistory;
} }
private async Task _SaveChatItemToDatabase(ChatHistory chatHistory, string uniqueToken) private async Task _SaveChatItemToDatabase(ChatHistory chatHistory, string uniqueToken)
{ {
var chatSummaryHistory = await _chatSummaryHistoryService.AsQueryable().Where(u => u.UniqueToken == uniqueToken).FirstAsync(); var chatSummaryHistory = await _chatSummaryHistoryService.AsQueryable().Where(u => u.UniqueToken == uniqueToken).FirstAsync();
@ -474,14 +490,16 @@ public class LLMChatCoreService : ITransient
} }
DataActionInput dataActionInput = new DataActionInput DataActionInput dataActionInput = new DataActionInput
{ {
ActionType = ChatActionEnums.AppendItem, ActionType = ChatActionEnum.AppendItem,
Item = chatSummaryHistory Item = chatSummaryHistory
}; };
await _dbAction.ActionWriter.WriteAsync(dataActionInput); await _dbAction.ActionWriter.WriteAsync(dataActionInput);
} }
#endregion
#endregion
#region #region
/// <summary> /// <summary>
/// 删除所属摘要的所有聊天记录 /// 删除所属摘要的所有聊天记录
/// </summary> /// </summary>
@ -496,15 +514,17 @@ public class LLMChatCoreService : ITransient
} }
DataActionInput dataActionInput = new DataActionInput DataActionInput dataActionInput = new DataActionInput
{ {
ActionType = ChatActionEnums.DeleteAll, ActionType = ChatActionEnum.DeleteAll,
Item = chatSummaryHistory Item = chatSummaryHistory
}; };
await _dbAction.ActionWriter.WriteAsync(dataActionInput); await _dbAction.ActionWriter.WriteAsync(dataActionInput);
return true; return true;
} }
#endregion
#endregion
#region #region
/// <summary> /// <summary>
/// 重命名所属摘要的标签 /// 重命名所属摘要的标签
/// </summary> /// </summary>
@ -520,12 +540,12 @@ public class LLMChatCoreService : ITransient
chatSummaryHistory.Summary = input.Summary; chatSummaryHistory.Summary = input.Summary;
DataActionInput dataActionInput = new DataActionInput DataActionInput dataActionInput = new DataActionInput
{ {
ActionType = ChatActionEnums.RenameSummary, ActionType = ChatActionEnum.RenameSummary,
Item = chatSummaryHistory Item = chatSummaryHistory
}; };
await _dbAction.ActionWriter.WriteAsync(dataActionInput); await _dbAction.ActionWriter.WriteAsync(dataActionInput);
return true; return true;
} }
#endregion
}
#endregion
}

View File

@ -1,10 +1,10 @@
using Admin.NET.Core.Ai.Entitys; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
using Admin.NET.Core.Ai.Option; //
using Admin.NET.Core.Ai.Services.Chat.Dto; // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
using Admin.NET.Core.Ai.Services.DataBase; //
using Admin.NET.Core.Ai.Services.SSE; // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Services.Chat; namespace Admin.NET.Core.Ai.Service;
/// <summary> /// <summary>
/// LLM聊天补全服务 /// LLM聊天补全服务
@ -95,7 +95,6 @@ public class LLMChatService : IDynamicApiController, ITransient
[ApiDescriptionSettings(Description = "获取模型列表", Name = "ModelList")] [ApiDescriptionSettings(Description = "获取模型列表", Name = "ModelList")]
public async Task<ModelListOutput> GetModelListAsync() => await _llmOptionService.GetModelListAsync(); public async Task<ModelListOutput> GetModelListAsync() => await _llmOptionService.GetModelListAsync();
/// <summary> /// <summary>
/// 切换模型 /// 切换模型
/// </summary> /// </summary>

View File

@ -1,7 +1,10 @@
using Admin.NET.Core.Ai.Option; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
using Admin.NET.Core.Ai.Services.Chat.Dto; //
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Services.Chat; namespace Admin.NET.Core.Ai.Service;
public class LLMOptionService : ITransient public class LLMOptionService : ITransient
{ {
@ -9,6 +12,7 @@ public class LLMOptionService : ITransient
private readonly UserManager _userManager; private readonly UserManager _userManager;
private readonly IOptions<LLMOptions> _llmOptions; private readonly IOptions<LLMOptions> _llmOptions;
private readonly SysCacheService _sysCacheService; private readonly SysCacheService _sysCacheService;
public LLMOptionService(ILogger<LLMOptionService> logger, public LLMOptionService(ILogger<LLMOptionService> logger,
UserManager userManager, UserManager userManager,
IOptions<LLMOptions> llmOptions, IOptions<LLMOptions> llmOptions,
@ -19,6 +23,7 @@ public class LLMOptionService : ITransient
_llmOptions = llmOptions; _llmOptions = llmOptions;
_sysCacheService = sysCacheService; _sysCacheService = sysCacheService;
} }
/// <summary> /// <summary>
/// 获取模型列表 /// 获取模型列表
/// 步骤: /// 步骤:
@ -55,6 +60,7 @@ public class LLMOptionService : ITransient
_sysCacheService.Set(key, output); _sysCacheService.Set(key, output);
return await Task.FromResult(output); return await Task.FromResult(output);
} }
/// <summary> /// <summary>
/// 可能存在用户手动修改了配置文件,如删除、添加、修改模型,此时需要更新缓存中的模型列表 /// 可能存在用户手动修改了配置文件,如删除、添加、修改模型,此时需要更新缓存中的模型列表
/// </summary> /// </summary>
@ -134,6 +140,7 @@ public class LLMOptionService : ITransient
} }
return await _UpdateModelList(input, cache, key); return await _UpdateModelList(input, cache, key);
} }
private async Task<bool> _SetNewModelList(ModelListChangeInput input, string key) private async Task<bool> _SetNewModelList(ModelListChangeInput input, string key)
{ {
var currentModel = _llmOptions.Value.Providers.FirstOrDefault(it => it.ProductName == input.ProviderName); var currentModel = _llmOptions.Value.Providers.FirstOrDefault(it => it.ProductName == input.ProviderName);
@ -171,4 +178,3 @@ public class LLMOptionService : ITransient
return await Task.FromResult(true); return await Task.FromResult(true);
} }
} }

View File

@ -1,8 +1,10 @@
namespace Admin.NET.Core.Ai.Services.DataBase; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Admin.NET.Core.Ai.Entitys; namespace Admin.NET.Core.Ai.Service;
using Admin.NET.Core.Ai.Enums;
using Admin.NET.Core.Ai.Services.DataBase.Dto;
/// <summary> /// <summary>
/// 异步对数据库进行操作 /// 异步对数据库进行操作

View File

@ -1,9 +1,12 @@
using System.Threading.Channels; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
using Admin.NET.Core.Ai.Services.DataBase.Dto; //
using Admin.NET.Core.Ai.Enums; // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
using Microsoft.Extensions.DependencyInjection; //
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Services.DataBase; using System.Threading.Channels;
namespace Admin.NET.Core.Ai.Service;
public class ChatChannelManager : ISingleton public class ChatChannelManager : ISingleton
{ {
@ -35,16 +38,19 @@ public class ChatChannelManager : ISingleton
switch (action.ActionType) switch (action.ActionType)
{ {
case ChatActionEnums.Append: case ChatActionEnum.Append:
await chatChannelActionService.AppendAsync(action.Item); await chatChannelActionService.AppendAsync(action.Item);
break; break;
case ChatActionEnums.AppendItem:
case ChatActionEnum.AppendItem:
await chatChannelActionService.AppendItemAsync(action.Item); await chatChannelActionService.AppendItemAsync(action.Item);
break; break;
case ChatActionEnums.DeleteAll:
case ChatActionEnum.DeleteAll:
await chatChannelActionService.DeleteAllAsync(action.Item); await chatChannelActionService.DeleteAllAsync(action.Item);
break; break;
case ChatActionEnums.RenameSummary:
case ChatActionEnum.RenameSummary:
await chatChannelActionService.RenameSummaryAsync(action.Item); await chatChannelActionService.RenameSummaryAsync(action.Item);
break; break;
} }

View File

@ -0,0 +1,13 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Service;
public class DataActionInput
{
public ChatActionEnum ActionType { get; set; }
public LLMChatSummaryHistory Item { get; set; }
}

View File

@ -1,14 +1,15 @@
using System.Net; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
using Admin.NET.Core.Ai.Handlers; //
using Admin.NET.Core.Ai.Interface; // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
using Admin.NET.Core.Ai.Models; //
using Admin.NET.Core.Ai.Option; // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Microsoft.SemanticKernel.Connectors.Ollama;
using OllamaSharp;
using Amazon.BedrockRuntime; using Amazon.BedrockRuntime;
using Amazon.Runtime; using Amazon.Runtime;
using OllamaSharp;
using System.Net;
namespace Admin.NET.Core.Ai.Services.Infrastructure; namespace Admin.NET.Core.Ai.Service;
/// <summary> /// <summary>
/// 模型切换工厂 /// 模型切换工厂
@ -17,10 +18,12 @@ namespace Admin.NET.Core.Ai.Services.Infrastructure;
public class ChangeModelFactory : ILLMFactory, ITransient public class ChangeModelFactory : ILLMFactory, ITransient
{ {
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
public ChangeModelFactory(IServiceProvider serviceProvider) public ChangeModelFactory(IServiceProvider serviceProvider)
{ {
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
} }
/// <summary> /// <summary>
/// 创建Kernel实例 /// 创建Kernel实例
/// </summary> /// </summary>
@ -31,6 +34,7 @@ public class ChangeModelFactory : ILLMFactory, ITransient
var builder = Kernel.CreateBuilder(); var builder = Kernel.CreateBuilder();
return GetKernel(builder, modelInput); return GetKernel(builder, modelInput);
} }
/// <summary> /// <summary>
/// 获取Kernel实例 /// 获取Kernel实例
/// </summary> /// </summary>
@ -62,6 +66,7 @@ public class ChangeModelFactory : ILLMFactory, ITransient
} }
ConfigureKernelCore(builder, httpClient, provider, modelInput.ModelId); ConfigureKernelCore(builder, httpClient, provider, modelInput.ModelId);
} }
/// <summary> /// <summary>
/// 配置Kernel核心代码 /// 配置Kernel核心代码
/// </summary> /// </summary>
@ -85,8 +90,7 @@ public class ChangeModelFactory : ILLMFactory, ITransient
); );
if (provider.ProductName == "OpenAI") if (provider.ProductName == "OpenAI")
{ {
#pragma warning disable SKEXP0010 // 禁用预览API的警告
#pragma warning disable SKEXP0010 // 禁用预览API的警告
// 如果模型是OpenAI则添加音频转文字服务 // 如果模型是OpenAI则添加音频转文字服务
builder.AddOpenAIAudioToText( builder.AddOpenAIAudioToText(
modelId: modelId, modelId: modelId,
@ -105,9 +109,10 @@ public class ChangeModelFactory : ILLMFactory, ITransient
apiKey: apiKey, apiKey: apiKey,
httpClient: httpClient httpClient: httpClient
); );
#pragma warning restore #pragma warning restore
} }
break; break;
case "AzureOpenAI": case "AzureOpenAI":
builder.AddAzureOpenAIChatCompletion( builder.AddAzureOpenAIChatCompletion(
deploymentName: modelId, deploymentName: modelId,
@ -115,7 +120,7 @@ public class ChangeModelFactory : ILLMFactory, ITransient
apiKey: apiKey, apiKey: apiKey,
httpClient: httpClient httpClient: httpClient
); );
#pragma warning disable SKEXP0010 // 禁用预览API的警告 #pragma warning disable SKEXP0010 // 禁用预览API的警告
builder.AddAzureOpenAIAudioToText( builder.AddAzureOpenAIAudioToText(
deploymentName: modelId, deploymentName: modelId,
endpoint: provider.ApiEndpoint, endpoint: provider.ApiEndpoint,
@ -134,36 +139,40 @@ public class ChangeModelFactory : ILLMFactory, ITransient
apiKey: apiKey, apiKey: apiKey,
httpClient: httpClient httpClient: httpClient
); );
#pragma warning restore SKEXP0010 // 禁用预览API的警告 #pragma warning restore SKEXP0010 // 禁用预览API的警告
break; break;
case "Ollama": case "Ollama":
var ollamaClient = new OllamaApiClient( var ollamaClient = new OllamaApiClient(
uriString: provider.ApiEndpoint, uriString: provider.ApiEndpoint,
defaultModel: modelId defaultModel: modelId
); );
#pragma warning disable SKEXP0070// 禁用预览API的警告 #pragma warning disable SKEXP0070// 禁用预览API的警告
builder.AddOllamaChatCompletion( builder.AddOllamaChatCompletion(
ollamaClient: ollamaClient ollamaClient: ollamaClient
); );
#pragma warning restore SKEXP0070// 禁用预览API的警告 #pragma warning restore SKEXP0070// 禁用预览API的警告
break; break;
case "Claude": case "Claude":
var credentials = new BasicAWSCredentials(provider.ApiKey, provider.ApiSecret); var credentials = new BasicAWSCredentials(provider.ApiKey, provider.ApiSecret);
var amazonBedrockRuntime = new AmazonBedrockRuntimeClient(credentials, new AmazonBedrockRuntimeConfig var amazonBedrockRuntime = new AmazonBedrockRuntimeClient(credentials, new AmazonBedrockRuntimeConfig
{ {
RegionEndpoint = Amazon.RegionEndpoint.GetBySystemName(provider.Region) RegionEndpoint = Amazon.RegionEndpoint.GetBySystemName(provider.Region)
}); });
#pragma warning disable SKEXP0070 #pragma warning disable SKEXP0070
builder.AddBedrockChatCompletionService( builder.AddBedrockChatCompletionService(
modelId: modelId, modelId: modelId,
bedrockRuntime: amazonBedrockRuntime bedrockRuntime: amazonBedrockRuntime
); );
#pragma warning restore SKEXP0070 #pragma warning restore SKEXP0070
break; break;
default: default:
throw new Exception($"未找到{provider.LLMType}模型提供者"); throw new Exception($"未找到{provider.LLMType}模型提供者");
} }
} }
/// <summary> /// <summary>
/// 获取HttpClient实例,可能为null /// 获取HttpClient实例,可能为null
/// </summary> /// </summary>
@ -204,4 +213,3 @@ public class ChangeModelFactory : ILLMFactory, ITransient
return httpMessageHandler == null ? null : new HttpClient(httpMessageHandler); return httpMessageHandler == null ? null : new HttpClient(httpMessageHandler);
} }
} }

View File

@ -1,9 +1,12 @@
using Admin.NET.Core.Ai.Models; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
using Admin.NET.Core.Ai.Option; //
using Admin.NET.Core.Ai.Utils; // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Admin.NET.Core.Ai.Services.Infrastructure; namespace Admin.NET.Core.Ai.Service;
/// <summary> /// <summary>
/// OpenRouter 客户端 /// OpenRouter 客户端
@ -19,6 +22,7 @@ public class LLMOpenRouterClient
_options = options.Value; _options = options.Value;
_httpClient.Timeout = TimeSpan.FromSeconds(_options.Timeout); _httpClient.Timeout = TimeSpan.FromSeconds(_options.Timeout);
} }
/// <summary> /// <summary>
/// 获取提示词的LLM的回答 /// 获取提示词的LLM的回答
/// </summary> /// </summary>
@ -41,6 +45,7 @@ public class LLMOpenRouterClient
} }
}); });
} }
/// <summary> /// <summary>
/// 获取聊天记录的LLM的回答 /// 获取聊天记录的LLM的回答
/// </summary> /// </summary>
@ -62,6 +67,7 @@ public class LLMOpenRouterClient
} }
}); });
} }
/// <summary> /// <summary>
/// 获取LLM的回答 /// 获取LLM的回答
/// </summary> /// </summary>
@ -71,7 +77,7 @@ public class LLMOpenRouterClient
/// <exception cref="ArgumentException">消息列表不能为空</exception> /// <exception cref="ArgumentException">消息列表不能为空</exception>
/// <exception cref="Exception">网络请求错误</exception> /// <exception cref="Exception">网络请求错误</exception>
/// <exception cref="JsonException">JSON解析错误</exception> /// <exception cref="JsonException">JSON解析错误</exception>
private async Task<string> GetLLMResponseAsync(List<LLMInputMessage> messages,Action<List<LLMInputMessage>> beforeSendAction = null) private async Task<string> GetLLMResponseAsync(List<LLMInputMessage> messages, Action<List<LLMInputMessage>> beforeSendAction = null)
{ {
try try
{ {
@ -89,7 +95,7 @@ public class LLMOpenRouterClient
var inputBody = new LLMInputBody(); var inputBody = new LLMInputBody();
inputBody.Model = defaultLLM.Model; inputBody.Model = defaultLLM.Model;
inputBody.Messages = messages; inputBody.Messages = messages;
var strBody = LLMJsonTools.SerializeObject(inputBody); var strBody = LLMJsonTool.SerializeObject(inputBody);
beforeSendAction?.Invoke(messages); // 在发送请求之前,可以对消息进行修改 beforeSendAction?.Invoke(messages); // 在发送请求之前,可以对消息进行修改
using (var content = new StringContent(strBody, Encoding.UTF8, "application/json")) using (var content = new StringContent(strBody, Encoding.UTF8, "application/json"))
using (var response = await _httpClient.PostAsync(_options.BaseUrl, content)) using (var response = await _httpClient.PostAsync(_options.BaseUrl, content))
@ -97,7 +103,7 @@ public class LLMOpenRouterClient
if (response.StatusCode == System.Net.HttpStatusCode.OK) if (response.StatusCode == System.Net.HttpStatusCode.OK)
{ {
var strResponse = await response.Content.ReadAsStringAsync(); var strResponse = await response.Content.ReadAsStringAsync();
var output = LLMJsonTools.DeserializeObject<LLMOutput>(strResponse); var output = LLMJsonTool.DeserializeObject<LLMOutput>(strResponse);
return output.Choices[0].Message.Content; return output.Choices[0].Message.Content;
} }
else else

View File

@ -1,7 +1,12 @@
using System.Threading.Channels; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
using Admin.NET.Core.Ai.Interface; //
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Services.SSE; using System.Threading.Channels;
namespace Admin.NET.Core.Ai.Service;
/// <summary> /// <summary>
/// SSE通道管理 /// SSE通道管理

View File

@ -0,0 +1,14 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Service;
/// <summary>
/// 聊天通道管理
/// </summary>
public class SseChannelManager : BaseSseChannelManager, ISingleton
{
}

View File

@ -0,0 +1,14 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Service;
/// <summary>
/// 深度思考通道管理
/// </summary>
public class SseDeepThinkingChannelManager : BaseSseChannelManager, ISingleton
{
}

View File

@ -1,4 +1,10 @@
namespace Admin.NET.Core.Ai.Services.SSE; // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Ai.Service;
/// <summary> /// <summary>
/// SSE服务 /// SSE服务
@ -72,4 +78,3 @@ public class SseService : ControllerBase
} }
} }
} }

View File

@ -1,7 +0,0 @@
namespace Admin.NET.Core.Ai.Services.Chat.Dto;
public class ChatListInput : BasePageInput
{
}

View File

@ -1,10 +0,0 @@
using Admin.NET.Core.Ai.Entitys;
namespace Admin.NET.Core.Ai.Services.Chat.Dto;
/// <summary>
/// 聊天列表输出
/// </summary>
public class ChatListOutput:LLMChatSummaryHistory
{
}

View File

@ -1,30 +0,0 @@
namespace Admin.NET.Core.Ai.Services.Chat.Dto;
public class ChatOutput
{
/// <summary>
/// 唯一标识
/// </summary>
public string? UniqueToken { get; set; }
/// <summary>
/// 备注
/// </summary>
public string? Note { get; set; }
/// <summary>
/// 状态
/// </summary>
public bool State { get; set; } = true;
/// <summary>
/// 摘要
/// </summary>
public string? Summary { get; set; } = "";
/// <summary>
/// 摘要ID
/// </summary>
public long? SummaryId { get; set; }
}

View File

@ -1,7 +0,0 @@
namespace Admin.NET.Core.Ai.Services.Chat.Dto;
public class ModelListChangeInput:ModelListOutputItem
{
}

View File

@ -1,11 +0,0 @@
using Admin.NET.Core.Ai.Entitys;
using Admin.NET.Core.Ai.Enums;
namespace Admin.NET.Core.Ai.Services.DataBase.Dto;
public class DataActionInput
{
public ChatActionEnums ActionType { get; set; }
public LLMChatSummaryHistory Item { get; set; }
}

View File

@ -1,10 +0,0 @@
using System.Threading.Channels;
namespace Admin.NET.Core.Ai.Services.SSE;
/// <summary>
/// 聊天通道管理
/// </summary>
public class SseChannelManager: BaseSseChannelManager,ISingleton
{
}

View File

@ -1,10 +0,0 @@
using System.Threading.Channels;
namespace Admin.NET.Core.Ai.Services.SSE;
/// <summary>
/// 深度思考通道管理
/// </summary>
public class SseDeepThinkingChannelManager: BaseSseChannelManager,ISingleton
{
}

View File

@ -1,12 +1,18 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
namespace Admin.NET.Core.Ai.Utils; namespace Admin.NET.Core;
/// <summary> /// <summary>
/// LLM JSON 工具类 /// LLM JSON 工具类
/// </summary> /// </summary>
public class LLMJsonTools public class LLMJsonTool
{ {
/// <summary> /// <summary>
/// 序列化对象 /// 序列化对象

View File

@ -34,6 +34,7 @@ global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Hosting; global using Microsoft.Extensions.Hosting;
global using Microsoft.Extensions.Logging; global using Microsoft.Extensions.Logging;
global using Microsoft.Extensions.Options; global using Microsoft.Extensions.Options;
global using Microsoft.SemanticKernel;
global using NewLife; global using NewLife;
global using NewLife.Caching; global using NewLife.Caching;
global using Newtonsoft.Json.Linq; global using Newtonsoft.Json.Linq;
@ -60,6 +61,3 @@ global using System.Text.RegularExpressions;
global using System.Web; global using System.Web;
global using UAParser; global using UAParser;
global using Yitter.IdGenerator; global using Yitter.IdGenerator;
global using Microsoft.SemanticKernel;
global using Microsoft.SemanticKernel.PromptTemplates.Handlebars;

View File

@ -157,13 +157,13 @@ public static class CodeGenHelper
{ {
return dataType.ToLower() switch return dataType.ToLower() switch
{ {
"tinytext" or "mediumtext" or "longtext" or "mid" or "text" or "varchar" or "char" or "nvarchar" or "nchar" or "timestamp" => "string", "tinytext" or "mediumtext" or "longtext" or "mid" or "text" or "varchar" or "char" or "nvarchar" or "nchar" or "string" or "timestamp" => "string",
"int" or "integer" => "int", "int" or "integer" or "int32" => "int",
"smallint" => "Int16", "smallint" => "Int16",
//"tinyint" => "byte", //"tinyint" => "byte",
"tinyint" => "bool", // MYSQL "tinyint" => "bool", // MYSQL
"bigint" => "long", "bigint" or "int64" => "long",
"bit" => "bool", "bit" or "boolean" => "bool",
"money" or "smallmoney" or "numeric" or "decimal" => "decimal", "money" or "smallmoney" or "numeric" or "decimal" => "decimal",
"real" => "Single", "real" => "Single",
"datetime" or "datetime2" or "smalldatetime" => "DateTime", "datetime" or "datetime2" or "smalldatetime" => "DateTime",

View File

@ -5,7 +5,6 @@
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Admin.NET.Core; using Admin.NET.Core;
using Admin.NET.Core.Ai.Option;
using AspNetCoreRateLimit; using AspNetCoreRateLimit;
using Furion; using Furion;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -44,9 +43,8 @@ public static class ProjectOptions
services.Configure<ClientRateLimitOptions>(App.Configuration.GetSection("ClientRateLimiting")); services.Configure<ClientRateLimitOptions>(App.Configuration.GetSection("ClientRateLimiting"));
services.Configure<ClientRateLimitPolicies>(App.Configuration.GetSection("ClientRateLimitPolicies")); services.Configure<ClientRateLimitPolicies>(App.Configuration.GetSection("ClientRateLimitPolicies"));
services.AddConfigurableOptions<LLMCustomOptions>(); //手动实现LLM接口配置选项 services.AddConfigurableOptions<LLMCustomOptions>(); // 手动实现LLM接口配置选项
services.AddConfigurableOptions<LLMOptions>(); //基于Microsoft Semantic Kernel实现,也是本应用的默认实现 services.AddConfigurableOptions<LLMOptions>(); // 基于Microsoft Semantic Kernel实现,也是本应用的默认实现
return services; return services;
} }

View File

@ -5,7 +5,6 @@
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Admin.NET.Core; using Admin.NET.Core;
using Admin.NET.Core.Ai.Extentions;
using Admin.NET.Core.Service; using Admin.NET.Core.Service;
using AspNetCoreRateLimit; using AspNetCoreRateLimit;
using Furion; using Furion;
@ -137,10 +136,9 @@ public class Startup : AppStartup
// SqlSugar // SqlSugar
services.AddSqlSugar(); services.AddSqlSugar();
#region LLM大模型 // 注册LLM大模型
services.AddLLMFactory(); // 注册LLM模型工厂,如果需要切换模型请引入ILLMFactory接口调用CreateKernel方法获取Kernel实例 services.AddLLMFactory(); // 注册LLM模型工厂,如果需要切换模型请引入ILLMFactory接口调用CreateKernel方法获取Kernel实例
services.AddLLM(); // 注册LLM大模型,注意:此扩展不能切换模型,只能使用一个模型 services.AddLLM(); // 注册LLM大模型,注意:此扩展不能切换模型,只能使用一个模型
#endregion
// 三方授权登录OAuth // 三方授权登录OAuth
services.AddOAuth(); services.AddOAuth();
@ -421,12 +419,14 @@ public class Startup : AppStartup
options.EnableDirectoryBrowsing = false; // 是否启用目录浏览 options.EnableDirectoryBrowsing = false; // 是否启用目录浏览
options.Title = "定时任务看板"; // 自定义看板标题 options.Title = "定时任务看板"; // 自定义看板标题
options.LoginHandle = async (username, password, httpContext) => options.LoginConfig.OnLoging = async (username, password, httpContext) =>
{ {
var res = await httpContext.RequestServices.GetRequiredService<SysAuthService>().SwaggerSubmitUrl(new SpecificationAuth { UserName = username, Password = password }); var res = await httpContext.RequestServices.GetRequiredService<SysAuthService>().SwaggerSubmitUrl(new SpecificationAuth { UserName = username, Password = password });
return res == 200; return res == 200;
}; };
options.LoginSessionKey = "schedule_session_key"; // 登录客户端存储的 Session 键 options.LoginConfig.DefaultUsername = "";
options.LoginConfig.DefaultPassword = "";
options.LoginConfig.SessionKey = "schedule_session_key"; // 登录客户端存储的 Session 键
}); });
// 配置Swagger-Knife4UI路由前缀一致代表独立不同则代表共存 // 配置Swagger-Knife4UI路由前缀一致代表独立不同则代表共存

View File

@ -26,7 +26,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" /> <PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.14.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.14.0" />
<PackageReference Include="Rezero.Api" Version="1.8.23" /> <PackageReference Include="Rezero.Api" Version="1.8.24" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -2,7 +2,7 @@
"name": "admin.net.pro", "name": "admin.net.pro",
"type": "module", "type": "module",
"version": "2.4.33", "version": "2.4.33",
"lastBuildTime": "2025.06.17", "lastBuildTime": "2025.06.19",
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架", "description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
"author": "zuohuaijun", "author": "zuohuaijun",
"license": "MIT", "license": "MIT",
@ -70,7 +70,7 @@
"uuid": "^11.1.0", "uuid": "^11.1.0",
"vcrontab-3": "^3.3.22", "vcrontab-3": "^3.3.22",
"vform3-builds": "^3.0.10", "vform3-builds": "^3.0.10",
"vue": "^3.5.16", "vue": "^3.5.17",
"vue-clipboard3": "^2.0.0", "vue-clipboard3": "^2.0.0",
"vue-demi": "0.14.10", "vue-demi": "0.14.10",
"vue-draggable-plus": "^0.6.0", "vue-draggable-plus": "^0.6.0",
@ -83,15 +83,14 @@
"vue-router": "^4.5.1", "vue-router": "^4.5.1",
"vue-signature-pad": "^3.0.2", "vue-signature-pad": "^3.0.2",
"vue3-tree-org": "^4.2.2", "vue3-tree-org": "^4.2.2",
"vxe-pc-ui": "^4.6.24", "vxe-pc-ui": "^4.6.26",
"vxe-table": "^4.13.40", "vxe-table": "^4.13.42",
"xe-utils": "^3.7.5", "xe-utils": "^3.7.5",
"xlsx-js-style": "^1.2.0" "xlsx-js-style": "^1.2.0"
}, },
"devDependencies": { "devDependencies": {
"@iconify/vue": "^5.0.0", "@iconify/vue": "^5.0.0",
"@plugin-web-update-notification/vite": "^2.0.0", "@plugin-web-update-notification/vite": "^2.0.0",
"@types/franc": "^6.0.0",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/node": "^22.15.32", "@types/node": "^22.15.32",
"@types/nprogress": "^0.2.3", "@types/nprogress": "^0.2.3",
@ -100,7 +99,7 @@
"@typescript-eslint/parser": "^8.34.1", "@typescript-eslint/parser": "^8.34.1",
"@vitejs/plugin-vue": "^5.2.4", "@vitejs/plugin-vue": "^5.2.4",
"@vitejs/plugin-vue-jsx": "^4.2.0", "@vitejs/plugin-vue-jsx": "^4.2.0",
"@vue/compiler-sfc": "^3.5.16", "@vue/compiler-sfc": "^3.5.17",
"code-inspector-plugin": "^0.20.12", "code-inspector-plugin": "^0.20.12",
"eslint": "^9.29.0", "eslint": "^9.29.0",
"eslint-plugin-vue": "^10.2.0", "eslint-plugin-vue": "^10.2.0",
@ -109,7 +108,7 @@
"prettier": "^3.5.3", "prettier": "^3.5.3",
"rollup-plugin-visualizer": "^6.0.3", "rollup-plugin-visualizer": "^6.0.3",
"sass": "^1.89.2", "sass": "^1.89.2",
"terser": "^5.42.0", "terser": "^5.43.0",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"vite": "^6.3.5", "vite": "^6.3.5",
"vite-plugin-cdn-import": "^1.0.1", "vite-plugin-cdn-import": "^1.0.1",

View File

@ -14,7 +14,7 @@
import { LLMChatSummaryHistory } from './llmchat-summary-history'; import { LLMChatSummaryHistory } from './llmchat-summary-history';
/** /**
* *
* *
* @export * @export
* @interface LLMChatHistory * @interface LLMChatHistory

View File

@ -14,7 +14,7 @@
import { LLMChatHistory } from './llmchat-history'; import { LLMChatHistory } from './llmchat-history';
/** /**
* *
* *
* @export * @export
* @interface LLMChatSummaryHistory * @interface LLMChatSummaryHistory

View File

@ -26,13 +26,12 @@ import JwChat from 'jwchat';
import 'jwchat/lib/style.css'; import 'jwchat/lib/style.css';
// 自定义字典组件 // 自定义字典组件
import sysDict from '/@/components/sysDict/sysDict.vue'; import sysDict from '/@/components/sysDict/sysDict.vue';
// AI组件
import ElementPlusX from 'vue-element-plus-x'; import ElementPlusX from 'vue-element-plus-x';
import 'vue-markdown-shiki/style' import 'vue-markdown-shiki/style'
import markdownPlugin from 'vue-markdown-shiki' //markodwn渲染组件,由于element-plus-x的thinking不支持markdown所以需要单独引入,未来element-plus-x组成成熟应该会被移转 import markdownPlugin from 'vue-markdown-shiki'
// 关闭自动打印 // 关闭自动打印
import { disAutoConnect } from 'vue-plugin-hiprint'; import { disAutoConnect } from 'vue-plugin-hiprint';
disAutoConnect(); disAutoConnect();
const app = createApp(App); const app = createApp(App);

View File

@ -50,13 +50,13 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
children: [], children: [],
}, },
{ {
path: '/llm/chat', path: '/llm/aiChat',
name: 'chat', name: 'aiChat',
component: () => import('/@/views/chat/index.vue'), component: () => import('/@/views/aiChat/index.vue'),
meta: { meta: {
title: 'AI对话', title: 'AI对话',
isKeepAlive: true, isKeepAlive: true,
} },
}, },
{ {
path: '/platform/job/dashboard', path: '/platform/job/dashboard',

View File

@ -1,6 +1,6 @@
import { useUserInfo } from '/@/stores/userInfo'; import { useUserInfo } from '/@/stores/userInfo';
const {userInfos} = useUserInfo(); const { userInfos } = useUserInfo();
/** /**
* *
@ -10,7 +10,6 @@ export const isSupperAdmin = (): boolean => {
return userInfos?.accountType === 999; return userInfos?.accountType === 999;
}; };
/** /**
* *
* @returns * @returns
@ -35,7 +34,6 @@ export const isNormalUser = (): boolean => {
return userInfos?.accountType === 777; return userInfos?.accountType === 777;
}; };
/** /**
* *
* @returns * @returns
@ -48,73 +46,73 @@ export const isMember = (): boolean => {
* *
* @returns * @returns
*/ */
export const userEmail = ():string => { export const userEmail = (): string => {
return userInfos?.email; return userInfos?.email;
} };
/** /**
* id * id
* @returns id * @returns id
*/ */
export const userName = ():string => { export const userName = (): string => {
return userInfos?.userName; return userInfos?.userName;
} };
/** /**
* *
* @returns * @returns
*/ */
export const userFriendName = ():string => ( export const userFriendName = (): string => (userInfos?.realName ? userInfos?.realName : userInfos?.account ? userInfos?.account : userInfos?.email);
userInfos?.realName ? userInfos?.realName : userInfos?.account ? userInfos?.account : userInfos?.email
)
/** /**
* id * id
* @returns id * @returns id
*/ */
export const tenantId = ():number => { export const tenantId = (): number => {
return userInfos?.tenantId; return userInfos?.tenantId;
} };
/*** /***
* . * .
*/ */
export const userAccount = ():string => userInfos?.account; export const userAccount = (): string => userInfos?.account;
/** /**
* *
* @returns * @returns
*/ */
export const userPhone = ():string => userInfos?.phone; export const userPhone = (): string => userInfos?.phone;
/** /**
* id * id
* @returns id. * @returns id.
*/ */
export const userId = ():number => userInfos?.id; export const userId = (): number => userInfos?.id;
/** /**
* id * id
* @returns id * @returns id
*/ */
export const orgId = ():number => userInfos?.orgId; export const orgId = (): number => userInfos?.orgId;
/** /**
* *
* @returns * @returns
*/ */
export const orgName = ():string => userInfos?.orgName; export const orgName = (): string => userInfos?.orgName;
/** /**
* id * id
* @returns id. * @returns id.
*/ */
export const posId = ():number => userInfos?.posId; export const posId = (): number => userInfos?.posId;
/** /**
* *
* @returns * @returns
*/ */
export const posName = ():string => userInfos?.posName; export const posName = (): string => userInfos?.posName;
export const hasPrivilege = (privilege: string):boolean => { export const hasPrivilege = (privilege: string): boolean => {
return userInfos.authApiList.includes(privilege); return userInfos.authApiList.includes(privilege);
} };

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -9,10 +9,10 @@ import { CodeInspectorPlugin } from 'code-inspector-plugin';
import fs from 'fs'; import fs from 'fs';
import { visualizer } from 'rollup-plugin-visualizer'; import { visualizer } from 'rollup-plugin-visualizer';
import { webUpdateNotice } from '@plugin-web-update-notification/vite'; import { webUpdateNotice } from '@plugin-web-update-notification/vite';
import { copyPublicPlugin } from 'vite-plugin-forvmsc';
// monaco 菜单汉化 https://wf0.github.io/example/plugins/I18n.html // monaco 菜单汉化 https://wf0.github.io/example/plugins/I18n.html
import monacoZhHans from './public/monaco/zh-hans.json'; import monacoZhHans from './public/monaco/zh-hans.json';
import nlsPlugin, { Languages, esbuildPluginMonacoEditorNls } from './public/monaco/vite-plugin-i18n-nls'; import nlsPlugin, { Languages, esbuildPluginMonacoEditorNls } from './public/monaco/vite-plugin-i18n-nls';
import { copyPublicPlugin } from 'vite-plugin-forvmsc'
const pathResolve = (dir: string) => { const pathResolve = (dir: string) => {
return resolve(__dirname, '.', dir); return resolve(__dirname, '.', dir);