mirror of
https://github.com/AIDotNet/AntSK.git
synced 2026-02-18 06:20:11 +08:00
Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1cc56dd553 | ||
|
|
64e949a88b | ||
|
|
a2390a7c97 | ||
|
|
559661bb6c | ||
|
|
79326de263 | ||
|
|
3815891b28 | ||
|
|
42d474382a | ||
|
|
fe691f2d44 | ||
|
|
3ee41a8ab1 | ||
|
|
7ca41dff8a | ||
|
|
ba2e86993e | ||
|
|
13878046a2 | ||
|
|
49ff8bf54f | ||
|
|
e9cc5a3993 | ||
|
|
b213964b63 | ||
|
|
bfbed44270 | ||
|
|
9b07d88392 | ||
|
|
3f8ed109f9 | ||
|
|
3f969627a4 | ||
|
|
d92970819a | ||
|
|
23e756fa9b | ||
|
|
5f58126fbf | ||
|
|
dcfd0ffb8f | ||
|
|
17221d056c | ||
|
|
4a9dcfada4 | ||
|
|
bb6c2bb020 | ||
|
|
a8760a34de | ||
|
|
1e432a5782 | ||
|
|
cb861ef2bb | ||
|
|
7cee8fd87a | ||
|
|
8ce0e5d348 | ||
|
|
90bce7c89f | ||
|
|
b840d0bcce | ||
|
|
bfa6d28289 | ||
|
|
f6e6ca9747 | ||
|
|
75f8d39648 | ||
|
|
9a939eba5a | ||
|
|
4e93efe821 | ||
|
|
8bdbee80a0 | ||
|
|
6bdf5dcc03 | ||
|
|
0bf0a9d78a | ||
|
|
38e9fea601 | ||
|
|
d2366b3b46 | ||
|
|
3aff93083a | ||
|
|
eb998199db | ||
|
|
1dd794af1b | ||
|
|
08c9923e7e | ||
|
|
06b109ca87 | ||
|
|
9b039335c7 | ||
|
|
041378e5fd | ||
|
|
6dc5ae10e3 | ||
|
|
5807f4c283 | ||
|
|
8ef4445908 | ||
|
|
8a0609e970 | ||
|
|
9f33b5009b | ||
|
|
50e66db8a1 | ||
|
|
c3e83b569a | ||
|
|
85d1c5ea7e | ||
|
|
ec1d126a02 | ||
|
|
e857695e70 | ||
|
|
fa9b2051fe | ||
|
|
d450efcffe | ||
|
|
2a6c84c200 | ||
|
|
138a952ace | ||
|
|
eb6528ecd2 | ||
|
|
2c30bbfa09 | ||
|
|
c5a78c2135 | ||
|
|
f03362ee41 | ||
|
|
fad3167d97 | ||
|
|
ad949681dd | ||
|
|
27999d76b0 | ||
|
|
83278352d6 | ||
|
|
fcc56f5fef | ||
|
|
4ebe2ecc32 | ||
|
|
e684cba527 | ||
|
|
888dc19ee0 | ||
|
|
731aea702f | ||
|
|
09e22bc76a | ||
|
|
74406d88a0 | ||
|
|
e5f9d97560 | ||
|
|
59e768aaea | ||
|
|
6a7cb24a5b | ||
|
|
1db40d534c | ||
|
|
11d6e30f7e | ||
|
|
9d5214aaae | ||
|
|
010b906271 | ||
|
|
16bf944edf | ||
|
|
5bae5a099a | ||
|
|
f771ea9521 | ||
|
|
994efbf37c | ||
|
|
938cd86c88 | ||
|
|
1339cbadbc | ||
|
|
bd0ad570ad | ||
|
|
234e649a7e | ||
|
|
c431dbc842 | ||
|
|
76283060d9 | ||
|
|
75ba506db4 | ||
|
|
0c8ad5fe8d | ||
|
|
68ce0db011 | ||
|
|
c36de1a1e9 | ||
|
|
44ef759abd | ||
|
|
0c3d9844be | ||
|
|
854c62a4ca | ||
|
|
5ed4fd5299 | ||
|
|
af5ec43571 | ||
|
|
d7b56d1590 | ||
|
|
b925f8890b | ||
|
|
5d80ee994a | ||
|
|
f73bd2dfda | ||
|
|
f340ee1088 | ||
|
|
edad2644aa | ||
|
|
8a56a0393a | ||
|
|
bd5ca06d8f | ||
|
|
e0985ecec3 | ||
|
|
e56b74d4af | ||
|
|
849b18f677 | ||
|
|
344128e49d | ||
|
|
56fc9dd517 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -324,10 +324,6 @@ ASALocalRun/
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
*.dll
|
||||
*.pdb
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
**/bin/
|
||||
|
||||
@@ -22,4 +22,5 @@ WORKDIR /app
|
||||
COPY --from=build /app/publish .
|
||||
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
RUN echo 'Asia/Shanghai' >/etc/timezone
|
||||
RUN apt update && apt install -y libpugixml-dev libtbb-dev
|
||||
ENTRYPOINT ["dotnet", "AntSK.dll"]
|
||||
|
||||
@@ -25,4 +25,5 @@ ENV PATH="/app:/opt/conda/bin:/usr/local/bin:${PATH}"
|
||||
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
RUN echo 'Asia/Shanghai' >/etc/timezone
|
||||
RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
ENTRYPOINT ["dotnet", "AntSK.dll"]
|
||||
RUN apt update && apt install -y libpugixml-dev libtbb-dev
|
||||
ENTRYPOINT ["dotnet", "AntSK.dll"]
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
- **知识库**:通过文档(Word、PDF、Excel、Txt、Markdown、Json、PPT)等形式导入知识库,可以进行知识库问答。
|
||||
|
||||
- **文生图**:集成**StableDiffusion** 本地模型,可以进行文生图。
|
||||
|
||||
- **GPTs 生成**:此平台支持创建个性化的GPT模型,尝试构建您自己的GPT模型。
|
||||
|
||||
- **API接口发布**:将内部功能以API的形式对外提供,便于开发者将AntSK 集成进其他应用,增强应用智慧。
|
||||
@@ -54,6 +56,8 @@ https://antsk.ai-dotnet.com/
|
||||
### 其他功能示例
|
||||
[视频示例](https://www.bilibili.com/video/BV1zH4y1h7Y9/)
|
||||
|
||||
[在线文档:http://antsk.cn](http://antsk.cn)
|
||||
|
||||
## ❓如何开始?
|
||||
|
||||
在这里我使用的是Postgres 作为数据存储和向量存储,因为Semantic Kernel和Kernel Memory都支持他,当然你也可以换成其他的。
|
||||
@@ -85,7 +89,7 @@ version: '3.8'
|
||||
services:
|
||||
antsk:
|
||||
container_name: antsk
|
||||
image: registry.cn-hangzhou.aliyuncs.com/AIDotNet/antsk:v0.2.3
|
||||
image: registry.cn-hangzhou.aliyuncs.com/AIDotNet/antsk:v0.2.7
|
||||
ports:
|
||||
- 5000:5000
|
||||
networks:
|
||||
@@ -98,6 +102,7 @@ services:
|
||||
volumes:
|
||||
- ./appsettings.json:/app/appsettings.json # 本地配置文件 需要放在同级目录
|
||||
- D://model:/app/model
|
||||
- D://model:/root/.cache/modelscope/hub/AI-ModelScope #使用Llamafactory时需要挂载 否则初始化的环境重启后会丢失
|
||||
networks:
|
||||
antsk:
|
||||
```
|
||||
@@ -173,7 +178,7 @@ DB我使用的是CodeFirst模式,只要配置好数据库链接,表结构是
|
||||
|
||||
## ✔️使用llamafactory
|
||||
```
|
||||
1、首先需要确保你的环境已经安装了python和pip,如果使用镜像,例如v0.2.3.2版本已经包含了 python全套环境则无需此步骤
|
||||
1、首先需要确保你的环境已经安装了python和pip,如果使用镜像,例如p0.2.4版本已经包含了 python全套环境则无需此步骤
|
||||
2、进入模型添加页面选择llamafactory
|
||||
3、点击初始化,可以检查pip install 环境是否完成
|
||||
4、选择一个喜欢的模型
|
||||
|
||||
@@ -3,9 +3,9 @@ version: '3.8'
|
||||
services:
|
||||
antsk:
|
||||
container_name: antsk
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.2.3
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.2.7
|
||||
# 如果需要pytorch环境需要使用下面这个镜像,镜像比较大
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.2.3.2
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:p0.2.7
|
||||
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.3
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.2.7
|
||||
# 如果需要pytorch环境需要使用下面这个镜像,镜像比较大
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.2.3.2
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:p0.2.7
|
||||
ports:
|
||||
- 5000:5000
|
||||
networks:
|
||||
|
||||
@@ -9,40 +9,44 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AntDesign.Charts" Version="0.5.1" />
|
||||
<PackageReference Include="AntDesign.ProLayout" Version="0.18.1" />
|
||||
<PackageReference Include="AntDesign.ProLayout" Version="0.18.2" />
|
||||
<PackageReference Include="BlazorComponents.Terminal" Version="0.6.0" />
|
||||
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
||||
|
||||
<PackageReference Include="pythonnet" Version="3.0.3" />
|
||||
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
|
||||
<PackageReference Include="AutoMapper" Version="8.1.0" />
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||
<PackageReference Include="Markdig" Version="0.36.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.148" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.151" />
|
||||
<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.6.3" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Core" Version="1.6.3" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Core" Version="1.6.3-alpha" />
|
||||
<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.KernelMemory.Core" Version="0.35.240321.1" />
|
||||
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.Postgres" Version="0.35.240321.1" />
|
||||
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.Qdrant" Version="0.35.240321.1" />
|
||||
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.Redis" Version="0.35.240321.1" />
|
||||
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.AzureAISearch" Version="0.35.240321.1" />
|
||||
|
||||
<PackageReference Include="LLamaSharp" Version="0.10.0" />
|
||||
<PackageReference Include="LLamaSharp.Backend.Cpu" Version="0.10.0" />
|
||||
<PackageReference Include="LLamaSharp.Backend.Cuda12" Version="0.10.0" />
|
||||
<PackageReference Include="LLamaSharp.kernel-memory" Version="0.10.0" />
|
||||
<PackageReference Include="LLamaSharp.semantic-kernel" Version="0.10.0" />
|
||||
<PackageReference Include="LLamaSharp" Version="0.11.2" />
|
||||
<PackageReference Include="LLamaSharp.Backend.Cpu" Version="0.11.2" />
|
||||
<PackageReference Include="LLamaSharp.Backend.Cuda12" Version="0.11.2" />
|
||||
<PackageReference Include="LLamaSharp.kernel-memory" Version="0.11.2" />
|
||||
<PackageReference Include="LLamaSharp.semantic-kernel" Version="0.11.2" />
|
||||
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AntSK.LLamaFactory\AntSK.LLamaFactory.csproj" />
|
||||
<ProjectReference Include="..\AntSk.LLM\AntSK.LLM.csproj" />
|
||||
<ProjectReference Include="..\AntSK.OCR\AntSK.OCR.csproj" />
|
||||
<ProjectReference Include="..\MiddleWare\AntSK.BackgroundTask\AntSK.BackgroundTask.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -69,6 +69,84 @@
|
||||
<param name="value"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.ExeclHelper.ExcelToDataTable(System.String,System.Boolean)">
|
||||
<summary>
|
||||
将excel导入到datatable
|
||||
</summary>
|
||||
<param name="filePath">excel路径</param>
|
||||
<param name="isColumnName">第一行是否是列名</param>
|
||||
<returns>返回datatable</returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.ExeclHelper.ExcelToDataTable(System.IO.Stream,System.Boolean)">
|
||||
<summary>
|
||||
将excel导入到datatable
|
||||
</summary>
|
||||
<param name="stream">流</param>
|
||||
<param name="isColumnName">第一行是否是列名</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.ExeclHelper.ExcelToList``1(System.IO.Stream)">
|
||||
<summary>
|
||||
excel转list
|
||||
</summary>
|
||||
<typeparam name="TResult"></typeparam>
|
||||
<param name="stream"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.ExeclHelper.ExcelToList``1(System.IO.Stream,System.String)">
|
||||
<summary>
|
||||
excel转list-根据sheetName得到List
|
||||
</summary>
|
||||
<typeparam name="TResult"></typeparam>
|
||||
<param name="stream"></param>
|
||||
<param name="sheetName"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.ExeclHelper.ListToExcel``1(``0[],System.String)">
|
||||
<summary>
|
||||
List导出excel 二进制流
|
||||
</summary>
|
||||
<typeparam name="T">实体</typeparam>
|
||||
<param name="data">List</param>
|
||||
<param name="sheetName">sheetname 可不填,默认Sheet0</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.ExeclHelper.DataTableToExcel(System.Data.DataTable,System.String,System.String)">
|
||||
<summary>
|
||||
Dt导出excel 二进制流
|
||||
</summary>
|
||||
<param name="dt">datatable</param>
|
||||
<param name="strFile">strFile</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.ExeclHelper.ListWriteExcel``1(``0[],System.String,System.String)">
|
||||
<summary>
|
||||
List写入excel
|
||||
</summary>
|
||||
<typeparam name="T"></typeparam>
|
||||
<param name="data"></param>
|
||||
<param name="strFile">路径</param>
|
||||
<param name="sheetName"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.ExeclHelper.DataTableWriteExcel(System.Data.DataTable,System.String,System.String)">
|
||||
<summary>
|
||||
dt写入excel
|
||||
</summary>
|
||||
<param name="dt">datatable</param>
|
||||
<param name="strFile">路径</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.ExeclHelper.SetCellDropdownList(NPOI.SS.UserModel.IWorkbook,NPOI.SS.UserModel.ISheet,System.Collections.Generic.List{System.String},System.String,System.Int32,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
设置单元格下拉框(除去标题行)
|
||||
</summary>
|
||||
<param name="workbook"></param>
|
||||
<param name="sheet"></param>
|
||||
<param name="ddlList"></param>
|
||||
<param name="firstcol"></param>
|
||||
<param name="lastcol"></param>
|
||||
</member>
|
||||
<member name="T:AntSK.Domain.Domain.Model.Enum.AIType">
|
||||
<summary>
|
||||
AI类型
|
||||
@@ -99,11 +177,28 @@
|
||||
总数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Domain.Other.EmbeddingConfig.LoadModel(System.String,System.String)">
|
||||
<summary>
|
||||
模型写死
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Domain.Other.KMExcelHandler.StepName">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Domain.Other.KMExcelHandler.InvokeAsync(Microsoft.KernelMemory.Pipeline.DataPipeline,System.Threading.CancellationToken)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="F:AntSK.Domain.Domain.Other.LLamaConfig.dicLLamaWeights">
|
||||
<summary>
|
||||
避免模型重复加载,本地缓存
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Domain.Other.QAHandler.StepName">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<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)">
|
||||
<summary>
|
||||
发送消息
|
||||
@@ -287,6 +382,26 @@
|
||||
API调用秘钥
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Apps.Relevance">
|
||||
<summary>
|
||||
相似度
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Apps.MaxAskPromptSize">
|
||||
<summary>
|
||||
提问最大token数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Apps.MaxMatchesCount">
|
||||
<summary>
|
||||
向量匹配数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Apps.AnswerTokens">
|
||||
<summary>
|
||||
回答最大token数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Funs.Path">
|
||||
<summary>
|
||||
接口描述
|
||||
@@ -771,6 +886,14 @@
|
||||
<param name="parameters"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Utils.ConvertUtils.ComparisonIgnoreCase(System.String,System.String)">
|
||||
<summary>
|
||||
忽略大小写匹配
|
||||
</summary>
|
||||
<param name="s"></param>
|
||||
<param name="value"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Utils.RepoFiles.SamplePluginsPath">
|
||||
<summary>
|
||||
Scan the local folders from the repo, looking for "samples/plugins" folder.
|
||||
|
||||
@@ -50,6 +50,8 @@ namespace AntSK.Domain.Common.DependencyInjection
|
||||
_repository.GetDB().CodeFirst.InitTables(type);
|
||||
}
|
||||
}
|
||||
//安装向量插件
|
||||
_repository.GetDB().Ado.ExecuteCommandAsync($"CREATE EXTENSION IF NOT EXISTS vector;");
|
||||
}
|
||||
return app;
|
||||
}
|
||||
|
||||
21
src/AntSK.Domain/Common/Embedding/BuilderBgeExtensions.cs
Normal file
21
src/AntSK.Domain/Common/Embedding/BuilderBgeExtensions.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using LLamaSharp.KernelMemory;
|
||||
using Microsoft.KernelMemory.AI;
|
||||
using Microsoft.KernelMemory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain.Common.Embedding
|
||||
{
|
||||
public static class BuilderBgeExtensions
|
||||
{
|
||||
public static IKernelMemoryBuilder WithBgeTextEmbeddingGeneration(this IKernelMemoryBuilder builder, HuggingfaceTextEmbeddingGenerator textEmbeddingGenerator)
|
||||
{
|
||||
builder.AddSingleton((ITextEmbeddingGenerator)textEmbeddingGenerator);
|
||||
builder.AddIngestionEmbeddingGenerator(textEmbeddingGenerator);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using LLama.Common;
|
||||
using LLama;
|
||||
using LLamaSharp.KernelMemory;
|
||||
using Microsoft.KernelMemory.AI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AntSK.Domain.Domain.Other;
|
||||
|
||||
namespace AntSK.Domain.Common.Embedding
|
||||
{
|
||||
public class HuggingfaceTextEmbeddingGenerator : ITextEmbeddingGenerator, ITextTokenizer, IDisposable
|
||||
{
|
||||
public int MaxTokens => 1024;
|
||||
|
||||
public int MaxTokenTotal => 1024;
|
||||
|
||||
|
||||
private readonly dynamic _embedder;
|
||||
|
||||
public HuggingfaceTextEmbeddingGenerator(string pyDllPath,string modelName)
|
||||
{
|
||||
_embedder = EmbeddingConfig.LoadModel(pyDllPath, modelName);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
EmbeddingConfig.Dispose();
|
||||
}
|
||||
|
||||
//public async Task<IList<ReadOnlyMemory<float>>> GenerateEmbeddingAsync(IList<string> data, CancellationToken cancellationToken = default)
|
||||
//{
|
||||
// IList<ReadOnlyMemory<float>> results = new List<ReadOnlyMemory<float>>();
|
||||
|
||||
// foreach (var d in data)
|
||||
// {
|
||||
// var embeddings = await EmbeddingConfig.GetEmbedding(d);
|
||||
// results.Add(new ReadOnlyMemory<float>(embeddings));
|
||||
// }
|
||||
// return results;
|
||||
//}
|
||||
|
||||
public async Task<Microsoft.KernelMemory.Embedding> GenerateEmbeddingAsync(string text, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var embeddings = await EmbeddingConfig.GetEmbedding(text);
|
||||
return new Microsoft.KernelMemory.Embedding(embeddings);
|
||||
}
|
||||
|
||||
public int CountTokens(string text)
|
||||
{
|
||||
return EmbeddingConfig.TokenCount(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
822
src/AntSK.Domain/Common/Excel/ExeclHelper.cs
Normal file
822
src/AntSK.Domain/Common/Excel/ExeclHelper.cs
Normal file
@@ -0,0 +1,822 @@
|
||||
using NPOI.HSSF.UserModel;
|
||||
using NPOI.SS.UserModel;
|
||||
using NPOI.SS.Util;
|
||||
using NPOI.XSSF.Streaming;
|
||||
using NPOI.XSSF.UserModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain
|
||||
{
|
||||
public class ExeclHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 将excel导入到datatable
|
||||
/// </summary>
|
||||
/// <param name="filePath">excel路径</param>
|
||||
/// <param name="isColumnName">第一行是否是列名</param>
|
||||
/// <returns>返回datatable</returns>
|
||||
public static DataTable ExcelToDataTable(string filePath, bool isColumnName)
|
||||
{
|
||||
DataTable dataTable = null;
|
||||
FileStream fs = null;
|
||||
DataColumn column = null;
|
||||
DataRow dataRow = null;
|
||||
IWorkbook workbook = null;
|
||||
ISheet sheet = null;
|
||||
IRow row = null;
|
||||
ICell cell = null;
|
||||
int startRow = 0;
|
||||
try
|
||||
{
|
||||
using (fs = File.OpenRead(filePath))
|
||||
{
|
||||
// 2007版本
|
||||
if (filePath.Contains(".xlsx"))
|
||||
workbook = new XSSFWorkbook(fs);
|
||||
// 2003版本
|
||||
else if (filePath.Contains(".xls"))
|
||||
workbook = new HSSFWorkbook(fs);
|
||||
|
||||
if (workbook != null)
|
||||
{
|
||||
sheet = workbook.GetSheetAt(0);//读取第一个sheet,当然也可以循环读取每个sheet
|
||||
dataTable = new DataTable();
|
||||
if (sheet != null)
|
||||
{
|
||||
int rowCount = sheet.LastRowNum;//总行数
|
||||
if (rowCount > 0)
|
||||
{
|
||||
IRow firstRow = sheet.GetRow(0);//第一行
|
||||
int cellCount = firstRow.LastCellNum;//列数
|
||||
|
||||
//构建datatable的列
|
||||
if (isColumnName)
|
||||
{
|
||||
startRow = 1;//如果第一行是列名,则从第二行开始读取
|
||||
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
|
||||
{
|
||||
cell = firstRow.GetCell(i);
|
||||
if (cell != null)
|
||||
{
|
||||
if (cell.StringCellValue != null)
|
||||
{
|
||||
column = new DataColumn(cell.StringCellValue);
|
||||
dataTable.Columns.Add(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
|
||||
{
|
||||
column = new DataColumn("column" + (i + 1));
|
||||
dataTable.Columns.Add(column);
|
||||
}
|
||||
}
|
||||
|
||||
//填充行
|
||||
for (int i = startRow; i <= rowCount; ++i)
|
||||
{
|
||||
row = sheet.GetRow(i);
|
||||
if (row == null) continue;
|
||||
|
||||
dataRow = dataTable.NewRow();
|
||||
for (int j = row.FirstCellNum; j < cellCount; ++j)
|
||||
{
|
||||
cell = row.GetCell(j);
|
||||
if (cell == null)
|
||||
{
|
||||
dataRow[j] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
//CellType(Unknown = -1,Numeric = 0,String = 1,Formula = 2,Blank = 3,Boolean = 4,Error = 5,)
|
||||
switch (cell.CellType)
|
||||
{
|
||||
case CellType.Blank:
|
||||
dataRow[j] = "";
|
||||
break;
|
||||
case CellType.Numeric:
|
||||
short format = cell.CellStyle.DataFormat;
|
||||
//对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
|
||||
if (format == 14 || format == 31 || format == 57 || format == 58)
|
||||
dataRow[j] = cell.DateCellValue;
|
||||
else
|
||||
dataRow[j] = cell.NumericCellValue;
|
||||
break;
|
||||
case CellType.String:
|
||||
dataRow[j] = cell.StringCellValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dataTable.Rows.Add(dataRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataTable;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (fs != null)
|
||||
{
|
||||
fs.Close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将excel导入到datatable
|
||||
/// </summary>
|
||||
/// <param name="stream">流</param>
|
||||
/// <param name="isColumnName">第一行是否是列名</param>
|
||||
/// <returns></returns>
|
||||
public static DataTable ExcelToDataTable(Stream stream, bool isColumnName)
|
||||
{
|
||||
DataTable dataTable = null;
|
||||
DataColumn column = null;
|
||||
DataRow dataRow = null;
|
||||
IWorkbook workbook = new XSSFWorkbook(stream);
|
||||
ISheet sheet = null;
|
||||
IRow row = null;
|
||||
ICell cell = null;
|
||||
int startRow = 0;
|
||||
try
|
||||
{
|
||||
|
||||
if (workbook != null)
|
||||
{
|
||||
sheet = workbook.GetSheetAt(0);//读取第一个sheet,当然也可以循环读取每个sheet
|
||||
dataTable = new DataTable();
|
||||
if (sheet != null)
|
||||
{
|
||||
int rowCount = sheet.LastRowNum;//总行数
|
||||
if (rowCount > 0)
|
||||
{
|
||||
IRow firstRow = sheet.GetRow(0);//第一行
|
||||
int cellCount = firstRow.LastCellNum;//列数
|
||||
|
||||
//构建datatable的列
|
||||
if (isColumnName)
|
||||
{
|
||||
startRow = 1;//如果第一行是列名,则从第二行开始读取
|
||||
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
|
||||
{
|
||||
cell = firstRow.GetCell(i);
|
||||
if (cell != null)
|
||||
{
|
||||
if (cell.StringCellValue != null)
|
||||
{
|
||||
column = new DataColumn(cell.StringCellValue);
|
||||
dataTable.Columns.Add(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
|
||||
{
|
||||
column = new DataColumn("column" + (i + 1));
|
||||
dataTable.Columns.Add(column);
|
||||
}
|
||||
}
|
||||
|
||||
//填充行
|
||||
for (int i = startRow; i <= rowCount; ++i)
|
||||
{
|
||||
row = sheet.GetRow(i);
|
||||
if (row == null) continue;
|
||||
|
||||
dataRow = dataTable.NewRow();
|
||||
for (int j = row.FirstCellNum; j < cellCount; ++j)
|
||||
{
|
||||
cell = row.GetCell(j);
|
||||
if (cell == null)
|
||||
{
|
||||
dataRow[j] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
//CellType(Unknown = -1,Numeric = 0,String = 1,Formula = 2,Blank = 3,Boolean = 4,Error = 5,)
|
||||
switch (cell.CellType)
|
||||
{
|
||||
case CellType.Blank:
|
||||
dataRow[j] = "";
|
||||
break;
|
||||
case CellType.Numeric:
|
||||
short format = cell.CellStyle.DataFormat;
|
||||
//对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
|
||||
if (format == 14 || format == 31 || format == 57 || format == 58)
|
||||
dataRow[j] = cell.DateCellValue;
|
||||
else
|
||||
dataRow[j] = cell.NumericCellValue;
|
||||
break;
|
||||
case CellType.String:
|
||||
dataRow[j] = cell.StringCellValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dataTable.Rows.Add(dataRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dataTable;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// excel转list
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="stream"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<TResult> ExcelToList<TResult>(Stream stream) where TResult : new()
|
||||
{
|
||||
var propertyInfos = typeof(TResult).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CustomAttributes.Count() > 0)
|
||||
.OrderBy(p => p.GetCustomAttribute<ExeclPropertyAttribute>().Order).ToArray();
|
||||
|
||||
List<TResult> list = new List<TResult>();
|
||||
|
||||
IWorkbook workbook = new XSSFWorkbook(stream);
|
||||
ISheet sheet = null;
|
||||
IRow row = null;
|
||||
ICell cell = null;
|
||||
int startRow = 1;
|
||||
try
|
||||
{
|
||||
|
||||
if (workbook != null)
|
||||
{
|
||||
sheet = workbook.GetSheetAt(0);//读取第一个sheet,当然也可以循环读取每个sheet
|
||||
if (sheet != null)
|
||||
{
|
||||
int rowCount = sheet.LastRowNum;//总行数
|
||||
if (rowCount > 0)
|
||||
{
|
||||
IRow firstRow = sheet.GetRow(0);//第一行
|
||||
int cellCount = firstRow.LastCellNum;//列数
|
||||
|
||||
//填充行
|
||||
for (int i = startRow; i <= rowCount; ++i)
|
||||
{
|
||||
row = sheet.GetRow(i);
|
||||
if (row == null) continue;
|
||||
bool emptyRow = true;//是否空行
|
||||
TResult dataModel = new TResult();
|
||||
|
||||
for (int j = row.FirstCellNum; j < cellCount; ++j)
|
||||
{
|
||||
var execlPropertyAttribute = propertyInfos[j].GetCustomAttribute<ExeclPropertyAttribute>();
|
||||
|
||||
cell = row.GetCell(j);
|
||||
if (cell == null)
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (cell.CellType)
|
||||
{
|
||||
case CellType.Blank:
|
||||
propertyInfos[j].SetValue(dataModel, "");
|
||||
break;
|
||||
case CellType.Numeric:
|
||||
short format = cell.CellStyle.DataFormat;
|
||||
//对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
|
||||
if (format == 14 || format == 31 || format == 57 || format == 58)
|
||||
propertyInfos[j].SetValue(dataModel, cell.DateCellValue);
|
||||
else
|
||||
{
|
||||
if (execlPropertyAttribute.CellType == CellType.String)
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, cell.NumericCellValue.ToString());
|
||||
}
|
||||
else
|
||||
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, cell.NumericCellValue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CellType.String:
|
||||
propertyInfos[j].SetValue(dataModel, cell.StringCellValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cell != null && !string.IsNullOrEmpty(cell.ToString().Trim()))
|
||||
{
|
||||
emptyRow = false;
|
||||
}
|
||||
}
|
||||
//非空数据行数据添加到DataTable
|
||||
if (!emptyRow)
|
||||
{
|
||||
list.Add(dataModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static IEnumerable<TResult> ExcelToListFileName<TResult>(Stream stream, string fileName) where TResult : new()
|
||||
{
|
||||
var propertyInfos = typeof(TResult).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CustomAttributes.Count() > 0)
|
||||
.OrderBy(p => p.GetCustomAttribute<ExeclPropertyAttribute>().Order).ToArray();
|
||||
|
||||
List<TResult> list = new List<TResult>();
|
||||
|
||||
IWorkbook workbook = null;
|
||||
if (fileName.Contains(".xlsx"))
|
||||
workbook = new XSSFWorkbook(stream);
|
||||
// 2003版本
|
||||
else if (fileName.Contains(".xls"))
|
||||
workbook = new HSSFWorkbook(stream);
|
||||
ISheet sheet = null;
|
||||
IRow row = null;
|
||||
ICell cell = null;
|
||||
int startRow = 1;
|
||||
try
|
||||
{
|
||||
|
||||
if (workbook != null)
|
||||
{
|
||||
sheet = workbook.GetSheetAt(0);//读取第一个sheet,当然也可以循环读取每个sheet
|
||||
if (sheet != null)
|
||||
{
|
||||
int rowCount = sheet.LastRowNum;//总行数
|
||||
if (rowCount > 0)
|
||||
{
|
||||
IRow firstRow = sheet.GetRow(0);//第一行
|
||||
int cellCount = firstRow.LastCellNum;//列数
|
||||
|
||||
//填充行
|
||||
for (int i = startRow; i <= rowCount; ++i)
|
||||
{
|
||||
row = sheet.GetRow(i);
|
||||
if (row == null) continue;
|
||||
bool emptyRow = true;//是否空行
|
||||
TResult dataModel = new TResult();
|
||||
|
||||
for (int j = row.FirstCellNum; j < cellCount; ++j)
|
||||
{
|
||||
var execlPropertyAttribute = propertyInfos[j].GetCustomAttribute<ExeclPropertyAttribute>();
|
||||
|
||||
cell = row.GetCell(j);
|
||||
if (cell == null)
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (cell.CellType)
|
||||
{
|
||||
case CellType.Blank:
|
||||
propertyInfos[j].SetValue(dataModel, "");
|
||||
break;
|
||||
case CellType.Numeric:
|
||||
short format = cell.CellStyle.DataFormat;
|
||||
//对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
|
||||
if (format == 14 || format == 31 || format == 57 || format == 58)
|
||||
propertyInfos[j].SetValue(dataModel, cell.DateCellValue);
|
||||
else
|
||||
{
|
||||
if (execlPropertyAttribute.CellType == CellType.String)
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, cell.NumericCellValue.ToString());
|
||||
}
|
||||
else
|
||||
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, cell.NumericCellValue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CellType.String:
|
||||
propertyInfos[j].SetValue(dataModel, cell.StringCellValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cell != null && !string.IsNullOrEmpty(cell.ToString().Trim()))
|
||||
{
|
||||
emptyRow = false;
|
||||
}
|
||||
}
|
||||
//非空数据行数据添加到DataTable
|
||||
if (!emptyRow)
|
||||
{
|
||||
list.Add(dataModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// excel转list-根据sheetName得到List
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="sheetName"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<TResult> ExcelToList<TResult>(Stream stream, string sheetName) where TResult : new()
|
||||
{
|
||||
var propertyInfos = typeof(TResult).GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.OrderBy(p => p.GetCustomAttribute<ExeclPropertyAttribute>().Order).ToArray();
|
||||
|
||||
List<TResult> list = new List<TResult>();
|
||||
|
||||
IWorkbook workbook = new XSSFWorkbook(stream);
|
||||
ISheet sheet = null;
|
||||
IRow row = null;
|
||||
ICell cell = null;
|
||||
int startRow = 1;
|
||||
try
|
||||
{
|
||||
|
||||
if (workbook != null)
|
||||
{
|
||||
sheet = workbook.GetSheet(sheetName);//根据sheet读取对应的DataTable
|
||||
if (sheet != null)
|
||||
{
|
||||
int rowCount = sheet.LastRowNum;//总行数
|
||||
if (rowCount > 0)
|
||||
{
|
||||
IRow firstRow = sheet.GetRow(0);//第一行
|
||||
int cellCount = firstRow.LastCellNum;//列数
|
||||
|
||||
//填充行
|
||||
for (int i = startRow; i <= rowCount; ++i)
|
||||
{
|
||||
row = sheet.GetRow(i);
|
||||
if (row == null) continue;
|
||||
bool emptyRow = true;//是否空行
|
||||
|
||||
TResult dataModel = new TResult();
|
||||
|
||||
for (int j = row.FirstCellNum; j < cellCount; ++j)
|
||||
{
|
||||
var execlPropertyAttribute = propertyInfos[j].GetCustomAttribute<ExeclPropertyAttribute>();
|
||||
|
||||
cell = row.GetCell(j);
|
||||
if (cell == null)
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (cell.CellType)
|
||||
{
|
||||
case CellType.Blank:
|
||||
propertyInfos[j].SetValue(dataModel, "");
|
||||
break;
|
||||
case CellType.Numeric:
|
||||
short format = cell.CellStyle.DataFormat;
|
||||
//对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
|
||||
if (format == 14 || format == 31 || format == 57 || format == 58)
|
||||
propertyInfos[j].SetValue(dataModel, cell.DateCellValue);
|
||||
else
|
||||
{
|
||||
if (execlPropertyAttribute.CellType == CellType.String)
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, cell.NumericCellValue.ToString());
|
||||
}
|
||||
else
|
||||
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, cell.NumericCellValue);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case CellType.String:
|
||||
propertyInfos[j].SetValue(dataModel, cell.StringCellValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cell != null && !string.IsNullOrEmpty(cell.ToString().Trim()))
|
||||
{
|
||||
emptyRow = false;
|
||||
}
|
||||
}
|
||||
//非空数据行数据添加到DataTable
|
||||
if (!emptyRow)
|
||||
{
|
||||
list.Add(dataModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List导出excel 二进制流
|
||||
/// </summary>
|
||||
/// <typeparam name="T">实体</typeparam>
|
||||
/// <param name="data">List</param>
|
||||
/// <param name="sheetName">sheetname 可不填,默认Sheet0</param>
|
||||
/// <returns></returns>
|
||||
public static byte[] ListToExcel<T>(T[] data, string sheetName = "Sheet0")
|
||||
{
|
||||
IWorkbook workbook = null;
|
||||
IRow row = null;
|
||||
ISheet sheet = null;
|
||||
ICell cell = null;
|
||||
var propertyInfos = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.OrderBy(p => p.GetCustomAttribute<ExeclPropertyAttribute>().Order).ToArray();
|
||||
workbook = new XSSFWorkbook();
|
||||
sheet = workbook.CreateSheet(sheetName);//创建一个名称为Sheet0的表
|
||||
int rowCount = data.Count();//行数
|
||||
int columnCount = propertyInfos.Length;//列数
|
||||
//设置列头
|
||||
row = sheet.CreateRow(0);//excel第一行设为列头
|
||||
for (int c = 0; c < columnCount; c++)
|
||||
{
|
||||
cell = row.CreateCell(c);
|
||||
cell.SetCellValue(propertyInfos[c].GetCustomAttribute<ExeclPropertyAttribute>().DisplayName);
|
||||
}
|
||||
//设置每行每列的单元格,
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
{
|
||||
row = sheet.CreateRow(i + 1);
|
||||
for (int j = 0; j < columnCount; j++)
|
||||
{
|
||||
cell = row.CreateCell(j);//excel第二行开始写入数据
|
||||
cell.SetCellValue(propertyInfos[j].GetValue(data[i])?.ToString());
|
||||
}
|
||||
}
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
{
|
||||
workbook.Write(memoryStream);//向打开的这个xls文件中写入数据
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dt导出excel 二进制流
|
||||
/// </summary>
|
||||
/// <param name="dt">datatable</param>
|
||||
/// <param name="strFile">strFile</param>
|
||||
/// <returns></returns>
|
||||
public static byte[] DataTableToExcel(DataTable dt, string strFile, string sheetName = "Sheet0")
|
||||
{
|
||||
bool result = false;
|
||||
IWorkbook workbook = null;
|
||||
FileStream fs = null;
|
||||
IRow row = null;
|
||||
ISheet sheet = null;
|
||||
ICell cell = null;
|
||||
|
||||
if (dt != null && dt.Rows.Count > 0)
|
||||
{
|
||||
workbook = new XSSFWorkbook();
|
||||
sheet = workbook.CreateSheet(sheetName);//创建一个名称为Sheet0的表
|
||||
int rowCount = dt.Rows.Count;//行数
|
||||
int columnCount = dt.Columns.Count;//列数
|
||||
|
||||
//设置列头
|
||||
row = sheet.CreateRow(0);//excel第一行设为列头
|
||||
for (int c = 0; c < columnCount; c++)
|
||||
{
|
||||
cell = row.CreateCell(c);
|
||||
cell.SetCellValue(dt.Columns[c].ColumnName);
|
||||
}
|
||||
|
||||
//设置每行每列的单元格,
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
{
|
||||
row = sheet.CreateRow(i + 1);
|
||||
for (int j = 0; j < columnCount; j++)
|
||||
{
|
||||
cell = row.CreateCell(j);//excel第二行开始写入数据
|
||||
cell.SetCellValue(dt.Rows[i][j].ToString());
|
||||
}
|
||||
}
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
{
|
||||
workbook.Write(memoryStream);//向打开的这个xls文件中写入数据
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List写入excel
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="strFile">路径</param>
|
||||
/// <param name="sheetName"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ListWriteExcel<T>(T[] data, string strFile, string sheetName = "Sheet0")
|
||||
{
|
||||
bool result = false;
|
||||
IWorkbook workbook = null;
|
||||
FileStream fs = null;
|
||||
IRow row = null;
|
||||
ISheet sheet = null;
|
||||
ICell cell = null;
|
||||
try
|
||||
{
|
||||
var propertyInfos = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.OrderBy(p => p.GetCustomAttribute<ExeclPropertyAttribute>().Order).ToArray();
|
||||
workbook = new XSSFWorkbook();
|
||||
sheet = workbook.CreateSheet(sheetName);//创建一个名称为Sheet0的表
|
||||
int rowCount = data.Count();//行数
|
||||
int columnCount = propertyInfos.Length;//列数
|
||||
//设置列头
|
||||
row = sheet.CreateRow(0);//excel第一行设为列头
|
||||
for (int c = 0; c < columnCount; c++)
|
||||
{
|
||||
cell = row.CreateCell(c);
|
||||
cell.SetCellValue(propertyInfos[c].GetCustomAttribute<ExeclPropertyAttribute>().DisplayName);
|
||||
}
|
||||
//设置每行每列的单元格,
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
{
|
||||
row = sheet.CreateRow(i + 1);
|
||||
for (int j = 0; j < columnCount; j++)
|
||||
{
|
||||
cell = row.CreateCell(j);//excel第二行开始写入数据
|
||||
cell.SetCellValue(propertyInfos[j].GetValue(data[i])?.ToString());
|
||||
}
|
||||
}
|
||||
using (fs = File.OpenWrite(strFile))
|
||||
{
|
||||
workbook.Write(fs);//向打开的这个xls文件中写入数据
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (fs != null)
|
||||
{
|
||||
fs.Close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// dt写入excel
|
||||
/// </summary>
|
||||
/// <param name="dt">datatable</param>
|
||||
/// <param name="strFile">路径</param>
|
||||
/// <returns></returns>
|
||||
public static bool DataTableWriteExcel(DataTable dt, string strFile, string sheetName = "Sheet0")
|
||||
{
|
||||
bool result = false;
|
||||
IWorkbook workbook = null;
|
||||
FileStream fs = null;
|
||||
IRow row = null;
|
||||
ISheet sheet = null;
|
||||
ICell cell = null;
|
||||
try
|
||||
{
|
||||
if (dt != null && dt.Rows.Count > 0)
|
||||
{
|
||||
workbook = new XSSFWorkbook();
|
||||
sheet = workbook.CreateSheet(sheetName);//创建一个名称为Sheet0的表
|
||||
int rowCount = dt.Rows.Count;//行数
|
||||
int columnCount = dt.Columns.Count;//列数
|
||||
|
||||
//设置列头
|
||||
row = sheet.CreateRow(0);//excel第一行设为列头
|
||||
for (int c = 0; c < columnCount; c++)
|
||||
{
|
||||
cell = row.CreateCell(c);
|
||||
cell.SetCellValue(dt.Columns[c].ColumnName);
|
||||
}
|
||||
|
||||
//设置每行每列的单元格,
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
{
|
||||
row = sheet.CreateRow(i + 1);
|
||||
for (int j = 0; j < columnCount; j++)
|
||||
{
|
||||
cell = row.CreateCell(j);//excel第二行开始写入数据
|
||||
cell.SetCellValue(dt.Rows[i][j].ToString());
|
||||
}
|
||||
}
|
||||
using (fs = File.OpenWrite(strFile))
|
||||
{
|
||||
workbook.Write(fs);//向打开的这个xls文件中写入数据
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (fs != null)
|
||||
{
|
||||
fs.Close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置单元格下拉框(除去标题行)
|
||||
/// </summary>
|
||||
/// <param name="workbook"></param>
|
||||
/// <param name="sheet"></param>
|
||||
/// <param name="ddlList"></param>
|
||||
/// <param name="firstcol"></param>
|
||||
/// <param name="lastcol"></param>
|
||||
public static void SetCellDropdownList(IWorkbook workbook, ISheet sheet, List<string> ddlList, string sheetname, int sheetIndex, int firstcol, int lastcol)
|
||||
{
|
||||
|
||||
# region 低版本Excel【HSSFWorkbook】设置下拉框
|
||||
//ISheet sheet2 = workbook.CreateSheet(sheetname);
|
||||
|
||||
////隐藏
|
||||
//workbook.SetSheetHidden(sheetIndex, 1);
|
||||
//int rowIndex = 0;
|
||||
//foreach (var item in ddlList)
|
||||
//{
|
||||
// IRow vrow = sheet2.CreateRow(rowIndex);
|
||||
// vrow.CreateCell(0).SetCellValue(item);
|
||||
|
||||
// rowIndex++;
|
||||
//}
|
||||
|
||||
////创建的下拉项的区域:
|
||||
//var rangeName = sheetname + "Range";
|
||||
//IName range = workbook.CreateName();
|
||||
//range.RefersToFormula = sheetname + "!$A$1:$A$" + rowIndex;
|
||||
//range.NameName = rangeName;
|
||||
//CellRangeAddressList regions = new CellRangeAddressList(1, 65535, firstcol, lastcol);
|
||||
|
||||
//DVConstraint constraint = DVConstraint.CreateFormulaListConstraint(rangeName);
|
||||
//HSSFDataValidation dataValidate = new HSSFDataValidation(regions, constraint);
|
||||
//dataValidate.CreateErrorBox("输入不合法", "请输入或选择下拉列表中的值。");
|
||||
//dataValidate.ShowPromptBox = true;
|
||||
//sheet.AddValidationData(dataValidate);
|
||||
#endregion
|
||||
|
||||
//高版本excel【XSSFWorkbook】 设置下拉框
|
||||
XSSFSheet sheetDDL = (XSSFSheet)workbook.CreateSheet(sheetname);
|
||||
workbook.SetSheetHidden(sheetIndex, 1); //隐藏下拉框数据sheet
|
||||
String[] datas = ddlList.ToArray(); //下拉框数据源
|
||||
XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper(sheetDDL);
|
||||
XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint)dvHelper.CreateExplicitListConstraint(datas);
|
||||
CellRangeAddressList addressList = new CellRangeAddressList(1, 65535, firstcol, lastcol); //下拉设置列
|
||||
XSSFDataValidation validation = (XSSFDataValidation)dvHelper.CreateValidation(dvConstraint, addressList);
|
||||
|
||||
validation.SuppressDropDownArrow = true;
|
||||
validation.ShowErrorBox = true;
|
||||
validation.ShowPromptBox = true;
|
||||
sheet.AddValidationData(validation);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/AntSK.Domain/Common/Excel/ExeclPropertyAttribute.cs
Normal file
28
src/AntSK.Domain/Common/Excel/ExeclPropertyAttribute.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using NPOI.SS.UserModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain
|
||||
{
|
||||
public class ExeclPropertyAttribute : Attribute
|
||||
{
|
||||
public ExeclPropertyAttribute()
|
||||
{
|
||||
|
||||
}
|
||||
public ExeclPropertyAttribute(string displayName, int order, CellType cellType = CellType.String)
|
||||
{
|
||||
DisplayName = displayName;
|
||||
Order = order;
|
||||
CellType = cellType;
|
||||
}
|
||||
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
public int Order { get; set; }
|
||||
|
||||
public CellType CellType { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -16,7 +17,7 @@ namespace AntSK.Domain.Domain.Interface
|
||||
IAsyncEnumerable<StreamingKernelContent> SendChatByAppAsync(Apps app, string questions, 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);
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,13 @@ namespace AntSK.Domain.Domain.Interface
|
||||
{
|
||||
public interface IKMService
|
||||
{
|
||||
MemoryServerless GetMemory(Apps app);
|
||||
MemoryServerless GetMemoryByApp(Apps app);
|
||||
|
||||
MemoryServerless GetMemoryByKMS(string kmsID, SearchClientConfig searchClientConfig = null);
|
||||
MemoryServerless GetMemoryByKMS(string kmsID);
|
||||
|
||||
Task<List<KMFile>> GetDocumentByFileID(string kmsId, string fileId);
|
||||
|
||||
Task<List<RelevantSource>> GetRelevantSourceList(string kmsIdListStr, string msg);
|
||||
Task<List<RelevantSource>> GetRelevantSourceList(Apps app, string msg);
|
||||
|
||||
List<UploadFileItem> FileList { get; }
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace AntSK.Domain.Domain.Interface
|
||||
public interface IKernelService
|
||||
{
|
||||
Kernel GetKernelByApp(Apps app);
|
||||
|
||||
Kernel GetKernelByAIModelID(string modelid);
|
||||
void ImportFunctionsByApp(Apps app, Kernel _kernel);
|
||||
Task<string> HistorySummarize(Kernel _kernel, string questions, string history);
|
||||
}
|
||||
|
||||
@@ -11,5 +11,24 @@ namespace AntSK.Domain.Domain.Model.Constant
|
||||
public const string KmsIdTag = "kmsid";
|
||||
public const string KmsIndex = "kms";
|
||||
public const string KmsSearchNull="知识库未搜索到相关内容";
|
||||
|
||||
public const string KmsPrompt = @"使用<data></data>标记的内容作为你的知识:
|
||||
<data>
|
||||
{{$doc}}
|
||||
</data>
|
||||
--------------------------
|
||||
回答要求:
|
||||
- 如果你不清楚答案,你需要澄清
|
||||
- 避免提及你是从<data></data>获取的知识
|
||||
- 保持答案与<data></data>众描述一致
|
||||
- 使用Markdown语法优化回答格式。
|
||||
- 如果Markdown有图片则正常显示
|
||||
--------------------------
|
||||
|
||||
历史聊天记录:{{ConversationSummaryPlugin.SummarizeConversation $history}}
|
||||
--------------------------
|
||||
用户问题: {{$input}}";
|
||||
|
||||
public const string KMExcelSplit = "*&antsk_excel&*";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,12 +21,16 @@ namespace AntSK.Domain.Domain.Model.Enum
|
||||
|
||||
[Display(Name = "灵积大模型")]
|
||||
DashScope = 5,
|
||||
|
||||
|
||||
[Display(Name = "LLamaFactory")]
|
||||
LLamaFactory = 6,
|
||||
|
||||
[Display(Name = "Bge Embedding")]
|
||||
BgeEmbedding = 7,
|
||||
[Display(Name = "StableDiffusion")]
|
||||
StableDiffusion = 8,
|
||||
[Display(Name = "模拟输出")]
|
||||
Mock = 100,
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -36,5 +40,6 @@ namespace AntSK.Domain.Domain.Model.Enum
|
||||
{
|
||||
Chat = 1,
|
||||
Embedding = 2,
|
||||
Image=3,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace AntSK.Domain.Domain.Model.Enum
|
||||
public enum AppType
|
||||
{
|
||||
chat = 1,
|
||||
kms = 2
|
||||
kms = 2,
|
||||
img=3
|
||||
}
|
||||
}
|
||||
|
||||
17
src/AntSK.Domain/Domain/Model/Excel/KMSExcelModel.cs
Normal file
17
src/AntSK.Domain/Domain/Model/Excel/KMSExcelModel.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain.Domain.Model.Excel
|
||||
{
|
||||
public class KMSExcelModel
|
||||
{
|
||||
[ExeclProperty("问题",0)]
|
||||
public string Question { get; set; }
|
||||
|
||||
[ExeclProperty("答案", 1)]
|
||||
public string Answer { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,14 @@ namespace AntSK.Domain.Domain.Model
|
||||
public string FilePath { get; set; } = "";
|
||||
|
||||
public string FileName { get; set; } = "";
|
||||
|
||||
public bool IsQA { get; set; } = false;
|
||||
}
|
||||
|
||||
|
||||
public class ImportKMSTaskReq : ImportKMSTaskDTO
|
||||
{
|
||||
public bool IsQA { get; set; }=false;
|
||||
public KmsDetails KmsDetail { get; set; } = new KmsDetails();
|
||||
}
|
||||
|
||||
@@ -29,6 +32,13 @@ namespace AntSK.Domain.Domain.Model
|
||||
{
|
||||
File = 1,
|
||||
Url = 2,
|
||||
Text = 3
|
||||
Text = 3,
|
||||
Excel=4
|
||||
}
|
||||
|
||||
public class QAModel
|
||||
{
|
||||
public string ChatModelId { get; set; }
|
||||
public string Context { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
{
|
||||
public string ID { get; set; } = "";
|
||||
public string Context { get; set; } = "";
|
||||
public string HtmlAnswers { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 发送是true 接收是false
|
||||
@@ -13,8 +12,6 @@
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
public string? FilePath { get; set; }
|
||||
|
||||
public string? FileName { get; set; }
|
||||
}
|
||||
}
|
||||
95
src/AntSK.Domain/Domain/Other/EmbeddingConfig.cs
Normal file
95
src/AntSK.Domain/Domain/Other/EmbeddingConfig.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using Microsoft.KernelMemory.AI.OpenAI.GPT3;
|
||||
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
|
||||
{
|
||||
public static class EmbeddingConfig
|
||||
{
|
||||
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)
|
||||
{
|
||||
//Runtime.PythonDLL = @"D:\Programs\Python\Python311\python311.dll";
|
||||
Runtime.PythonDLL = pythondllPath;
|
||||
PythonEngine.Initialize();
|
||||
PythonEngine.BeginAllowThreads();
|
||||
|
||||
try
|
||||
{
|
||||
using (Py.GIL())// 初始化Python环境的Global Interpreter Lock)
|
||||
{
|
||||
dynamic modelscope = Py.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 HuggingFaceBgeEmbeddings = HuggingFaceBgeEmbeddingstemp.HuggingFaceBgeEmbeddings;
|
||||
string model_name = model_dir;
|
||||
dynamic model_kwargs = new PyDict();
|
||||
model_kwargs["device"] = new PyString("cpu");
|
||||
dynamic hugginmodel = HuggingFaceBgeEmbeddings(
|
||||
model_name: model_dir,
|
||||
model_kwargs: model_kwargs
|
||||
);
|
||||
model = hugginmodel;
|
||||
return hugginmodel;
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
else
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
||||
public static Task<float[]> GetEmbedding(string queryStr)
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
PyObject queryResult = model.embed_query(queryStr);
|
||||
var floatList = queryResult.As<float[]>();
|
||||
return Task.FromResult(floatList); ;
|
||||
}
|
||||
}
|
||||
|
||||
public static int TokenCount(string queryStr)
|
||||
{
|
||||
//using (Py.GIL())
|
||||
//{
|
||||
// PyObject queryResult = model.client.tokenize(queryStr);
|
||||
// // 使用Python的内置len()函数获取长度
|
||||
// PyObject lenFunc = Py.Import("builtins").GetAttr("len");
|
||||
// PyObject length = lenFunc.Invoke(queryResult["input_ids"]);
|
||||
// int len = length.As<int>(); // 将PyObject转换为C#中的整数
|
||||
// return len;
|
||||
|
||||
//}
|
||||
var tokenCount1 = GPT3Tokenizer.Encode(queryStr).Count;
|
||||
return tokenCount1;
|
||||
}
|
||||
|
||||
public static void Dispose()
|
||||
{
|
||||
Console.WriteLine("python dispose");
|
||||
}
|
||||
}
|
||||
}
|
||||
156
src/AntSK.Domain/Domain/Other/KMExcelHandler.cs
Normal file
156
src/AntSK.Domain/Domain/Other/KMExcelHandler.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
using AntSK.Domain.Domain.Model.Constant;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.KernelMemory.AI.OpenAI;
|
||||
using Microsoft.KernelMemory.Configuration;
|
||||
using Microsoft.KernelMemory.DataFormats.Text;
|
||||
using Microsoft.KernelMemory.Diagnostics;
|
||||
using Microsoft.KernelMemory.Extensions;
|
||||
using Microsoft.KernelMemory.Pipeline;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain.Domain.Other
|
||||
{
|
||||
public class KMExcelHandler: IPipelineStepHandler
|
||||
{
|
||||
private readonly TextPartitioningOptions _options;
|
||||
private readonly IPipelineOrchestrator _orchestrator;
|
||||
private readonly ILogger<KMExcelHandler> _log;
|
||||
private readonly TextChunker.TokenCounter _tokenCounter;
|
||||
|
||||
public KMExcelHandler(
|
||||
string stepName,
|
||||
IPipelineOrchestrator orchestrator,
|
||||
TextPartitioningOptions? options = null,
|
||||
ILogger<KMExcelHandler>? log = null)
|
||||
{
|
||||
this.StepName = stepName;
|
||||
this._orchestrator = orchestrator;
|
||||
this._options = options ?? new TextPartitioningOptions();
|
||||
this._options.Validate();
|
||||
|
||||
this._log = log ?? DefaultLogger<KMExcelHandler>.Instance;
|
||||
this._tokenCounter = DefaultGPTTokenizer.StaticCountTokens;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string StepName { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<(bool success, DataPipeline updatedPipeline)> InvokeAsync(
|
||||
DataPipeline pipeline, CancellationToken cancellationToken = default)
|
||||
{
|
||||
this._log.LogDebug("Partitioning text, pipeline '{0}/{1}'", pipeline.Index, pipeline.DocumentId);
|
||||
|
||||
if (pipeline.Files.Count == 0)
|
||||
{
|
||||
this._log.LogWarning("Pipeline '{0}/{1}': there are no files to process, moving to next pipeline step.", pipeline.Index, pipeline.DocumentId);
|
||||
return (true, pipeline);
|
||||
}
|
||||
|
||||
foreach (DataPipeline.FileDetails uploadedFile in pipeline.Files)
|
||||
{
|
||||
// Track new files being generated (cannot edit originalFile.GeneratedFiles while looping it)
|
||||
Dictionary<string, DataPipeline.GeneratedFileDetails> newFiles = new();
|
||||
|
||||
foreach (KeyValuePair<string, DataPipeline.GeneratedFileDetails> generatedFile in uploadedFile.GeneratedFiles)
|
||||
{
|
||||
var file = generatedFile.Value;
|
||||
if (file.AlreadyProcessedBy(this))
|
||||
{
|
||||
this._log.LogTrace("File {0} already processed by this handler", file.Name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Partition only the original text
|
||||
if (file.ArtifactType != DataPipeline.ArtifactTypes.ExtractedText)
|
||||
{
|
||||
this._log.LogTrace("Skipping file {0} (not original text)", file.Name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use a different partitioning strategy depending on the file type
|
||||
List<string> partitions;
|
||||
List<string> sentences;
|
||||
BinaryData partitionContent = await this._orchestrator.ReadFileAsync(pipeline, file.Name, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Skip empty partitions. Also: partitionContent.ToString() throws an exception if there are no bytes.
|
||||
if (partitionContent.ToArray().Length == 0) { continue; }
|
||||
|
||||
switch (file.MimeType)
|
||||
{
|
||||
case MimeTypes.PlainText:
|
||||
{
|
||||
this._log.LogDebug("Partitioning text file {0}", file.Name);
|
||||
string content = partitionContent.ToString();
|
||||
var excelList = content.Split(KmsConstantcs.KMExcelSplit, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
sentences = excelList;
|
||||
partitions = excelList;
|
||||
break;
|
||||
}
|
||||
|
||||
case MimeTypes.MarkDown:
|
||||
{
|
||||
this._log.LogDebug("Partitioning text file {0}", file.Name);
|
||||
string content = partitionContent.ToString();
|
||||
var excelList = content.Split(KmsConstantcs.KMExcelSplit, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
sentences = excelList;
|
||||
partitions = excelList;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
this._log.LogWarning("File {0} cannot be partitioned, type '{1}' not supported", file.Name, file.MimeType);
|
||||
// Don't partition other files
|
||||
continue;
|
||||
}
|
||||
|
||||
if (partitions.Count == 0) { continue; }
|
||||
|
||||
this._log.LogDebug("Saving {0} file partitions", partitions.Count);
|
||||
for (int partitionNumber = 0; partitionNumber < partitions.Count; partitionNumber++)
|
||||
{
|
||||
// TODO: turn partitions in objects with more details, e.g. page number
|
||||
string text = partitions[partitionNumber];
|
||||
int sectionNumber = 0; // TODO: use this to store the page number (if any)
|
||||
BinaryData textData = new(text);
|
||||
|
||||
int tokenCount = this._tokenCounter(text);
|
||||
this._log.LogDebug("Partition size: {0} tokens", tokenCount);
|
||||
|
||||
var destFile = uploadedFile.GetPartitionFileName(partitionNumber);
|
||||
await this._orchestrator.WriteFileAsync(pipeline, destFile, textData, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var destFileDetails = new DataPipeline.GeneratedFileDetails
|
||||
{
|
||||
Id = Guid.NewGuid().ToString("N"),
|
||||
ParentId = uploadedFile.Id,
|
||||
Name = destFile,
|
||||
Size = text.Length,
|
||||
MimeType = MimeTypes.PlainText,
|
||||
ArtifactType = DataPipeline.ArtifactTypes.TextPartition,
|
||||
PartitionNumber = partitionNumber,
|
||||
SectionNumber = sectionNumber,
|
||||
Tags = pipeline.Tags,
|
||||
ContentSHA256 = textData.CalculateSHA256(),
|
||||
};
|
||||
newFiles.Add(destFile, destFileDetails);
|
||||
destFileDetails.MarkProcessedBy(this);
|
||||
}
|
||||
|
||||
file.MarkProcessedBy(this);
|
||||
}
|
||||
|
||||
// Add new files to pipeline status
|
||||
foreach (var file in newFiles)
|
||||
{
|
||||
uploadedFile.GeneratedFiles.Add(file.Key, file.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return (true, pipeline);
|
||||
}
|
||||
}
|
||||
}
|
||||
154
src/AntSK.Domain/Domain/Other/QAHandler.cs
Normal file
154
src/AntSK.Domain/Domain/Other/QAHandler.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using AntSK.Domain.Domain.Model;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.KernelMemory.AI.OpenAI;
|
||||
using Microsoft.KernelMemory.Configuration;
|
||||
using Microsoft.KernelMemory.DataFormats.Text;
|
||||
using Microsoft.KernelMemory.Diagnostics;
|
||||
using Microsoft.KernelMemory.Extensions;
|
||||
using Microsoft.KernelMemory.Pipeline;
|
||||
using Newtonsoft.Json;
|
||||
using RestSharp;
|
||||
using System.Security.Policy;
|
||||
using System.Text;
|
||||
|
||||
namespace AntSK.Domain.Domain.Other
|
||||
{
|
||||
public class QAHandler : IPipelineStepHandler
|
||||
{
|
||||
private readonly TextPartitioningOptions _options;
|
||||
private readonly IPipelineOrchestrator _orchestrator;
|
||||
private readonly ILogger<QAHandler> _log;
|
||||
private readonly TextChunker.TokenCounter _tokenCounter;
|
||||
public QAHandler(
|
||||
string stepName,
|
||||
IPipelineOrchestrator orchestrator,
|
||||
TextPartitioningOptions? options = null,
|
||||
ILogger<QAHandler>? log = null
|
||||
)
|
||||
{
|
||||
this.StepName = stepName;
|
||||
this._orchestrator = orchestrator;
|
||||
this._options = options ?? new TextPartitioningOptions();
|
||||
this._options.Validate();
|
||||
|
||||
this._log = log ?? DefaultLogger<QAHandler>.Instance;
|
||||
this._tokenCounter = DefaultGPTTokenizer.StaticCountTokens;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string StepName { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<(bool success, DataPipeline updatedPipeline)> InvokeAsync(
|
||||
DataPipeline pipeline, CancellationToken cancellationToken = default)
|
||||
{
|
||||
this._log.LogDebug("Partitioning text, pipeline '{0}/{1}'", pipeline.Index, pipeline.DocumentId);
|
||||
|
||||
if (pipeline.Files.Count == 0)
|
||||
{
|
||||
this._log.LogWarning("Pipeline '{0}/{1}': there are no files to process, moving to next pipeline step.", pipeline.Index, pipeline.DocumentId);
|
||||
return (true, pipeline);
|
||||
}
|
||||
|
||||
foreach (DataPipeline.FileDetails uploadedFile in pipeline.Files)
|
||||
{
|
||||
// Track new files being generated (cannot edit originalFile.GeneratedFiles while looping it)
|
||||
Dictionary<string, DataPipeline.GeneratedFileDetails> newFiles = new();
|
||||
|
||||
foreach (KeyValuePair<string, DataPipeline.GeneratedFileDetails> generatedFile in uploadedFile.GeneratedFiles)
|
||||
{
|
||||
var file = generatedFile.Value;
|
||||
if (file.AlreadyProcessedBy(this))
|
||||
{
|
||||
this._log.LogTrace("File {0} already processed by this handler", file.Name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Partition only the original text
|
||||
if (file.ArtifactType != DataPipeline.ArtifactTypes.ExtractedText)
|
||||
{
|
||||
this._log.LogTrace("Skipping file {0} (not original text)", file.Name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use a different partitioning strategy depending on the file type
|
||||
List<string> partitions;
|
||||
List<string> sentences;
|
||||
BinaryData partitionContent = await this._orchestrator.ReadFileAsync(pipeline, file.Name, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Skip empty partitions. Also: partitionContent.ToString() throws an exception if there are no bytes.
|
||||
if (partitionContent.ToArray().Length == 0) { continue; }
|
||||
|
||||
switch (file.MimeType)
|
||||
{
|
||||
case MimeTypes.PlainText:
|
||||
case MimeTypes.MarkDown:
|
||||
{
|
||||
this._log.LogDebug("Partitioning text file {0}", file.Name);
|
||||
string content = partitionContent.ToString();
|
||||
|
||||
using (HttpClient httpclient = new HttpClient())
|
||||
{
|
||||
httpclient.Timeout = TimeSpan.FromMinutes(10);
|
||||
StringContent scontent = new StringContent(JsonConvert.SerializeObject(new QAModel() { ChatModelId = StepName, Context = content }), Encoding.UTF8, "application/json");
|
||||
HttpResponseMessage response = await httpclient.PostAsync("http://localhost:5000/api/KMS/QA", scontent);
|
||||
List<string> qaList = JsonConvert.DeserializeObject<List<string>>( await response.Content.ReadAsStringAsync());
|
||||
sentences = qaList;
|
||||
partitions = qaList;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
this._log.LogWarning("File {0} cannot be partitioned, type '{1}' not supported", file.Name, file.MimeType);
|
||||
// Don't partition other files
|
||||
continue;
|
||||
}
|
||||
|
||||
if (partitions.Count == 0) { continue; }
|
||||
|
||||
this._log.LogDebug("Saving {0} file partitions", partitions.Count);
|
||||
for (int partitionNumber = 0; partitionNumber < partitions.Count; partitionNumber++)
|
||||
{
|
||||
// TODO: turn partitions in objects with more details, e.g. page number
|
||||
string text = partitions[partitionNumber];
|
||||
int sectionNumber = 0; // TODO: use this to store the page number (if any)
|
||||
BinaryData textData = new(text);
|
||||
|
||||
int tokenCount = this._tokenCounter(text);
|
||||
this._log.LogDebug("Partition size: {0} tokens", tokenCount);
|
||||
|
||||
var destFile = uploadedFile.GetPartitionFileName(partitionNumber);
|
||||
await this._orchestrator.WriteFileAsync(pipeline, destFile, textData, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var destFileDetails = new DataPipeline.GeneratedFileDetails
|
||||
{
|
||||
Id = Guid.NewGuid().ToString("N"),
|
||||
ParentId = uploadedFile.Id,
|
||||
Name = destFile,
|
||||
Size = text.Length,
|
||||
MimeType = MimeTypes.PlainText,
|
||||
ArtifactType = DataPipeline.ArtifactTypes.TextPartition,
|
||||
PartitionNumber = partitionNumber,
|
||||
SectionNumber = sectionNumber,
|
||||
Tags = pipeline.Tags,
|
||||
ContentSHA256 = textData.CalculateSHA256(),
|
||||
};
|
||||
newFiles.Add(destFile, destFileDetails);
|
||||
destFileDetails.MarkProcessedBy(this);
|
||||
}
|
||||
|
||||
file.MarkProcessedBy(this);
|
||||
}
|
||||
|
||||
// Add new files to pipeline status
|
||||
foreach (var file in newFiles)
|
||||
{
|
||||
uploadedFile.GeneratedFiles.Add(file.Key, file.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return (true, pipeline);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,21 @@
|
||||
using AntSK.Domain.Common.DependencyInjection;
|
||||
using AntSK.Domain.Domain.Interface;
|
||||
using AntSK.Domain.Repositories;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel;
|
||||
using System.Text;
|
||||
using AntSK.Domain.Utils;
|
||||
using AntSK.Domain.Domain.Model.Dto;
|
||||
using AntSK.Domain.Domain.Model.Constant;
|
||||
using DocumentFormat.OpenXml.Drawing;
|
||||
using System.Reflection.Metadata;
|
||||
using Microsoft.KernelMemory;
|
||||
using System.Collections.Generic;
|
||||
using Markdig;
|
||||
using ChatHistory = Microsoft.SemanticKernel.ChatCompletion.ChatHistory;
|
||||
using Microsoft.SemanticKernel.Plugins.Core;
|
||||
using Azure.Core;
|
||||
using AntSK.Domain.Domain.Model;
|
||||
using AntSK.Domain.Domain.Model.Constant;
|
||||
using AntSK.Domain.Domain.Model.Dto;
|
||||
using AntSK.Domain.Repositories;
|
||||
using AntSK.Domain.Utils;
|
||||
using AntSK.LLM.StableDiffusion;
|
||||
using Markdig;
|
||||
using Microsoft.KernelMemory;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using ChatHistory = Microsoft.SemanticKernel.ChatCompletion.ChatHistory;
|
||||
|
||||
namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
@@ -23,7 +23,8 @@ namespace AntSK.Domain.Domain.Service
|
||||
public class ChatService(
|
||||
IKernelService _kernelService,
|
||||
IKMService _kMService,
|
||||
IKmsDetails_Repositories _kmsDetails_Repositories
|
||||
IKmsDetails_Repositories _kmsDetails_Repositories,
|
||||
IAIModels_Repositories _aIModels_Repositories
|
||||
) : IChatService
|
||||
{
|
||||
/// <summary>
|
||||
@@ -41,7 +42,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
//如果模板为空,给默认提示词
|
||||
app.Prompt = app.Prompt.ConvertToString() + "{{$input}}";
|
||||
}
|
||||
KernelArguments args =new KernelArguments();
|
||||
KernelArguments args = new KernelArguments();
|
||||
if (history.Count > 10)
|
||||
{
|
||||
app.Prompt = @"${{ConversationSummaryPlugin.SummarizeConversation $history}}" + app.Prompt;
|
||||
@@ -50,14 +51,14 @@ namespace AntSK.Domain.Domain.Service
|
||||
{ "input", questions }
|
||||
};
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
args=new()
|
||||
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需要缩小
|
||||
OpenAIPromptExecutionSettings settings = new() { Temperature = temperature };
|
||||
@@ -67,7 +68,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
settings.ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions;
|
||||
}
|
||||
var func = _kernel.CreateFunctionFromPrompt(app.Prompt, settings);
|
||||
var chatResult = _kernel.InvokeStreamingAsync(function: func,
|
||||
var chatResult = _kernel.InvokeStreamingAsync(function: func,
|
||||
arguments: args);
|
||||
await foreach (var content in chatResult)
|
||||
{
|
||||
@@ -77,11 +78,12 @@ namespace AntSK.Domain.Domain.Service
|
||||
|
||||
public async IAsyncEnumerable<StreamingKernelContent> SendKmsByAppAsync(Apps app, string questions, ChatHistory history, string filePath, List<RelevantSource> relevantSources = null)
|
||||
{
|
||||
var relevantSourceList = await _kMService.GetRelevantSourceList(app.KmsIdList, questions);
|
||||
relevantSources?.Clear();
|
||||
var relevantSourceList = await _kMService.GetRelevantSourceList(app, questions);
|
||||
var _kernel = _kernelService.GetKernelByApp(app);
|
||||
if (!string.IsNullOrWhiteSpace(filePath))
|
||||
{
|
||||
var memory = _kMService.GetMemory(app);
|
||||
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)
|
||||
@@ -101,19 +103,42 @@ namespace AntSK.Domain.Domain.Service
|
||||
var dataMsg = new StringBuilder();
|
||||
if (relevantSourceList.Any())
|
||||
{
|
||||
bool isSearch = false;
|
||||
foreach (var item in relevantSourceList)
|
||||
{
|
||||
//匹配相似度
|
||||
if (item.Relevance >= app.Relevance / 100)
|
||||
{
|
||||
dataMsg.AppendLine(item.ToString());
|
||||
isSearch = true;
|
||||
}
|
||||
}
|
||||
|
||||
//处理markdown显示
|
||||
relevantSources?.AddRange(relevantSourceList);
|
||||
foreach (var item in relevantSourceList)
|
||||
{
|
||||
dataMsg.AppendLine(item.ToString());
|
||||
item.Text = Markdown.ToHtml(item.Text);
|
||||
}
|
||||
|
||||
KernelFunction jsonFun = _kernel.Plugins.GetFunction("KMSPlugin", "Ask1");
|
||||
var chatResult = _kernel.InvokeStreamingAsync(function: jsonFun,
|
||||
arguments: new KernelArguments() { ["doc"] = dataMsg, ["history"] = string.Join("\n", history.Select(x => x.Role + ": " + x.Content)), ["questions"] = questions });
|
||||
|
||||
await foreach (var content in chatResult)
|
||||
if (isSearch)
|
||||
{
|
||||
yield return content;
|
||||
//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 chatResult = _kernel.InvokeStreamingAsync(function: func,
|
||||
arguments: new KernelArguments() { ["doc"] = dataMsg.ToString(), ["history"] = string.Join("\n", history.Select(x => x.Role + ": " + x.Content)), ["input"] = questions });
|
||||
|
||||
await foreach (var content in chatResult)
|
||||
{
|
||||
yield return content;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new StreamingTextContent(KmsConstantcs.KmsSearchNull);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -122,6 +147,113 @@ namespace AntSK.Domain.Domain.Service
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<string> SendImgByAppAsync(Apps app, string questions)
|
||||
{
|
||||
var imageModel = _aIModels_Repositories.GetFirst(p => p.Id == app.ImageModelID);
|
||||
KernelArguments args = new() {
|
||||
{ "input", questions }
|
||||
};
|
||||
var _kernel = _kernelService.GetKernelByApp(app);
|
||||
var temperature = app.Temperature / 100; //存的是0~100需要缩小
|
||||
OpenAIPromptExecutionSettings settings = new() { Temperature = temperature };
|
||||
var func = _kernel.CreateFunctionFromPrompt("Translate this into English:{{$input}}", settings);
|
||||
var chatResult = await _kernel.InvokeAsync(function: func, arguments: args);
|
||||
if (chatResult.IsNotNull())
|
||||
{
|
||||
//Can Load stable-diffusion library in diffenert environment
|
||||
|
||||
//SDHelper.LoadLibrary()
|
||||
string versionString = string.Empty;
|
||||
string extensionString = string.Empty;
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
extensionString = ".dll";
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
extensionString = ".so";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("OS Platform no support");
|
||||
}
|
||||
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo("nvcc", "--version");
|
||||
startInfo.RedirectStandardOutput = true;
|
||||
startInfo.UseShellExecute = false;
|
||||
startInfo.CreateNoWindow = true;
|
||||
using (Process process = Process.Start(startInfo))
|
||||
{
|
||||
if (process != null)
|
||||
{
|
||||
string result = process.StandardOutput.ReadToEnd();
|
||||
Regex regex = new Regex(@"release (\d+).[\d]");
|
||||
Match match = regex.Match(result);
|
||||
if (match.Success)
|
||||
{
|
||||
switch (match.Groups[1].Value.ToString())
|
||||
{
|
||||
case "11":
|
||||
versionString = "Cuda11";
|
||||
break;
|
||||
case "12":
|
||||
versionString = "Cuda12";
|
||||
break;
|
||||
default:
|
||||
versionString = "CPU";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("nvcc get an error");
|
||||
}
|
||||
}
|
||||
|
||||
string libraryPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "StableDiffusion", "Backend", versionString, "stable-diffusion" + extensionString);
|
||||
NativeLibrary.TryLoad(libraryPath, out _);
|
||||
string prompt = chatResult.GetValue<string>();
|
||||
if (!SDHelper.IsInitialized)
|
||||
{
|
||||
Structs.ModelParams modelParams = new Structs.ModelParams
|
||||
{
|
||||
ModelPath = imageModel.ModelName,
|
||||
RngType = Structs.RngType.CUDA_RNG,
|
||||
//VaePath = vaePath,
|
||||
//KeepVaeOnCpu = keepVaeOnCpu,
|
||||
//set false can get a better image, otherwise can use lower vram
|
||||
VaeTiling = false,
|
||||
//LoraModelDir = loraModelDir,
|
||||
};
|
||||
bool result = SDHelper.Initialize(modelParams);
|
||||
}
|
||||
|
||||
Structs.TextToImageParams textToImageParams = new Structs.TextToImageParams
|
||||
{
|
||||
Prompt = prompt,
|
||||
NegativePrompt = "bad quality, wrong image, worst quality",
|
||||
SampleMethod = (Structs.SampleMethod)Enum.Parse(typeof(Structs.SampleMethod), "EULER_A"),
|
||||
//the base image size in SD1.5 is 512x512
|
||||
Width = 512,
|
||||
Height = 512,
|
||||
NormalizeInput = true,
|
||||
ClipSkip = -1,
|
||||
CfgScale = 7,
|
||||
SampleSteps = 20,
|
||||
Seed = -1,
|
||||
};
|
||||
Bitmap[] outputImages = SDHelper.TextToImage(textToImageParams);
|
||||
var base64 = ImageUtils.BitmapToBase64(outputImages[0]);
|
||||
return base64;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ChatHistory> GetChatHistory(List<MessageInfo> MessageList)
|
||||
{
|
||||
ChatHistory history = new ChatHistory();
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
using AntSK.Domain.Domain.Interface;
|
||||
using AntSK.Domain.Domain.Model;
|
||||
using AntSK.Domain.Domain.Model.Constant;
|
||||
using AntSK.Domain.Domain.Model.Excel;
|
||||
using AntSK.Domain.Domain.Other;
|
||||
using AntSK.Domain.Repositories;
|
||||
using Microsoft.KernelMemory;
|
||||
using Microsoft.KernelMemory.Handlers;
|
||||
using System.Text;
|
||||
|
||||
namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
@@ -20,18 +24,40 @@ namespace AntSK.Domain.Domain.Service
|
||||
try
|
||||
{
|
||||
var km = _kmss_Repositories.GetFirst(p => p.Id == req.KmsId);
|
||||
|
||||
var _memory = _kMService.GetMemoryByKMS(km.Id);
|
||||
string fileid = req.KmsDetail.Id;
|
||||
List<string> step = new List<string>();
|
||||
if (req.IsQA)
|
||||
{
|
||||
_memory.Orchestrator.AddHandler<TextExtractionHandler>("extract_text");
|
||||
_memory.Orchestrator.AddHandler<QAHandler>(km.ChatModelID);
|
||||
_memory.Orchestrator.AddHandler<GenerateEmbeddingsHandler>("generate_embeddings");
|
||||
_memory.Orchestrator.AddHandler<SaveRecordsHandler>("save_memory_records");
|
||||
step.Add("extract_text");
|
||||
step.Add(km.ChatModelID);
|
||||
step.Add("generate_embeddings");
|
||||
step.Add("save_memory_records");
|
||||
}
|
||||
|
||||
switch (req.ImportType)
|
||||
{
|
||||
case ImportType.File:
|
||||
//导入文件
|
||||
{
|
||||
var importResult = _memory.ImportDocumentAsync(new Document(fileid)
|
||||
.AddFile(req.FilePath)
|
||||
.AddTag(KmsConstantcs.KmsIdTag, req.KmsId)
|
||||
, index: KmsConstantcs.KmsIndex).Result;
|
||||
//导入文件
|
||||
if (req.IsQA)
|
||||
{
|
||||
var importResult = _memory.ImportDocumentAsync(new Document(fileid)
|
||||
.AddFile(req.FilePath)
|
||||
.AddTag(KmsConstantcs.KmsIdTag, req.KmsId)
|
||||
,index: KmsConstantcs.KmsIndex ,steps: step.ToArray()).Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
var importResult = _memory.ImportDocumentAsync(new Document(fileid)
|
||||
.AddFile(req.FilePath)
|
||||
.AddTag(KmsConstantcs.KmsIdTag, req.KmsId)
|
||||
, index: KmsConstantcs.KmsIndex).Result;
|
||||
}
|
||||
//查询文档数量
|
||||
var docTextList = _kMService.GetDocumentByFileID(km.Id, fileid).Result;
|
||||
string fileGuidName = Path.GetFileName(req.FilePath);
|
||||
@@ -44,8 +70,16 @@ namespace AntSK.Domain.Domain.Service
|
||||
case ImportType.Url:
|
||||
{
|
||||
//导入url
|
||||
var importResult = _memory.ImportWebPageAsync(req.Url, fileid, new TagCollection() { { KmsConstantcs.KmsIdTag, req.KmsId } }
|
||||
, index: KmsConstantcs.KmsIndex).Result;
|
||||
if (req.IsQA)
|
||||
{
|
||||
var importResult = _memory.ImportWebPageAsync(req.Url, fileid, new TagCollection() { { KmsConstantcs.KmsIdTag, req.KmsId } }
|
||||
, index: KmsConstantcs.KmsIndex, steps: step.ToArray()).Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
var importResult = _memory.ImportWebPageAsync(req.Url, fileid, new TagCollection() { { KmsConstantcs.KmsIdTag, req.KmsId } }
|
||||
, index: KmsConstantcs.KmsIndex).Result;
|
||||
}
|
||||
//查询文档数量
|
||||
var docTextList = _kMService.GetDocumentByFileID(km.Id, fileid).Result;
|
||||
req.KmsDetail.Url = req.Url;
|
||||
@@ -55,8 +89,16 @@ namespace AntSK.Domain.Domain.Service
|
||||
case ImportType.Text:
|
||||
//导入文本
|
||||
{
|
||||
var importResult = _memory.ImportTextAsync(req.Text, fileid, new TagCollection() { { KmsConstantcs.KmsIdTag, req.KmsId } }
|
||||
, index: KmsConstantcs.KmsIndex).Result;
|
||||
if (req.IsQA)
|
||||
{
|
||||
var importResult = _memory.ImportTextAsync(req.Text, fileid, new TagCollection() { { KmsConstantcs.KmsIdTag, req.KmsId } }
|
||||
, index: KmsConstantcs.KmsIndex, steps: step.ToArray()).Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
var importResult = _memory.ImportTextAsync(req.Text, fileid, new TagCollection() { { KmsConstantcs.KmsIdTag, req.KmsId } }
|
||||
, index: KmsConstantcs.KmsIndex).Result;
|
||||
}
|
||||
//查询文档数量
|
||||
var docTextList = _kMService.GetDocumentByFileID(km.Id, fileid).Result;
|
||||
req.KmsDetail.Url = req.Url;
|
||||
@@ -64,6 +106,36 @@ namespace AntSK.Domain.Domain.Service
|
||||
|
||||
}
|
||||
break;
|
||||
case ImportType.Excel:
|
||||
using (var fs = File.OpenRead(req.FilePath))
|
||||
{
|
||||
var excelList= ExeclHelper.ExcelToList<KMSExcelModel>(fs);
|
||||
_memory.Orchestrator.AddHandler<TextExtractionHandler>("extract_text");
|
||||
_memory.Orchestrator.AddHandler<KMExcelHandler>("antsk_excel_split");
|
||||
_memory.Orchestrator.AddHandler<GenerateEmbeddingsHandler>("generate_embeddings");
|
||||
_memory.Orchestrator.AddHandler<SaveRecordsHandler>("save_memory_records");
|
||||
|
||||
StringBuilder text = new StringBuilder();
|
||||
foreach (var item in excelList)
|
||||
{
|
||||
text.AppendLine(@$"Question:{item.Question}{Environment.NewLine}Answer:{item.Answer}{KmsConstantcs.KMExcelSplit}");
|
||||
}
|
||||
var importResult = _memory.ImportTextAsync(text.ToString(), fileid, new TagCollection() { { KmsConstantcs.KmsIdTag, req.KmsId } }
|
||||
, index: KmsConstantcs.KmsIndex,
|
||||
steps: new[]
|
||||
{
|
||||
"extract_text",
|
||||
"antsk_excel_split",
|
||||
"generate_embeddings",
|
||||
"save_memory_records"
|
||||
}
|
||||
).Result;
|
||||
req.KmsDetail.FileName = req.FileName;
|
||||
string fileGuidName = Path.GetFileName(req.FilePath);
|
||||
req.KmsDetail.FileGuidName = fileGuidName;
|
||||
req.KmsDetail.DataCount = excelList.Count();
|
||||
}
|
||||
break;
|
||||
}
|
||||
req.KmsDetail.Status = Model.Enum.ImportKmsStatus.Success;
|
||||
_kmsDetails_Repositories.Update(req.KmsDetail);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using AntDesign;
|
||||
using AntSK.Domain.Common.DependencyInjection;
|
||||
using AntSK.Domain.Common.Embedding;
|
||||
using AntSK.Domain.Domain.Interface;
|
||||
using AntSK.Domain.Domain.Model.Constant;
|
||||
using AntSK.Domain.Domain.Model.Dto;
|
||||
@@ -7,6 +8,7 @@ using AntSK.Domain.Domain.Other;
|
||||
using AntSK.Domain.Options;
|
||||
using AntSK.Domain.Repositories;
|
||||
using AntSK.Domain.Utils;
|
||||
using AntSK.OCR;
|
||||
using DocumentFormat.OpenXml.Drawing.Diagrams;
|
||||
using LLama;
|
||||
using LLamaSharp.KernelMemory;
|
||||
@@ -15,6 +17,7 @@ using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.KernelMemory;
|
||||
using Microsoft.KernelMemory.Configuration;
|
||||
using Microsoft.KernelMemory.DataFormats;
|
||||
using Microsoft.KernelMemory.FileSystem.DevTools;
|
||||
using Microsoft.KernelMemory.MemoryStorage;
|
||||
using Microsoft.KernelMemory.MemoryStorage.DevTools;
|
||||
@@ -35,7 +38,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
|
||||
public List<UploadFileItem> FileList => _fileList;
|
||||
|
||||
public MemoryServerless GetMemory(Apps app)
|
||||
public MemoryServerless GetMemoryByApp(Apps app)
|
||||
{
|
||||
var chatModel = _aIModels_Repositories.GetFirst(p => p.Id == app.ChatModelID);
|
||||
var embedModel = _aIModels_Repositories.GetFirst(p => p.Id == app.EmbeddingModelID);
|
||||
@@ -44,9 +47,9 @@ namespace AntSK.Domain.Domain.Service
|
||||
|
||||
var searchClientConfig = new SearchClientConfig
|
||||
{
|
||||
MaxAskPromptSize = 2048,
|
||||
MaxMatchesCount = 3,
|
||||
AnswerTokens = 1000,
|
||||
MaxAskPromptSize = app.MaxAskPromptSize,
|
||||
MaxMatchesCount = app.MaxMatchesCount,
|
||||
AnswerTokens = app.AnswerTokens,
|
||||
EmptyAnswer = KmsConstantcs.KmsSearchNull
|
||||
};
|
||||
|
||||
@@ -70,7 +73,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
return _memory;
|
||||
}
|
||||
|
||||
public MemoryServerless GetMemoryByKMS(string kmsID, SearchClientConfig searchClientConfig = null)
|
||||
public MemoryServerless GetMemoryByKMS(string kmsID)
|
||||
{
|
||||
//if (_memory.IsNull())
|
||||
{
|
||||
@@ -84,32 +87,34 @@ namespace AntSK.Domain.Domain.Service
|
||||
var embeddingHttpClient = OpenAIHttpClientHandlerUtil.GetHttpClient(embedModel.EndPoint);
|
||||
|
||||
//搜索配置
|
||||
if (searchClientConfig.IsNull())
|
||||
{
|
||||
searchClientConfig = new SearchClientConfig
|
||||
{
|
||||
MaxAskPromptSize = 2048,
|
||||
MaxMatchesCount = 3,
|
||||
AnswerTokens = 1000,
|
||||
EmptyAnswer = KmsConstantcs.KmsSearchNull
|
||||
};
|
||||
}
|
||||
//if (searchClientConfig.IsNull())
|
||||
//{
|
||||
// searchClientConfig = new SearchClientConfig
|
||||
// {
|
||||
// MaxAskPromptSize = 2048,
|
||||
// MaxMatchesCount = 3,
|
||||
// AnswerTokens = 1000,
|
||||
// EmptyAnswer = KmsConstantcs.KmsSearchNull
|
||||
// };
|
||||
//}
|
||||
|
||||
var memoryBuild = new KernelMemoryBuilder()
|
||||
.WithSearchClientConfig(searchClientConfig)
|
||||
//.WithSearchClientConfig(searchClientConfig)
|
||||
.WithCustomTextPartitioningOptions(new TextPartitioningOptions
|
||||
{
|
||||
MaxTokensPerLine = kms.MaxTokensPerLine,
|
||||
MaxTokensPerParagraph = kms.MaxTokensPerParagraph,
|
||||
OverlappingTokens = kms.OverlappingTokens
|
||||
});
|
||||
//加载OCR
|
||||
WithOcr(memoryBuild, kms);
|
||||
//加载会话模型
|
||||
WithTextGenerationByAIType(memoryBuild, chatModel, chatHttpClient);
|
||||
//加载向量模型
|
||||
WithTextEmbeddingGenerationByAIType(memoryBuild, embedModel, embeddingHttpClient);
|
||||
//加载向量库
|
||||
WithMemoryDbByVectorDB(memoryBuild);
|
||||
|
||||
|
||||
_memory = memoryBuild.Build<MemoryServerless>();
|
||||
return _memory;
|
||||
}
|
||||
@@ -118,6 +123,14 @@ namespace AntSK.Domain.Domain.Service
|
||||
//}
|
||||
}
|
||||
|
||||
private static void WithOcr(IKernelMemoryBuilder memoryBuild, Kmss kms)
|
||||
{
|
||||
if (kms.IsOCR == 1)
|
||||
{
|
||||
memoryBuild.WithCustomImageOcr(new AntSKOcrEngine());
|
||||
}
|
||||
}
|
||||
|
||||
private void WithTextEmbeddingGenerationByAIType(IKernelMemoryBuilder memory, AIModels embedModel,
|
||||
HttpClient embeddingHttpClient)
|
||||
{
|
||||
@@ -147,6 +160,11 @@ namespace AntSK.Domain.Domain.Service
|
||||
var embedder = new LLamaEmbedder(weights, parameters);
|
||||
memory.WithLLamaSharpTextEmbeddingGeneration(new LLamaSharpTextEmbeddingGenerator(embedder));
|
||||
break;
|
||||
case Model.Enum.AIType.BgeEmbedding:
|
||||
string pyDll = embedModel.EndPoint;
|
||||
string bgeEmbeddingModelName = embedModel.ModelName;
|
||||
memory.WithBgeTextEmbeddingGeneration(new HuggingfaceTextEmbeddingGenerator(pyDll,bgeEmbeddingModelName));
|
||||
break;
|
||||
case Model.Enum.AIType.DashScope:
|
||||
memory.WithDashScopeDefaults(embedModel.ModelKey);
|
||||
break;
|
||||
@@ -183,6 +201,14 @@ namespace AntSK.Domain.Domain.Service
|
||||
var executor = new StatelessExecutor(weights, parameters);
|
||||
memory.WithLLamaSharpTextGeneration(new LlamaSharpTextGenerator(weights, context, executor));
|
||||
break;
|
||||
case Model.Enum.AIType.LLamaFactory:
|
||||
|
||||
memory.WithOpenAITextGeneration(new OpenAIConfig()
|
||||
{
|
||||
APIKey = "NotNull",
|
||||
TextModel = chatModel.ModelName
|
||||
}, null, chatHttpClient);
|
||||
break;
|
||||
case Model.Enum.AIType.DashScope:
|
||||
memory.WithDashScopeTextGeneration(new Cnblogs.KernelMemory.AI.DashScope.DashScopeConfig
|
||||
{
|
||||
@@ -248,7 +274,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
foreach (var memoryDb in memoryDbs)
|
||||
{
|
||||
var items = await memoryDb.GetListAsync(memoryIndex.Name, new List<MemoryFilter>() { new MemoryFilter().ByDocument(fileId) }, 100, true).ToListAsync();
|
||||
var items = await memoryDb.GetListAsync(memoryIndex.Name, new List<MemoryFilter>() { new MemoryFilter().ByDocument(fileId) }, 1000, true).ToListAsync();
|
||||
docTextList.AddRange(items.Select(item => new KMFile()
|
||||
{
|
||||
DocumentId = item.GetDocumentId(),
|
||||
@@ -263,15 +289,15 @@ namespace AntSK.Domain.Domain.Service
|
||||
return docTextList;
|
||||
}
|
||||
|
||||
public async Task<List<RelevantSource>> GetRelevantSourceList(string kmsIdListStr, string msg)
|
||||
public async Task<List<RelevantSource>> GetRelevantSourceList(Apps app ,string msg)
|
||||
{
|
||||
var result = new List<RelevantSource>();
|
||||
if (string.IsNullOrWhiteSpace(kmsIdListStr))
|
||||
if (string.IsNullOrWhiteSpace(app.KmsIdList))
|
||||
return result;
|
||||
var kmsIdList = kmsIdListStr.Split(",");
|
||||
var kmsIdList = app.KmsIdList.Split(",");
|
||||
if (!kmsIdList.Any()) return result;
|
||||
|
||||
var memory = GetMemoryByKMS(kmsIdList.FirstOrDefault()!);
|
||||
var memory = GetMemoryByApp(app);
|
||||
|
||||
var filters = kmsIdList.Select(kmsId => new MemoryFilter().ByTag(KmsConstantcs.KmsIdTag, kmsId)).ToList();
|
||||
|
||||
@@ -283,7 +309,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
result.AddRange(item.Partitions.Select(part => new RelevantSource()
|
||||
{
|
||||
SourceName = item.SourceName,
|
||||
Text = Markdown.ToHtml(part.Text),
|
||||
Text = part.Text,
|
||||
Relevance = part.Relevance
|
||||
}));
|
||||
}
|
||||
@@ -305,7 +331,10 @@ namespace AntSK.Domain.Domain.Service
|
||||
"application/pdf",
|
||||
"application/json",
|
||||
"text/x-markdown",
|
||||
"text/markdown"
|
||||
"text/markdown",
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/tiff"
|
||||
};
|
||||
|
||||
string[] exceptExts = [".md", ".pdf"];
|
||||
|
||||
@@ -18,6 +18,8 @@ using AntSK.Domain.Domain.Model.Enum;
|
||||
using AntSK.LLM.LLamaFactory;
|
||||
using System.Reflection;
|
||||
using DocumentFormat.OpenXml.Drawing;
|
||||
using Microsoft.KernelMemory;
|
||||
using OpenCvSharp.ML;
|
||||
|
||||
namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
@@ -57,7 +59,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
var chatHttpClient = OpenAIHttpClientHandlerUtil.GetHttpClient(chatModel.EndPoint);
|
||||
|
||||
var builder = Kernel.CreateBuilder();
|
||||
WithTextGenerationByAIType(builder, app, chatModel, chatHttpClient);
|
||||
WithTextGenerationByAIType(builder, chatModel, chatHttpClient);
|
||||
|
||||
_kernel = builder.Build();
|
||||
RegisterPluginsWithKernel(_kernel);
|
||||
@@ -69,7 +71,18 @@ namespace AntSK.Domain.Domain.Service
|
||||
//}
|
||||
}
|
||||
|
||||
private void WithTextGenerationByAIType(IKernelBuilder builder, Apps app, AIModels chatModel, HttpClient chatHttpClient)
|
||||
public Kernel GetKernelByAIModelID(string modelid)
|
||||
{
|
||||
var chatModel = _aIModels_Repositories.GetById(modelid);
|
||||
var chatHttpClient = OpenAIHttpClientHandlerUtil.GetHttpClient(chatModel.EndPoint);
|
||||
var builder = Kernel.CreateBuilder();
|
||||
WithTextGenerationByAIType(builder, chatModel, chatHttpClient);
|
||||
_kernel = builder.Build();
|
||||
RegisterPluginsWithKernel(_kernel);
|
||||
return _kernel;
|
||||
}
|
||||
|
||||
private void WithTextGenerationByAIType(IKernelBuilder builder,AIModels chatModel, HttpClient chatHttpClient)
|
||||
{
|
||||
switch (chatModel.AIType)
|
||||
{
|
||||
@@ -96,7 +109,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
|
||||
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, app.Id));
|
||||
builder.Services.AddKeyedSingleton<ITextGenerationService>("spark-desk", new SparkDeskTextCompletion(options, chatModel.Id));
|
||||
break;
|
||||
|
||||
case Model.Enum.AIType.DashScope:
|
||||
|
||||
@@ -8,6 +8,7 @@ using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -67,7 +68,9 @@ namespace AntSK.Domain.Domain.Service
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
process.WaitForExit();
|
||||
OnLogMessageReceived("--------------------完成--------------------");
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
await cmdTask;
|
||||
}
|
||||
|
||||
public async Task StartLLamaFactory(string modelName, string templateName)
|
||||
@@ -106,7 +109,10 @@ namespace AntSK.Domain.Domain.Service
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
process.WaitForExit();
|
||||
|
||||
OnLogMessageReceived("--------------------完成--------------------");
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
await cmdTask;
|
||||
}
|
||||
|
||||
private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace AntSK.Domain.Repositories
|
||||
/// </summary>
|
||||
public string? EmbeddingModelID { get; set; }
|
||||
|
||||
public string? ImageModelID { get; set; }
|
||||
/// <summary>
|
||||
/// 温度
|
||||
/// </summary>
|
||||
@@ -53,6 +54,7 @@ namespace AntSK.Domain.Repositories
|
||||
/// <summary>
|
||||
/// 提示词
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "varchar(2000)")]
|
||||
public string? Prompt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -76,5 +78,28 @@ namespace AntSK.Domain.Repositories
|
||||
/// API调用秘钥
|
||||
/// </summary>
|
||||
public string? SecretKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 相似度
|
||||
/// </summary>
|
||||
[SugarColumn(DefaultValue = "70")]
|
||||
public double Relevance { get; set; } = 70f;
|
||||
|
||||
/// <summary>
|
||||
/// 提问最大token数
|
||||
/// </summary>
|
||||
[SugarColumn(DefaultValue = "2048")]
|
||||
public int MaxAskPromptSize { get; set; } = 2048;
|
||||
/// <summary>
|
||||
/// 向量匹配数
|
||||
/// </summary>
|
||||
[SugarColumn(DefaultValue = "3")]
|
||||
public int MaxMatchesCount { get; set; } = 3;
|
||||
|
||||
/// <summary>
|
||||
/// 回答最大token数
|
||||
/// </summary>
|
||||
[SugarColumn(DefaultValue = "2048")]
|
||||
public int AnswerTokens { get; set; } = 2048;
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,7 @@ namespace AntSK.Domain.Repositories
|
||||
[SugarColumn(DefaultValue = "49")]
|
||||
public int OverlappingTokens { get; set; } = 49;
|
||||
|
||||
|
||||
[SugarColumn(DefaultValue = "0")]
|
||||
public int IsOCR { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,5 +250,16 @@ namespace AntSK.Domain.Utils
|
||||
|
||||
return nameValueCollection.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 忽略大小写匹配
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ComparisonIgnoreCase(this string s, string value)
|
||||
{
|
||||
return s.Equals(value, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
39
src/AntSK.Domain/Utils/ImageUtils.cs
Normal file
39
src/AntSK.Domain/Utils/ImageUtils.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain.Utils
|
||||
{
|
||||
public class ImageUtils
|
||||
{
|
||||
public static string BitmapToBase64(Bitmap bitmap)
|
||||
{
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
{
|
||||
// 保存为JPEG格式,也可以选择Png,Gif等等
|
||||
bitmap.Save(memoryStream, ImageFormat.Jpeg);
|
||||
|
||||
// 获取内存流的字节数组
|
||||
byte[] imageBytes = memoryStream.ToArray();
|
||||
|
||||
// 将字节转换为Base64字符串
|
||||
string base64String = Convert.ToBase64String(imageBytes);
|
||||
return base64String;
|
||||
}
|
||||
}
|
||||
public static List<string> BitmapListToBase64(Bitmap[] bitmaps)
|
||||
{
|
||||
List<string> base64Strings = new List<string>();
|
||||
|
||||
foreach (Bitmap bitmap in bitmaps)
|
||||
{
|
||||
base64Strings.Add(BitmapToBase64(bitmap));
|
||||
}
|
||||
return base64Strings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import subprocess
|
||||
import shlex
|
||||
import os
|
||||
class Start(object):
|
||||
|
||||
def __init__(self,model_name_or_path):
|
||||
self.model_name_or_path=model_name_or_path
|
||||
|
||||
def StartCommand(self):
|
||||
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
|
||||
os.environ['API_PORT'] = '8000'
|
||||
# 构建要执行的命令
|
||||
command = (
|
||||
'python api_demo.py'
|
||||
' --model_name_or_path E:/model/Qwen1.5-0.5B-Chat_back'
|
||||
' --template default '
|
||||
)
|
||||
|
||||
# 使用shlex.split()去安全地分割命令字符串
|
||||
command = shlex.split(command)
|
||||
|
||||
# 执行命令
|
||||
subprocess.run(command, shell=True)
|
||||
|
||||
if __name__ == "__main__":
|
||||
star= Start('model_name_or_path')
|
||||
star.StartCommand()
|
||||
@@ -1,49 +0,0 @@
|
||||
from llmtuner import ChatModel
|
||||
from llmtuner.extras.misc import torch_gc
|
||||
|
||||
|
||||
try:
|
||||
import platform
|
||||
|
||||
if platform.system() != "Windows":
|
||||
import readline # noqa: F401
|
||||
except ImportError:
|
||||
print("Install `readline` for a better experience.")
|
||||
|
||||
|
||||
def main():
|
||||
chat_model = ChatModel()
|
||||
messages = []
|
||||
print("Welcome to the CLI application, use `clear` to remove the history, use `exit` to exit the application.")
|
||||
|
||||
while True:
|
||||
try:
|
||||
query = input("\nUser: ")
|
||||
except UnicodeDecodeError:
|
||||
print("Detected decoding error at the inputs, please set the terminal encoding to utf-8.")
|
||||
continue
|
||||
except Exception:
|
||||
raise
|
||||
|
||||
if query.strip() == "exit":
|
||||
break
|
||||
|
||||
if query.strip() == "clear":
|
||||
messages = []
|
||||
torch_gc()
|
||||
print("History has been removed.")
|
||||
continue
|
||||
|
||||
messages.append({"role": "user", "content": query})
|
||||
print("Assistant: ", end="", flush=True)
|
||||
|
||||
response = ""
|
||||
for new_text in chat_model.stream_chat(messages):
|
||||
print(new_text, end="", flush=True)
|
||||
response += new_text
|
||||
print()
|
||||
messages.append({"role": "assistant", "content": response})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,10 +0,0 @@
|
||||
from llmtuner import Evaluator
|
||||
|
||||
|
||||
def main():
|
||||
evaluator = Evaluator()
|
||||
evaluator.eval()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,9 +0,0 @@
|
||||
from llmtuner import export_model
|
||||
|
||||
|
||||
def main():
|
||||
export_model()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,14 +0,0 @@
|
||||
from llmtuner import run_exp
|
||||
|
||||
|
||||
def main():
|
||||
run_exp()
|
||||
|
||||
|
||||
def _mp_fn(index):
|
||||
# For xla_spawn (TPUs)
|
||||
main()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,11 +0,0 @@
|
||||
from llmtuner import create_ui
|
||||
|
||||
|
||||
def main():
|
||||
demo = create_ui()
|
||||
demo.queue()
|
||||
demo.launch(server_name="0.0.0.0", share=False, inbrowser=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,11 +0,0 @@
|
||||
from llmtuner import create_web_demo
|
||||
|
||||
|
||||
def main():
|
||||
demo = create_web_demo()
|
||||
demo.queue()
|
||||
demo.launch(server_name="0.0.0.0", share=False, inbrowser=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,4 +1,4 @@
|
||||
torch>=1.13.1
|
||||
torch>=1.13.1 --index-url https://download.pytorch.org/whl/cu121
|
||||
transformers>=4.37.2
|
||||
datasets>=2.14.3
|
||||
accelerate>=0.27.2
|
||||
@@ -16,3 +16,5 @@ sse-starlette
|
||||
matplotlib
|
||||
fire
|
||||
modelscope
|
||||
langchain-community
|
||||
sentence_transformers
|
||||
19
src/AntSK.OCR/AntSK.OCR.csproj
Normal file
19
src/AntSK.OCR/AntSK.OCR.csproj
Normal file
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.KernelMemory.Core" Version="0.35.240321.1" />
|
||||
<PackageReference Include="OpenCvSharp4.runtime.win" Version="4.9.0.20240103" />
|
||||
<PackageReference Include="Sdcb.OpenCvSharp4.mini.runtime.debian.12-x64" Version="4.8.0.20231125" />
|
||||
<PackageReference Include="Sdcb.OpenVINO" Version="0.6.4" />
|
||||
<PackageReference Include="Sdcb.OpenVINO.PaddleOCR.Models.Online" Version="0.6.2" />
|
||||
<PackageReference Include="Sdcb.OpenVINO.PaddleOCR" Version="0.6.3" />
|
||||
<PackageReference Include="Sdcb.OpenVINO.runtime.ubuntu.22.04-x64" Version="2024.0.0" />
|
||||
<PackageReference Include="Sdcb.OpenVINO.runtime.win-x64" Version="2024.0.0" />
|
||||
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
56
src/AntSK.OCR/AntSKOcrEngine.cs
Normal file
56
src/AntSK.OCR/AntSKOcrEngine.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Microsoft.KernelMemory.DataFormats;
|
||||
using Sdcb.OpenVINO.PaddleOCR;
|
||||
using Sdcb.OpenVINO.PaddleOCR.Models.Online;
|
||||
using Sdcb.OpenVINO.PaddleOCR.Models;
|
||||
using OpenCvSharp;
|
||||
|
||||
namespace AntSK.OCR
|
||||
{
|
||||
/// <summary>
|
||||
/// OCR
|
||||
/// </summary>
|
||||
public class AntSKOcrEngine : IOcrEngine
|
||||
{
|
||||
FullOcrModel model;
|
||||
public Task<string> ExtractTextFromImageAsync(Stream imageContent, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
model = OnlineFullModels.ChineseV4.DownloadAsync().Result;
|
||||
}
|
||||
using (PaddleOcrAll all = new(model)
|
||||
{
|
||||
AllowRotateDetection = true,
|
||||
Enable180Classification = true,
|
||||
})
|
||||
{
|
||||
Mat src = Cv2.ImDecode(StreamToByte(imageContent), ImreadModes.Color);
|
||||
PaddleOcrResult result = all.Run(src);
|
||||
return Task.FromResult(result.Text);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
return Task.FromResult("");
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] StreamToByte(Stream stream)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
byte[] buffer = new byte[1024]; //自定义大小,例如 1024
|
||||
int bytesRead;
|
||||
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
memoryStream.Write(buffer, 0, bytesRead);
|
||||
}
|
||||
byte[] bytes = memoryStream.ToArray();
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docker", "Docker", "{9F2E19
|
||||
..\docker-compose.simple.yml = ..\docker-compose.simple.yml
|
||||
..\docker-compose.yml = ..\docker-compose.yml
|
||||
..\Dockerfile = ..\Dockerfile
|
||||
..\Dockerfile-py = ..\Dockerfile-py
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MiddleWare", "MiddleWare", "{40DDB1DC-571B-4A95-9F34-47F52981C511}"
|
||||
@@ -24,6 +25,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntSK.Test", "AntSK.Test\An
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntSK.LLamaFactory", "AntSK.LLamaFactory\AntSK.LLamaFactory.csproj", "{664DFA1F-68B7-49C7-B889-FA14D1756D3D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntSK.OCR", "AntSK.OCR\AntSK.OCR.csproj", "{6195F7AA-18C2-4372-85CA-11FC4B522686}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Settings", "Settings", "{EB227FAB-6060-4271-9A0A-6C99C7965126}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
NuGet.config = NuGet.config
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -54,6 +62,10 @@ Global
|
||||
{664DFA1F-68B7-49C7-B889-FA14D1756D3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{664DFA1F-68B7-49C7-B889-FA14D1756D3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{664DFA1F-68B7-49C7-B889-FA14D1756D3D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6195F7AA-18C2-4372-85CA-11FC4B522686}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6195F7AA-18C2-4372-85CA-11FC4B522686}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6195F7AA-18C2-4372-85CA-11FC4B522686}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6195F7AA-18C2-4372-85CA-11FC4B522686}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -7,14 +7,19 @@
|
||||
<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>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="llamafactory\**" />
|
||||
<Content Remove="llamafactory\**" />
|
||||
<EmbeddedResource Remove="llamafactory\**" />
|
||||
<None Remove="llamafactory\**" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.2" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Downloader" Version="3.0.6" />
|
||||
<PackageReference Include="Downloader" Version="3.0.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -22,11 +27,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="plugins\KMSPlugin\Ask1\skprompt.txt">
|
||||
<None Update="plugins\**">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="plugins\KMSPlugin\Ask\skprompt.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using AntSK.Domain.Options;
|
||||
using AntSK.Domain;
|
||||
using AntSK.Domain.Domain.Model.Excel;
|
||||
using AntSK.Domain.Options;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace AntSK.Controllers
|
||||
@@ -41,5 +43,17 @@ namespace AntSK.Controllers
|
||||
|
||||
return Ok(uploads);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下载模板
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> DownExcelTemplate()
|
||||
{
|
||||
var list = new List<KMSExcelModel>();
|
||||
var file = ExeclHelper.ListToExcel<KMSExcelModel>(list.ToArray(), "AntSK导入模板");
|
||||
return File(file, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "AntSK导入模板.xlsx");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
using AntSK.Domain.Repositories;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace AntSK.Controllers
|
||||
{
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class InitController : ControllerBase
|
||||
{
|
||||
private readonly IApps_Repositories _repository;
|
||||
|
||||
public InitController(IApps_Repositories repository)
|
||||
{
|
||||
_repository = repository;
|
||||
}
|
||||
/// <summary>
|
||||
/// 初始化DB 和表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public IActionResult InitTable()
|
||||
{
|
||||
_repository.GetDB().DbMaintenance.CreateDatabase();
|
||||
_repository.GetDB().CodeFirst.InitTables(typeof(Apps));
|
||||
_repository.GetDB().CodeFirst.InitTables(typeof(Kmss));
|
||||
_repository.GetDB().CodeFirst.InitTables(typeof(KmsDetails));
|
||||
_repository.GetDB().CodeFirst.InitTables(typeof(Users));
|
||||
_repository.GetDB().CodeFirst.InitTables(typeof(Apis));
|
||||
_repository.GetDB().CodeFirst.InitTables(typeof(AIModels));
|
||||
//创建vector插件如果数据库没有则需要提供支持向量的数据库
|
||||
_repository.GetDB().Ado.ExecuteCommandAsync($"CREATE EXTENSION IF NOT EXISTS vector;");
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,17 @@
|
||||
using AntSK.BackgroundTask;
|
||||
using AntDesign;
|
||||
using AntSK.BackgroundTask;
|
||||
using AntSK.Domain.Common.Map;
|
||||
using AntSK.Domain.Domain.Interface;
|
||||
using AntSK.Domain.Domain.Model;
|
||||
using AntSK.Domain.Domain.Model.Enum;
|
||||
using AntSK.Domain.Domain.Service;
|
||||
using AntSK.Domain.Repositories;
|
||||
using AntSK.Domain.Utils;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AntSK.Controllers
|
||||
{
|
||||
@@ -17,14 +24,17 @@ namespace AntSK.Controllers
|
||||
{
|
||||
private readonly IKmsDetails_Repositories _kmsDetailsRepositories;
|
||||
private readonly BackgroundTaskBroker<ImportKMSTaskReq> _taskBroker;
|
||||
private readonly IKernelService _kernelService;
|
||||
|
||||
public KMSController(
|
||||
IKmsDetails_Repositories kmsDetailsRepositories,
|
||||
BackgroundTaskBroker<ImportKMSTaskReq> taskBroker
|
||||
BackgroundTaskBroker<ImportKMSTaskReq> taskBroker,
|
||||
IKernelService kernelService
|
||||
)
|
||||
{
|
||||
_kmsDetailsRepositories = kmsDetailsRepositories;
|
||||
_taskBroker = taskBroker;
|
||||
_kernelService = kernelService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -35,7 +45,6 @@ namespace AntSK.Controllers
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> ImportKMSTask(ImportKMSTaskDTO model)
|
||||
{
|
||||
Console.WriteLine("api/kms/ImportKMSTask 开始");
|
||||
ImportKMSTaskReq req = model.ToDTO<ImportKMSTaskReq>();
|
||||
KmsDetails detail = new KmsDetails()
|
||||
{
|
||||
@@ -48,9 +57,36 @@ namespace AntSK.Controllers
|
||||
|
||||
await _kmsDetailsRepositories.InsertAsync(detail);
|
||||
req.KmsDetail = detail;
|
||||
req.IsQA=model.IsQA;
|
||||
_taskBroker.QueueWorkItem(req);
|
||||
Console.WriteLine("api/kms/ImportKMSTask 结束");
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> QA(QAModel model)
|
||||
{
|
||||
var kernel = _kernelService.GetKernelByAIModelID(model.ChatModelId);
|
||||
var lines = TextChunker.SplitPlainTextLines(model.Context, 299);
|
||||
var paragraphs = TextChunker.SplitPlainTextParagraphs(lines, 4000);
|
||||
KernelFunction jsonFun = kernel.Plugins.GetFunction("KMSPlugin", "QA");
|
||||
|
||||
List<string> qaList = new List<string>();
|
||||
foreach (var para in paragraphs)
|
||||
{
|
||||
var qaresult = await kernel.InvokeAsync(function: jsonFun, new KernelArguments() { ["input"] = para });
|
||||
var qaListStr = qaresult.GetValue<string>().ConvertToString();
|
||||
|
||||
string pattern = @"Q\d+:.*?A\d+:.*?(?=(Q\d+:|$))";
|
||||
RegexOptions options = RegexOptions.Singleline;
|
||||
|
||||
foreach (Match match in Regex.Matches(qaListStr, pattern, options))
|
||||
{
|
||||
qaList.Add(match.Value.Trim()); // Trim用于删除可能的首尾空格
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Ok(qaList);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,45 +24,57 @@
|
||||
<IconPicker @bind-Value="@context.Icon"></IconPicker>
|
||||
</FormItem>
|
||||
<FormItem Label="类型" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<RadioGroup @bind-Value="context.Type">
|
||||
<RadioGroup @bind-Value="context.Type" OnChange="OnAppTypeChange" TValue="string">
|
||||
<Radio RadioButton Value="@AppType.chat.ToString()">会话应用</Radio>
|
||||
<Radio RadioButton Value="@AppType.kms.ToString()">知识库</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem Label="描述" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Input Placeholder="请输入描述" @bind-Value="@context.Describe" />
|
||||
</FormItem>
|
||||
<Radio RadioButton Value="@AppType.kms.ToString()">知识库</Radio>
|
||||
<Radio RadioButton Value="@AppType.img.ToString()">做图应用</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem Label="描述" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Input Placeholder="请输入描述" @bind-Value="@context.Describe" />
|
||||
</FormItem>
|
||||
|
||||
<FormItem Label="会话模型" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Select DataSource="@_chatList"
|
||||
@bind-Value="@context.ChatModelID"
|
||||
ValueProperty="c=>c.Id"
|
||||
LabelProperty="c=>'【'+c.AIType.ToString()+'】'+c.ModelDescription">
|
||||
</Select>
|
||||
<Button Type="@ButtonType.Link" OnClick="NavigateModelList">去创建</Button>
|
||||
</FormItem>
|
||||
<FormItem Label="向量模型" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Select DataSource="@_embedignList"
|
||||
@bind-Value="@context.EmbeddingModelID"
|
||||
<FormItem Label="会话模型" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Select DataSource="@_chatList"
|
||||
@bind-Value="@context.ChatModelID"
|
||||
ValueProperty="c=>c.Id"
|
||||
LabelProperty="c=>'【'+c.AIType.ToString()+'】'+c.ModelDescription">
|
||||
</Select>
|
||||
<Button Type="@ButtonType.Link" OnClick="NavigateModelList">去创建</Button>
|
||||
</FormItem>
|
||||
@if (@context.Type == AppType.chat.ToString())
|
||||
@if (@context.Type != AppType.img.ToString())
|
||||
{
|
||||
|
||||
<FormItem Label="向量模型" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Select DataSource="@_embedingList"
|
||||
@bind-Value="@context.EmbeddingModelID"
|
||||
ValueProperty="c=>c.Id"
|
||||
LabelProperty="c=>'【'+c.AIType.ToString()+'】'+c.ModelDescription">
|
||||
</Select>
|
||||
<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" />
|
||||
</FormItem>
|
||||
|
||||
<FormItem Label="温度系数" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<span>更确定</span>
|
||||
<Slider TValue="double" Style="display: inline-block;width: 300px; " Min="0" Max="100" DefaultValue="70" @bind-Value="@context.Temperature" />
|
||||
<span>更发散</span>
|
||||
</FormItem>
|
||||
|
||||
<FormItem Label="API插件列表" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
}
|
||||
else
|
||||
{
|
||||
<FormItem Label="图片模型" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Select DataSource="@_imageList"
|
||||
@bind-Value="@context.ImageModelID"
|
||||
ValueProperty="c=>c.Id"
|
||||
LabelProperty="c=>'【'+c.AIType.ToString()+'】'+c.ModelDescription">
|
||||
</Select>
|
||||
<Button Type="@ButtonType.Link" OnClick="NavigateModelList">去创建</Button>
|
||||
</FormItem>
|
||||
}
|
||||
@if (@context.Type == AppType.chat.ToString())
|
||||
{
|
||||
<FormItem Label="API插件列表" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Select Mode="multiple"
|
||||
@bind-Values="apiIds"
|
||||
Placeholder="选择API插件, 选择后会开启自动调用"
|
||||
@@ -110,6 +122,19 @@
|
||||
}
|
||||
</SelectOptions>
|
||||
</Select>
|
||||
<Button Type="@ButtonType.Link" OnClick="NavigateKmsList">去创建</Button>
|
||||
</FormItem>
|
||||
<FormItem Label="提问最大token数" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<AntDesign.InputNumber @bind-Value="context.MaxAskPromptSize" PlaceHolder="提问最大token数"></AntDesign.InputNumber>
|
||||
</FormItem>
|
||||
<FormItem Label="回答最大token数" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<AntDesign.InputNumber @bind-Value="context.AnswerTokens" PlaceHolder="回答最大token数"></AntDesign.InputNumber>
|
||||
</FormItem>
|
||||
<FormItem Label="向量匹配数" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<AntDesign.InputNumber @bind-Value="context.MaxMatchesCount" PlaceHolder="向量匹配数"></AntDesign.InputNumber>
|
||||
</FormItem>
|
||||
<FormItem Label="最低相似度(%)" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Slider TValue="double" Style="display: inline-block;width: 300px; " Min="0" Max="100" DefaultValue="70" @bind-Value="@context.Relevance" />
|
||||
</FormItem>
|
||||
}
|
||||
<FormItem Label=" " Style="margin-top:32px" WrapperCol="LayoutModel._submitFormLayout.WrapperCol">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AntDesign;
|
||||
using AntSK.Domain.Domain.Model.Constant;
|
||||
using AntSK.Domain.Domain.Model.Enum;
|
||||
using AntSK.Domain.Domain.Service;
|
||||
using AntSK.Domain.Repositories;
|
||||
@@ -45,7 +46,8 @@ namespace AntSK.Pages.AppPage
|
||||
public Dictionary<string, string> _funList = new Dictionary<string, string>();
|
||||
|
||||
private List<AIModels> _chatList;
|
||||
private List<AIModels> _embedignList;
|
||||
private List<AIModels> _embedingList;
|
||||
private List<AIModels> _imageList;
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
@@ -53,7 +55,8 @@ namespace AntSK.Pages.AppPage
|
||||
_apiList = _apis_Repositories.GetList();
|
||||
var models=_aimodels_Repositories.GetList();
|
||||
_chatList = models.Where(p => p.AIModelType == AIModelType.Chat).ToList();
|
||||
_embedignList = models.Where(p => p.AIModelType == AIModelType.Embedding).ToList();
|
||||
_embedingList = models.Where(p => p.AIModelType == AIModelType.Embedding).ToList();
|
||||
_imageList = models.Where(p => p.AIModelType == AIModelType.Image).ToList();
|
||||
|
||||
_functionService.SearchMarkedMethods();
|
||||
foreach (var func in _functionService.Functions)
|
||||
@@ -87,7 +90,14 @@ namespace AntSK.Pages.AppPage
|
||||
}
|
||||
_appModel.KmsIdList = string.Join(",", kmsIds);
|
||||
}
|
||||
|
||||
if (_appModel.Type == AppType.kms.ToString())
|
||||
{
|
||||
if (string.IsNullOrEmpty(_appModel.Prompt)|| !_appModel.Prompt.Contains("{{$doc}}") || !_appModel.Prompt.Contains("{{$input}}"))
|
||||
{
|
||||
_ = Message.Error("知识库提示词必须包含 {{$doc}} 和 {{$input}}", 2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (apiIds.IsNotNull())
|
||||
{
|
||||
_appModel.ApiFunctionList = string.Join(",", apiIds);
|
||||
@@ -97,7 +107,7 @@ namespace AntSK.Pages.AppPage
|
||||
|
||||
_appModel.NativeFunctionList = string.Join(",", funIds);
|
||||
}
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(AppId))
|
||||
{
|
||||
//新增
|
||||
@@ -133,6 +143,25 @@ namespace AntSK.Pages.AppPage
|
||||
{
|
||||
NavigationManager.NavigateTo("/setting/modellist");
|
||||
}
|
||||
|
||||
private void NavigateKmsList()
|
||||
{
|
||||
NavigationManager.NavigateTo("/KmsList");
|
||||
}
|
||||
|
||||
|
||||
private void OnAppTypeChange(string value)
|
||||
{
|
||||
if (value == AppType.kms.ToString() && string.IsNullOrEmpty( _appModel.Prompt))
|
||||
{
|
||||
_appModel.Prompt = KmsConstantcs.KmsPrompt;
|
||||
}
|
||||
|
||||
if (value == AppType.chat.ToString())
|
||||
{
|
||||
_appModel.Prompt = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -58,6 +58,10 @@
|
||||
<Tag Color="@PresetColor.Green.ToString()">知识库</Tag>
|
||||
|
||||
}
|
||||
else if (context.Type == AppType.img.ToString())
|
||||
{
|
||||
<Tag Color="@PresetColor.Red.ToString()">做图应用</Tag>
|
||||
}
|
||||
</DescriptionTemplate>
|
||||
</CardMeta>
|
||||
</Card>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
@inherits AuthComponentBase
|
||||
|
||||
<GridRow Gutter="(16, 16)">
|
||||
<GridCol Span="12">
|
||||
<GridCol Span="14">
|
||||
<Card Style="height:75vh;overflow: auto;">
|
||||
<TitleTemplate>
|
||||
<Icon Type="setting" /> 选择应用
|
||||
@@ -30,7 +30,7 @@
|
||||
</Body>
|
||||
</Card>
|
||||
</GridCol>
|
||||
<GridCol Span="12">
|
||||
<GridCol Span="10">
|
||||
<Card Style="height: 75vh;overflow: auto;">
|
||||
<TitleTemplate>
|
||||
<Icon Type="search" /> 调试结果
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
</GridCol>
|
||||
<GridCol Span="23">
|
||||
<div class="chat-bubble received">
|
||||
@((MarkupString)(item.HtmlAnswers))
|
||||
@((MarkupString)(item.Context))
|
||||
</div>
|
||||
|
||||
</GridCol>
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
using AntSK.Domain.Domain.Interface;
|
||||
using AntSK.Domain.Domain.Model;
|
||||
using AntSK.Domain.Domain.Model.Dto;
|
||||
using AntSK.Domain.Domain.Model.Enum;
|
||||
using AntSK.Domain.Repositories;
|
||||
using AntSK.Domain.Utils;
|
||||
using AntSK.LLM.StableDiffusion;
|
||||
using Blazored.LocalStorage;
|
||||
using Markdig;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace AntSK.Pages.ChatPage.Components
|
||||
@@ -47,7 +51,7 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
await LoadData();
|
||||
LoadData();
|
||||
var msgs = await _localStorage.GetItemAsync<List<MessageInfo>>("msgs");
|
||||
if (msgs != null && msgs.Count > 0)
|
||||
{
|
||||
@@ -57,12 +61,12 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await LoadData();
|
||||
LoadData();
|
||||
}
|
||||
|
||||
private async Task LoadData()
|
||||
private void LoadData()
|
||||
{
|
||||
app =await _apps_Repositories.GetFirstAsync(p => p.Id == AppId);
|
||||
app = _apps_Repositories.GetFirst(p => p.Id == AppId);
|
||||
}
|
||||
|
||||
protected async Task OnClearAsync()
|
||||
@@ -76,7 +80,9 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
{
|
||||
MessageList.Clear();
|
||||
await _localStorage.SetItemAsync<List<MessageInfo>>("msgs", MessageList);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
_ = Message.Info("清理成功");
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -107,9 +113,7 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
Sendding = true;
|
||||
await SendAsync(_messageInput,filePath);
|
||||
_messageInput = "";
|
||||
Sendding = false;
|
||||
|
||||
await _localStorage.SetItemAsync<List<MessageInfo>>("msgs", MessageList);
|
||||
Sendding = false;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
@@ -144,23 +148,48 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
{
|
||||
history = await _chatService.GetChatHistory(MessageList);
|
||||
}
|
||||
|
||||
switch (app.Type)
|
||||
{
|
||||
case "chat" when filePath == null||app.EmbeddingModelID.IsNull():
|
||||
//普通会话
|
||||
await SendChat(questions, history, app);
|
||||
break;
|
||||
|
||||
default:
|
||||
//知识库问答
|
||||
await SendKms(questions, history, app, filePath);
|
||||
break;
|
||||
if (app.Type == AppType.chat.ToString() && (filePath == null || app.EmbeddingModelID.IsNull()))
|
||||
{
|
||||
await SendChat(questions, history, app);
|
||||
}
|
||||
else if (app.Type == AppType.kms.ToString() || filePath != null || app.EmbeddingModelID.IsNotNull())
|
||||
{
|
||||
await SendKms(questions, history, app, filePath);
|
||||
|
||||
}
|
||||
else if (app.Type == AppType.img.ToString())
|
||||
{
|
||||
await SendImg(questions,app);
|
||||
}
|
||||
|
||||
//缓存消息记录
|
||||
if (app.Type != AppType.img.ToString())
|
||||
{
|
||||
await _localStorage.SetItemAsync<List<MessageInfo>>("msgs", MessageList);
|
||||
}
|
||||
|
||||
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private async Task SendImg(string questions,Apps app)
|
||||
{
|
||||
MessageInfo info = new MessageInfo();
|
||||
info.ID = Guid.NewGuid().ToString();
|
||||
info.CreateTime = DateTime.Now;
|
||||
var base64= await _chatService.SendImgByAppAsync(app, questions);
|
||||
if (string.IsNullOrEmpty(base64))
|
||||
{
|
||||
info.Context = "生成失败";
|
||||
}
|
||||
else
|
||||
{
|
||||
info.Context = $"<img src=\"data:image/jpeg;base64,{base64}\" alt=\"Base64 Image\" />";
|
||||
}
|
||||
MessageList.Add(info);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送知识库问答
|
||||
/// </summary>
|
||||
@@ -179,14 +208,13 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
info = new MessageInfo();
|
||||
info.ID = Guid.NewGuid().ToString();
|
||||
info.Context = content.ConvertToString();
|
||||
info.HtmlAnswers = content.ConvertToString();
|
||||
info.CreateTime = DateTime.Now;
|
||||
|
||||
MessageList.Add(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
info.HtmlAnswers += content.ConvertToString();
|
||||
info.Context += content.ConvertToString();
|
||||
await Task.Delay(50);
|
||||
}
|
||||
await InvokeAsync(StateHasChanged);
|
||||
@@ -214,14 +242,13 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
info = new MessageInfo();
|
||||
info.ID = Guid.NewGuid().ToString();
|
||||
info.Context = content.ConvertToString();
|
||||
info.HtmlAnswers = content.ConvertToString();
|
||||
info.CreateTime = DateTime.Now;
|
||||
|
||||
MessageList.Add(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
info.HtmlAnswers += content.ConvertToString();
|
||||
info.Context += content.ConvertToString();
|
||||
await Task.Delay(50);
|
||||
}
|
||||
await InvokeAsync(StateHasChanged);
|
||||
@@ -235,7 +262,7 @@ namespace AntSK.Pages.ChatPage.Components
|
||||
if (info.IsNotNull())
|
||||
{
|
||||
// info!.HtmlAnswers = markdown.Transform(info.HtmlAnswers);
|
||||
info!.HtmlAnswers = Markdown.ToHtml(info.HtmlAnswers);
|
||||
info!.Context = Markdown.ToHtml(info.Context);
|
||||
|
||||
}
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
@@ -50,6 +50,9 @@
|
||||
<FormItem Label="重叠部分(token)" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<AntDesign.InputNumber @bind-Value="context.OverlappingTokens" PlaceHolder="重叠部分"></AntDesign.InputNumber>
|
||||
</FormItem>
|
||||
<FormItem Label="是否开启OCR" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Switch @bind-Value="@isOcr" />
|
||||
</FormItem>
|
||||
|
||||
<FormItem Label=" " Style="margin-top:32px" WrapperCol="LayoutModel._submitFormLayout.WrapperCol">
|
||||
<Button Type="primary" HtmlType="submit">
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace AntSK.Pages.KmsPage
|
||||
|
||||
private List<AIModels> _chatList { get; set; }
|
||||
private List<AIModels> _embeddingList { get; set; }
|
||||
|
||||
private bool isOcr { get; set; }
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
@@ -36,6 +38,7 @@ namespace AntSK.Pages.KmsPage
|
||||
{
|
||||
//查看
|
||||
_kmsModel = await _kmss_Repositories.GetFirstAsync(p => p.Id == KmsId);
|
||||
isOcr = _kmsModel.IsOCR == 1;
|
||||
}
|
||||
}
|
||||
private void HandleSubmit()
|
||||
@@ -51,6 +54,10 @@ namespace AntSK.Pages.KmsPage
|
||||
_ = Message.Error("行切片需小于段落切片!", 2);
|
||||
return;
|
||||
}
|
||||
if (isOcr)
|
||||
{
|
||||
_kmsModel.IsOCR = 1;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(KmsId))
|
||||
{
|
||||
|
||||
84
src/AntSK/Pages/KmsPage/Components/KmsTest.razor
Normal file
84
src/AntSK/Pages/KmsPage/Components/KmsTest.razor
Normal file
@@ -0,0 +1,84 @@
|
||||
@namespace AntSK.Pages.KmsPage
|
||||
@using AntSK.Domain.Repositories
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using AntSK.Domain.Domain.Model.Dto
|
||||
@using AntSK.Domain.Domain.Interface
|
||||
@using AntSK.Domain.Domain.Model.Constant
|
||||
@using Microsoft.KernelMemory
|
||||
@inherits AntDomComponentBase
|
||||
|
||||
<GridContent>
|
||||
<Row Gutter="24">
|
||||
<Col Lg="7" Md="24">
|
||||
<TextArea @bind-Value="_msg" MinRows="8"/>
|
||||
<Button Type="@ButtonType.Primary" Style="margin-top:10px;" OnClick="Search">搜索</Button>
|
||||
</Col>
|
||||
<Col Lg="17" Md="24">
|
||||
<AntList DataSource="@_data" TItem="RelevantSource">
|
||||
<ListItem>
|
||||
<ListItemMeta Description="@context.Text">
|
||||
<TitleTemplate>
|
||||
<a>@("文件:" + context.SourceName + " 相似度:" + context.Relevance)</a>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
</ListItem>
|
||||
</AntList>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
</GridContent>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string KmsId { get; set; }
|
||||
|
||||
[Inject]
|
||||
IKMService _kMService { get; set; }
|
||||
[Inject]
|
||||
IKmsDetails_Repositories _kmsDetails_Repositories { get; set; }
|
||||
private MemoryServerless _memory { get; set; }
|
||||
private List<RelevantSource> _data = new List<RelevantSource>();
|
||||
private string _msg;
|
||||
private Dictionary<string, string> fileNameDic = new Dictionary<string, string>();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
_memory=_kMService.GetMemoryByKMS(KmsId);
|
||||
}
|
||||
|
||||
private async Task Search()
|
||||
{
|
||||
_data.Clear();
|
||||
var filters = new MemoryFilter().ByTag(KmsConstantcs.KmsIdTag, KmsId);
|
||||
var searchResult = await _memory.SearchAsync(_msg, index: KmsConstantcs.KmsIndex, filters: [filters]);
|
||||
|
||||
_data.AddRange(
|
||||
searchResult.Results.SelectMany(item => item.Partitions.Select(part => new RelevantSource()
|
||||
{
|
||||
SourceName = GetFileName(item.SourceName),
|
||||
Text = part.Text,
|
||||
Relevance = part.Relevance
|
||||
})).Take(10).ToList()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private string GetFileName(string fileGuidName)
|
||||
{
|
||||
if (fileNameDic.ContainsKey(fileGuidName))
|
||||
{
|
||||
return fileNameDic[fileGuidName];
|
||||
}
|
||||
|
||||
var fileDetail = _kmsDetails_Repositories.GetFirst(p => p.FileGuidName == fileGuidName);
|
||||
if (fileDetail == null)
|
||||
{
|
||||
return fileGuidName;
|
||||
}
|
||||
var fileName = fileDetail.FileName;
|
||||
fileNameDic.Add(fileGuidName, fileName);
|
||||
return fileName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,100 +6,111 @@
|
||||
@using AntSK.Services.Auth
|
||||
@inherits AuthComponentBase
|
||||
|
||||
<div>
|
||||
<PageContainer Title="知识库文档">
|
||||
<ChildContent>
|
||||
<div class="standardList">
|
||||
<Card Class="listCard"
|
||||
Title="知识库文档"
|
||||
Style="margin-top: 24px;"
|
||||
BodyStyle="padding: 0 32px 40px 32px">
|
||||
|
||||
<Extra>
|
||||
<Button Type="@ButtonType.Primary" Style="position: absolute; right:360px; margin-bottom: 8px;" OnClick="Refresh">刷新 </Button>
|
||||
<Dropdown Style="position: absolute; right: 20px; margin-bottom: 8px;">
|
||||
<Overlay>
|
||||
<Menu>
|
||||
@(_fileUpload(() => FileShowModal()))
|
||||
@(_urlUpload(() => UrlShowModal()))
|
||||
@(_textUpload(() => TextShowModal()))
|
||||
</Menu>
|
||||
</Overlay>
|
||||
<Card Class="tabsCard">
|
||||
<CardTabs>
|
||||
<Tabs DefaultActiveKey="1">
|
||||
<TabPane Key="1">
|
||||
<TabTemplate>知识库文档</TabTemplate>
|
||||
<ChildContent>
|
||||
<div class="standardList">
|
||||
<Card Class="listCard"
|
||||
Title="知识库文档">
|
||||
|
||||
<Extra>
|
||||
<Button Type="@ButtonType.Primary" Style="position: absolute; right:360px; margin-bottom: 8px;" OnClick="Refresh">刷新 </Button>
|
||||
<Dropdown Style="position: absolute; right: 20px; margin-bottom: 8px;" Trigger="@(new Trigger[] { Trigger.Click })">
|
||||
<Overlay>
|
||||
<Menu>
|
||||
@(_fileUpload(() => FileShowModal()))
|
||||
@(_urlUpload(() => UrlShowModal()))
|
||||
@(_textUpload(() => TextShowModal()))
|
||||
@(_excelUpload(() => ExcelShowModal()))
|
||||
</Menu>
|
||||
</Overlay>
|
||||
<ChildContent>
|
||||
<Button>导入 <Icon Type="down" /></Button>
|
||||
</ChildContent>
|
||||
</Dropdown>
|
||||
<div class="extraContent" style="margin-right:100px;">
|
||||
<Search Class="extraContentSearch" Placeholder="搜索文档" @bind-Value="_model.Id" />
|
||||
</div>
|
||||
|
||||
</Extra>
|
||||
<ChildContent>
|
||||
<Button>导入 <Icon Type="down" /></Button>
|
||||
</ChildContent>
|
||||
</Dropdown>
|
||||
<div class="extraContent" style="margin-right:100px;">
|
||||
<Search Class="extraContentSearch" Placeholder="搜索文档" @bind-Value="_model.Id" />
|
||||
</div>
|
||||
|
||||
</Extra>
|
||||
<ChildContent>
|
||||
<AntList TItem="KmsDetails"
|
||||
DataSource="_data"
|
||||
ItemLayout="ListItemLayout.Horizontal">
|
||||
<ListItem Actions="@(new[] {
|
||||
<AntList TItem="KmsDetails"
|
||||
DataSource="_data"
|
||||
ItemLayout="ListItemLayout.Horizontal" Size="small">
|
||||
<ListItem Actions="@(new[] {
|
||||
detail(()=> FileDetail(context.Id)) ,
|
||||
delete(async ()=>await DeleteFile(context.Id)) ,
|
||||
})">
|
||||
<ListItemMeta Description="@context.Id">
|
||||
<TitleTemplate>
|
||||
<div>文件ID</div>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
<ListItemMeta Description="@context.Type">
|
||||
<TitleTemplate>
|
||||
<div>文件类型</div>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
@if (@context.Type == "file")
|
||||
{
|
||||
<ListItemMeta Avatar="" Description="@context.FileName">
|
||||
<TitleTemplate>
|
||||
<a>文件名称</a>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
}
|
||||
else if (@context.Type == "url")
|
||||
{
|
||||
<ListItemMeta Avatar="" Description="@context.Url">
|
||||
<TitleTemplate>
|
||||
<a href="@context.Url" target="_blank">Url</a>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
}
|
||||
else if (@context.Type == "text")
|
||||
{
|
||||
<ListItemMeta Avatar="" Description="……">
|
||||
<TitleTemplate>
|
||||
<a>文本内容</a>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
}
|
||||
<ListItemMeta Avatar="" Description="@context.DataCount.ToString()">
|
||||
<TitleTemplate>
|
||||
<a>文档切片数量</a>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
<ListItemMeta Avatar="" Description="@context.Status.ToString()">
|
||||
<TitleTemplate>
|
||||
<a>状态</a>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
<div class="listContent">
|
||||
<div class="listContentItem">
|
||||
<span>创建时间</span>
|
||||
<p>@context.CreateTime.ToString("yyyy-MM-dd HH:mm")</p>
|
||||
</div>
|
||||
</div>
|
||||
</ListItem>
|
||||
</AntList>
|
||||
</ChildContent>
|
||||
</Card>
|
||||
</div>
|
||||
</ChildContent>
|
||||
</PageContainer>
|
||||
</div>
|
||||
<ListItemMeta Description="@context.Id">
|
||||
<TitleTemplate>
|
||||
<div>文件ID</div>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
<ListItemMeta Description="@context.Type">
|
||||
<TitleTemplate>
|
||||
<div>文件类型</div>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
@if (@context.Type == "file" || @context.Type == "excel")
|
||||
{
|
||||
<ListItemMeta Avatar="" Description="@context.FileName">
|
||||
<TitleTemplate>
|
||||
<a>文件名称</a>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
}
|
||||
else if (@context.Type == "url")
|
||||
{
|
||||
<ListItemMeta Avatar="" Description="@context.Url">
|
||||
<TitleTemplate>
|
||||
<a href="@context.Url" target="_blank">Url</a>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
}
|
||||
else if (@context.Type == "text")
|
||||
{
|
||||
<ListItemMeta Avatar="" Description="……">
|
||||
<TitleTemplate>
|
||||
<a>文本内容</a>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
}
|
||||
<ListItemMeta Avatar="" Description="@context.DataCount.ToString()">
|
||||
<TitleTemplate>
|
||||
<a>文档切片数量</a>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
<ListItemMeta Avatar="" Description="@context.Status.ToString()">
|
||||
<TitleTemplate>
|
||||
<a>状态</a>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
<div class="listContent">
|
||||
<div class="listContentItem">
|
||||
<span>创建时间</span>
|
||||
<p>@context.CreateTime.ToString("yyyy-MM-dd HH:mm")</p>
|
||||
</div>
|
||||
</div>
|
||||
</ListItem>
|
||||
</AntList>
|
||||
</ChildContent>
|
||||
</Card>
|
||||
</div>
|
||||
</ChildContent>
|
||||
</TabPane>
|
||||
<TabPane Key="2">
|
||||
<TabTemplate>搜索测试</TabTemplate>
|
||||
<ChildContent>
|
||||
<KmsTest KmsId="@KmsId"></KmsTest>
|
||||
</ChildContent>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</CardTabs>
|
||||
</Card>
|
||||
|
||||
<Modal Title="链接读取"
|
||||
Visible="@_urlVisible"
|
||||
@@ -113,6 +124,12 @@
|
||||
<FormItem Label="URL地址">
|
||||
<Input @bind-Value="@context.Url" />
|
||||
</FormItem>
|
||||
<FormItem Label="切分方式">
|
||||
<RadioGroup @bind-Value="@_isQa">
|
||||
<Radio Value="false">直接切分</Radio>
|
||||
<Radio Value="true">QA切分</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@@ -124,10 +141,16 @@
|
||||
<Form Model="@textModel"
|
||||
LabelColSpan="8"
|
||||
WrapperColSpan="16"
|
||||
@ref="@_textForm">
|
||||
@ref="@_textForm">
|
||||
<FormItem Label="文本内容">
|
||||
<TextArea @bind-Value="@context.Text" Rows="5" />
|
||||
</FormItem>
|
||||
<FormItem Label="切分方式">
|
||||
<RadioGroup @bind-Value="@_isQa">
|
||||
<Radio Value="false">直接切分</Radio>
|
||||
<Radio Value="true">QA切分</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@@ -135,7 +158,7 @@
|
||||
Visible="@_fileVisible"
|
||||
OnOk="@FileHandleOk"
|
||||
OnCancel="@FileHandleCancel"
|
||||
ConfirmLoading="@_fileConfirmLoading">
|
||||
ConfirmLoading="@_fileConfirmLoading">
|
||||
<Upload Action="@("api/File/UploadFile")"
|
||||
Name="file"
|
||||
Drag
|
||||
@@ -147,15 +170,50 @@
|
||||
<Icon Type="inbox" />
|
||||
</p>
|
||||
<p class="ant-upload-text">单击或拖动文件到此区域进行上传</p>
|
||||
@if (km.IsOCR == 1)
|
||||
{
|
||||
<p class="ant-upload-hint">
|
||||
支持 txt、word、pdf、md、excel、ppt、jpeg、png、tiff 等文件。
|
||||
</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p class="ant-upload-hint">
|
||||
支持 txt、word、pdf、md、excel、ppt 等文件。
|
||||
</p>
|
||||
}
|
||||
|
||||
</Upload>
|
||||
<RadioGroup @bind-Value="@_isQa" Style="margin-top:5px;">
|
||||
<Radio Value="false">直接切分</Radio>
|
||||
<Radio Value="true">QA切分</Radio>
|
||||
</RadioGroup>
|
||||
</Modal>
|
||||
|
||||
<Modal Title="Excel导入"
|
||||
Visible="@_excelVisible"
|
||||
OnOk="@ExcelHandleOk"
|
||||
OnCancel="@ExcelHandleCancel"
|
||||
ConfirmLoading="@_excelConfirmLoading">
|
||||
<a href="api/File/DownExcelTemplate" target="_blank">下载模板</a>
|
||||
<Upload Action="@("api/File/UploadFile")"
|
||||
Name="file"
|
||||
Drag
|
||||
Multiple
|
||||
Accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
BeforeUpload="iKMService.BeforeUpload"
|
||||
OnSingleCompleted="iKMService.OnSingleCompleted">
|
||||
<p class="ant-upload-drag-icon">
|
||||
<Icon Type="inbox" />
|
||||
</p>
|
||||
<p class="ant-upload-text">单击或拖动文件到此区域进行上传</p>
|
||||
<p class="ant-upload-hint">
|
||||
支持txt、word、pdf、md、excel、ppt等文件。
|
||||
支持excel文件。
|
||||
</p>
|
||||
</Upload>
|
||||
</Modal>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
RenderFragment _fileUpload(Action clickAction) =>@<MenuItem>
|
||||
<a target="_blank" rel="noopener noreferrer" @onclick="@clickAction">
|
||||
文件导入
|
||||
@@ -174,6 +232,12 @@
|
||||
</a>
|
||||
</MenuItem>;
|
||||
|
||||
RenderFragment _excelUpload(Action clickAction) =>@<MenuItem>
|
||||
<a target="_blank" rel="noopener noreferrer" @onclick="@clickAction">
|
||||
Excel导入
|
||||
</a>
|
||||
</MenuItem>;
|
||||
|
||||
RenderFragment detail(Action clickAction) => @<a key="detail" @onclick="@clickAction">详情</a>;
|
||||
RenderFragment delete(Action clickAction) => @<a key="edit" @onclick="@clickAction">删除</a>;
|
||||
}
|
||||
|
||||
@@ -19,35 +19,6 @@ namespace AntSK.Pages.KmsPage
|
||||
[Parameter]
|
||||
public string KmsId { get; set; }
|
||||
|
||||
private readonly KmsDetails _model = new KmsDetails();
|
||||
|
||||
private bool _urlVisible = false;
|
||||
private bool _urlConfirmLoading = false;
|
||||
|
||||
private bool _fileVisible = false;
|
||||
private bool _fileConfirmLoading = false;
|
||||
|
||||
private bool _textVisible = false;
|
||||
private bool _textConfirmLoading = false;
|
||||
|
||||
private List<FileInfoModel> fileList = new List<FileInfoModel>();
|
||||
|
||||
private Form<UrlModel> _urlForm;
|
||||
private UrlModel urlModel = new UrlModel();
|
||||
|
||||
private Form<TextModel> _textForm;
|
||||
private TextModel textModel = new TextModel();
|
||||
|
||||
private readonly IDictionary<string, ProgressStatus> _pStatus = new Dictionary<string, ProgressStatus>
|
||||
{
|
||||
{"active", ProgressStatus.Active},
|
||||
{"exception", ProgressStatus.Exception},
|
||||
{"normal", ProgressStatus.Normal},
|
||||
{"success", ProgressStatus.Success}
|
||||
};
|
||||
|
||||
private List<KmsDetails> _data = new List<KmsDetails>();
|
||||
|
||||
[Inject]
|
||||
protected IConfirmService _confirmService { get; set; }
|
||||
|
||||
@@ -71,11 +42,49 @@ namespace AntSK.Pages.KmsPage
|
||||
[Inject]
|
||||
protected IHttpService _httpService { get; set; }
|
||||
|
||||
private Kmss km;
|
||||
|
||||
private readonly KmsDetails _model = new KmsDetails();
|
||||
|
||||
private bool _urlVisible = false;
|
||||
private bool _urlConfirmLoading = false;
|
||||
|
||||
private bool _fileVisible = false;
|
||||
private bool _fileConfirmLoading = false;
|
||||
|
||||
private bool _textVisible = false;
|
||||
private bool _textConfirmLoading = false;
|
||||
|
||||
private bool _excelVisible = false;
|
||||
private bool _excelConfirmLoading = false;
|
||||
|
||||
private List<FileInfoModel> fileList = new List<FileInfoModel>();
|
||||
|
||||
private Form<UrlModel> _urlForm;
|
||||
private UrlModel urlModel = new UrlModel();
|
||||
|
||||
private Form<TextModel> _textForm;
|
||||
private TextModel textModel = new TextModel();
|
||||
|
||||
private readonly IDictionary<string, ProgressStatus> _pStatus = new Dictionary<string, ProgressStatus>
|
||||
{
|
||||
{"active", ProgressStatus.Active},
|
||||
{"exception", ProgressStatus.Exception},
|
||||
{"normal", ProgressStatus.Normal},
|
||||
{"success", ProgressStatus.Success}
|
||||
};
|
||||
|
||||
private List<KmsDetails> _data = new List<KmsDetails>();
|
||||
|
||||
|
||||
private bool _isQa { get; set; } = false;
|
||||
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
_data = await _kmsDetails_Repositories.GetListAsync(p => p.KmsId == KmsId);
|
||||
var km = _kmss_Repositories.GetFirst(p => p.Id == KmsId);
|
||||
km = _kmss_Repositories.GetFirst(p => p.Id == KmsId);
|
||||
//使用知识库设置的参数,
|
||||
_memory = iKMService.GetMemoryByKMS(km.Id);
|
||||
}
|
||||
@@ -109,6 +118,7 @@ namespace AntSK.Pages.KmsPage
|
||||
ImportType = ImportType.Url,
|
||||
KmsId = KmsId,
|
||||
Url = urlModel.Url,
|
||||
IsQA = _isQa
|
||||
});
|
||||
_data = await _kmsDetails_Repositories.GetListAsync(p => p.KmsId == KmsId);
|
||||
_urlVisible = false;
|
||||
@@ -149,7 +159,8 @@ namespace AntSK.Pages.KmsPage
|
||||
{
|
||||
ImportType = ImportType.Text,
|
||||
KmsId = KmsId,
|
||||
Text = textModel.Text
|
||||
Text = textModel.Text,
|
||||
IsQA = _isQa
|
||||
});
|
||||
_data = await _kmsDetails_Repositories.GetListAsync(p => p.KmsId == KmsId);
|
||||
_textVisible = false;
|
||||
@@ -187,7 +198,8 @@ namespace AntSK.Pages.KmsPage
|
||||
ImportType = ImportType.File,
|
||||
KmsId = KmsId,
|
||||
FilePath = item.Url,
|
||||
FileName = item.FileName
|
||||
FileName = item.FileName,
|
||||
IsQA=_isQa
|
||||
});
|
||||
}
|
||||
_data = await _kmsDetails_Repositories.GetListAsync(p => p.KmsId == KmsId);
|
||||
@@ -212,19 +224,48 @@ namespace AntSK.Pages.KmsPage
|
||||
_fileVisible = true;
|
||||
}
|
||||
|
||||
private void OnSingleCompleted(UploadInfo fileinfo)
|
||||
#endregion File
|
||||
|
||||
#region Excel
|
||||
private async Task ExcelHandleOk(MouseEventArgs e)
|
||||
{
|
||||
if (fileinfo.File.State == UploadState.Success)
|
||||
try
|
||||
{
|
||||
//文件列表
|
||||
fileList.Add(new FileInfoModel()
|
||||
foreach (var item in iKMService.FileList)
|
||||
{
|
||||
FileName = fileinfo.File.FileName,
|
||||
FilePath = fileinfo.File.Url = fileinfo.File.Response
|
||||
});
|
||||
var result = await _httpService.PostAsync(NavigationManager.BaseUri + "api/KMS/ImportKMSTask", new ImportKMSTaskDTO()
|
||||
{
|
||||
ImportType = ImportType.Excel,
|
||||
KmsId = KmsId,
|
||||
FilePath = item.Url,
|
||||
FileName = item.FileName,
|
||||
IsQA = false
|
||||
});
|
||||
}
|
||||
_data = await _kmsDetails_Repositories.GetListAsync(p => p.KmsId == KmsId);
|
||||
//上传文档
|
||||
_excelVisible = false;
|
||||
iKMService.FileList.Clear();
|
||||
_ = _message.Info("加入队列,进入后台处理中!", 2);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message + " ---- " + ex.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
private void ExcelHandleCancel(MouseEventArgs e)
|
||||
{
|
||||
_excelVisible = false;
|
||||
}
|
||||
|
||||
private void ExcelShowModal()
|
||||
{
|
||||
_excelVisible = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void FileDetail(string fileid)
|
||||
{
|
||||
NavigationManager.NavigateTo($"/kms/detaillist/{KmsId}/{fileid}");
|
||||
@@ -256,7 +297,5 @@ namespace AntSK.Pages.KmsPage
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion File
|
||||
}
|
||||
}
|
||||
@@ -8,16 +8,30 @@
|
||||
|
||||
|
||||
<Button Type="@ButtonType.Primary" OnClick="NavigateBack">返回</Button>
|
||||
<AntList DataSource="@_data" TItem="KMFile">
|
||||
<Divider />
|
||||
<AntList DataSource="@_data" TItem="KMFile" ItemLayout="ListItemLayout.Horizontal" Grid="LayoutModel._listGridType">
|
||||
<ListItem >
|
||||
<ListItemMeta Description="@context.Text">
|
||||
<TitleTemplate>
|
||||
<a>@context.LastUpdate</a>
|
||||
</TitleTemplate>
|
||||
</ListItemMeta>
|
||||
<Card Hoverable Bordered Class="card" Style="max-height:247px;" Actions="(new[] {
|
||||
info(()=> Info(context.Text)) ,
|
||||
})">
|
||||
<CardMeta>
|
||||
<DescriptionTemplate>
|
||||
<Paragraph class="item" Ellipsis Style="display: -webkit-box; -webkit-line-clamp: 3;-webkit-box-orient: vertical;overflow: hidden; text-overflow: ellipsis;white-space: normal;height:65px;">
|
||||
<!--todo: Ellipsis not working-->
|
||||
@context.Text
|
||||
</Paragraph>
|
||||
</DescriptionTemplate>
|
||||
</CardMeta>
|
||||
</Card>
|
||||
</ListItem>
|
||||
</AntList>
|
||||
|
||||
@code {
|
||||
<Modal Visible="_infolVisible" Footer="null" Closable Title="详情" OnCancel="OnCancelLog" DestroyOnClose Width="1000" MaxBodyHeight="600">
|
||||
<Paragraph>
|
||||
@_infoText
|
||||
</Paragraph>
|
||||
</Modal>
|
||||
|
||||
@code {
|
||||
RenderFragment info(Action clickAction) =>@<a key="info" @onclick="@clickAction">查看</a>;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ namespace AntSK.Pages.KmsPage
|
||||
|
||||
private List<KMFile> _data = new List<KMFile>();
|
||||
|
||||
private bool _infolVisible=false;
|
||||
private string _infoText = "";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
@@ -26,5 +29,16 @@ namespace AntSK.Pages.KmsPage
|
||||
{
|
||||
NavigationManager.NavigateTo($"/kms/detail/{KmsId}");
|
||||
}
|
||||
|
||||
private void Info(string text)
|
||||
{
|
||||
_infoText = text;
|
||||
_infolVisible = true;
|
||||
}
|
||||
|
||||
private void OnCancelLog()
|
||||
{
|
||||
_infolVisible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
@context.Describe
|
||||
</span>
|
||||
<br />
|
||||
<span style="color:#c6c6c6">行切片:@context.MaxTokensPerLine 段落切片:@context.MaxTokensPerParagraph 重叠:@context.OverlappingTokens</span>
|
||||
<span style="color:#c6c6c6">段落切片:@context.MaxTokensPerParagraph 行切片:@context.MaxTokensPerLine 重叠:@context.OverlappingTokens</span>
|
||||
</Paragraph>
|
||||
</DescriptionTemplate>
|
||||
</CardMeta>
|
||||
|
||||
@@ -24,18 +24,31 @@
|
||||
</FormItem>
|
||||
|
||||
<FormItem Label="AI类型" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<EnumRadioGroup @bind-Value="context.AIType"></EnumRadioGroup>
|
||||
<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">
|
||||
<Radio RadioButton Value="@(AIModelType.Chat)">会话模型</Radio>
|
||||
<Radio RadioButton Value="@(AIModelType.Embedding)">向量模型</Radio>
|
||||
<RadioGroup @bind-Value="context.AIModelType">
|
||||
@if (context.AIType == AIType.StableDiffusion)
|
||||
{
|
||||
<Radio RadioButton Value="@(AIModelType.Image)">图片模型</Radio>
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (context.AIType != AIType.BgeEmbedding)
|
||||
{
|
||||
<Radio RadioButton Value="@(AIModelType.Chat)">会话模型</Radio>
|
||||
}
|
||||
@if (context.AIType != AIType.LLamaFactory && context.AIType != AIType.Mock && context.AIType != AIType.SparkDesk)
|
||||
{
|
||||
<Radio RadioButton Value="@(AIModelType.Embedding)">向量模型</Radio>
|
||||
}
|
||||
}
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
@if (context.AIModelType == AIModelType.Embedding)
|
||||
{
|
||||
<FormItem Label="注意事项" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<b>请不要使用不同维度的向量模型,否则会导致无法向量存储</b>
|
||||
<span style="color:red"><b>请不要使用不同维度的向量模型,否则会导致无法向量存储</b></span>
|
||||
</FormItem>
|
||||
}
|
||||
|
||||
@@ -84,7 +97,7 @@
|
||||
<Input Placeholder="请输入模型名称" @bind-Value="@context.ModelName" />
|
||||
</FormItem>
|
||||
}
|
||||
@if (context.AIType == AIType.LLamaSharp)
|
||||
@if (context.AIType == AIType.LLamaSharp || context.AIType == AIType.StableDiffusion)
|
||||
{
|
||||
<FormItem Label="模型路径" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<InputGroup>
|
||||
@@ -113,6 +126,9 @@
|
||||
<FormItem Label="请求地址" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Input Placeholder="http://localhost:8080/" @bind-Value="@context.EndPoint" />
|
||||
</FormItem>
|
||||
<FormItem Label="环境安装" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Button Type="primary" OnClick="PipInstall">环境安装</Button>
|
||||
</FormItem>
|
||||
<FormItem Label="llama factory服务" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<InputGroup>
|
||||
@if (!llamaFactoryIsStart)
|
||||
@@ -124,11 +140,31 @@
|
||||
<Button OnClick="StopLFService" Disabled="@(!llamaFactoryIsStart)">停止</Button>
|
||||
}
|
||||
</InputGroup>
|
||||
</FormItem>
|
||||
}
|
||||
|
||||
@if (context.AIType == AIType.BgeEmbedding)
|
||||
{
|
||||
<FormItem Label="模型名称" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Select DataSource="@bgeEmbeddingList"
|
||||
@bind-Value="@context.ModelName"
|
||||
ValueProperty="c=>c"
|
||||
LabelProperty="c=>c">
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem Label="环境安装" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Button Type="primary" OnClick="PipInstall" >初始化</Button>
|
||||
<FormItem Label="PythonDll路径" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Input Placeholder="D:\Programs\Python\Python311\python311.dll" @bind-Value="@context.EndPoint" />
|
||||
</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>
|
||||
</FormItem>
|
||||
}
|
||||
|
||||
@if (context.AIType == AIType.Mock)
|
||||
{
|
||||
}
|
||||
@@ -168,3 +204,7 @@
|
||||
</Modal>
|
||||
|
||||
|
||||
@code
|
||||
{
|
||||
|
||||
}
|
||||
@@ -3,6 +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.Service;
|
||||
using AntSK.Domain.Options;
|
||||
using AntSK.Domain.Repositories;
|
||||
@@ -12,6 +13,7 @@ using BlazorComponents.Terminal;
|
||||
using DocumentFormat.OpenXml.Office2010.Excel;
|
||||
using Downloader;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using NRedisStack.Search;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace AntSK.Pages.Setting.AIModel
|
||||
@@ -58,6 +60,10 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
private TerminalParagraph para;
|
||||
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 = "初始化";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
@@ -75,12 +81,25 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
llamaFactoryIsStart = llamaFactoryDic.Value == "false" ? false : true;
|
||||
}
|
||||
|
||||
|
||||
//目前只支持gguf的 所以筛选一下
|
||||
_modelFiles = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), LLamaSharpOption.FileDirectory)).Where(p=>p.Contains(".gguf")).ToArray();
|
||||
_modelFiles = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), LLamaSharpOption.FileDirectory)).Where(p=> p.Contains(".gguf")||p.Contains(".ckpt")|| p.Contains(".safetensors")).ToArray();
|
||||
if (!string.IsNullOrEmpty(ModelPath))
|
||||
{
|
||||
string extension = Path.GetExtension(ModelPath);
|
||||
switch (extension)
|
||||
{
|
||||
case ".gguf":
|
||||
_aiModel.AIType = AIType.LLamaSharp;
|
||||
break;
|
||||
case ".safetensors":
|
||||
case ".ckpt":
|
||||
_aiModel.AIType = AIType.StableDiffusion;
|
||||
break;
|
||||
|
||||
}
|
||||
//下载页跳入
|
||||
_aiModel.AIType = AIType.LLamaSharp;
|
||||
|
||||
_downloadModalVisible = true;
|
||||
|
||||
_downloadUrl = $"https://hf-mirror.com{ModelPath.Replace("---","/")}";
|
||||
@@ -214,7 +233,7 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
/// <summary>
|
||||
/// 启动服务
|
||||
/// </summary>
|
||||
private void StartLFService()
|
||||
private async Task StartLFService()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_aiModel.ModelName))
|
||||
{
|
||||
@@ -248,6 +267,37 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
_ILLamaFactoryService.PipInstall();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task BgeDownload()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_aiModel.ModelName))
|
||||
{
|
||||
_ = Message.Error("请输入模型名称!", 2);
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(_aiModel.EndPoint))
|
||||
{
|
||||
_ = Message.Error("请输入正确的Python dll路径!", 2);
|
||||
return;
|
||||
}
|
||||
|
||||
BgeIsStart = true;
|
||||
BgeBtnText = "正在初始化...";
|
||||
await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
EmbeddingConfig.LoadModel(_aiModel.EndPoint, _aiModel.ModelName);
|
||||
BgeBtnText = "初始化完成";
|
||||
BgeIsStart = false;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
_ = Message.Error(ex.Message, 2);
|
||||
BgeIsStart = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
private async Task CmdLogHandler(string message)
|
||||
{
|
||||
await InvokeAsync(() =>
|
||||
@@ -263,5 +313,28 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
private void OnCancelLog() {
|
||||
_logModalVisible = false;
|
||||
}
|
||||
|
||||
private void AITypeChange(AIType aiType)
|
||||
{
|
||||
switch (aiType)
|
||||
{
|
||||
case AIType.LLamaFactory:
|
||||
_aiModel.EndPoint = "http://localhost:8000/";
|
||||
_aiModel.AIModelType=AIModelType.Chat;
|
||||
break;
|
||||
case AIType.StableDiffusion:
|
||||
_aiModel.AIModelType = AIModelType.Image;
|
||||
break;
|
||||
case AIType.Mock:
|
||||
_aiModel.AIModelType = AIModelType.Chat;
|
||||
break ;
|
||||
case AIType.BgeEmbedding:
|
||||
_aiModel.AIModelType = AIModelType.Embedding;
|
||||
break;
|
||||
default:
|
||||
_aiModel.AIModelType = AIModelType.Chat;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,24 @@
|
||||
|
||||
<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">
|
||||
@@ -52,6 +60,7 @@
|
||||
</Card>
|
||||
</ListItem>
|
||||
</AntList>
|
||||
</Spin>
|
||||
</div>
|
||||
</ChildContent>
|
||||
</PageContainer>
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
using AntDesign;
|
||||
using AntSK.Domain.Domain.Model.hfmirror;
|
||||
using AntSK.Domain.Utils;
|
||||
using AntSK.Models;
|
||||
using AntSK.Services;
|
||||
using DocumentFormat.OpenXml.Office2010.Excel;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Newtonsoft.Json;
|
||||
using RestSharp;
|
||||
using AntSK.Domain.Utils;
|
||||
using AntSK.Domain.Domain.Model.hfmirror;
|
||||
|
||||
namespace AntSK.Pages.Setting.AIModel
|
||||
{
|
||||
@@ -16,27 +13,55 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
private readonly IList<string> _selectCategories = new List<string>();
|
||||
|
||||
private List<HfModels> _modelList = new List<HfModels>();
|
||||
|
||||
private string _modelType="gguf";
|
||||
private bool loaddding = false;
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
InitData("");
|
||||
}
|
||||
|
||||
private void InitData(string searchKey)
|
||||
private async Task InitData(string searchKey)
|
||||
{
|
||||
var param = searchKey.ConvertToString().Split(" ");
|
||||
|
||||
string urlBase = "https://hf-mirror.com/models-json?sort=trending&search=gguf";
|
||||
if (param.Count() > 0)
|
||||
loaddding = true;
|
||||
if (_modelType.Contains("safetensors"))
|
||||
{
|
||||
urlBase += "+" + string.Join("+", param);
|
||||
_modelList.Clear();
|
||||
var param = searchKey.ConvertToString().Split(" ");
|
||||
string[] lines = File.ReadAllLines(Path.Combine(AppContext.BaseDirectory, "StableDiffusionModelList.txt"));
|
||||
foreach (string line in lines)
|
||||
{
|
||||
string urlBase = $"https://hf-mirror.com/models-json?sort=trending&search={line}";
|
||||
if (param.Count() > 0)
|
||||
{
|
||||
urlBase += "+" + string.Join("+", param);
|
||||
}
|
||||
RestClient client = new RestClient();
|
||||
RestRequest request = new RestRequest(urlBase, Method.Get);
|
||||
var response =await client.ExecuteAsync(request);
|
||||
var model = JsonConvert.DeserializeObject<HfModel>(response.Content);
|
||||
_modelList.AddRange(model.models);
|
||||
}
|
||||
|
||||
}
|
||||
RestClient client = new RestClient();
|
||||
RestRequest request = new RestRequest(urlBase, Method.Get);
|
||||
var response = client.Execute(request);
|
||||
var model = JsonConvert.DeserializeObject<HfModel>(response.Content);
|
||||
_modelList = model.models;
|
||||
else
|
||||
{
|
||||
var param = searchKey.ConvertToString().Split(" ");
|
||||
|
||||
string urlBase = $"https://hf-mirror.com/models-json?sort=trending&search={_modelType}";
|
||||
if (param.Count() > 0)
|
||||
{
|
||||
urlBase += "+" + string.Join("+", param);
|
||||
}
|
||||
RestClient client = new RestClient();
|
||||
RestRequest request = new RestRequest(urlBase, Method.Get);
|
||||
var response = await client.ExecuteAsync(request);
|
||||
var model = JsonConvert.DeserializeObject<HfModel>(response.Content);
|
||||
_modelList = model.models;
|
||||
}
|
||||
|
||||
loaddding = false;
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private async Task Search(string searchKey)
|
||||
@@ -48,5 +73,10 @@ namespace AntSK.Pages.Setting.AIModel
|
||||
{
|
||||
NavigationManager.NavigateTo($"/setting/modeldown/detail/{modelPath}");
|
||||
}
|
||||
|
||||
private void OnModelTypeChange(string value)
|
||||
{
|
||||
InitData("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,14 @@
|
||||
{
|
||||
<Tag Color="@PresetColor.Cyan.ToString()">LLamaFactory</Tag>
|
||||
}
|
||||
else if (context.AIType == AIType.BgeEmbedding)
|
||||
{
|
||||
<Tag Color="@PresetColor.Gold.ToString()">BgeEmbedding</Tag>
|
||||
}
|
||||
else if (context.AIType == AIType.StableDiffusion)
|
||||
{
|
||||
<Tag Color="@PresetColor.Lime.ToString()">StableDiffusion</Tag>
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -85,6 +93,10 @@
|
||||
{
|
||||
<Tag Color="@PresetColor.Green.ToString()">向量模型</Tag>
|
||||
}
|
||||
else if (context.AIModelType == AIModelType.Image)
|
||||
{
|
||||
<Tag Color="@PresetColor.Lime.ToString()">图片模型</Tag>
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
<div class="listContentItem" style="width:20%">
|
||||
|
||||
@@ -65,15 +65,14 @@ builder.Services.AddBackgroundTaskBroker().AddHandler<ImportKMSTaskReq, BackGrou
|
||||
{
|
||||
NativeLibraryConfig
|
||||
.Instance
|
||||
.WithCuda(false)
|
||||
.WithLogs(true);
|
||||
.WithCuda(false);
|
||||
}
|
||||
else if (LLamaSharpOption.RunType.ToUpper() == "GPU")
|
||||
{
|
||||
NativeLibraryConfig
|
||||
.Instance
|
||||
.WithCuda(true)
|
||||
.WithLogs(true);
|
||||
.WithAvx(NativeLibraryConfig.AvxLevel.Avx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace AntSK.Services.OpenApi
|
||||
string result = "";
|
||||
var _kernel = _kernelService.GetKernelByApp(app);
|
||||
|
||||
var relevantSource = await _kMService.GetRelevantSourceList(app.KmsIdList, questions);
|
||||
var relevantSource = await _kMService.GetRelevantSourceList(app, questions);
|
||||
var dataMsg = new StringBuilder();
|
||||
if (relevantSource.Any())
|
||||
{
|
||||
@@ -210,9 +210,12 @@ namespace AntSK.Services.OpenApi
|
||||
dataMsg.AppendLine(item.ToString());
|
||||
}
|
||||
|
||||
KernelFunction jsonFun = _kernel.Plugins.GetFunction("KMSPlugin", "Ask1");
|
||||
var chatResult = await _kernel.InvokeAsync(function: jsonFun,
|
||||
arguments: new KernelArguments() { ["doc"] = dataMsg, ["history"] = string.Join("\n", history.Select(x => x.Role + ": " + x.Content)), ["questions"] = questions });
|
||||
//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 chatResult = await _kernel.InvokeAsync(function: func,
|
||||
arguments: new KernelArguments() { ["doc"] = dataMsg, ["history"] = string.Join("\n", history.Select(x => x.Role + ": " + x.Content)), ["input"] = questions });
|
||||
if (chatResult.IsNotNull())
|
||||
{
|
||||
string answers = chatResult.GetValue<string>();
|
||||
@@ -236,15 +239,15 @@ namespace AntSK.Services.OpenApi
|
||||
for (int i = 0; i < model.messages.Count() - 1; i++)
|
||||
{
|
||||
var item = model.messages[i];
|
||||
if (item.role.ToLower() == "user")
|
||||
if (item.role.ComparisonIgnoreCase("user"))
|
||||
{
|
||||
history.AddUserMessage(item.content);
|
||||
}
|
||||
else if (item.role.ToLower() == "assistant")
|
||||
else if (item.role.ComparisonIgnoreCase("assistant"))
|
||||
{
|
||||
history.AddAssistantMessage(item.content);
|
||||
}
|
||||
else if (item.role.ToLower() == "system")
|
||||
else if (item.role.ComparisonIgnoreCase("system"))
|
||||
{
|
||||
history.AddSystemMessage(item.content);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ Facts:
|
||||
--------------------------
|
||||
History:{{ConversationSummaryPlugin.SummarizeConversation $history}}
|
||||
--------------------------
|
||||
Question: {{$questions}}
|
||||
Question: {{$input}}
|
||||
--------------------------
|
||||
Given only the facts above, provide a comprehensive/detailed answer.
|
||||
You don't know where the knowledge comes from, just answer.
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
|
||||
历史聊天记录:{{ConversationSummaryPlugin.SummarizeConversation $history}}
|
||||
--------------------------
|
||||
用户问题: {{$questions}}
|
||||
用户问题: {{$input}}
|
||||
|
||||
|
||||
12
src/AntSK/plugins/KMSPlugin/QA/config.json
Normal file
12
src/AntSK/plugins/KMSPlugin/QA/config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"description": "知识库问答",
|
||||
"execution_settings": {
|
||||
"default": {
|
||||
"temperature": 0.0,
|
||||
"top_p": 0.0,
|
||||
"presence_penalty": 0.0,
|
||||
"frequency_penalty": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/AntSK/plugins/KMSPlugin/QA/skprompt.txt
Normal file
13
src/AntSK/plugins/KMSPlugin/QA/skprompt.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
我会给你一段文本,学习它们,并整理学习成果,要求为:
|
||||
1. 提出最多 25 个问题。
|
||||
2. 给出每个问题的答案。
|
||||
3. 答案要详细完整,答案可以包含普通文字、链接、代码、表格、公示、媒体链接等 markdown 元素。
|
||||
4. 按格式返回多个问题和答案:
|
||||
|
||||
Q1: 问题。
|
||||
A1: 答案。
|
||||
Q2:
|
||||
A2:
|
||||
……
|
||||
|
||||
我的文本:"""{{$input}}"""
|
||||
@@ -57,5 +57,11 @@
|
||||
"key": "setting.modeldown"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "http://antsk.cn/",
|
||||
"name": "文档",
|
||||
"key": "antskdoc",
|
||||
"icon": "question-circle"
|
||||
}
|
||||
]
|
||||
@@ -13,6 +13,37 @@
|
||||
<PackageReference Include="Cnblogs.SemanticKernel.Connectors.DashScope" Version="0.3.2" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel" Version="1.6.3" />
|
||||
<PackageReference Include="Sdcb.SparkDesk" Version="3.0.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="StableDiffusion\Backend\CPU\stable-diffusion.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="StableDiffusion\Backend\CPU\stable-diffusion.so">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="StableDiffusion\Backend\Cuda11\stable-diffusion.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="StableDiffusion\Backend\Cuda11\stable-diffusion.so">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="StableDiffusion\Backend\Cuda12\stable-diffusion.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="StableDiffusion\Backend\Cuda12\stable-diffusion.so">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="StableDiffusion\Backend\ROCm\stable-diffusion.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="StableDiffusion\Backend\ROCm\stable-diffusion.so">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="StableDiffusionModelList.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
BIN
src/AntSk.LLM/StableDiffusion/Backend/CPU/stable-diffusion.dll
Normal file
BIN
src/AntSk.LLM/StableDiffusion/Backend/CPU/stable-diffusion.dll
Normal file
Binary file not shown.
BIN
src/AntSk.LLM/StableDiffusion/Backend/CPU/stable-diffusion.so
Normal file
BIN
src/AntSk.LLM/StableDiffusion/Backend/CPU/stable-diffusion.so
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/AntSk.LLM/StableDiffusion/Backend/Cuda11/stable-diffusion.so
Normal file
BIN
src/AntSk.LLM/StableDiffusion/Backend/Cuda11/stable-diffusion.so
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/AntSk.LLM/StableDiffusion/Backend/Cuda12/stable-diffusion.so
Normal file
BIN
src/AntSk.LLM/StableDiffusion/Backend/Cuda12/stable-diffusion.so
Normal file
Binary file not shown.
BIN
src/AntSk.LLM/StableDiffusion/Backend/ROCm/stable-diffusion.dll
Normal file
BIN
src/AntSk.LLM/StableDiffusion/Backend/ROCm/stable-diffusion.dll
Normal file
Binary file not shown.
BIN
src/AntSk.LLM/StableDiffusion/Backend/ROCm/stable-diffusion.so
Normal file
BIN
src/AntSk.LLM/StableDiffusion/Backend/ROCm/stable-diffusion.so
Normal file
Binary file not shown.
108
src/AntSk.LLM/StableDiffusion/Native.cs
Normal file
108
src/AntSk.LLM/StableDiffusion/Native.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AntSK.LLM.StableDiffusion
|
||||
{
|
||||
using static AntSK.LLM.StableDiffusion.Structs;
|
||||
using int32_t = Int32;
|
||||
using int64_t = Int64;
|
||||
using SdContext = IntPtr;
|
||||
using SDImagePtr = IntPtr;
|
||||
using UpscalerContext = IntPtr;
|
||||
|
||||
internal class Native
|
||||
{
|
||||
const string DllName = "stable-diffusion";
|
||||
|
||||
internal delegate void SdLogCallback(SdLogLevel level, [MarshalAs(UnmanagedType.LPStr)] string text, IntPtr data);
|
||||
internal delegate void SdProgressCallback(int step, int steps, float time, IntPtr data);
|
||||
|
||||
[DllImport(DllName, EntryPoint = "new_sd_ctx", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal extern static SdContext new_sd_ctx(string model_path,
|
||||
string vae_path,
|
||||
string taesd_path,
|
||||
string control_net_path_c_str,
|
||||
string lora_model_dir,
|
||||
string embed_dir_c_str,
|
||||
string stacked_id_embed_dir_c_str,
|
||||
bool vae_decode_only,
|
||||
bool vae_tiling,
|
||||
bool free_params_immediately,
|
||||
int n_threads,
|
||||
WeightType weightType,
|
||||
RngType rng_type,
|
||||
ScheduleType s,
|
||||
bool keep_clip_on_cpu,
|
||||
bool keep_control_net_cpu,
|
||||
bool keep_vae_on_cpu);
|
||||
|
||||
|
||||
[DllImport(DllName, EntryPoint = "txt2img", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern SDImagePtr txt2img(SdContext sd_ctx,
|
||||
string prompt,
|
||||
string negative_prompt,
|
||||
int clip_skip,
|
||||
float cfg_scale,
|
||||
int width,
|
||||
int height,
|
||||
SampleMethod sample_method,
|
||||
int sample_steps,
|
||||
int64_t seed,
|
||||
int batch_count,
|
||||
SDImagePtr control_cond,
|
||||
float control_strength,
|
||||
float style_strength,
|
||||
bool normalize_input,
|
||||
string input_id_images_path);
|
||||
|
||||
[DllImport(DllName, EntryPoint = "img2img", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern SDImagePtr img2img(SdContext sd_ctx,
|
||||
SDImage init_image,
|
||||
string prompt_c_str,
|
||||
string negative_prompt_c_str,
|
||||
int clip_skip,
|
||||
float cfg_scale,
|
||||
int width,
|
||||
int height,
|
||||
SampleMethod sample_method,
|
||||
int sample_steps,
|
||||
float strength,
|
||||
int64_t seed,
|
||||
int batch_count);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern IntPtr preprocess_canny(IntPtr imgData,
|
||||
int width,
|
||||
int height,
|
||||
float high_threshold,
|
||||
float low_threshold,
|
||||
float weak,
|
||||
float strong,
|
||||
bool inverse);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern UpscalerContext new_upscaler_ctx(string esrgan_path,
|
||||
int n_threads,
|
||||
WeightType wtype);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern int32_t get_num_physical_cores();
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern void free_sd_ctx(SdContext sd_ctx);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern void free_upscaler_ctx(UpscalerContext upscaler_ctx);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern SDImage upscale(UpscalerContext upscaler_ctx, SDImage input_image, int upscale_factor);
|
||||
|
||||
[DllImport(DllName, EntryPoint = "sd_set_log_callback", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern void sd_set_log_callback(SdLogCallback cb, IntPtr data);
|
||||
|
||||
[DllImport(DllName, EntryPoint = "sd_set_progress_callback", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern void sd_set_progress_callback(SdProgressCallback cb, IntPtr data);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
234
src/AntSk.LLM/StableDiffusion/SDHelper.cs
Normal file
234
src/AntSk.LLM/StableDiffusion/SDHelper.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AntSK.LLM.StableDiffusion
|
||||
{
|
||||
using static AntSK.LLM.StableDiffusion.Structs;
|
||||
using SdContext = IntPtr;
|
||||
using SDImagePtr = IntPtr;
|
||||
using UpscalerContext = IntPtr;
|
||||
|
||||
public static class SDHelper
|
||||
{
|
||||
public static bool IsInitialized => SdContext.Zero != sd_ctx;
|
||||
public static bool IsUpscalerInitialized => UpscalerContext.Zero != upscaler_ctx;
|
||||
|
||||
private static SdContext sd_ctx = new SdContext();
|
||||
private static UpscalerContext upscaler_ctx = new UpscalerContext();
|
||||
|
||||
public static event EventHandler<StableDiffusionEventArgs.StableDiffusionLogEventArgs> Log;
|
||||
public static event EventHandler<StableDiffusionEventArgs.StableDiffusionProgressEventArgs> Progress;
|
||||
static readonly Native.SdLogCallback sd_Log_Cb;
|
||||
static readonly Native.SdProgressCallback sd_Progress_Cb;
|
||||
|
||||
//Hide the code below so that the process can be seen in console.
|
||||
//static SDHelper()
|
||||
//{
|
||||
// sd_Log_Cb = new Native.SdLogCallback(OnNativeLog);
|
||||
// Native.sd_set_log_callback(sd_Log_Cb, IntPtr.Zero);
|
||||
|
||||
// sd_Progress_Cb = new Native.SdProgressCallback(OnProgressRunning);
|
||||
// Native.sd_set_progress_callback(sd_Progress_Cb, IntPtr.Zero);
|
||||
|
||||
//}
|
||||
|
||||
public static bool Initialize(ModelParams modelParams)
|
||||
{
|
||||
sd_ctx = Native.new_sd_ctx(modelParams.ModelPath,
|
||||
modelParams.VaePath,
|
||||
modelParams.TaesdPath,
|
||||
modelParams.ControlnetPath,
|
||||
modelParams.LoraModelDir,
|
||||
modelParams.EmbeddingsPath,
|
||||
modelParams.StackedIdEmbeddingsPath,
|
||||
modelParams.VaeDecodeOnly,
|
||||
modelParams.VaeTiling,
|
||||
modelParams.FreeParamsImmediately,
|
||||
modelParams.Threads,
|
||||
modelParams.SdType,
|
||||
modelParams.RngType,
|
||||
modelParams.Schedule,
|
||||
modelParams.KeepClipOnCpu,
|
||||
modelParams.KeepControlNetOnCpu,
|
||||
modelParams.KeepVaeOnCpu);
|
||||
return SdContext.Zero != sd_ctx;
|
||||
}
|
||||
|
||||
public static bool InitializeUpscaler(UpscalerParams @params)
|
||||
{
|
||||
upscaler_ctx = Native.new_upscaler_ctx(@params.ESRGANPath, @params.Threads, @params.SdType);
|
||||
return UpscalerContext.Zero != upscaler_ctx;
|
||||
}
|
||||
|
||||
public static void FreeSD()
|
||||
{
|
||||
if (SdContext.Zero != sd_ctx)
|
||||
{
|
||||
Native.free_sd_ctx(sd_ctx);
|
||||
sd_ctx = SdContext.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public static void FreeUpscaler()
|
||||
{
|
||||
if (UpscalerContext.Zero != upscaler_ctx)
|
||||
{
|
||||
Native.free_upscaler_ctx(upscaler_ctx);
|
||||
upscaler_ctx = UpscalerContext.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public static Bitmap[] TextToImage(TextToImageParams textToImageParams)
|
||||
{
|
||||
if (!IsInitialized) throw new ArgumentNullException("Model not loaded!");
|
||||
|
||||
IntPtr cnPtr = IntPtr.Zero;
|
||||
if (textToImageParams.ControlCond != null)
|
||||
{
|
||||
if (textToImageParams.ControlCond.Width > 1)
|
||||
{
|
||||
SDImage cnImg = GetSDImageFromBitmap(textToImageParams.ControlCond);
|
||||
cnPtr = GetPtrFromImage(cnImg);
|
||||
}
|
||||
}
|
||||
|
||||
SDImagePtr sd_Image_ptr = Native.txt2img(sd_ctx,
|
||||
textToImageParams.Prompt,
|
||||
textToImageParams.NegativePrompt,
|
||||
textToImageParams.ClipSkip,
|
||||
textToImageParams.CfgScale,
|
||||
textToImageParams.Width,
|
||||
textToImageParams.Height,
|
||||
textToImageParams.SampleMethod,
|
||||
textToImageParams.SampleSteps,
|
||||
textToImageParams.Seed,
|
||||
textToImageParams.BatchCount,
|
||||
cnPtr,
|
||||
textToImageParams.ControlStrength,
|
||||
textToImageParams.StyleStrength,
|
||||
textToImageParams.NormalizeInput,
|
||||
textToImageParams.InputIdImagesPath);
|
||||
|
||||
Bitmap[] images = new Bitmap[textToImageParams.BatchCount];
|
||||
for (int i = 0; i < textToImageParams.BatchCount; i++)
|
||||
{
|
||||
SDImage sd_image = Marshal.PtrToStructure<SDImage>(sd_Image_ptr + i * Marshal.SizeOf<SDImage>());
|
||||
images[i] = GetBitmapFromSdImage(sd_image);
|
||||
}
|
||||
return images;
|
||||
}
|
||||
|
||||
|
||||
public static Bitmap ImageToImage(ImageToImageParams imageToImageParams)
|
||||
{
|
||||
if (!IsInitialized) throw new ArgumentNullException("Model not loaded!");
|
||||
SDImage input_sd_image = GetSDImageFromBitmap(imageToImageParams.InputImage);
|
||||
|
||||
SDImagePtr sdImgPtr = Native.img2img(sd_ctx,
|
||||
input_sd_image,
|
||||
imageToImageParams.Prompt,
|
||||
imageToImageParams.NegativePrompt,
|
||||
imageToImageParams.ClipSkip,
|
||||
imageToImageParams.CfgScale,
|
||||
imageToImageParams.Width,
|
||||
imageToImageParams.Height,
|
||||
imageToImageParams.SampleMethod,
|
||||
imageToImageParams.SampleSteps,
|
||||
imageToImageParams.Strength,
|
||||
imageToImageParams.Seed,
|
||||
imageToImageParams.BatchCount);
|
||||
SDImage sdImg = Marshal.PtrToStructure<SDImage>(sdImgPtr);
|
||||
|
||||
return GetBitmapFromSdImage(sdImg);
|
||||
}
|
||||
|
||||
public static Bitmap UpscaleImage(Bitmap image, int upscaleFactor)
|
||||
{
|
||||
if (!IsUpscalerInitialized) throw new ArgumentNullException("Upscaler not loaded!");
|
||||
SDImage inputSDImg = GetSDImageFromBitmap(image);
|
||||
SDImage result = Native.upscale(upscaler_ctx, inputSDImg, upscaleFactor);
|
||||
return GetBitmapFromSdImage(result);
|
||||
}
|
||||
|
||||
private static Bitmap GetBitmapFromSdImage(SDImage sd_Image)
|
||||
{
|
||||
int width = (int)sd_Image.Width;
|
||||
int height = (int)sd_Image.Height;
|
||||
int channel = (int)sd_Image.Channel;
|
||||
byte[] bytes = new byte[width * height * channel];
|
||||
Marshal.Copy(sd_Image.Data, bytes, 0, bytes.Length);
|
||||
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
|
||||
int stride = bmp.Width * channel;
|
||||
byte[] des = new byte[bytes.Length];
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
for (int j = 0; j < width; j++)
|
||||
{
|
||||
des[stride * i + channel * j + 0] = bytes[stride * i + channel * j + 2];
|
||||
des[stride * i + channel * j + 1] = bytes[stride * i + channel * j + 1];
|
||||
des[stride * i + channel * j + 2] = bytes[stride * i + channel * j + 0];
|
||||
}
|
||||
}
|
||||
BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat);
|
||||
Marshal.Copy(des, 0, bitmapData.Scan0, bytes.Length);
|
||||
bmp.UnlockBits(bitmapData);
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
private static SDImage GetSDImageFromBitmap(Bitmap bmp)
|
||||
{
|
||||
int width = bmp.Width;
|
||||
int height = bmp.Height;
|
||||
int channel = Bitmap.GetPixelFormatSize(bmp.PixelFormat) / 8;
|
||||
int stride = width * channel;
|
||||
byte[] bytes = new byte[width * height * channel];
|
||||
BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bmp.PixelFormat);
|
||||
Marshal.Copy(bitmapData.Scan0, bytes, 0, bytes.Length);
|
||||
bmp.UnlockBits(bitmapData);
|
||||
|
||||
byte[] sdImageBytes = new byte[bytes.Length];
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
for (int j = 0; j < width; j++)
|
||||
{
|
||||
sdImageBytes[stride * i + j * 3 + 0] = bytes[stride * i + j * 3 + 2];
|
||||
sdImageBytes[stride * i + j * 3 + 1] = bytes[stride * i + j * 3 + 1];
|
||||
sdImageBytes[stride * i + j * 3 + 2] = bytes[stride * i + j * 3 + 0];
|
||||
}
|
||||
}
|
||||
|
||||
SDImage sd_Image = new SDImage
|
||||
{
|
||||
Width = (uint)width,
|
||||
Height = (uint)height,
|
||||
Channel = 3,
|
||||
Data = Marshal.UnsafeAddrOfPinnedArrayElement(sdImageBytes, 0),
|
||||
};
|
||||
|
||||
return sd_Image;
|
||||
}
|
||||
|
||||
private static IntPtr GetPtrFromImage(SDImage sdImg)
|
||||
{
|
||||
IntPtr imgPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SDImage)));
|
||||
Marshal.StructureToPtr(sdImg, imgPtr, false);
|
||||
return imgPtr;
|
||||
}
|
||||
|
||||
private static void OnNativeLog(SdLogLevel level, string text, IntPtr data)
|
||||
{
|
||||
Log?.Invoke(null, new StableDiffusionEventArgs.StableDiffusionLogEventArgs { Level = level, Text = text });
|
||||
}
|
||||
|
||||
private static void OnProgressRunning(int step, int steps, float time, IntPtr data)
|
||||
{
|
||||
Progress?.Invoke(null, new StableDiffusionEventArgs.StableDiffusionProgressEventArgs { Step = step, Steps = steps, Time = time });
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
33
src/AntSk.LLM/StableDiffusion/StableDiffusionEventArgs.cs
Normal file
33
src/AntSk.LLM/StableDiffusion/StableDiffusionEventArgs.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using static AntSK.LLM.StableDiffusion.Structs;
|
||||
|
||||
namespace AntSK.LLM.StableDiffusion
|
||||
{
|
||||
public class StableDiffusionEventArgs
|
||||
{
|
||||
public class StableDiffusionProgressEventArgs : EventArgs
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public int Step { get; set; }
|
||||
public int Steps { get; set; }
|
||||
public float Time { get; set; }
|
||||
public IntPtr Data { get; set; }
|
||||
|
||||
public double Progress => (double)Step / Steps;
|
||||
public float IterationsPerSecond => 1.0f / Time;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class StableDiffusionLogEventArgs : EventArgs
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public SdLogLevel Level { get; set; }
|
||||
public string Text { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/AntSk.LLM/StableDiffusion/StableDiffusionService.cs
Normal file
13
src/AntSk.LLM/StableDiffusion/StableDiffusionService.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.LLM.StableDiffusion
|
||||
{
|
||||
public static class StableDiffusionService
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
154
src/AntSk.LLM/StableDiffusion/Structs.cs
Normal file
154
src/AntSk.LLM/StableDiffusion/Structs.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
namespace AntSK.LLM.StableDiffusion
|
||||
{
|
||||
using int64_t = Int64;
|
||||
using uint32_t = UInt32;
|
||||
|
||||
public class Structs
|
||||
{
|
||||
public class ModelParams
|
||||
{
|
||||
public string ModelPath = string.Empty;
|
||||
public string VaePath = string.Empty;
|
||||
public string TaesdPath = string.Empty;
|
||||
public string ControlnetPath = string.Empty;
|
||||
public string LoraModelDir = string.Empty;
|
||||
public string EmbeddingsPath = string.Empty;
|
||||
public string StackedIdEmbeddingsPath = string.Empty;
|
||||
public bool VaeDecodeOnly = false;
|
||||
public bool VaeTiling = true;
|
||||
public bool FreeParamsImmediately = false;
|
||||
public int Threads = Native.get_num_physical_cores();
|
||||
public WeightType SdType = WeightType.SD_TYPE_COUNT;
|
||||
public RngType RngType = RngType.CUDA_RNG;
|
||||
public ScheduleType Schedule = ScheduleType.DEFAULT;
|
||||
public bool KeepClipOnCpu = false;
|
||||
public bool KeepControlNetOnCpu = false;
|
||||
public bool KeepVaeOnCpu = false;
|
||||
}
|
||||
|
||||
public class TextToImageParams
|
||||
{
|
||||
public string Prompt = string.Empty;
|
||||
public string NegativePrompt = string.Empty;
|
||||
public int ClipSkip = 0;
|
||||
public float CfgScale = 7;
|
||||
public int Width = 512;
|
||||
public int Height = 512;
|
||||
public SampleMethod SampleMethod = SampleMethod.EULER_A;
|
||||
public int SampleSteps = 20;
|
||||
public int64_t Seed = -1;
|
||||
public int BatchCount = 1;
|
||||
public Bitmap ControlCond = new Bitmap(1, 1);
|
||||
public float ControlStrength = 0.9f;
|
||||
public float StyleStrength = 0.75f;
|
||||
public bool NormalizeInput = false;
|
||||
public string InputIdImagesPath = string.Empty;
|
||||
}
|
||||
|
||||
public class ImageToImageParams
|
||||
{
|
||||
public Bitmap InputImage;
|
||||
public string Prompt = string.Empty;
|
||||
public string NegativePrompt = string.Empty;
|
||||
public int ClipSkip = -1;
|
||||
public float CfgScale = 7.0f;
|
||||
public int Width = 512;
|
||||
public int Height = 512;
|
||||
public SampleMethod SampleMethod = SampleMethod.EULER_A;
|
||||
public int SampleSteps = 20;
|
||||
public float Strength = 0.75f;
|
||||
public int64_t Seed = 42;
|
||||
public int BatchCount = 1;
|
||||
}
|
||||
|
||||
public class UpscalerParams
|
||||
{
|
||||
public string ESRGANPath = string.Empty;
|
||||
public int Threads = Native.get_num_physical_cores();
|
||||
public WeightType SdType = WeightType.SD_TYPE_COUNT;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct SDImage
|
||||
{
|
||||
public uint32_t Width;
|
||||
public uint32_t Height;
|
||||
public uint32_t Channel;
|
||||
public IntPtr Data;
|
||||
}
|
||||
|
||||
public enum WeightType
|
||||
{
|
||||
SD_TYPE_F32 = 0,
|
||||
SD_TYPE_F16 = 1,
|
||||
SD_TYPE_Q4_0 = 2,
|
||||
SD_TYPE_Q4_1 = 3,
|
||||
// SD_TYPE_Q4_2 = 4, support has been removed
|
||||
// SD_TYPE_Q4_3 (5) support has been removed
|
||||
SD_TYPE_Q5_0 = 6,
|
||||
SD_TYPE_Q5_1 = 7,
|
||||
SD_TYPE_Q8_0 = 8,
|
||||
SD_TYPE_Q8_1 = 9,
|
||||
// k-quantizations
|
||||
SD_TYPE_Q2_K = 10,
|
||||
SD_TYPE_Q3_K = 11,
|
||||
SD_TYPE_Q4_K = 12,
|
||||
SD_TYPE_Q5_K = 13,
|
||||
SD_TYPE_Q6_K = 14,
|
||||
SD_TYPE_Q8_K = 15,
|
||||
SD_TYPE_IQ2_XXS = 16,
|
||||
SD_TYPE_IQ2_XS = 17,
|
||||
SD_TYPE_IQ3_XXS = 18,
|
||||
SD_TYPE_IQ1_S = 19,
|
||||
SD_TYPE_IQ4_NL = 20,
|
||||
SD_TYPE_IQ3_S = 21,
|
||||
SD_TYPE_IQ2_S = 22,
|
||||
SD_TYPE_IQ4_XS = 23,
|
||||
SD_TYPE_I8,
|
||||
SD_TYPE_I16,
|
||||
SD_TYPE_I32,
|
||||
SD_TYPE_COUNT,
|
||||
};
|
||||
|
||||
public enum RngType
|
||||
{
|
||||
STD_DEFAULT_RNG,
|
||||
CUDA_RNG
|
||||
};
|
||||
|
||||
public enum ScheduleType
|
||||
{
|
||||
DEFAULT,
|
||||
DISCRETE,
|
||||
KARRAS,
|
||||
N_SCHEDULES
|
||||
};
|
||||
|
||||
public enum SampleMethod
|
||||
{
|
||||
EULER_A,
|
||||
EULER,
|
||||
HEUN,
|
||||
DPM2,
|
||||
DPMPP2S_A,
|
||||
DPMPP2M,
|
||||
DPMPP2Mv2,
|
||||
LCM,
|
||||
N_SAMPLE_METHODS
|
||||
};
|
||||
|
||||
public enum SdLogLevel
|
||||
{
|
||||
Debug,
|
||||
Info,
|
||||
Warn,
|
||||
Error
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
6
src/AntSk.LLM/StableDiffusionModelList.txt
Normal file
6
src/AntSk.LLM/StableDiffusionModelList.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
AsAHuman/chilloutmix
|
||||
GraMpa7/dreamsharper
|
||||
Airic/Anything-V4.5
|
||||
liqira/anythingv3
|
||||
wind1/MoYou
|
||||
Reuploadingfromcivitai/DosMix
|
||||
Reference in New Issue
Block a user