mirror of
https://github.com/AIDotNet/AntSK.git
synced 2026-02-18 06:20:11 +08:00
Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8315b6f37f | ||
|
|
7bc708e6ae | ||
|
|
e6f2c5c2fe | ||
|
|
5cab781362 | ||
|
|
02d7994bae | ||
|
|
b740957157 | ||
|
|
2480ec1272 | ||
|
|
35c98a0d14 | ||
|
|
0964a5ad5b | ||
|
|
a95131efe9 | ||
|
|
7783cdf3c4 | ||
|
|
7a65f33cb6 | ||
|
|
6efd01db3f | ||
|
|
1e2322b573 | ||
|
|
2cb2241a66 | ||
|
|
64efdd7881 | ||
|
|
be28e32803 | ||
|
|
468422baee | ||
|
|
7b1c6c8c64 | ||
|
|
7ff0ea0bfe | ||
|
|
6bed4356f0 | ||
|
|
73b65f7305 | ||
|
|
0ea52eced9 | ||
|
|
498e9ba9f6 | ||
|
|
125695665b | ||
|
|
0e08b3ae85 | ||
|
|
7cb8f99e7e | ||
|
|
d15cb527d0 | ||
|
|
9cb36174fd | ||
|
|
6265f94ef2 | ||
|
|
09d90b654c | ||
|
|
64e2bca2e6 | ||
|
|
328ece6d73 | ||
|
|
fabb8c2044 | ||
|
|
6ca75df880 | ||
|
|
3d4dfaced1 | ||
|
|
d532bf3bb6 | ||
|
|
e1fd288875 | ||
|
|
91eae9cfa8 | ||
|
|
b0059942d3 | ||
|
|
a716982878 | ||
|
|
3d4e48f9f5 | ||
|
|
1f212d3156 | ||
|
|
7d91ef6ba1 | ||
|
|
2a450b00de | ||
|
|
3a97068248 | ||
|
|
1d9d95899a | ||
|
|
7ae8e52b57 | ||
|
|
f5c195a1d0 | ||
|
|
78a6b662d3 | ||
|
|
5f814eb76c | ||
|
|
d9e5ebb464 | ||
|
|
bce0e9183c | ||
|
|
c40a7bcf22 | ||
|
|
97a7d447ab | ||
|
|
f803b9538b | ||
|
|
1ac34c1702 | ||
|
|
e07b480da1 | ||
|
|
9036af57e3 | ||
|
|
93288f9b5c | ||
|
|
f40dd8b013 | ||
|
|
c6b83d0695 | ||
|
|
592c850198 | ||
|
|
4a3930ac7b | ||
|
|
c05ba0af3e | ||
|
|
630ee51df6 | ||
|
|
d0e75e26c3 | ||
|
|
af2930a371 |
2
LICENSE
2
LICENSE
@@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Copyright [2024] [许泽宇]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
19
README.en.md
19
README.en.md
@@ -39,9 +39,10 @@ AntSK is suitable for various business scenarios, such as:
|
||||
|
||||
## ✏️Function Examples
|
||||
### Online Demo
|
||||
```
|
||||
https://antsk.ai-dotnet.com/
|
||||
```
|
||||
[document](http://antsk.cn/)
|
||||
|
||||
[demo](https://antsk.ai-dotnet.com/)
|
||||
|
||||
```
|
||||
Default account: test
|
||||
|
||||
@@ -198,12 +199,12 @@ This project exists thanks to all the people who contribute.
|
||||
<img src="https://contrib.rocks/image?repo=AIDotNet/AntSK&max=1000&columns=15&anon=1" />
|
||||
</a>
|
||||
|
||||
## 🚨 Code of Conduct
|
||||
|
||||
This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community.
|
||||
For more information see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
|
||||
|
||||
To learn more or get started with **AntSK**, follow my official WeChat account and join the discussion group.
|
||||
## 🚨 Use Protocol
|
||||
This warehouse follows the [Apache-2.0 License]( https://github.com/AIDotNet/AntSK?tab=Apache -2.0-1-ov file) open source protocol.
|
||||
The Apache open source license allows the use of AntSK in commercial environments, provided that the license terms are followed. One of the main terms is to retain the copyright and license statements.
|
||||
If you plan to use AntSK in commercial projects, you need to ensure that you follow the following steps:
|
||||
1. Copyright statement containing Apache license. [Apache-2.0 License]( https://github.com/AIDotNet/AntSK?tab=Apache -2.0-1-ov file).
|
||||
2. If you modify the software source code, you need to clearly indicate these modifications in the source code.
|
||||
|
||||
## ☎️Contact Me
|
||||
If you have any questions or suggestions, please contact me through my official WeChat account. We also have a discussion group where you can send a message to join, and then I will add you to the group.
|
||||
|
||||
26
README.md
26
README.md
@@ -8,7 +8,7 @@
|
||||
|
||||
- **内存内核 (Kernel Memory)**:具备持续学习和存储知识点的能力,AntSK 拥有长期记忆功能,累积经验,提供更个性化的交互体验。
|
||||
|
||||
- **知识库**:通过文档(Word、PDF、Excel、Txt、Markdown、Json、PPT)等形式导入知识库,可以进行知识库问答。
|
||||
- **知识库**:通过文档(Word、PDF、Excel、Txt、Markdown、Json、PPT)等形式导入知识库,可以进行知识库问答,支持本地bge-embedding 向量模型 ,以及bge-rerank 重排模型。
|
||||
|
||||
- **文生图**:集成**StableDiffusion** 本地模型,可以进行文生图。
|
||||
|
||||
@@ -42,9 +42,11 @@ AntSK 适用于多种业务场景,例如:
|
||||
|
||||
## ✏️功能示例
|
||||
### 在线演示
|
||||
```
|
||||
https://antsk.ai-dotnet.com/
|
||||
```
|
||||
|
||||
[文档地址](http://antsk.cn/)
|
||||
|
||||
[体验地址](https://antsk.ai-dotnet.com/)
|
||||
|
||||
```
|
||||
默认账号:test
|
||||
|
||||
@@ -91,7 +93,7 @@ version: '3.8'
|
||||
services:
|
||||
antsk:
|
||||
container_name: antsk
|
||||
image: registry.cn-hangzhou.aliyuncs.com/AIDotNet/antsk:v0.2.9
|
||||
image: registry.cn-hangzhou.aliyuncs.com/AIDotNet/antsk:v0.3.1
|
||||
ports:
|
||||
- 5000:5000
|
||||
networks:
|
||||
@@ -205,14 +207,20 @@ DB我使用的是CodeFirst模式,只要配置好数据库链接,表结构是
|
||||
<img src="https://contrib.rocks/image?repo=AIDotNet/AntSK&max=1000&columns=15&anon=1" />
|
||||
</a>
|
||||
|
||||
## 🚨 行为准则
|
||||
## 🚨 使用协议
|
||||
|
||||
该项目采用了贡献者公约定义的行为准则,以阐明我们社区的预期行为。有关更多信息,请参见 .NET Foundation 行为准则。 [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
|
||||
本仓库遵循 [Apache-2.0 License](https://github.com/AIDotNet/AntSK?tab=Apache-2.0-1-ov-file) 开源协议。
|
||||
Apache开源许可证允许在商业环境中使用AntSK,前提是需要遵守许可证的条款。主要条款之一是要保留版权声明和许可证声明。
|
||||
|
||||
如果您打算在商业项目中使用AntSK,您需要确保遵守以下步骤:
|
||||
|
||||
1、包含Apache许可证的版权声明。 [Apache-2.0 License](https://github.com/AIDotNet/AntSK?tab=Apache-2.0-1-ov-file) 。
|
||||
|
||||
2、如果您修改了软件源代码,您需要在源代码中明确标明这些修改。
|
||||
|
||||
想了解更多信息或开始使用 **AntSK**,可以关注我的公众号以及加入交流群。
|
||||
|
||||
## ☎️联系我
|
||||
如有任何问题或建议,请通过以下方式关注我的公众号,发消息与我联系,我们也有交流群,可以发送进群等消息,然后我会拉你进交流群
|
||||
如有任何问题或建议,请通过以下方式关注我的公众号《许泽宇的技术分享》,发消息与我联系,我们也有AIDotnet交流群,可以发送进群等消息,然后我会拉你进交流群
|
||||

|
||||
|
||||
## 🌟 Star History
|
||||
|
||||
@@ -3,9 +3,9 @@ version: '3.8'
|
||||
services:
|
||||
antsk:
|
||||
container_name: antsk
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.2.9
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.3.1
|
||||
# 如果需要pytorch环境需要使用下面这个镜像,镜像比较大
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:p0.2.9
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:p0.3.1
|
||||
ports:
|
||||
- 5000:5000
|
||||
networks:
|
||||
|
||||
@@ -18,9 +18,9 @@ services:
|
||||
- ./pg/data:/var/lib/postgresql/data
|
||||
antsk:
|
||||
container_name: antsk
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.2.9
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.3.1
|
||||
# 如果需要pytorch环境需要使用下面这个镜像,镜像比较大
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:p0.2.9
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:p0.3.1
|
||||
ports:
|
||||
- 5000:5000
|
||||
networks:
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<DocumentationFile>AntSK.Domain.xml</DocumentationFile>
|
||||
<NoWarn>CA1050,CA1707,CA2007,VSTHRD111,CS1591,RCS1110,CA5394,SKEXP0001,SKEXP0002,SKEXP0003,SKEXP0004,SKEXP0010,SKEXP0011,,SKEXP0012,SKEXP0020,SKEXP0021,SKEXP0022,SKEXP0023,SKEXP0024,SKEXP0025,SKEXP0026,SKEXP0027,SKEXP0028,SKEXP0029,SKEXP0030,SKEXP0031,SKEXP0032,SKEXP0040,SKEXP0041,SKEXP0042,SKEXP0050,SKEXP0051,SKEXP0052,SKEXP0053,SKEXP0054,SKEXP0055,SKEXP0060,SKEXP0061,SKEXP0101,SKEXP0102</NoWarn>
|
||||
<NoWarn>CA1050,CA1707,CA2007,VSTHRD111,CS1591,RCS1110,CA5394,SKEXP0001,SKEXP0002,SKEXP0003,SKEXP0004,SKEXP0010,SKEXP0011,,SKEXP0012,SKEXP0020,SKEXP0021,SKEXP0022,SKEXP0023,SKEXP0024,SKEXP0025,SKEXP0026,SKEXP0027,SKEXP0028,SKEXP0029,SKEXP0030,SKEXP0031,SKEXP0032,SKEXP0040,SKEXP0041,SKEXP0042,SKEXP0050,SKEXP0051,SKEXP0052,SKEXP0053,SKEXP0054,SKEXP0055,SKEXP0060,SKEXP0061,SKEXP0101,SKEXP0102,KMEXP00</NoWarn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AntDesign.Charts" Version="0.5.1" />
|
||||
<PackageReference Include="AntDesign.ProLayout" Version="0.18.2" />
|
||||
<PackageReference Include="AntDesign.ProLayout" Version="0.19.0" />
|
||||
<PackageReference Include="BlazorComponents.Terminal" Version="0.6.0" />
|
||||
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||
<PackageReference Include="Markdig" Version="0.37.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.152" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.154" />
|
||||
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.118" />
|
||||
<PackageReference Include="RestSharp" Version="110.2.0" />
|
||||
<PackageReference Include="NPOI" Version="2.7.0" />
|
||||
|
||||
<PackageReference Include="Microsoft.SemanticKernel" Version="1.7.1" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Core" Version="1.7.1" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Core" Version="1.7.1-alpha" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel" Version="1.11.1" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Core" Version="1.11.1" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Core" Version="1.11.1-alpha" />
|
||||
<PackageReference Include="Microsoft.KernelMemory.Core" Version="$(KMVersion)" />
|
||||
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.Postgres" Version="$(KMVersion)" />
|
||||
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.Qdrant" Version="$(KMVersion)" />
|
||||
|
||||
@@ -157,11 +157,6 @@
|
||||
模型类型
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Domain.Model.MessageInfo.IsSend">
|
||||
<summary>
|
||||
发送是true 接收是false
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Domain.Model.PageList`1.PageIndex">
|
||||
<summary>
|
||||
当前页,从1开始
|
||||
@@ -177,7 +172,12 @@
|
||||
总数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Domain.Other.EmbeddingConfig.LoadModel(System.String,System.String)">
|
||||
<member name="M:AntSK.Domain.Domain.Other.Bge.BegRerankConfig.LoadModel(System.String,System.String)">
|
||||
<summary>
|
||||
模型写死
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Domain.Other.Bge.BgeEmbeddingConfig.LoadModel(System.String,System.String)">
|
||||
<summary>
|
||||
模型写死
|
||||
</summary>
|
||||
@@ -199,7 +199,7 @@
|
||||
<member name="M:AntSK.Domain.Domain.Other.QAHandler.InvokeAsync(Microsoft.KernelMemory.Pipeline.DataPipeline,System.Threading.CancellationToken)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Domain.Service.ChatService.SendChatByAppAsync(AntSK.Domain.Repositories.Apps,System.String,Microsoft.SemanticKernel.ChatCompletion.ChatHistory)">
|
||||
<member name="M:AntSK.Domain.Domain.Service.ChatService.SendChatByAppAsync(AntSK.Domain.Repositories.Apps,Microsoft.SemanticKernel.ChatCompletion.ChatHistory)">
|
||||
<summary>
|
||||
发送消息
|
||||
</summary>
|
||||
@@ -402,6 +402,36 @@
|
||||
回答最大token数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Chats.UserName">
|
||||
<summary>
|
||||
用户名
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Chats.AppId">
|
||||
<summary>
|
||||
应用ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Chats.Context">
|
||||
<summary>
|
||||
消息内容
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Chats.IsSend">
|
||||
<summary>
|
||||
发送是true 接收是false
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Chats.CreateTime">
|
||||
<summary>
|
||||
创建事件
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Chats.FileName">
|
||||
<summary>
|
||||
文件名
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Funs.Path">
|
||||
<summary>
|
||||
接口描述
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AntSK.Domain.Domain.Other;
|
||||
using AntSK.Domain.Domain.Other.Bge;
|
||||
|
||||
namespace AntSK.Domain.Common.Embedding
|
||||
{
|
||||
@@ -22,12 +22,12 @@ namespace AntSK.Domain.Common.Embedding
|
||||
|
||||
public HuggingfaceTextEmbeddingGenerator(string pyDllPath,string modelName)
|
||||
{
|
||||
_embedder = EmbeddingConfig.LoadModel(pyDllPath, modelName);
|
||||
_embedder = BgeEmbeddingConfig.LoadModel(pyDllPath, modelName);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
EmbeddingConfig.Dispose();
|
||||
BgeEmbeddingConfig.Dispose();
|
||||
}
|
||||
|
||||
//public async Task<IList<ReadOnlyMemory<float>>> GenerateEmbeddingAsync(IList<string> data, CancellationToken cancellationToken = default)
|
||||
@@ -44,13 +44,13 @@ namespace AntSK.Domain.Common.Embedding
|
||||
|
||||
public async Task<Microsoft.KernelMemory.Embedding> GenerateEmbeddingAsync(string text, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var embeddings = await EmbeddingConfig.GetEmbedding(text);
|
||||
var embeddings = await BgeEmbeddingConfig.GetEmbedding(text);
|
||||
return new Microsoft.KernelMemory.Embedding(embeddings);
|
||||
}
|
||||
|
||||
public int CountTokens(string text)
|
||||
{
|
||||
return EmbeddingConfig.TokenCount(text);
|
||||
return BgeEmbeddingConfig.TokenCount(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<Project>
|
||||
<!-- See https://aka.ms/dotnet/msbuild/customize for more details on customizing your build -->
|
||||
<PropertyGroup>
|
||||
|
||||
<KMVersion>0.36.240416.1</KMVersion>
|
||||
<LLamaSharpVersion>0.11.2</LLamaSharpVersion>
|
||||
<KMVersion>0.61.240519.2</KMVersion>
|
||||
<LLamaSharpVersion>0.12.0</LLamaSharpVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -14,10 +14,10 @@ namespace AntSK.Domain.Domain.Interface
|
||||
{
|
||||
public interface IChatService
|
||||
{
|
||||
IAsyncEnumerable<StreamingKernelContent> SendChatByAppAsync(Apps app, string questions, ChatHistory history);
|
||||
IAsyncEnumerable<string> SendChatByAppAsync(Apps app, ChatHistory history);
|
||||
|
||||
IAsyncEnumerable<StreamingKernelContent> SendKmsByAppAsync(Apps app, string questions, ChatHistory history, string filePath, List<RelevantSource> relevantSources = null);
|
||||
Task<string> SendImgByAppAsync(Apps app, string questions);
|
||||
Task<ChatHistory> GetChatHistory(List<MessageInfo> MessageList);
|
||||
Task<ChatHistory> GetChatHistory(List<Chats> MessageList, ChatHistory history);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,10 @@ namespace AntSK.Domain.Domain.Model.Constant
|
||||
public class KmsConstantcs
|
||||
{
|
||||
public const string KmsIdTag = "kmsid";
|
||||
public const string FileIdTag = "fileid";
|
||||
public const string AppIdTag = "appid";
|
||||
public const string KmsIndex = "kms";
|
||||
public const string FileIndex = "kms";
|
||||
public const string KmsSearchNull="知识库未搜索到相关内容";
|
||||
|
||||
public const string KmsPrompt = @"使用<data></data>标记的内容作为你的知识:
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace AntSK.Domain.Domain.Model.Dto
|
||||
public string Text { get; set; }
|
||||
public float Relevance { get; set; }
|
||||
|
||||
public double RerankScore { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[file:{SourceName};Relevance:{(Relevance * 100):F2}%]:{Text}";
|
||||
|
||||
@@ -26,8 +26,10 @@ namespace AntSK.Domain.Domain.Model.Enum
|
||||
LLamaFactory = 6,
|
||||
[Display(Name = "Bge Embedding")]
|
||||
BgeEmbedding = 7,
|
||||
[Display(Name = "Bge Rerank")]
|
||||
BgeRerank = 8,
|
||||
[Display(Name = "StableDiffusion")]
|
||||
StableDiffusion = 8,
|
||||
StableDiffusion = 9,
|
||||
[Display(Name = "模拟输出")]
|
||||
Mock = 100,
|
||||
|
||||
@@ -41,5 +43,6 @@ namespace AntSK.Domain.Domain.Model.Enum
|
||||
Chat = 1,
|
||||
Embedding = 2,
|
||||
Image=3,
|
||||
Rerank=4
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
namespace AntSK.Domain.Domain.Model
|
||||
{
|
||||
public class MessageInfo
|
||||
{
|
||||
public string ID { get; set; } = "";
|
||||
public string Context { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 发送是true 接收是false
|
||||
/// </summary>
|
||||
public bool IsSend { get; set; } = false;
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
public string? FileName { get; set; }
|
||||
}
|
||||
}
|
||||
81
src/AntSK.Domain/Domain/Other/Bge/BegRerankConfig.cs
Normal file
81
src/AntSK.Domain/Domain/Other/Bge/BegRerankConfig.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using Newtonsoft.Json;
|
||||
using Python.Runtime;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static Python.Runtime.Py;
|
||||
|
||||
namespace AntSK.Domain.Domain.Other.Bge
|
||||
{
|
||||
public static class BegRerankConfig
|
||||
{
|
||||
public static dynamic model { get; set; }
|
||||
|
||||
static object lockobj = new object();
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 模型写死
|
||||
/// </summary>
|
||||
public static dynamic LoadModel(string pythondllPath, string modelName)
|
||||
{
|
||||
lock (lockobj)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Runtime.PythonDLL))
|
||||
{
|
||||
Runtime.PythonDLL = pythondllPath;
|
||||
}
|
||||
PythonEngine.Initialize();
|
||||
try
|
||||
{
|
||||
using (GIL())// 初始化Python环境的Global Interpreter Lock)
|
||||
{
|
||||
dynamic modelscope = Py.Import("modelscope");
|
||||
dynamic flagEmbedding = Py.Import("FlagEmbedding");
|
||||
|
||||
dynamic model_dir = modelscope.snapshot_download(modelName, revision: "master");
|
||||
dynamic flagReranker = flagEmbedding.FlagReranker(model_dir, use_fp16: true);
|
||||
model = flagReranker;
|
||||
return model;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return model;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static double Rerank(List<string> list)
|
||||
{
|
||||
using (GIL())
|
||||
{
|
||||
try
|
||||
{
|
||||
PyList pyList = new PyList();
|
||||
foreach (string item in list)
|
||||
{
|
||||
pyList.Append(item.ToPython()); // 将C# string转换为Python对象并添加到PyList中
|
||||
}
|
||||
PyObject result = model.compute_score(pyList, normalize: true);
|
||||
return result.As<double>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.KernelMemory.AI.OpenAI.GPT3;
|
||||
using Microsoft.KernelMemory.AI.OpenAI;
|
||||
using Microsoft.KernelMemory.AI.OpenAI.GPT3;
|
||||
using Python.Runtime;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -7,9 +8,9 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static Python.Runtime.Py;
|
||||
|
||||
namespace AntSK.Domain.Domain.Other
|
||||
namespace AntSK.Domain.Domain.Other.Bge
|
||||
{
|
||||
public static class EmbeddingConfig
|
||||
public static class BgeEmbeddingConfig
|
||||
{
|
||||
public static dynamic model { get; set; }
|
||||
|
||||
@@ -27,18 +28,20 @@ namespace AntSK.Domain.Domain.Other
|
||||
if (model == null)
|
||||
{
|
||||
//Runtime.PythonDLL = @"D:\Programs\Python\Python311\python311.dll";
|
||||
Runtime.PythonDLL = pythondllPath;
|
||||
if (string.IsNullOrEmpty(Runtime.PythonDLL))
|
||||
{
|
||||
Runtime.PythonDLL = pythondllPath;
|
||||
}
|
||||
PythonEngine.Initialize();
|
||||
PythonEngine.BeginAllowThreads();
|
||||
|
||||
try
|
||||
{
|
||||
using (Py.GIL())// 初始化Python环境的Global Interpreter Lock)
|
||||
using (GIL())// 初始化Python环境的Global Interpreter Lock)
|
||||
{
|
||||
dynamic modelscope = Py.Import("modelscope");
|
||||
dynamic modelscope = Import("modelscope");
|
||||
//dynamic model_dir = modelscope.snapshot_download("AI-ModelScope/bge-large-zh-v1.5", revision: "master");
|
||||
dynamic model_dir = modelscope.snapshot_download(modelName, revision: "master");
|
||||
dynamic HuggingFaceBgeEmbeddingstemp = Py.Import("langchain_community.embeddings.huggingface");
|
||||
dynamic HuggingFaceBgeEmbeddingstemp = Import("langchain_community.embeddings.huggingface");
|
||||
dynamic HuggingFaceBgeEmbeddings = HuggingFaceBgeEmbeddingstemp.HuggingFaceBgeEmbeddings;
|
||||
string model_name = model_dir;
|
||||
dynamic model_kwargs = new PyDict();
|
||||
@@ -51,7 +54,7 @@ namespace AntSK.Domain.Domain.Other
|
||||
return hugginmodel;
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
@@ -63,7 +66,7 @@ namespace AntSK.Domain.Domain.Other
|
||||
|
||||
public static Task<float[]> GetEmbedding(string queryStr)
|
||||
{
|
||||
using (Py.GIL())
|
||||
using (GIL())
|
||||
{
|
||||
PyObject queryResult = model.embed_query(queryStr);
|
||||
var floatList = queryResult.As<float[]>();
|
||||
@@ -83,7 +86,7 @@ namespace AntSK.Domain.Domain.Other
|
||||
// return len;
|
||||
|
||||
//}
|
||||
var tokenCount1 = GPT3Tokenizer.Encode(queryStr).Count;
|
||||
var tokenCount1 = DefaultGPTTokenizer.StaticCountTokens(queryStr);
|
||||
return tokenCount1;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AntSK.Domain.Domain.Model.Constant;
|
||||
using AntSK.Domain.Utils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.KernelMemory.AI.OpenAI;
|
||||
using Microsoft.KernelMemory.Configuration;
|
||||
@@ -134,7 +135,7 @@ namespace AntSK.Domain.Domain.Other
|
||||
PartitionNumber = partitionNumber,
|
||||
SectionNumber = sectionNumber,
|
||||
Tags = pipeline.Tags,
|
||||
ContentSHA256 = textData.CalculateSHA256(),
|
||||
ContentSHA256 = textData.AntSKCalculateSHA256(),
|
||||
};
|
||||
newFiles.Add(destFile, destFileDetails);
|
||||
destFileDetails.MarkProcessedBy(this);
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace AntSK.Domain.Domain.Other
|
||||
ContextSize = lsConfig?.ContextSize ?? 2048,
|
||||
Seed = lsConfig?.Seed ?? 0,
|
||||
GpuLayerCount = lsConfig?.GpuLayerCount ?? 20,
|
||||
EmbeddingMode = true
|
||||
Embeddings = true
|
||||
};
|
||||
var weights = LLamaWeights.LoadFromFile(parameters);
|
||||
dicLLamaWeights.Add(modelPath, (weights, parameters));
|
||||
|
||||
@@ -151,7 +151,7 @@ namespace AntSK.Domain.Domain.Other
|
||||
PartitionNumber = partitionNumber,
|
||||
SectionNumber = sectionNumber,
|
||||
Tags = pipeline.Tags,
|
||||
ContentSHA256 = textData.CalculateSHA256(),
|
||||
ContentSHA256 = textData.AntSKCalculateSHA256(),
|
||||
};
|
||||
newFiles.Add(destFile, destFileDetails);
|
||||
destFileDetails.MarkProcessedBy(this);
|
||||
|
||||
@@ -3,12 +3,14 @@ using AntSK.Domain.Domain.Interface;
|
||||
using AntSK.Domain.Domain.Model;
|
||||
using AntSK.Domain.Domain.Model.Constant;
|
||||
using AntSK.Domain.Domain.Model.Dto;
|
||||
using AntSK.Domain.Domain.Other.Bge;
|
||||
using AntSK.Domain.Repositories;
|
||||
using AntSK.Domain.Utils;
|
||||
using AntSK.LLM.StableDiffusion;
|
||||
using Markdig;
|
||||
using Microsoft.KernelMemory;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
@@ -34,45 +36,54 @@ namespace AntSK.Domain.Domain.Service
|
||||
/// <param name="questions"></param>
|
||||
/// <param name="history"></param>
|
||||
/// <returns></returns>
|
||||
public async IAsyncEnumerable<StreamingKernelContent> SendChatByAppAsync(Apps app, string questions, ChatHistory history)
|
||||
public async IAsyncEnumerable<string> SendChatByAppAsync(Apps app, ChatHistory history)
|
||||
{
|
||||
|
||||
if (string.IsNullOrEmpty(app.Prompt) || !app.Prompt.Contains("{{$input}}"))
|
||||
{
|
||||
//如果模板为空,给默认提示词
|
||||
app.Prompt = app.Prompt.ConvertToString() + "{{$input}}";
|
||||
}
|
||||
KernelArguments args = new KernelArguments();
|
||||
if (history.Count > 10)
|
||||
{
|
||||
app.Prompt = @"${{ConversationSummaryPlugin.SummarizeConversation $history}}" + app.Prompt;
|
||||
args = new() {
|
||||
{ "history", string.Join("\n", history.Select(x => x.Role + ": " + x.Content)) },
|
||||
{ "input", questions }
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
args = new()
|
||||
{
|
||||
{ "input", $"{string.Join("\n", history.Select(x => x.Role + ": " + x.Content))}{Environment.NewLine} user:{questions}" }
|
||||
};
|
||||
}
|
||||
|
||||
var _kernel = _kernelService.GetKernelByApp(app);
|
||||
var chat = _kernel.GetRequiredService<IChatCompletionService>();
|
||||
var temperature = app.Temperature / 100;//存的是0~100需要缩小
|
||||
OpenAIPromptExecutionSettings settings = new() { Temperature = temperature };
|
||||
List<string> completionList = new List<string>();
|
||||
if (!string.IsNullOrEmpty(app.ApiFunctionList) || !string.IsNullOrEmpty(app.NativeFunctionList))//这里还需要加上本地插件的
|
||||
{
|
||||
_kernelService.ImportFunctionsByApp(app, _kernel);
|
||||
settings.ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions;
|
||||
settings.ToolCallBehavior = ToolCallBehavior.EnableKernelFunctions;
|
||||
while (true)
|
||||
{
|
||||
ChatMessageContent result = await chat.GetChatMessageContentAsync(history, settings, _kernel);
|
||||
if (result.Content is not null)
|
||||
{
|
||||
string chunkCompletion = result.Content.ConvertToString();
|
||||
completionList.Add(chunkCompletion);
|
||||
foreach (var content in completionList)
|
||||
{
|
||||
yield return content.ConvertToString();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
history.Add(result);
|
||||
|
||||
IEnumerable<FunctionCallContent> functionCalls = FunctionCallContent.GetFunctionCalls(result);
|
||||
if (!functionCalls.Any())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var functionCall in functionCalls)
|
||||
{
|
||||
FunctionResultContent resultContent = await functionCall.InvokeAsync(_kernel);
|
||||
|
||||
history.Add(resultContent.ToChatMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
var func = _kernel.CreateFunctionFromPrompt(app.Prompt, settings);
|
||||
var chatResult = _kernel.InvokeStreamingAsync(function: func,
|
||||
arguments: args);
|
||||
await foreach (var content in chatResult)
|
||||
else
|
||||
{
|
||||
yield return content;
|
||||
var chatResult = chat.GetStreamingChatMessageContentsAsync(history, settings, _kernel);
|
||||
await foreach (var content in chatResult)
|
||||
{
|
||||
yield return content.ConvertToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,40 +95,103 @@ namespace AntSK.Domain.Domain.Service
|
||||
if (!string.IsNullOrWhiteSpace(filePath))
|
||||
{
|
||||
var memory = _kMService.GetMemoryByApp(app);
|
||||
var fileId = Guid.NewGuid().ToString();
|
||||
var result = await memory.ImportDocumentAsync(new Microsoft.KernelMemory.Document(fileId).AddFile(filePath)
|
||||
.AddTag(KmsConstantcs.KmsIdTag, app.Id)
|
||||
, index: KmsConstantcs.KmsIndex);
|
||||
|
||||
var filters = new MemoryFilter().ByTag(KmsConstantcs.KmsIdTag, app.Id);
|
||||
// 匹配GUID的正则表达式
|
||||
string pattern = @"\b[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}\b";
|
||||
|
||||
var searchResult = await memory.SearchAsync(questions, index: KmsConstantcs.KmsIndex, filters: [filters]);
|
||||
relevantSourceList.AddRange(searchResult.Results.SelectMany(item => item.Partitions.Select(part => new RelevantSource()
|
||||
// 使用正则表达式找到匹配
|
||||
Match match = Regex.Match(filePath, pattern);
|
||||
if (match.Success)
|
||||
{
|
||||
SourceName = item.SourceName,
|
||||
Text = Markdown.ToHtml(part.Text),
|
||||
Relevance = part.Relevance
|
||||
})));
|
||||
var fileId = match.Value;
|
||||
|
||||
var status=await memory.IsDocumentReadyAsync(fileId, index: KmsConstantcs.KmsIndex);
|
||||
if (!status)
|
||||
{
|
||||
var result = await memory.ImportDocumentAsync(new Document(fileId).AddFile(filePath)
|
||||
.AddTag(KmsConstantcs.AppIdTag, app.Id)
|
||||
.AddTag(KmsConstantcs.FileIdTag, fileId)
|
||||
, index: KmsConstantcs.FileIndex);
|
||||
}
|
||||
|
||||
var filters = new List<MemoryFilter>() {
|
||||
new MemoryFilter().ByTag(KmsConstantcs.AppIdTag, app.Id),
|
||||
new MemoryFilter().ByTag(KmsConstantcs.FileIdTag, fileId)
|
||||
};
|
||||
|
||||
var searchResult = await memory.SearchAsync(questions, index: KmsConstantcs.FileIndex, filters: filters);
|
||||
relevantSourceList.AddRange(searchResult.Results.SelectMany(item => item.Partitions.Select(part => new RelevantSource()
|
||||
{
|
||||
SourceName = item.SourceName,
|
||||
Text = Markdown.ToHtml(part.Text),
|
||||
Relevance = part.Relevance
|
||||
})));
|
||||
app.Prompt = KmsConstantcs.KmsPrompt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var dataMsg = new StringBuilder();
|
||||
if (relevantSourceList.Any())
|
||||
{
|
||||
if (!string.IsNullOrEmpty(app.RerankModelID))
|
||||
{
|
||||
var rerankModel=_aIModels_Repositories.GetById(app.RerankModelID);
|
||||
BegRerankConfig.LoadModel(rerankModel.EndPoint, rerankModel.ModelName);
|
||||
//进行rerank
|
||||
foreach (var item in relevantSourceList)
|
||||
{
|
||||
List<string> rerank = new List<string>();
|
||||
rerank.Add(questions);
|
||||
rerank.Add(item.Text);
|
||||
item.RerankScore = BegRerankConfig.Rerank(rerank);
|
||||
|
||||
}
|
||||
relevantSourceList = relevantSourceList.OrderByDescending(p => p.RerankScore).Take(app.MaxMatchesCount).ToList();
|
||||
}
|
||||
|
||||
bool isSearch = false;
|
||||
foreach (var item in relevantSourceList)
|
||||
{
|
||||
//匹配相似度
|
||||
if (item.Relevance >= app.Relevance / 100)
|
||||
if (!string.IsNullOrEmpty(app.RerankModelID))
|
||||
{
|
||||
dataMsg.AppendLine(item.ToString());
|
||||
isSearch = true;
|
||||
//匹配重排后相似度
|
||||
if (item.RerankScore >= app.Relevance / 100)
|
||||
{
|
||||
dataMsg.AppendLine(item.ToString());
|
||||
isSearch = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//匹配相似度
|
||||
if (item.Relevance >= app.Relevance / 100)
|
||||
{
|
||||
dataMsg.AppendLine(item.ToString());
|
||||
isSearch = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//处理markdown显示
|
||||
relevantSources?.AddRange(relevantSourceList);
|
||||
Dictionary<string, string> fileDic = new Dictionary<string, string>();
|
||||
foreach (var item in relevantSourceList)
|
||||
{
|
||||
if (fileDic.ContainsKey(item.SourceName))
|
||||
{
|
||||
item.SourceName = fileDic[item.SourceName];
|
||||
}
|
||||
else
|
||||
{
|
||||
var fileDetail = _kmsDetails_Repositories.GetFirst(p => p.FileGuidName == item.SourceName);
|
||||
if (fileDetail.IsNotNull())
|
||||
{
|
||||
string fileName = fileDetail.FileName;
|
||||
fileDic.Add(item.SourceName, fileName);
|
||||
item.SourceName = fileName;
|
||||
}
|
||||
}
|
||||
item.Text = Markdown.ToHtml(item.Text);
|
||||
}
|
||||
|
||||
@@ -126,7 +200,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
//KernelFunction jsonFun = _kernel.Plugins.GetFunction("KMSPlugin", "Ask1");
|
||||
var temperature = app.Temperature / 100;//存的是0~100需要缩小
|
||||
OpenAIPromptExecutionSettings settings = new() { Temperature = temperature };
|
||||
var func = _kernel.CreateFunctionFromPrompt(app.Prompt, settings);
|
||||
var func = _kernel.CreateFunctionFromPrompt(app.Prompt , settings);
|
||||
|
||||
var chatResult = _kernel.InvokeStreamingAsync(function: func,
|
||||
arguments: new KernelArguments() { ["doc"] = dataMsg.ToString(), ["history"] = string.Join("\n", history.Select(x => x.Role + ": " + x.Content)), ["input"] = questions });
|
||||
@@ -254,25 +328,20 @@ namespace AntSK.Domain.Domain.Service
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ChatHistory> GetChatHistory(List<MessageInfo> MessageList)
|
||||
public async Task<ChatHistory> GetChatHistory(List<Chats> MessageList, ChatHistory history)
|
||||
{
|
||||
ChatHistory history = new ChatHistory();
|
||||
if (MessageList.Count > 1)
|
||||
foreach (var item in MessageList)
|
||||
{
|
||||
|
||||
foreach (var item in MessageList)
|
||||
if (item.IsSend)
|
||||
{
|
||||
if (item.IsSend)
|
||||
{
|
||||
history.AddUserMessage(item.Context);
|
||||
}
|
||||
else
|
||||
{
|
||||
history.AddAssistantMessage(item.Context);
|
||||
}
|
||||
history.AddUserMessage(item.Context);
|
||||
}
|
||||
else
|
||||
{
|
||||
history.AddAssistantMessage(item.Context);
|
||||
}
|
||||
}
|
||||
return history;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,14 +45,30 @@ namespace AntSK.Domain.Domain.Service
|
||||
var embedModel = _aIModels_Repositories.GetFirst(p => p.Id == app.EmbeddingModelID);
|
||||
var chatHttpClient = OpenAIHttpClientHandlerUtil.GetHttpClient(chatModel.EndPoint);
|
||||
var embeddingHttpClient = OpenAIHttpClientHandlerUtil.GetHttpClient(embedModel.EndPoint);
|
||||
|
||||
var searchClientConfig = new SearchClientConfig
|
||||
SearchClientConfig searchClientConfig;
|
||||
if (string.IsNullOrEmpty(app.RerankModelID))
|
||||
{
|
||||
MaxAskPromptSize = app.MaxAskPromptSize,
|
||||
MaxMatchesCount = app.MaxMatchesCount,
|
||||
AnswerTokens = app.AnswerTokens,
|
||||
EmptyAnswer = KmsConstantcs.KmsSearchNull
|
||||
};
|
||||
//不重排直接取查询数
|
||||
searchClientConfig = new SearchClientConfig
|
||||
{
|
||||
MaxAskPromptSize = app.MaxAskPromptSize,
|
||||
MaxMatchesCount = app.MaxMatchesCount,
|
||||
AnswerTokens = app.AnswerTokens,
|
||||
EmptyAnswer = KmsConstantcs.KmsSearchNull
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
//重排取rerank数
|
||||
searchClientConfig = new SearchClientConfig
|
||||
{
|
||||
MaxAskPromptSize = app.MaxAskPromptSize,
|
||||
MaxMatchesCount = app.RerankCount,
|
||||
AnswerTokens = app.AnswerTokens,
|
||||
EmptyAnswer = KmsConstantcs.KmsSearchNull
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
var memoryBuild = new KernelMemoryBuilder()
|
||||
.WithSearchClientConfig(searchClientConfig)
|
||||
@@ -280,7 +296,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
DocumentId = item.GetDocumentId(),
|
||||
Text = item.GetPartitionText(),
|
||||
Url = item.GetWebPageUrl(),
|
||||
Url = item.GetWebPageUrl(KmsConstantcs.KmsIndex),
|
||||
LastUpdate = item.GetLastUpdate().LocalDateTime.ToString("yyyy-MM-dd HH:mm:ss"),
|
||||
File = item.GetFileName()
|
||||
}));
|
||||
|
||||
@@ -20,6 +20,8 @@ using System.Reflection;
|
||||
using DocumentFormat.OpenXml.Drawing;
|
||||
using Microsoft.KernelMemory;
|
||||
using OpenCvSharp.ML;
|
||||
using LLamaSharp.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
|
||||
namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
@@ -105,11 +107,13 @@ namespace AntSK.Domain.Domain.Service
|
||||
var (weights, parameters) = LLamaConfig.GetLLamaConfig(chatModel.ModelName);
|
||||
var ex = new StatelessExecutor(weights, parameters);
|
||||
builder.Services.AddKeyedSingleton<ITextGenerationService>("local-llama", new LLamaSharpTextCompletion(ex));
|
||||
builder.Services.AddKeyedSingleton<IChatCompletionService>("local-llama-chat", new LLamaSharpChatCompletion(ex));
|
||||
break;
|
||||
|
||||
case Model.Enum.AIType.SparkDesk:
|
||||
var options = new SparkDeskOptions { AppId = chatModel.EndPoint, ApiSecret = chatModel.ModelKey, ApiKey = chatModel.ModelName, ModelVersion = Sdcb.SparkDesk.ModelVersion.V3_5 };
|
||||
builder.Services.AddKeyedSingleton<ITextGenerationService>("spark-desk", new SparkDeskTextCompletion(options, chatModel.Id));
|
||||
builder.Services.AddKeyedSingleton<IChatCompletionService>("spark-desk-chat", new SparkDeskChatCompletion(options, chatModel.Id));
|
||||
break;
|
||||
|
||||
case Model.Enum.AIType.DashScope:
|
||||
@@ -118,6 +122,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
|
||||
case Model.Enum.AIType.Mock:
|
||||
builder.Services.AddKeyedSingleton<ITextGenerationService>("mock", new MockTextCompletion());
|
||||
builder.Services.AddKeyedSingleton<IChatCompletionService>("mock-chat", new MockChatCompletion());
|
||||
break;
|
||||
case Model.Enum.AIType.LLamaFactory:
|
||||
builder.AddOpenAIChatCompletion(
|
||||
@@ -173,7 +178,6 @@ namespace AntSK.Domain.Domain.Service
|
||||
|
||||
var getParametes = new List<KernelParameterMetadata>() {
|
||||
new KernelParameterMetadata("jsonbody"){
|
||||
Name="json参数字符串",
|
||||
ParameterType=typeof(string),
|
||||
Description=$"背景文档:{Environment.NewLine}{api.InputPrompt} {Environment.NewLine}提取出对应的json格式字符串,参考如下格式:{Environment.NewLine}{api.Query}"
|
||||
}
|
||||
@@ -212,7 +216,6 @@ namespace AntSK.Domain.Domain.Service
|
||||
//处理json body
|
||||
var postParametes = new List<KernelParameterMetadata>() {
|
||||
new KernelParameterMetadata("jsonbody"){
|
||||
Name="json参数字符串",
|
||||
ParameterType=typeof(string),
|
||||
Description=$"背景文档:{Environment.NewLine}{api.InputPrompt} {Environment.NewLine}提取出对应的json格式字符串,参考如下格式:{Environment.NewLine}{api.JsonBody}"
|
||||
}
|
||||
@@ -300,8 +303,8 @@ namespace AntSK.Domain.Domain.Service
|
||||
KernelFunction sunFun = _kernel.Plugins.GetFunction("ConversationSummaryPlugin", "SummarizeConversation");
|
||||
var summary = await _kernel.InvokeAsync(sunFun, new() { ["input"] = $"内容是:{history.ToString()} {Environment.NewLine} 请注意用中文总结" });
|
||||
string his = summary.GetValue<string>();
|
||||
var msg = $"history:{Environment.NewLine}{history.ToString()}{Environment.NewLine} user:{questions}{Environment.NewLine}"; ;
|
||||
var msg = $"history:{Environment.NewLine}{his}{Environment.NewLine} user:{questions}{Environment.NewLine}";
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,9 @@ namespace AntSK.Domain.Repositories
|
||||
/// </summary>
|
||||
public string? EmbeddingModelID { get; set; }
|
||||
|
||||
public string? RerankModelID { get; set; }
|
||||
|
||||
|
||||
public string? ImageModelID { get; set; }
|
||||
/// <summary>
|
||||
/// 温度
|
||||
@@ -96,6 +99,9 @@ namespace AntSK.Domain.Repositories
|
||||
[SugarColumn(DefaultValue = "3")]
|
||||
public int MaxMatchesCount { get; set; } = 3;
|
||||
|
||||
|
||||
[SugarColumn(DefaultValue = "20")]
|
||||
public int RerankCount { get; set; } = 20;
|
||||
/// <summary>
|
||||
/// 回答最大token数
|
||||
/// </summary>
|
||||
|
||||
41
src/AntSK.Domain/Repositories/AI/Chat/Chats.cs
Normal file
41
src/AntSK.Domain/Repositories/AI/Chat/Chats.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using AntSK.Domain.Domain.Model.Enum;
|
||||
using SqlSugar;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
[SugarTable("Chats")]
|
||||
public partial class Chats
|
||||
{
|
||||
[SugarColumn(IsPrimaryKey = true)]
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
/// <summary>
|
||||
/// 应用ID
|
||||
/// </summary>
|
||||
public string AppId { get; set; }
|
||||
/// <summary>
|
||||
/// 消息内容
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "varchar(4000)")]
|
||||
public string Context { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 发送是true 接收是false
|
||||
/// </summary>
|
||||
public bool IsSend { get; set; } = false;
|
||||
/// <summary>
|
||||
/// 创建事件
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件名
|
||||
/// </summary>
|
||||
public string? FileName { get; set; }
|
||||
}
|
||||
}
|
||||
11
src/AntSK.Domain/Repositories/AI/Chat/Chats_Repositories.cs
Normal file
11
src/AntSK.Domain/Repositories/AI/Chat/Chats_Repositories.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
using AntSK.Domain.Common.DependencyInjection;
|
||||
using AntSK.Domain.Repositories.Base;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
[ServiceDescription(typeof(IChats_Repositories), ServiceLifetime.Scoped)]
|
||||
public class Chats_Repositories : Repository<Chats>, IChats_Repositories
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using AntSK.Domain.Repositories.Base;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
public interface IChats_Repositories : IRepository<Chats>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Web;
|
||||
using System.Security.Cryptography;
|
||||
using System.Web;
|
||||
|
||||
namespace AntSK.Domain.Utils
|
||||
{
|
||||
@@ -261,5 +262,11 @@ namespace AntSK.Domain.Utils
|
||||
{
|
||||
return s.Equals(value, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static string AntSKCalculateSHA256(this BinaryData binaryData)
|
||||
{
|
||||
byte[] byteArray = SHA256.HashData(binaryData.ToMemory().Span);
|
||||
return Convert.ToHexString(byteArray).ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,4 +17,5 @@ matplotlib
|
||||
fire
|
||||
modelscope
|
||||
langchain-community
|
||||
sentence_transformers
|
||||
sentence_transformers
|
||||
FlagEmbedding
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<Project>
|
||||
<!-- See https://aka.ms/dotnet/msbuild/customize for more details on customizing your build -->
|
||||
<PropertyGroup>
|
||||
|
||||
<KMVersion>0.36.240416.1</KMVersion>
|
||||
<LLamaSharpVersion>0.11.2</LLamaSharpVersion>
|
||||
<KMVersion>0.61.240519.2</KMVersion>
|
||||
<LLamaSharpVersion>0.12.0</LLamaSharpVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DocumentationFile>AntSK.xml</DocumentationFile>
|
||||
<NoWarn>CA1050,CA1707,CA2007,VSTHRD111,CS1591,RCS1110,CA5394,SKEXP0001,SKEXP0002,SKEXP0003,SKEXP0004,SKEXP0010,SKEXP0011,,SKEXP0012,SKEXP0020,SKEXP0021,SKEXP0022,SKEXP0023,SKEXP0024,SKEXP0025,SKEXP0026,SKEXP0027,SKEXP0028,SKEXP0029,SKEXP0030,SKEXP0031,SKEXP0032,SKEXP0040,SKEXP0041,SKEXP0042,SKEXP0050,SKEXP0051,SKEXP0052,SKEXP0053,SKEXP0054,SKEXP0055,SKEXP0060,SKEXP0061,SKEXP0101,SKEXP0102</NoWarn>
|
||||
<ApplicationIcon>AntSKlogo.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -14,6 +15,10 @@
|
||||
<EmbeddedResource Remove="llamafactory\**" />
|
||||
<None Remove="llamafactory\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="AntSKlogo.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.2" />
|
||||
|
||||
BIN
src/AntSK/AntSKlogo.ico
Normal file
BIN
src/AntSK/AntSKlogo.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -8,7 +8,7 @@
|
||||
@inject INotificationService _notice
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<AntDesign.ProLayout.BasicLayout Logo="@("https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg")"
|
||||
<AntDesign.ProLayout.BasicLayout Logo="@("/assets/logo.svg")"
|
||||
MenuData="_menuData">
|
||||
<RightContentRender>
|
||||
<AntSK.Components.RightContent />
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<Button Type="@ButtonType.Link" OnClick="NavigateModelList">去创建</Button>
|
||||
</FormItem>
|
||||
<FormItem Label="提示词" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<TextArea MinRows="4" Placeholder="请输入提示词,用户输入使用{{$input}} 来做占位符" @bind-Value="@context.Prompt" />
|
||||
<TextArea MinRows="4" Placeholder="请输入角色信息" @bind-Value="@context.Prompt" />
|
||||
</FormItem>
|
||||
<FormItem Label="温度系数" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<span>更确定</span>
|
||||
@@ -61,6 +61,7 @@
|
||||
<span>更发散</span>
|
||||
</FormItem>
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<FormItem Label="图片模型" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
@@ -124,6 +125,17 @@
|
||||
</Select>
|
||||
<Button Type="@ButtonType.Link" OnClick="NavigateKmsList">去创建</Button>
|
||||
</FormItem>
|
||||
<FormItem Label="Rerank重排模型" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Select DataSource="@_rerankList"
|
||||
@bind-Value="@context.RerankModelID"
|
||||
ValueProperty="c=>c.Id"
|
||||
LabelProperty="c=>'【'+c.AIType.ToString()+'】'+c.ModelDescription">
|
||||
</Select>
|
||||
<Button Type="@ButtonType.Link" OnClick="NavigateModelList">去创建</Button>
|
||||
</FormItem>
|
||||
<FormItem Label="Rerank数" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<AntDesign.InputNumber @bind-Value="context.RerankCount" PlaceHolder="Rerank数"></AntDesign.InputNumber>
|
||||
</FormItem>
|
||||
<FormItem Label="提问最大token数" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<AntDesign.InputNumber @bind-Value="context.MaxAskPromptSize" PlaceHolder="提问最大token数"></AntDesign.InputNumber>
|
||||
</FormItem>
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace AntSK.Pages.AppPage
|
||||
|
||||
private List<AIModels> _chatList;
|
||||
private List<AIModels> _embedingList;
|
||||
private List<AIModels> _rerankList;
|
||||
private List<AIModels> _imageList;
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
@@ -56,6 +57,7 @@ namespace AntSK.Pages.AppPage
|
||||
var models=_aimodels_Repositories.GetList();
|
||||
_chatList = models.Where(p => p.AIModelType == AIModelType.Chat).ToList();
|
||||
_embedingList = models.Where(p => p.AIModelType == AIModelType.Embedding).ToList();
|
||||
_rerankList = models.Where(p => p.AIModelType == AIModelType.Rerank).ToList();
|
||||
_imageList = models.Where(p => p.AIModelType == AIModelType.Image).ToList();
|
||||
|
||||
_functionService.SearchMarkedMethods();
|
||||
@@ -141,7 +143,7 @@ namespace AntSK.Pages.AppPage
|
||||
|
||||
private void NavigateModelList()
|
||||
{
|
||||
NavigationManager.NavigateTo("/setting/modellist");
|
||||
NavigationManager.NavigateTo("/modelmanager/modellist");
|
||||
}
|
||||
|
||||
private void NavigateKmsList()
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
<Body>
|
||||
@if (!string.IsNullOrEmpty(AppId))
|
||||
{
|
||||
<ChatView AppId="@AppId" ShowTitle=false OnRelevantSources="OnRelevantSources"></ChatView>
|
||||
<Watermark Content="AntSK">
|
||||
<ChatView AppId="@AppId" ShowTitle=false OnRelevantSources="OnRelevantSources"></ChatView>
|
||||
</Watermark>
|
||||
}
|
||||
</Body>
|
||||
</Card>
|
||||
@@ -41,7 +43,14 @@
|
||||
<Body>
|
||||
<AntList Bordered DataSource="@_relevantSources" Style="padding:10px;">
|
||||
<ChildContent Context="item">
|
||||
<span> <b>@item.SourceName </b> 相似度:<Text Mark> @item.Relevance</Text></span>
|
||||
<span> <b>@item.SourceName </b> </span>
|
||||
<br />
|
||||
<span>相似度:<Text Mark> @item.Relevance</Text></span>
|
||||
@if (@item.RerankScore != 0)
|
||||
{
|
||||
<br />
|
||||
<span> Rerank相关性:<Text Mark> @item.RerankScore</Text></span>
|
||||
}
|
||||
<Body>
|
||||
@((MarkupString)(@item.Text))
|
||||
</Body>
|
||||
@@ -59,12 +68,10 @@
|
||||
flex-direction: column;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
@layout OpenLayout
|
||||
@inherits AntDomComponentBase
|
||||
|
||||
|
||||
<div id="chat">
|
||||
@if (ShowTitle)
|
||||
{
|
||||
@@ -64,7 +65,7 @@
|
||||
<Flex Justify="end">
|
||||
|
||||
<AntDesign.Input @bind-Value="@(_messageInput)" DebounceMilliseconds="@(-1)" Placeholder="输入消息回车发送" OnPressEnter="@(async () => await OnSendAsync())" Disabled="@Sendding"></AntDesign.Input>
|
||||
@if (app.EmbeddingModelID!=null)
|
||||
@if (app.EmbeddingModelID != null)
|
||||
{
|
||||
<Upload Action="@("api/File/UploadFile")"
|
||||
Name="file"
|
||||
|
||||
@@ -6,14 +6,18 @@ using AntSK.Domain.Domain.Model.Enum;
|
||||
using AntSK.Domain.Repositories;
|
||||
using AntSK.Domain.Utils;
|
||||
using AntSK.LLM.StableDiffusion;
|
||||
using AntSK.Models;
|
||||
using Blazored.LocalStorage;
|
||||
using DocumentFormat.OpenXml.InkML;
|
||||
using Markdig;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
|
||||
using Microsoft.JSInterop;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AntSK.Pages.ChatPage.Components
|
||||
{
|
||||
@@ -36,8 +40,10 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
[Inject] IChatService _chatService { get; set; }
|
||||
[Inject] IJSRuntime _JSRuntime { get; set; }
|
||||
[Inject] ILocalStorageService _localStorage { get; set; }
|
||||
[Inject] IChats_Repositories _chats_Repositories { get; set; }
|
||||
[Inject] ProtectedSessionStorage _protectedSessionStore { get; set; }
|
||||
|
||||
protected List<MessageInfo> MessageList = [];
|
||||
protected List<Chats> MessageList = [];
|
||||
protected string? _messageInput;
|
||||
protected string _json = "";
|
||||
protected bool Sendding = false;
|
||||
@@ -48,25 +54,87 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
|
||||
private List<RelevantSource> _relevantSources = new List<RelevantSource>();
|
||||
|
||||
private string _userName { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
LoadData();
|
||||
var msgs = await _localStorage.GetItemAsync<List<MessageInfo>>("msgs");
|
||||
await LoadData();
|
||||
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await LoadData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化加载数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task LoadData()
|
||||
{
|
||||
app = _apps_Repositories.GetFirst(p => p.Id == AppId);
|
||||
var userSessionStorageResult = await _protectedSessionStore.GetAsync<UserSession>("UserSession");
|
||||
var userSession = userSessionStorageResult.Success ? userSessionStorageResult.Value : null;
|
||||
_userName = userSession?.UserName;
|
||||
await GetMsgList();
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取聊天记录列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task GetMsgList()
|
||||
{
|
||||
List<Chats> msgs = new List<Chats>();
|
||||
if (string.IsNullOrEmpty(_userName))
|
||||
{
|
||||
//匿名访问使用localstore
|
||||
msgs = await _localStorage.GetItemAsync<List<Chats>>($"msgs:{AppId}");
|
||||
}
|
||||
else
|
||||
{
|
||||
msgs = await _chats_Repositories.GetListAsync(p => p.AppId == AppId && p.UserName == _userName);
|
||||
}
|
||||
if (msgs != null && msgs.Count > 0)
|
||||
{
|
||||
MessageList = msgs;
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
/// <summary>
|
||||
/// 清空聊天记录列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task ClearMsgList()
|
||||
{
|
||||
LoadData();
|
||||
MessageList.Clear();
|
||||
if (string.IsNullOrEmpty(_userName))
|
||||
{
|
||||
await _localStorage.SetItemAsync<List<Chats>>($"msgs:{AppId}", MessageList);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _chats_Repositories.DeleteAsync(p => p.AppId == AppId && p.UserName == _userName);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadData()
|
||||
/// <summary>
|
||||
/// 保存聊天记录
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task SaveMsg(List<Chats> MessageList)
|
||||
{
|
||||
app = _apps_Repositories.GetFirst(p => p.Id == AppId);
|
||||
if (string.IsNullOrEmpty(_userName))
|
||||
{
|
||||
await _localStorage.SetItemAsync<List<Chats>>($"msgs:{AppId}", MessageList);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MessageList.Count() > 0)
|
||||
{
|
||||
await _chats_Repositories.InsertAsync(MessageList.LastOrDefault());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task OnClearAsync()
|
||||
@@ -78,11 +146,11 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
var result = await _confirmService.Show(content, title, ConfirmButtons.YesNo);
|
||||
if (result == ConfirmResult.Yes)
|
||||
{
|
||||
MessageList.Clear();
|
||||
await _localStorage.SetItemAsync<List<MessageInfo>>("msgs", MessageList);
|
||||
|
||||
await ClearMsgList();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
_ = Message.Info("清理成功");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -102,18 +170,33 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
var filePath = fileList.FirstOrDefault()?.Url;
|
||||
var fileName = fileList.FirstOrDefault()?.FileName;
|
||||
|
||||
MessageList.Add(new MessageInfo()
|
||||
var chat = new Chats()
|
||||
{
|
||||
ID = Guid.NewGuid().ToString(),
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
UserName = _userName,
|
||||
AppId = AppId,
|
||||
Context = _messageInput,
|
||||
CreateTime = DateTime.Now,
|
||||
IsSend = true
|
||||
});
|
||||
|
||||
};
|
||||
MessageList.Add(chat);
|
||||
if (!string.IsNullOrEmpty(_userName))
|
||||
{
|
||||
await _chats_Repositories.InsertAsync(chat);
|
||||
}
|
||||
|
||||
Sendding = true;
|
||||
await SendAsync(_messageInput,filePath);
|
||||
_messageInput = "";
|
||||
Sendding = false;
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await SendAsync(_messageInput, filePath);
|
||||
}).ContinueWith(task => {
|
||||
|
||||
_messageInput = "";
|
||||
Sendding = false;
|
||||
InvokeAsync(StateHasChanged);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
@@ -123,7 +206,9 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
}
|
||||
|
||||
}
|
||||
protected async Task OnCopyAsync(MessageInfo item)
|
||||
|
||||
|
||||
protected async Task OnCopyAsync(Chats item)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
@@ -135,48 +220,78 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
MessageList = MessageList.Where(w => w.ID != id).ToList();
|
||||
MessageList = MessageList.Where(w => w.Id != id).ToList();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始发送消息
|
||||
/// </summary>
|
||||
/// <param name="questions"></param>
|
||||
/// <param name="filePath"></param>
|
||||
/// <returns></returns>
|
||||
protected async Task<bool> SendAsync(string questions, string? filePath)
|
||||
{
|
||||
ChatHistory history = new ChatHistory();
|
||||
|
||||
//处理多轮会话
|
||||
Apps app = _apps_Repositories.GetFirst(p => p.Id == AppId);
|
||||
if (MessageList.Count > 0)
|
||||
{
|
||||
history = await _chatService.GetChatHistory(MessageList);
|
||||
}
|
||||
ChatHistory history;
|
||||
|
||||
if (app.Type == AppType.chat.ToString() && (filePath == null || app.EmbeddingModelID.IsNull()))
|
||||
{
|
||||
await SendChat(questions, history, app);
|
||||
if (string.IsNullOrEmpty(app.Prompt))
|
||||
{
|
||||
app.Prompt = "你叫AntSK,是一个人工智能助手";
|
||||
}
|
||||
//聊天应用增加系统角色
|
||||
history = new ChatHistory(app.Prompt.ConvertToString());
|
||||
|
||||
if (MessageList.Count > 0)
|
||||
{
|
||||
history = await _chatService.GetChatHistory(MessageList, history);
|
||||
}
|
||||
await SendChat(history, app);
|
||||
}
|
||||
else if (app.Type == AppType.kms.ToString() || filePath != null || app.EmbeddingModelID.IsNotNull())
|
||||
{
|
||||
history = new ChatHistory();
|
||||
|
||||
if (MessageList.Count > 0)
|
||||
{
|
||||
history = await _chatService.GetChatHistory(MessageList, history);
|
||||
}
|
||||
await SendKms(questions, history, app, filePath);
|
||||
|
||||
|
||||
}
|
||||
else if (app.Type == AppType.img.ToString())
|
||||
{
|
||||
await SendImg(questions,app);
|
||||
await SendImg(questions, app);
|
||||
}
|
||||
|
||||
//缓存消息记录
|
||||
if (app.Type != AppType.img.ToString())
|
||||
{
|
||||
await _localStorage.SetItemAsync<List<MessageInfo>>("msgs", MessageList);
|
||||
await SaveMsg(MessageList);
|
||||
if (OnRelevantSources.IsNotNull())
|
||||
{
|
||||
await OnRelevantSources.InvokeAsync(_relevantSources);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return await Task.FromResult(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送图片对话
|
||||
/// </summary>
|
||||
/// <param name="questions"></param>
|
||||
/// <param name="app"></param>
|
||||
/// <returns></returns>
|
||||
private async Task SendImg(string questions,Apps app)
|
||||
{
|
||||
MessageInfo info = new MessageInfo();
|
||||
info.ID = Guid.NewGuid().ToString();
|
||||
Chats info = new Chats();
|
||||
info.Id = Guid.NewGuid().ToString();
|
||||
info.UserName=_userName;
|
||||
info.AppId=AppId;
|
||||
info.CreateTime = DateTime.Now;
|
||||
var base64= await _chatService.SendImgByAppAsync(app, questions);
|
||||
if (string.IsNullOrEmpty(base64))
|
||||
@@ -199,27 +314,23 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
/// <returns></returns>
|
||||
private async Task SendKms(string questions, ChatHistory history, Apps app, string? filePath)
|
||||
{
|
||||
MessageInfo info = null;
|
||||
Chats info = new Chats()
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
AppId = AppId,
|
||||
UserName = _userName,
|
||||
CreateTime = DateTime.Now,
|
||||
Context=""
|
||||
};
|
||||
MessageList.Add(info);
|
||||
var chatResult = _chatService.SendKmsByAppAsync(app, questions, history, filePath, _relevantSources);
|
||||
await foreach (var content in chatResult)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
info = new MessageInfo();
|
||||
info.ID = Guid.NewGuid().ToString();
|
||||
info.Context = content.ConvertToString();
|
||||
info.CreateTime = DateTime.Now;
|
||||
|
||||
MessageList.Add(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
info.Context += content.ConvertToString();
|
||||
await Task.Delay(50);
|
||||
}
|
||||
info.Context += content.ConvertToString();
|
||||
await Task.Delay(50);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
await OnRelevantSources.InvokeAsync(_relevantSources);
|
||||
//全部处理完后再处理一次Markdown
|
||||
await MarkDown(info);
|
||||
}
|
||||
@@ -227,20 +338,21 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
/// <summary>
|
||||
/// 发送普通对话
|
||||
/// </summary>
|
||||
/// <param name="questions"></param>
|
||||
/// <param name="history"></param>
|
||||
/// <param name="app"></param>
|
||||
/// <returns></returns>
|
||||
private async Task SendChat(string questions, ChatHistory history, Apps app)
|
||||
private async Task SendChat(ChatHistory history, Apps app)
|
||||
{
|
||||
MessageInfo info = null;
|
||||
var chatResult = _chatService.SendChatByAppAsync(app, questions, history);
|
||||
Chats info = null;
|
||||
var chatResult = _chatService.SendChatByAppAsync(app, history);
|
||||
await foreach (var content in chatResult)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
info = new MessageInfo();
|
||||
info.ID = Guid.NewGuid().ToString();
|
||||
info = new Chats();
|
||||
info.Id = Guid.NewGuid().ToString();
|
||||
info.UserName = _userName;
|
||||
info.AppId = AppId;
|
||||
info.Context = content.ConvertToString();
|
||||
info.CreateTime = DateTime.Now;
|
||||
|
||||
@@ -257,7 +369,12 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
await MarkDown(info);
|
||||
}
|
||||
|
||||
private async Task MarkDown(MessageInfo info)
|
||||
/// <summary>
|
||||
/// 处理markdown
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <returns></returns>
|
||||
private async Task MarkDown(Chats info)
|
||||
{
|
||||
if (info.IsNotNull())
|
||||
{
|
||||
@@ -270,6 +387,10 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
await _JSRuntime.ScrollToBottomAsync("scrollDiv");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传文件事件
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
private void OnSingleCompleted(UploadInfo fileInfo)
|
||||
{
|
||||
fileList.Add(new()
|
||||
@@ -281,6 +402,11 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
});
|
||||
_kMService.OnSingleCompleted(fileInfo);
|
||||
}
|
||||
/// <summary>
|
||||
/// 移除文件事件
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<bool> HandleFileRemove(UploadFileItem file)
|
||||
{
|
||||
fileList.RemoveAll(x => x.FileName == file.FileName);
|
||||
|
||||
@@ -6,14 +6,16 @@
|
||||
@page "/OpenChat/{AppId}"
|
||||
@layout OpenLayout
|
||||
|
||||
|
||||
<ChatView AppId="@AppId" ShowTitle=true>
|
||||
|
||||
</ChatView>
|
||||
|
||||
|
||||
<style>
|
||||
#chat{
|
||||
height:100% ;
|
||||
display:flex;
|
||||
#chat {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-x: hidden;
|
||||
font-family: Arial, sans-serif;
|
||||
@@ -21,7 +23,7 @@
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
@code{
|
||||
@code {
|
||||
[Parameter]
|
||||
public string AppId { get; set; }
|
||||
}
|
||||
@@ -70,7 +70,7 @@ namespace AntSK.Pages
|
||||
|
||||
private void NavToAIModel()
|
||||
{
|
||||
NavigationManager.NavigateTo("/setting/modellist");
|
||||
NavigationManager.NavigateTo("/modelmanager/modellist");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace AntSK.Pages.KmsPage
|
||||
|
||||
private void NavigateModelList()
|
||||
{
|
||||
NavigationManager.NavigateTo("/setting/modellist");
|
||||
NavigationManager.NavigateTo("/modelmanager/modellist");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
@using AntSK.LLamaFactory.Model
|
||||
@using AntSK.LLamaFactory
|
||||
@using BlazorComponents.Terminal
|
||||
@page "/setting/model/add"
|
||||
@page "/setting/model/add/{ModelId}"
|
||||
@page "/setting/model/addbypath/{ModelPath}"
|
||||
@page "/modelmanager/model/add"
|
||||
@page "/modelmanager/model/add/{ModelId}"
|
||||
@page "/modelmanager/model/addbypath/{ModelPath}"
|
||||
@using AntSK.Services.Auth
|
||||
@inherits AuthComponentBase
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@@ -27,21 +27,25 @@
|
||||
<EnumRadioGroup @bind-Value="context.AIType" ButtonStyle="RadioButtonStyle.Solid" OnChange="AITypeChange" TEnum="AIType"> </EnumRadioGroup>
|
||||
</FormItem>
|
||||
<FormItem Label="模型类型" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<RadioGroup @bind-Value="context.AIModelType">
|
||||
<RadioGroup @bind-Value="context.AIModelType">
|
||||
@if (context.AIType == AIType.StableDiffusion)
|
||||
{
|
||||
<Radio RadioButton Value="@(AIModelType.Image)">图片模型</Radio>
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
@if (context.AIType != AIType.BgeEmbedding)
|
||||
@if (context.AIType != AIType.BgeEmbedding && context.AIType != AIType.BgeRerank)
|
||||
{
|
||||
<Radio RadioButton Value="@(AIModelType.Chat)">会话模型</Radio>
|
||||
}
|
||||
@if (context.AIType != AIType.LLamaFactory && context.AIType != AIType.Mock && context.AIType != AIType.SparkDesk)
|
||||
@if (context.AIType != AIType.LLamaFactory && context.AIType != AIType.Mock && context.AIType != AIType.SparkDesk && context.AIType != AIType.BgeRerank)
|
||||
{
|
||||
<Radio RadioButton Value="@(AIModelType.Embedding)">向量模型</Radio>
|
||||
}
|
||||
@if (context.AIType == AIType.BgeRerank)
|
||||
{
|
||||
<Radio RadioButton Value="@(AIModelType.Rerank)">Rerank重排模型</Radio>
|
||||
}
|
||||
}
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
@@ -61,7 +65,7 @@
|
||||
<Input Placeholder="请输入部署名" @bind-Value="@context.ModelName" />
|
||||
</FormItem>
|
||||
<FormItem Label="模型秘钥" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<InputPassword @bind-Value="@context.ModelKey" Placeholder="请输入模型秘钥" Size="@InputSize.Large" />
|
||||
<InputPassword @bind-Value="@context.ModelKey" Placeholder="请输入模型秘钥" />
|
||||
</FormItem>
|
||||
}
|
||||
@if (context.AIType == AIType.OpenAI)
|
||||
@@ -73,7 +77,7 @@
|
||||
<Input Placeholder="请输入模型名称" @bind-Value="@context.ModelName" />
|
||||
</FormItem>
|
||||
<FormItem Label="模型秘钥" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<InputPassword @bind-Value="@context.ModelKey" Placeholder="请输入模型秘钥" Size="@InputSize.Large" />
|
||||
<InputPassword @bind-Value="@context.ModelKey" Placeholder="请输入模型秘钥" />
|
||||
</FormItem>
|
||||
}
|
||||
@if (context.AIType == AIType.SparkDesk)
|
||||
@@ -81,12 +85,13 @@
|
||||
<FormItem Label="APPID" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Input Placeholder="请输入APPID" @bind-Value="@context.EndPoint" />
|
||||
</FormItem>
|
||||
<FormItem Label="APISecret" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<InputPassword @bind-Value="@context.ModelKey" Placeholder="APISecret" />
|
||||
</FormItem>
|
||||
<FormItem Label="APIKey" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Input Placeholder="请输入请输入APIKey" @bind-Value="@context.ModelName" />
|
||||
</FormItem>
|
||||
<FormItem Label="APISecret" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<InputPassword @bind-Value="@context.ModelKey" Placeholder="APISecret" Size="@InputSize.Large" />
|
||||
</FormItem>
|
||||
|
||||
}
|
||||
@if (context.AIType == AIType.DashScope)
|
||||
{
|
||||
@@ -140,7 +145,7 @@
|
||||
<Button OnClick="StopLFService" Disabled="@(!llamaFactoryIsStart)">停止</Button>
|
||||
}
|
||||
</InputGroup>
|
||||
</FormItem>
|
||||
</FormItem>
|
||||
}
|
||||
|
||||
@if (context.AIType == AIType.BgeEmbedding)
|
||||
@@ -152,19 +157,45 @@
|
||||
LabelProperty="c=>c">
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem Label="PythonDll路径" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Input Placeholder="D:\Programs\Python\Python311\python311.dll" @bind-Value="@context.EndPoint" />
|
||||
|
||||
<FormItem Label="Python路径" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Popover ContentTemplate="@_content" Title="提示" Style="width:100%">
|
||||
<Input Placeholder="D:\Programs\Python\Python311\python311.dll" @bind-Value="@context.EndPoint" />
|
||||
</Popover>
|
||||
</FormItem>
|
||||
|
||||
<FormItem Label="环境安装" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Button Type="primary" OnClick="PipInstall">环境安装</Button>
|
||||
</FormItem>
|
||||
<FormItem Label="下载并初始化" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Spin Tip="请等待..." Spinning="@(BgeEmbeddingIsStart)">
|
||||
<Button Type="primary" Disabled="@(BgeEmbeddingIsStart)" OnClick="BgeEmbedding">@BgeEmbeddingBtnText</Button>
|
||||
</Spin>
|
||||
</FormItem>
|
||||
}
|
||||
@if (context.AIType == AIType.BgeRerank)
|
||||
{
|
||||
<FormItem Label="模型名称" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Select DataSource="@bgeRerankList"
|
||||
@bind-Value="@context.ModelName"
|
||||
ValueProperty="c=>c"
|
||||
LabelProperty="c=>c">
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem Label="Python路径" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Popover ContentTemplate="@_content" Title="提示" Style="width:100%">
|
||||
<Input Placeholder="D:\Programs\Python\Python311\python311.dll" @bind-Value="@context.EndPoint" />
|
||||
</Popover>
|
||||
</FormItem>
|
||||
<FormItem Label="环境安装" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Button Type="primary" OnClick="PipInstall">环境安装</Button>
|
||||
</FormItem>
|
||||
<FormItem Label="下载并初始化" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Spin Tip="请等待..." Spinning="@(BgeIsStart)" >
|
||||
<Button Type="primary" Disabled="@(BgeIsStart)" OnClick="BgeDownload">@BgeBtnText</Button>
|
||||
<Spin Tip="请等待..." Spinning="@(BgeRerankIsStart)">
|
||||
<Button Type="primary" Disabled="@(BgeRerankIsStart)" OnClick="BgeRerank">@BgeRerankBtnText</Button>
|
||||
</Spin>
|
||||
</FormItem>
|
||||
}
|
||||
|
||||
@if (context.AIType == AIType.Mock)
|
||||
{
|
||||
}
|
||||
@@ -206,5 +237,8 @@
|
||||
|
||||
@code
|
||||
{
|
||||
|
||||
RenderFragment _content =
|
||||
@<div>
|
||||
<p>在windows上使用 python311.dll文件,在linux上使用 libpython3.10.so</p>
|
||||
</div>;
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using AntDesign.ProLayout;
|
||||
using AntSK.Domain.Domain.Interface;
|
||||
using AntSK.Domain.Domain.Model.Constant;
|
||||
using AntSK.Domain.Domain.Model.Enum;
|
||||
using AntSK.Domain.Domain.Other;
|
||||
using AntSK.Domain.Domain.Other.Bge;
|
||||
using AntSK.Domain.Domain.Service;
|
||||
using AntSK.Domain.Options;
|
||||
using AntSK.Domain.Repositories;
|
||||
@@ -61,8 +61,13 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
private bool _logModalVisible;
|
||||
|
||||
private List<string> bgeEmbeddingList = new List<string>() { "AI-ModelScope/bge-small-zh-v1.5", "AI-ModelScope/bge-base-zh-v1.5", "AI-ModelScope/bge-large-zh-v1.5" };
|
||||
private bool BgeIsStart = false;
|
||||
private string BgeBtnText = "初始化";
|
||||
private List<string> bgeRerankList = new List<string>() { "Xorbits/bge-reranker-base", "Xorbits/bge-reranker-large", "AI-ModelScope/bge-reranker-v2-m3", "AI-ModelScope/bge-reranker-v2-gemma"};
|
||||
private bool BgeEmbeddingIsStart = false;
|
||||
private string BgeEmbeddingBtnText = "初始化";
|
||||
|
||||
private bool BgeRerankIsStart = false;
|
||||
private string BgeRerankBtnText = "初始化";
|
||||
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
@@ -150,7 +155,7 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
|
||||
private void Back()
|
||||
{
|
||||
NavigationManager.NavigateTo("/setting/modellist");
|
||||
NavigationManager.NavigateTo("/modelmanager/modellist");
|
||||
}
|
||||
|
||||
private async Task StartDownload()
|
||||
@@ -268,7 +273,7 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
}
|
||||
}
|
||||
|
||||
private async Task BgeDownload()
|
||||
private async Task BgeEmbedding()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_aiModel.ModelName))
|
||||
{
|
||||
@@ -277,27 +282,60 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
}
|
||||
if (string.IsNullOrEmpty(_aiModel.EndPoint))
|
||||
{
|
||||
_ = Message.Error("请输入正确的Python dll路径!", 2);
|
||||
_ = Message.Error("请输入正确的Python dll或python so路径!", 2);
|
||||
return;
|
||||
}
|
||||
|
||||
BgeIsStart = true;
|
||||
BgeBtnText = "正在初始化...";
|
||||
BgeEmbeddingIsStart = true;
|
||||
BgeEmbeddingBtnText = "正在初始化...";
|
||||
await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
EmbeddingConfig.LoadModel(_aiModel.EndPoint, _aiModel.ModelName);
|
||||
BgeBtnText = "初始化完成";
|
||||
BgeIsStart = false;
|
||||
BgeEmbeddingConfig.LoadModel(_aiModel.EndPoint, _aiModel.ModelName);
|
||||
BgeEmbeddingBtnText = "初始化完成";
|
||||
BgeEmbeddingIsStart = false;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
_ = Message.Error(ex.Message, 2);
|
||||
BgeIsStart = false;
|
||||
BgeEmbeddingIsStart = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async Task BgeRerank()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_aiModel.ModelName))
|
||||
{
|
||||
_ = Message.Error("请输入模型名称!", 2);
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(_aiModel.EndPoint))
|
||||
{
|
||||
_ = Message.Error("请输入正确的Python dll或python so路径!", 2);
|
||||
return;
|
||||
}
|
||||
|
||||
BgeRerankIsStart = true;
|
||||
BgeRerankBtnText = "正在初始化...";
|
||||
await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
BegRerankConfig.LoadModel(_aiModel.EndPoint, _aiModel.ModelName);
|
||||
BgeRerankBtnText = "初始化完成";
|
||||
BgeRerankIsStart = false;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
_ = Message.Error(ex.Message, 2);
|
||||
BgeRerankIsStart = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private async Task CmdLogHandler(string message)
|
||||
{
|
||||
await InvokeAsync(() =>
|
||||
@@ -331,6 +369,9 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
case AIType.BgeEmbedding:
|
||||
_aiModel.AIModelType = AIModelType.Embedding;
|
||||
break;
|
||||
case AIType.BgeRerank:
|
||||
_aiModel.AIModelType = AIModelType.Rerank;
|
||||
break;
|
||||
default:
|
||||
_aiModel.AIModelType = AIModelType.Chat;
|
||||
break;
|
||||
|
||||
@@ -1,69 +1,69 @@
|
||||
@namespace AntSK.Pages.Setting.AIModel
|
||||
@page "/setting/modeldown"
|
||||
@page "/modelmanager/modeldown"
|
||||
@using AntSK.Services.Auth
|
||||
@inherits AuthComponentBase
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using AntSK.Domain.Domain.Model.hfmirror;
|
||||
using AntSK.Domain.Domain.Model.hfmirror
|
||||
@using AntSK.Domain.Domain.Model.hfmirror
|
||||
@attribute [Authorize(Roles = "AntSKAdmin")]
|
||||
|
||||
<div>
|
||||
<PageContainer Title="模型列表">
|
||||
<Content>
|
||||
<RadioGroup @bind-Value="@_modelType" OnChange="OnModelTypeChange" TValue="string">
|
||||
<Radio Value="@("gguf")" DefaultChecked=true>LLama本地模型(gguf)</Radio>
|
||||
<Radio Value="@("safetensors")">StableDiffusion(safetensors)</Radio>
|
||||
<Radio Value="@("ckpt")">StableDiffusion2(ckpt)</Radio>
|
||||
</RadioGroup>
|
||||
<div style="text-align: center;">
|
||||
|
||||
<PageContainer Title="模型列表">
|
||||
<Content>
|
||||
<RadioGroup @bind-Value="@_modelType" OnChange="OnModelTypeChange" TValue="string">
|
||||
<Radio Value="@("gguf")" DefaultChecked=true>LLama本地模型(gguf)</Radio>
|
||||
<Radio Value="@("safetensors")">StableDiffusion(safetensors)</Radio>
|
||||
<Radio Value="@("ckpt")">StableDiffusion2(ckpt)</Radio>
|
||||
</RadioGroup>
|
||||
<div style="text-align: center;">
|
||||
|
||||
<Search Placeholder="输入回车"
|
||||
EnterButton="@("搜索")"
|
||||
Size="large"
|
||||
Style="max-width: 522px; width: 100%;"
|
||||
OnSearch="Search" />
|
||||
|
||||
</div>
|
||||
</Content>
|
||||
<ChildContent>
|
||||
<div class="filterCardList">
|
||||
<Spin Tip="加载中..." Spinning="@(loaddding)">
|
||||
<AntList TItem="HfModels"
|
||||
Grid="LayoutModel._listGridType"
|
||||
DataSource="_modelList">
|
||||
<ListItem NoFlex>
|
||||
<Card Hoverable
|
||||
BodyStyle="padding-bottom: 20px;"
|
||||
Actions="new[] {
|
||||
down(()=> Down(context.Id))
|
||||
<Search Placeholder="输入回车"
|
||||
EnterButton="@("搜索")"
|
||||
Size="large"
|
||||
Style="max-width: 522px; width: 100%;"
|
||||
OnSearch="Search" />
|
||||
|
||||
</div>
|
||||
</Content>
|
||||
<ChildContent>
|
||||
<div class="filterCardList">
|
||||
<Spin Tip="加载中..." Spinning="@(loaddding)">
|
||||
<AntList TItem="HfModels"
|
||||
Grid="LayoutModel._listGridType"
|
||||
DataSource="_modelList">
|
||||
<ListItem NoFlex>
|
||||
<Card Hoverable
|
||||
BodyStyle="padding-bottom: 20px;"
|
||||
Actions="new[] {
|
||||
down(()=> Down(context.Id))
|
||||
}">
|
||||
<CardMeta>
|
||||
<TitleTemplate>
|
||||
@context.Id
|
||||
</TitleTemplate>
|
||||
<AvatarTemplate>
|
||||
<Avatar Size="small" Src="@context.AuthorData.AvatarUrl" />
|
||||
</AvatarTemplate>
|
||||
</CardMeta>
|
||||
<div class="cardItemContent">
|
||||
<div class="cardInfo">
|
||||
<div>
|
||||
<p>Downloads</p>
|
||||
<p>@context.Downloads.ToString("0,0")</p>
|
||||
<CardMeta>
|
||||
<TitleTemplate>
|
||||
@context.Id
|
||||
</TitleTemplate>
|
||||
<AvatarTemplate>
|
||||
<Avatar Size="small" Src="@context.AuthorData.AvatarUrl" />
|
||||
</AvatarTemplate>
|
||||
</CardMeta>
|
||||
<div class="cardItemContent">
|
||||
<div class="cardInfo">
|
||||
<div>
|
||||
<p>Downloads</p>
|
||||
<p>@context.Downloads.ToString("0,0")</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>Likes</p>
|
||||
<p>@context.Likes.ToString("0,0")</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p>Likes</p>
|
||||
<p>@context.Likes.ToString("0,0")</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</ListItem>
|
||||
</AntList>
|
||||
</Spin>
|
||||
</div>
|
||||
</ChildContent>
|
||||
</PageContainer>
|
||||
</Card>
|
||||
</ListItem>
|
||||
</AntList>
|
||||
</Spin>
|
||||
</div>
|
||||
</ChildContent>
|
||||
</PageContainer>
|
||||
</div>
|
||||
@code
|
||||
{
|
||||
RenderFragment down(Action clickAction) =>@<a key="down" @onclick="@clickAction">下载</a>;
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
|
||||
private void Down(string modelPath)
|
||||
{
|
||||
NavigationManager.NavigateTo($"/setting/modeldown/detail/{modelPath}");
|
||||
NavigationManager.NavigateTo($"/modelmanager/modeldown/detail/{modelPath}");
|
||||
}
|
||||
|
||||
private void OnModelTypeChange(string value)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@namespace AntSK.Pages.Setting.AIModel
|
||||
@page "/setting/modeldown/detail/{ModelName}/{ModelPath}"
|
||||
@page "/modelmanager/modeldown/detail/{ModelName}/{ModelPath}"
|
||||
@using AntSK.Services.Auth
|
||||
@inherits AuthComponentBase
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
|
||||
private void Down(string path)
|
||||
{
|
||||
NavigationManager.NavigateTo($"/setting/model/addbypath/{path.Replace("?download=true", "").Replace("/", "---")}");
|
||||
NavigationManager.NavigateTo($"/modelmanager/model/addbypath/{path.Replace("?download=true", "").Replace("/", "---")}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@namespace AntSK.Pages.Setting.AIModel
|
||||
@using AntSK.Domain.Repositories
|
||||
@using AntSK.Domain.Domain.Model.Enum
|
||||
@page "/setting/modellist"
|
||||
@page "/modelmanager/modellist"
|
||||
@inject NavigationManager NavigationManager
|
||||
@using AntSK.Services.Auth
|
||||
@inherits AuthComponentBase
|
||||
@@ -39,44 +39,48 @@
|
||||
delete(async ()=>await Delete(context.Id))
|
||||
}" Style="width:100%">
|
||||
<div class="listContent" style="width:100%">
|
||||
<div class="listContentItem" style="width:20%">
|
||||
<div class="listContentItem" style="width:15%">
|
||||
<b>模型描述</b>
|
||||
<p>@context.ModelDescription</p>
|
||||
<p title="@context.ModelDescription">@context.ModelDescription</p>
|
||||
</div>
|
||||
<div class="listContentItem" style="width:10%">
|
||||
<b>AI类型</b>
|
||||
<p>
|
||||
@if (context.AIType == AIType.OpenAI)
|
||||
{
|
||||
<Tag Color="@PresetColor.Yellow.ToString()">OpenAI</Tag>
|
||||
<Tag Color="@PresetColor.Pink.ToString()">OpenAI</Tag>
|
||||
}
|
||||
else if (context.AIType == AIType.AzureOpenAI)
|
||||
{
|
||||
<Tag Color="@PresetColor.Green.ToString()">AzureOpenAI</Tag>
|
||||
<Tag Color="@PresetColor.Red.ToString()">AzureOpenAI</Tag>
|
||||
}
|
||||
else if (context.AIType == AIType.LLamaSharp)
|
||||
{
|
||||
<Tag Color="@PresetColor.Red.ToString()">LLamaSharp</Tag>
|
||||
<Tag Color="@PresetColor.Yellow.ToString()">LLamaSharp</Tag>
|
||||
}
|
||||
else if (context.AIType == AIType.SparkDesk)
|
||||
{
|
||||
<Tag Color="@PresetColor.Orange.ToString()">SparkDesk</Tag>
|
||||
<Tag Color="@PresetColor.Cyan.ToString()">SparkDesk</Tag>
|
||||
}
|
||||
else if (context.AIType == AIType.Mock)
|
||||
{
|
||||
<Tag Color="@PresetColor.Cyan.ToString()">Mock</Tag>
|
||||
<Tag Color="@PresetColor.Green.ToString()">Mock</Tag>
|
||||
}
|
||||
else if (context.AIType == AIType.LLamaFactory)
|
||||
{
|
||||
<Tag Color="@PresetColor.Cyan.ToString()">LLamaFactory</Tag>
|
||||
<Tag Color="@PresetColor.Blue.ToString()">LLamaFactory</Tag>
|
||||
}
|
||||
else if (context.AIType == AIType.BgeEmbedding)
|
||||
{
|
||||
<Tag Color="@PresetColor.Gold.ToString()">BgeEmbedding</Tag>
|
||||
<Tag Color="@PresetColor.Purple.ToString()">BgeEmbedding</Tag>
|
||||
}
|
||||
else if (context.AIType == AIType.BgeRerank)
|
||||
{
|
||||
<Tag Color="@PresetColor.GeekBlue.ToString()">BgeRerank</Tag>
|
||||
}
|
||||
else if (context.AIType == AIType.StableDiffusion)
|
||||
{
|
||||
<Tag Color="@PresetColor.Lime.ToString()">StableDiffusion</Tag>
|
||||
<Tag Color="@PresetColor.Magenta.ToString()">StableDiffusion</Tag>
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
@@ -97,15 +101,19 @@
|
||||
{
|
||||
<Tag Color="@PresetColor.Lime.ToString()">图片模型</Tag>
|
||||
}
|
||||
else if (context.AIModelType == AIModelType.Rerank)
|
||||
{
|
||||
<Tag Color="@PresetColor.GeekBlue.ToString()">Rerank重排模型</Tag>
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
<div class="listContentItem" style="width:20%">
|
||||
<div class="listContentItem" style="width:25%">
|
||||
<b>模型地址</b>
|
||||
<p>@context.EndPoint</p>
|
||||
<p title="@context.EndPoint">@context.EndPoint</p>
|
||||
</div>
|
||||
<div class="listContentItem" style="width:10%">
|
||||
<div class="listContentItem" style="width:15%">
|
||||
<b>模型名称</b>
|
||||
<p>@context.ModelName</p>
|
||||
<p title="@context.ModelName">@context.ModelName</p>
|
||||
</div>
|
||||
</div>
|
||||
</ListItem>
|
||||
@@ -116,7 +124,31 @@
|
||||
</ChildContent>
|
||||
</PageContainer>
|
||||
</div>
|
||||
<style>
|
||||
.listContentItem {
|
||||
width: 20%;
|
||||
overflow: hidden; /* 防止内容溢出 */
|
||||
text-overflow: ellipsis; /* 超出部分显示省略号 */
|
||||
white-space: nowrap; /* 防止内容换行 */
|
||||
}
|
||||
|
||||
/* 为需要显示工具提示的元素设置title属性 */
|
||||
.listContentItem p[title] {
|
||||
cursor: pointer; /* 鼠标移动上去时显示小手势 */
|
||||
}
|
||||
|
||||
/* 悬停样式 */
|
||||
.listContentItem:hover p[title]:before {
|
||||
content: attr(title); /* 使用title属性的内容 */
|
||||
position: absolute;
|
||||
background: #333; /* 工具提示的背景颜色 */
|
||||
color: #fff; /* 工具提示的文字颜色 */
|
||||
padding: 4px 8px; /* 工具提示内部的填充 */
|
||||
border-radius: 4px; /* 工具提示的边框圆角 */
|
||||
text-align: center; /* 工具提示文字居中对齐 */
|
||||
z-index: 1000; /* 工具提示在最顶层 */
|
||||
}
|
||||
</style>
|
||||
@code
|
||||
{
|
||||
RenderFragment edit(Action clickAction) =>@<a key="edit" @onclick="@clickAction">修改</a>;
|
||||
|
||||
@@ -51,12 +51,12 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
|
||||
public async Task AddModel()
|
||||
{
|
||||
NavigationManager.NavigateTo("/setting/model/add");
|
||||
NavigationManager.NavigateTo("/modelmanager/model/add");
|
||||
}
|
||||
|
||||
public void Edit(string modelid)
|
||||
{
|
||||
NavigationManager.NavigateTo("/setting/model/add/" + modelid);
|
||||
NavigationManager.NavigateTo("/modelmanager/model/add/" + modelid);
|
||||
}
|
||||
|
||||
public async Task Delete(string modelid)
|
||||
|
||||
121
src/AntSK/Pages/Setting/ChatHistory/ChatHistory.razor
Normal file
121
src/AntSK/Pages/Setting/ChatHistory/ChatHistory.razor
Normal file
@@ -0,0 +1,121 @@
|
||||
@namespace AntSK.Pages.Setting.AIModel
|
||||
@page "/setting/chathistory"
|
||||
@using AntSK.Services.Auth
|
||||
@inherits AuthComponentBase
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using System.ComponentModel
|
||||
@using AntDesign.TableModels
|
||||
@using AntSK.Domain.Repositories
|
||||
@using AntSK.Domain.Common.Map
|
||||
@attribute [Authorize(Roles = "AntSKAdmin")]
|
||||
|
||||
<Table @ref="table"
|
||||
TItem="ChatsDto"
|
||||
DataSource="@chatDtoList"
|
||||
Total="_total"
|
||||
@bind-PageIndex="_pageIndex"
|
||||
@bind-PageSize="_pageSize"
|
||||
OnChange="OnChange"
|
||||
Size="TableSize.Small"
|
||||
RowKey="x=>x.Id">
|
||||
<TitleTemplate>
|
||||
<GridRow>
|
||||
<GridCol Span="4">
|
||||
<Title Level="3">聊天记录</Title>
|
||||
</GridCol>
|
||||
<GridCol Span="8" Offset="12">
|
||||
<Search Placeholder="搜索" @bind-Value="searchString" OnSearch="Search" />
|
||||
</GridCol>
|
||||
</GridRow>
|
||||
</TitleTemplate>
|
||||
<ColumnDefinitions>
|
||||
<PropertyColumn Property="c=>c.Id" />
|
||||
<PropertyColumn Title="用户名" Property="c=>c.UserName" />
|
||||
<PropertyColumn Title="应用名称" Property="c=>c.AppName" />
|
||||
<PropertyColumn Title="发送/接收" Property="c=>c.SendReveice" />
|
||||
<ActionColumn Title="消息内容" Width="30%">
|
||||
<Space>
|
||||
<SpaceItem>
|
||||
@((MarkupString)(context.Context))
|
||||
</SpaceItem>
|
||||
</Space>
|
||||
</ActionColumn>
|
||||
<PropertyColumn Title="时间" Property="c=>c.CreateTime" Format="yyyy-MM-dd HH:mm:ss" />
|
||||
</ColumnDefinitions>
|
||||
</Table>
|
||||
|
||||
@using System.Text.Json;
|
||||
@code {
|
||||
[Inject] IChats_Repositories _chats_Repositories { get; set; }
|
||||
|
||||
ChatsDto[] chatDtoList;
|
||||
|
||||
ITable table;
|
||||
|
||||
int _pageIndex = 1;
|
||||
int _pageSize = 10;
|
||||
int _total = 0;
|
||||
string searchString;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await InitData();
|
||||
}
|
||||
|
||||
public async Task OnChange(QueryModel<ChatsDto> queryModel)
|
||||
{
|
||||
await InitData();
|
||||
}
|
||||
|
||||
private async Task InitData()
|
||||
{
|
||||
if (string.IsNullOrEmpty(searchString))
|
||||
{
|
||||
_total = _chats_Repositories.Count(p => true);
|
||||
var chatList = _chats_Repositories.GetDB().Queryable<Chats, Apps>((c, a) => new object[] {
|
||||
SqlSugar.JoinType.Left,c.AppId==a.Id
|
||||
}).Select((c, a) => new ChatsDto
|
||||
{
|
||||
Id = c.Id,
|
||||
UserName = c.UserName,
|
||||
AppId = c.AppId,
|
||||
IsSend = c.IsSend,
|
||||
SendReveice = c.IsSend ? "发送" : "接收",
|
||||
Context = c.Context,
|
||||
CreateTime = c.CreateTime,
|
||||
AppName = a.Name
|
||||
}).ToPageList(_pageIndex, _pageSize);
|
||||
chatDtoList = chatList.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
_total = _chats_Repositories.Count(p => p.UserName.Contains(searchString) || p.Context.Contains(searchString));
|
||||
var chatList = _chats_Repositories.GetDB().Queryable<Chats, Apps>((c, a) => new object[] {
|
||||
SqlSugar.JoinType.Left,c.AppId==a.Id
|
||||
}).Select((c, a) => new ChatsDto
|
||||
{
|
||||
Id = c.Id,
|
||||
UserName = c.UserName,
|
||||
AppId = c.AppId,
|
||||
IsSend = c.IsSend,
|
||||
SendReveice = c.IsSend ? "发送" : "接收",
|
||||
Context = c.Context,
|
||||
CreateTime = c.CreateTime,
|
||||
AppName = a.Name
|
||||
}).Where(c => c.UserName.Contains(searchString) || c.Context.Contains(searchString)).ToPageList(_pageIndex, _pageSize);
|
||||
chatDtoList = chatList.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Search(string searchKey)
|
||||
{
|
||||
await InitData();
|
||||
}
|
||||
|
||||
public class ChatsDto : Chats
|
||||
{
|
||||
public string AppName { get; set; }
|
||||
public string SendReveice { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -72,6 +72,7 @@
|
||||
}
|
||||
|
||||
kmsDetails_Repositories.GetDB().Ado.ExecuteCommand("DROP TABLE IF EXISTS \"km-kms\"");
|
||||
kmsDetails_Repositories.GetDB().Ado.ExecuteCommand("DROP TABLE IF EXISTS \"km-file\"");
|
||||
var kmsDetails = await kmsDetails_Repositories.GetListAsync();
|
||||
foreach (var detail in kmsDetails)
|
||||
{
|
||||
|
||||
@@ -68,17 +68,17 @@ builder.Services.AddBackgroundTaskBroker().AddHandler<ImportKMSTaskReq, BackGrou
|
||||
.WithCuda(false)
|
||||
.WithLogCallback((level, message) => {
|
||||
Console.WriteLine($"[llama {level}]: {message.TrimEnd('\n')}");
|
||||
});
|
||||
});
|
||||
}
|
||||
else if (LLamaSharpOption.RunType.ToUpper() == "GPU")
|
||||
{
|
||||
NativeLibraryConfig
|
||||
.Instance
|
||||
.WithCuda(true)
|
||||
.WithAvx(NativeLibraryConfig.AvxLevel.Avx)
|
||||
.WithLogCallback((level, message) => {
|
||||
Console.WriteLine($"[llama {level}]: {message.TrimEnd('\n')}");
|
||||
});
|
||||
})
|
||||
.WithAvx(NativeLibraryConfig.AvxLevel.Avx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,13 +41,14 @@ namespace AntSK.Services.OpenApi
|
||||
{
|
||||
case "chat":
|
||||
//普通会话
|
||||
history.AddUserMessage(questions);
|
||||
if (model.stream)
|
||||
{
|
||||
OpenAIStreamResult result1 = new OpenAIStreamResult();
|
||||
result1.created = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
result1.choices = new List<StreamChoicesModel>()
|
||||
{ new StreamChoicesModel() { delta = new OpenAIMessage() { role = "assistant" } } };
|
||||
await SendChatStream(HttpContext, result1, app, questions,history);
|
||||
await SendChatStream(HttpContext, result1, app,history);
|
||||
HttpContext.Response.ContentType = "application/json";
|
||||
await HttpContext.Response.WriteAsync(JsonConvert.SerializeObject(result1));
|
||||
await HttpContext.Response.CompleteAsync();
|
||||
@@ -59,14 +60,12 @@ namespace AntSK.Services.OpenApi
|
||||
result2.created = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
result2.choices = new List<ChoicesModel>()
|
||||
{ new ChoicesModel() { message = new OpenAIMessage() { role = "assistant" } } };
|
||||
result2.choices[0].message.content = await SendChat(questions,history, app);
|
||||
result2.choices[0].message.content = await SendChat(history, app);
|
||||
HttpContext.Response.ContentType = "application/json";
|
||||
await HttpContext.Response.WriteAsync(JsonConvert.SerializeObject(result2));
|
||||
await HttpContext.Response.CompleteAsync();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "kms":
|
||||
//知识库问答
|
||||
if (model.stream)
|
||||
@@ -91,16 +90,15 @@ namespace AntSK.Services.OpenApi
|
||||
await HttpContext.Response.WriteAsync(JsonConvert.SerializeObject(result4));
|
||||
await HttpContext.Response.CompleteAsync();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SendChatStream(HttpContext HttpContext, OpenAIStreamResult result, Apps app,string questions, ChatHistory history)
|
||||
private async Task SendChatStream(HttpContext HttpContext, OpenAIStreamResult result, Apps app, ChatHistory history)
|
||||
{
|
||||
HttpContext.Response.Headers.Add("Content-Type", "text/event-stream");
|
||||
var chatResult = _chatService.SendChatByAppAsync(app, questions, history);
|
||||
var chatResult = _chatService.SendChatByAppAsync(app, history);
|
||||
await foreach (var content in chatResult)
|
||||
{
|
||||
result.choices[0].delta.content = content.ConvertToString();
|
||||
@@ -113,7 +111,6 @@ namespace AntSK.Services.OpenApi
|
||||
|
||||
await HttpContext.Response.WriteAsync("data: [DONE]");
|
||||
await HttpContext.Response.Body.FlushAsync();
|
||||
|
||||
await HttpContext.Response.CompleteAsync();
|
||||
}
|
||||
|
||||
@@ -124,49 +121,48 @@ namespace AntSK.Services.OpenApi
|
||||
/// <param name="history"></param>
|
||||
/// <param name="app"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<string> SendChat(string questions, ChatHistory history, Apps app)
|
||||
private async Task<string> SendChat(ChatHistory history, Apps app)
|
||||
{
|
||||
string result = "";
|
||||
|
||||
if (string.IsNullOrEmpty(app.Prompt) || !app.Prompt.Contains("{{$input}}"))
|
||||
{
|
||||
//如果模板为空,给默认提示词
|
||||
app.Prompt = app.Prompt.ConvertToString() + "{{$input}}";
|
||||
}
|
||||
KernelArguments args = new KernelArguments();
|
||||
if (history.Count > 10)
|
||||
{
|
||||
app.Prompt = @"${{ConversationSummaryPlugin.SummarizeConversation $history}}" + app.Prompt;
|
||||
args = new() {
|
||||
{ "history", string.Join("\n", history.Select(x => x.Role + ": " + x.Content)) },
|
||||
{ "input", questions }
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
args = new()
|
||||
{
|
||||
{ "input", $"{string.Join("\n", history.Select(x => x.Role + ": " + x.Content))}{Environment.NewLine} user:{questions}" }
|
||||
};
|
||||
}
|
||||
|
||||
var _kernel = _kernelService.GetKernelByApp(app);
|
||||
var temperature = app.Temperature / 100; //存的是0~100需要缩小
|
||||
var chat = _kernel.GetRequiredService<IChatCompletionService>();
|
||||
|
||||
var temperature = app.Temperature / 100;//存的是0~100需要缩小
|
||||
OpenAIPromptExecutionSettings settings = new() { Temperature = temperature };
|
||||
List<string> completionList = new List<string>();
|
||||
if (!string.IsNullOrEmpty(app.ApiFunctionList) || !string.IsNullOrEmpty(app.NativeFunctionList))//这里还需要加上本地插件的
|
||||
{
|
||||
_kernelService.ImportFunctionsByApp(app, _kernel);
|
||||
settings.ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions;
|
||||
}
|
||||
var func = _kernel.CreateFunctionFromPrompt(app.Prompt, settings);
|
||||
var chatResult =await _kernel.InvokeAsync(function: func, arguments: args);
|
||||
if (chatResult.IsNotNull())
|
||||
{
|
||||
string answers = chatResult.GetValue<string>();
|
||||
result = answers;
|
||||
}
|
||||
settings.ToolCallBehavior = ToolCallBehavior.EnableKernelFunctions;
|
||||
while (true)
|
||||
{
|
||||
ChatMessageContent result = await chat.GetChatMessageContentAsync(history, settings, _kernel);
|
||||
if (result.Content is not null)
|
||||
{
|
||||
string chunkCompletion = result.Content.ConvertToString();
|
||||
completionList.Add(chunkCompletion);
|
||||
return chunkCompletion;
|
||||
}
|
||||
history.Add(result);
|
||||
IEnumerable<FunctionCallContent> functionCalls = FunctionCallContent.GetFunctionCalls(result);
|
||||
if (!functionCalls.Any())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
foreach (var functionCall in functionCalls)
|
||||
{
|
||||
FunctionResultContent resultContent = await functionCall.InvokeAsync(_kernel);
|
||||
|
||||
history.Add(resultContent.ToChatMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ChatMessageContent result = await chat.GetChatMessageContentAsync(history, settings, _kernel);
|
||||
return result.Content.ConvertToString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private async Task SendKmsStream(HttpContext HttpContext, OpenAIStreamResult result, Apps app, string questions,ChatHistory history)
|
||||
|
||||
@@ -1 +1,30 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" version="1.1" viewBox="0 0 200 200"><title>Group 28 Copy 5</title><desc>Created with Sketch.</desc><defs><linearGradient id="linearGradient-1" x1="62.102%" x2="108.197%" y1="0%" y2="37.864%"><stop offset="0%" stop-color="#4285EB"/><stop offset="100%" stop-color="#2EC7FF"/></linearGradient><linearGradient id="linearGradient-2" x1="69.644%" x2="54.043%" y1="0%" y2="108.457%"><stop offset="0%" stop-color="#29CDFF"/><stop offset="37.86%" stop-color="#148EFF"/><stop offset="100%" stop-color="#0A60FF"/></linearGradient><linearGradient id="linearGradient-3" x1="69.691%" x2="16.723%" y1="-12.974%" y2="117.391%"><stop offset="0%" stop-color="#FA816E"/><stop offset="41.473%" stop-color="#F74A5C"/><stop offset="100%" stop-color="#F51D2C"/></linearGradient><linearGradient id="linearGradient-4" x1="68.128%" x2="30.44%" y1="-35.691%" y2="114.943%"><stop offset="0%" stop-color="#FA8E7D"/><stop offset="51.264%" stop-color="#F74A5C"/><stop offset="100%" stop-color="#F51D2C"/></linearGradient></defs><g id="Page-1" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="logo" transform="translate(-20.000000, -20.000000)"><g id="Group-28-Copy-5" transform="translate(20.000000, 20.000000)"><g id="Group-27-Copy-3"><g id="Group-25" fill-rule="nonzero"><g id="2"><path id="Shape" fill="url(#linearGradient-1)" d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C99.2571609,26.9692191 101.032305,26.9692191 102.20193,28.1378823 L129.985225,55.8983314 C134.193707,60.1033528 141.017005,60.1033528 145.225487,55.8983314 C149.433969,51.69331 149.433969,44.8756232 145.225487,40.6706018 L108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z"/><path id="Shape" fill="url(#linearGradient-2)" d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C100.999864,25.6271836 105.751642,20.541824 112.729652,19.3524487 C117.915585,18.4685261 123.585219,20.4140239 129.738554,25.1889424 C125.624663,21.0784292 118.571995,14.0340304 108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z"/></g><path id="Shape" fill="url(#linearGradient-3)" d="M153.685633,135.854579 C157.894115,140.0596 164.717412,140.0596 168.925894,135.854579 L195.959977,108.842726 C200.659183,104.147384 200.659183,96.5636133 195.960527,91.8688194 L168.690777,64.7181159 C164.472332,60.5180858 157.646868,60.5241425 153.435895,64.7316526 C149.227413,68.936674 149.227413,75.7543607 153.435895,79.9593821 L171.854035,98.3623765 C173.02366,99.5310396 173.02366,101.304724 171.854035,102.473387 L153.685633,120.626849 C149.47715,124.83187 149.47715,131.649557 153.685633,135.854579 Z"/></g><ellipse id="Combined-Shape" cx="100.519" cy="100.437" fill="url(#linearGradient-4)" rx="23.6" ry="23.581"/></g></g></g></g></svg>
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="370.000000pt" height="370.000000pt" viewBox="0 0 370.000000 370.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,370.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M1914 3198 c-87 -152 -450 -815 -526 -960 l-46 -86 26 -7 c15 -4 116
|
||||
-3 225 1 l197 7 69 121 c38 66 83 150 101 185 l32 65 19 -25 c10 -13 44 -71
|
||||
75 -129 32 -58 73 -134 92 -168 l35 -64 213 4 c117 1 215 6 219 9 8 9 -57 139
|
||||
-203 404 -177 324 -439 785 -446 785 0 0 -38 -64 -82 -142z"/>
|
||||
<path d="M772 3019 c-198 -53 -353 -165 -459 -332 -13 -20 -41 -72 -63 -115
|
||||
-51 -102 -64 -184 -58 -372 5 -129 8 -153 33 -215 48 -118 105 -205 195 -295
|
||||
75 -75 101 -93 215 -152 l130 -66 440 -11 c242 -7 467 -16 499 -22 119 -21
|
||||
211 -93 263 -204 24 -51 28 -72 28 -145 -2 -190 -105 -314 -305 -365 l-45 -11
|
||||
-3 -212 -2 -212 22 0 c63 1 202 43 298 91 93 45 116 63 201 148 86 87 102 109
|
||||
153 211 65 131 76 182 76 345 -1 248 -46 365 -209 537 -80 85 -157 141 -277
|
||||
201 l-91 46 -494 11 -494 11 -40 26 c-76 50 -142 121 -171 186 -25 54 -29 74
|
||||
-29 152 1 76 5 99 27 147 47 101 142 175 263 205 l65 16 0 208 0 209 -47 -1
|
||||
c-27 0 -81 -9 -121 -20z"/>
|
||||
<path d="M830 1153 c-38 -7 -42 -14 -123 -156 -153 -271 -169 -304 -151 -311
|
||||
8 -3 109 -6 224 -6 l209 0 70 128 c132 242 176 330 168 339 -9 9 -356 14 -397
|
||||
6z"/>
|
||||
<path d="M2802 1152 l-42 -7 93 -170 c121 -220 154 -273 175 -279 55 -15 114
|
||||
-17 263 -11 l166 7 -119 222 c-66 121 -122 224 -126 227 -10 10 -359 18 -410
|
||||
11z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -35,9 +35,27 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/modelmanager",
|
||||
"name": "模型管理",
|
||||
"key": "modelmanager",
|
||||
"icon": "shop",
|
||||
"children": [
|
||||
{
|
||||
"path": "/modelmanager/modellist",
|
||||
"name": "模型管理",
|
||||
"key": "modelmanager.modellist"
|
||||
},
|
||||
{
|
||||
"path": "/modelmanager/modeldown",
|
||||
"name": "模型下载",
|
||||
"key": "modelmanager.modeldown"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/setting",
|
||||
"name": "设置",
|
||||
"name": "系统设置",
|
||||
"key": "setting",
|
||||
"icon": "setting",
|
||||
"children": [
|
||||
@@ -47,14 +65,9 @@
|
||||
"key": "setting.user"
|
||||
},
|
||||
{
|
||||
"path": "/setting/modellist",
|
||||
"name": "模型管理",
|
||||
"key": "setting.modellist"
|
||||
},
|
||||
{
|
||||
"path": "/setting/modeldown",
|
||||
"name": "模型下载",
|
||||
"key": "setting.modeldown"
|
||||
"path": "/setting/chathistory",
|
||||
"name": "聊天记录",
|
||||
"key": "setting.chathistory"
|
||||
},
|
||||
{
|
||||
"path": "/setting/delkms",
|
||||
@@ -65,8 +78,14 @@
|
||||
},
|
||||
{
|
||||
"path": "http://antsk.cn/",
|
||||
"name": "文档",
|
||||
"name": "使用文档",
|
||||
"key": "antskdoc",
|
||||
"icon": "question-circle"
|
||||
},
|
||||
{
|
||||
"path": "https://www.bilibili.com/video/BV1vK421b7NF",
|
||||
"name": "教程视频",
|
||||
"key": "antskvideo",
|
||||
"icon": "video-camera"
|
||||
}
|
||||
]
|
||||
@@ -11,7 +11,7 @@
|
||||
<PackageReference Include="RestSharp" Version="110.2.0" />
|
||||
<PackageReference Include="Cnblogs.KernelMemory.AI.DashScope" Version="0.1.0" />
|
||||
<PackageReference Include="Cnblogs.SemanticKernel.Connectors.DashScope" Version="0.3.2" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel" Version="1.6.3" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel" Version="1.10.0" />
|
||||
<PackageReference Include="Sdcb.SparkDesk" Version="3.0.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
55
src/AntSk.LLM/Mock/MockChatCompletion.cs
Normal file
55
src/AntSk.LLM/Mock/MockChatCompletion.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using AntSK.LLM.SparkDesk;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Sdcb.SparkDesk;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Unicode;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.LLM.Mock
|
||||
{
|
||||
public class MockChatCompletion : IChatCompletionService
|
||||
{
|
||||
private readonly Dictionary<string, object?> _attributes = new();
|
||||
private readonly SparkDeskClient _client;
|
||||
private string _chatId;
|
||||
private readonly SparkDeskOptions _options;
|
||||
|
||||
private static readonly JsonSerializerOptions _jsonSerializerOptions = new()
|
||||
{
|
||||
NumberHandling = JsonNumberHandling.AllowReadingFromString,
|
||||
Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
|
||||
};
|
||||
|
||||
public IReadOnlyDictionary<string, object?> Attributes => _attributes;
|
||||
|
||||
public MockChatCompletion()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<ChatMessageContent>> GetChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
string result = $"这是一条Mock数据,便于聊天测试,你的消息是:{chatHistory.LastOrDefault().ToString()}";
|
||||
return [new(AuthorRole.Assistant, result.ToString())];
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<StreamingChatMessageContent> GetStreamingChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
string result = $"这是一条Mock数据,便于聊天测试,你的消息是:{chatHistory.LastOrDefault().ToString()}";
|
||||
foreach (var c in result)
|
||||
{
|
||||
yield return new StreamingChatMessageContent(AuthorRole.Assistant, c.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
231
src/AntSk.LLM/SparkDesk/SparkDeskChatCompletion.cs
Normal file
231
src/AntSk.LLM/SparkDesk/SparkDeskChatCompletion.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Sdcb.SparkDesk;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Unicode;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.LLM.SparkDesk
|
||||
{
|
||||
public class SparkDeskChatCompletion : IChatCompletionService
|
||||
{
|
||||
private readonly Dictionary<string, object?> _attributes = new();
|
||||
private readonly SparkDeskClient _client;
|
||||
private string _chatId;
|
||||
private readonly SparkDeskOptions _options;
|
||||
|
||||
private static readonly JsonSerializerOptions _jsonSerializerOptions = new()
|
||||
{
|
||||
NumberHandling = JsonNumberHandling.AllowReadingFromString,
|
||||
Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
|
||||
};
|
||||
|
||||
public IReadOnlyDictionary<string, object?> Attributes => _attributes;
|
||||
|
||||
public SparkDeskChatCompletion(SparkDeskOptions options, string chatId)
|
||||
{
|
||||
_options = options;
|
||||
_chatId = chatId;
|
||||
_client = new(options.AppId, options.ApiKey, options.ApiSecret);
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<ChatMessageContent>> GetChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
var parameters = new ChatRequestParameters
|
||||
{
|
||||
ChatId = _chatId,
|
||||
};
|
||||
|
||||
OpenAIPromptExecutionSettings chatExecutionSettings = OpenAIPromptExecutionSettings.FromExecutionSettings(executionSettings);
|
||||
|
||||
parameters.Temperature = (float)chatExecutionSettings.Temperature;
|
||||
parameters.MaxTokens = chatExecutionSettings.MaxTokens ?? parameters.MaxTokens;
|
||||
|
||||
IList<KernelFunctionMetadata> functions = kernel?.Plugins.GetFunctionsMetadata().Where(x => x.PluginName == "AntSkFunctions").ToList() ?? [];
|
||||
var functionDefs = functions.Select(func => new FunctionDef(func.Name, func.Description, func.Parameters.Select(p => new FunctionParametersDef(p.Name, p.ParameterType?.IsClass == true ? "object" : "string", p.Description, p.IsRequired)).ToList())).ToList();
|
||||
|
||||
List<ChatMessage> messages = GetSparkMessage(chatHistory);
|
||||
|
||||
var result = await _client.ChatAsync(_options.ModelVersion, messages.ToArray(), parameters, functionDefs.Count > 0 ? [.. functionDefs] : null, cancellationToken: cancellationToken);
|
||||
|
||||
if (result.FunctionCall != null)
|
||||
{
|
||||
var func = functions.Where(x => x.Name == result.FunctionCall.Name).FirstOrDefault();
|
||||
|
||||
if (func == null)
|
||||
{
|
||||
return new List<ChatMessageContent> { new(AuthorRole.Assistant, $"插件{result.FunctionCall.Name}未注册") }.AsReadOnly();
|
||||
}
|
||||
|
||||
if (kernel.Plugins.TryGetFunction(func.PluginName, func.Name, out var function))
|
||||
{
|
||||
var arguments = new KernelArguments();
|
||||
|
||||
var JsonElement = JsonDocument.Parse(result.FunctionCall.Arguments).RootElement;
|
||||
foreach (var parameter in func.Parameters)
|
||||
{
|
||||
var error = "";
|
||||
try
|
||||
{
|
||||
if (JsonElement.TryGetProperty(parameter.Name, out var property))
|
||||
{
|
||||
arguments.Add(parameter.Name, property.Deserialize(parameter.ParameterType!, _jsonSerializerOptions));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = $"参数{parameter.Name}解析错误:{ex.Message}";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
{
|
||||
return new List<ChatMessageContent> { new(AuthorRole.Assistant, error) }.AsReadOnly();
|
||||
|
||||
}
|
||||
}
|
||||
var functionResult = await function.InvokeAsync(kernel, arguments, cancellationToken);
|
||||
messages = [ ChatMessage.FromUser(messages.LastOrDefault().Content),
|
||||
ChatMessage.FromSystem($@"
|
||||
执行函数调用成功
|
||||
函数描述:{func.Description}
|
||||
函数执行结果:{functionResult}
|
||||
"),
|
||||
ChatMessage.FromUser("请根据函数调用结果回答我的问题,不要超出函数调用结果的返回,以及不要有多余描述:")];
|
||||
|
||||
|
||||
var callResult = await _client.ChatAsync(_options.ModelVersion, messages.ToArray(), parameters, null);
|
||||
ChatMessageContent chatMessageContent = new(AuthorRole.Assistant, callResult.Text.ToString(), modelId: "SparkDesk");
|
||||
|
||||
return new List<ChatMessageContent> { chatMessageContent }.AsReadOnly();
|
||||
|
||||
}
|
||||
return new List<ChatMessageContent> { new(AuthorRole.Assistant, "未找到插件") }.AsReadOnly();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
ChatMessageContent chatMessageContent = new(AuthorRole.Assistant, result.Text.ToString(), modelId: "SparkDesk");
|
||||
|
||||
return new List<ChatMessageContent> { chatMessageContent }.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async IAsyncEnumerable<StreamingChatMessageContent> GetStreamingChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
var parameters = new ChatRequestParameters
|
||||
{
|
||||
ChatId = _chatId,
|
||||
};
|
||||
OpenAIPromptExecutionSettings chatExecutionSettings = OpenAIPromptExecutionSettings.FromExecutionSettings(executionSettings);
|
||||
|
||||
parameters.Temperature = (float)chatExecutionSettings.Temperature;
|
||||
parameters.MaxTokens = chatExecutionSettings.MaxTokens ?? parameters.MaxTokens;
|
||||
|
||||
IList<KernelFunctionMetadata> functions = kernel?.Plugins.GetFunctionsMetadata().Where(x => x.PluginName == "AntSkFunctions").ToList() ?? [];
|
||||
var functionDefs = functions.Select(func => new FunctionDef(func.Name, func.Description, func.Parameters.Select(p => new FunctionParametersDef(p.Name, p.ParameterType?.IsClass == true ? "object" : "string", p.Description, p.IsRequired)).ToList())).ToList();
|
||||
List<ChatMessage> messages = GetSparkMessage(chatHistory);
|
||||
await foreach (StreamedChatResponse msg in _client.ChatAsStreamAsync(_options.ModelVersion, messages.ToArray(), parameters, functionDefs.Count > 0 ? [.. functionDefs] : null, cancellationToken: cancellationToken))
|
||||
{
|
||||
|
||||
yield return new StreamingChatMessageContent(AuthorRole.Assistant, msg);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private static List<ChatMessage> GetSparkMessage(ChatHistory chatHistory)
|
||||
{
|
||||
List<ChatMessage> messages = new List<ChatMessage>();
|
||||
foreach (var msg in chatHistory.ToList())
|
||||
{
|
||||
string role = "";
|
||||
if (msg.Role == AuthorRole.User)
|
||||
{
|
||||
role = "user";
|
||||
}
|
||||
else if (msg.Role == AuthorRole.System)
|
||||
{
|
||||
role = "system";
|
||||
}
|
||||
else
|
||||
{
|
||||
role = "assistant";
|
||||
}
|
||||
messages.Add(new ChatMessage(role, msg.ToString()));
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
|
||||
private static string? ProcessFunctionResult(object functionResult, ToolCallBehavior? toolCallBehavior)
|
||||
{
|
||||
if (functionResult is string stringResult)
|
||||
{
|
||||
return stringResult;
|
||||
}
|
||||
|
||||
if (functionResult is ChatMessageContent chatMessageContent)
|
||||
{
|
||||
return chatMessageContent.ToString();
|
||||
}
|
||||
|
||||
return JsonSerializer.Serialize(functionResult, _jsonSerializerOptions);
|
||||
}
|
||||
|
||||
public static Dictionary<string, object> ParseJsonElement(JsonElement element, string propertyName)
|
||||
{
|
||||
Dictionary<string, object> dict = new();
|
||||
|
||||
switch (element.ValueKind)
|
||||
{
|
||||
case JsonValueKind.Object:
|
||||
foreach (JsonProperty property in element.EnumerateObject())
|
||||
{
|
||||
dict.Add(property.Name, ParseJsonElement(property.Value, property.Name));
|
||||
}
|
||||
break;
|
||||
|
||||
case JsonValueKind.Array:
|
||||
List<object> list = new List<object>();
|
||||
foreach (JsonElement arrayElement in element.EnumerateArray())
|
||||
{
|
||||
list.Add(ParseJsonElement(arrayElement, ""));
|
||||
}
|
||||
dict.Add(propertyName, list);
|
||||
break;
|
||||
|
||||
case JsonValueKind.String:
|
||||
dict.Add(propertyName, element.GetString());
|
||||
break;
|
||||
|
||||
case JsonValueKind.Number:
|
||||
dict.Add(propertyName, element.GetInt32());
|
||||
break;
|
||||
|
||||
case JsonValueKind.True:
|
||||
case JsonValueKind.False:
|
||||
dict.Add(propertyName, element.GetBoolean());
|
||||
break;
|
||||
|
||||
default:
|
||||
dict.Add(propertyName, "Unsupported value type");
|
||||
break;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user