Compare commits

...

147 Commits
0.2.4 ... 0.3.1

Author SHA1 Message Date
zyxucp
c40a7bcf22 Merge pull request #76 from AIDotNet/feature_bge
Feature bge
2024-04-20 23:19:10 +08:00
zeyu xu
97a7d447ab add rerank kms 2024-04-20 23:18:07 +08:00
zeyu xu
f803b9538b fix 调整目录 2024-04-20 21:17:27 +08:00
zeyu xu
1ac34c1702 add 应用增加rerank 2024-04-20 21:09:34 +08:00
zeyu xu
e07b480da1 add bgemodel 2024-04-20 21:02:44 +08:00
zeyu xu
9036af57e3 重命名 2024-04-20 20:56:55 +08:00
zeyu xu
93288f9b5c add bgererank 模型下载 2024-04-20 20:56:00 +08:00
zyxucp
f40dd8b013 Merge pull request #75 from AIDotNet/feature_menu
add 模型管理页面 文字超长的样式处理
2024-04-20 10:42:23 +08:00
zeyu xu
c6b83d0695 add 模型管理页面 文字超长的样式处理 2024-04-20 10:41:48 +08:00
zyxucp
592c850198 Merge pull request #74 from AIDotNet/feature_menu
add 单独剥离模型管理菜单
2024-04-20 10:31:43 +08:00
zeyu xu
4a3930ac7b add 单独剥离模型管理菜单 2024-04-20 10:31:19 +08:00
zyxucp
c05ba0af3e Update README.md 2024-04-19 23:20:44 +08:00
zyxucp
630ee51df6 Update docker-compose.simple.yml 2024-04-19 23:20:26 +08:00
zyxucp
d0e75e26c3 Update docker-compose.yml 2024-04-19 23:20:04 +08:00
zyxucp
62c36c3072 Merge pull request #73 from AIDotNet/feature_deldimensions
add DelDimensions
2024-04-19 23:09:33 +08:00
zeyu xu
baef309064 add DelDimensions 2024-04-19 23:08:50 +08:00
zeyu xu
d717cbad9c update nuget sqlsugar 2024-04-19 22:12:02 +08:00
zeyu xu
5ef0624605 fix 修改WithLogCallback 日志输出 2024-04-19 22:04:08 +08:00
zyxucp
98f0f9fe84 Update README.md 2024-04-18 22:15:30 +08:00
zeyu xu
28a23271e9 fix 文件名修改 2024-04-18 22:05:23 +08:00
zeyu xu
f1ba0bdf10 add 模型删除校验 2024-04-18 21:49:09 +08:00
zeyu xu
0d5513f374 add Directory.Build.props 2024-04-18 21:23:25 +08:00
zyxucp
4812cc308c Update README.md 2024-04-17 22:59:46 +08:00
zyxucp
584f7faded add 环境变量 2024-04-17 18:25:58 +08:00
zyxucp
08dcef2d8b Update docker-compose.simple.yml 2024-04-16 21:56:58 +08:00
zyxucp
68218733a2 Update docker-compose.yml 2024-04-16 21:56:40 +08:00
zyxucp
eb64cbf3d4 update 升级km nuget版本 2024-04-16 17:01:32 +08:00
zyxucp
f0e8a55522 Merge pull request #72 from AIDotNet/feature_qa1
fix 修改切分使用服务注入
2024-04-16 13:56:39 +08:00
zyxucp
5ec5a0bde4 fix 修改切分使用服务注入 2024-04-16 13:54:24 +08:00
zyxucp
1cc56dd553 Merge pull request #71 from AIDotNet/feature_qa
Feature qa
2024-04-15 23:27:02 +08:00
zeyu xu
64e949a88b add qa切片 2024-04-15 23:26:23 +08:00
zeyu xu
a2390a7c97 add qa问答 2024-04-15 23:21:11 +08:00
zeyu xu
559661bb6c add qa 参数 2024-04-15 21:30:06 +08:00
zyxucp
79326de263 Merge pull request #70 from IntptrMax/Add-stable-diffusion-reference-for-Windows
Add stable diffusion reference for windows
2024-04-15 10:37:03 +08:00
IntptrMax
3815891b28 remove unused stable-diffusion.dll 2024-04-15 08:51:17 +08:00
IntptrMax
42d474382a Merge branch 'AIDotNet:main' into Add-stable-diffusion-reference-for-Windows 2024-04-15 08:36:29 +08:00
IntptrMax
fe691f2d44 1.Update some Stable Diffusion code 2024-04-15 08:34:16 +08:00
IntptrMax
3ee41a8ab1 1. Add references for Stable Diffusion for windows.
2. Update load lib code
2024-04-15 08:22:12 +08:00
zeyu xu
7ca41dff8a add docker file py 2024-04-13 10:56:47 +08:00
zeyu xu
ba2e86993e add dll 2024-04-13 10:55:42 +08:00
zyxucp
13878046a2 忽略文件 2024-04-12 12:13:43 +08:00
zeyu xu
49ff8bf54f fix 删除空引用 2024-04-11 23:35:53 +08:00
zeyu xu
e9cc5a3993 add loadding 2024-04-11 22:32:00 +08:00
zyxucp
b213964b63 Merge pull request #67 from IntptrMax/UpdateStableDiffusion
Update Stable Diffusion
2024-04-11 21:53:44 +08:00
IntptrMax
bfbed44270 Update Stable Diffusion 2024-04-11 15:11:17 +08:00
zyxucp
9b07d88392 Update Dockerfile-py 2024-04-10 23:31:20 +08:00
zyxucp
3f8ed109f9 fix nuget 2024-04-10 23:23:18 +08:00
zyxucp
3f969627a4 fix 修改ocr runtime 2024-04-10 22:51:37 +08:00
zyxucp
d92970819a Merge pull request #65 from AIDotNet/feature_ocr
add runtime
2024-04-10 22:39:28 +08:00
zyxucp
23e756fa9b add runtime 2024-04-10 22:37:32 +08:00
zyxucp
5f58126fbf Merge pull request #64 from AIDotNet/feature_ocr
Feature ocr
2024-04-10 22:25:36 +08:00
zyxucp
dcfd0ffb8f add ocr 2024-04-10 22:23:59 +08:00
zyxucp
17221d056c add img 2024-04-10 21:57:45 +08:00
zyxucp
4a9dcfada4 fix 修改默认key 2024-04-10 21:54:26 +08:00
zyxucp
bb6c2bb020 fix 升级LLamaSharp 2024-04-09 12:32:39 +08:00
zyxucp
a8760a34de fix 修改地址错误问题 2024-04-09 12:20:15 +08:00
zeyu xu
1e432a5782 fix 删除pynet 2024-04-08 14:50:34 +08:00
zeyu xu
cb861ef2bb fix OCR 2024-04-08 12:38:14 +08:00
zeyu xu
7cee8fd87a add OCR 和文档查询上限 2024-04-08 12:10:32 +08:00
zeyu xu
8ce0e5d348 add ocr 2024-04-07 22:31:57 +08:00
zyxucp
90bce7c89f Merge branch 'main' of https://github.com/AIDotNet/AntSK 2024-04-07 15:59:03 +08:00
zyxucp
b840d0bcce fix add gpu avx 2024-04-07 15:58:26 +08:00
zyxucp
bfa6d28289 Update README.md 2024-04-07 14:40:47 +08:00
zeyu xu
f6e6ca9747 Merge branch 'main' of github.com:AIDotNet/AntSK 2024-04-07 11:44:15 +08:00
zeyu xu
75f8d39648 fix 修改类型 2024-04-07 11:44:05 +08:00
zyxucp
9a939eba5a fix 修改异步为同步 2024-04-07 11:03:18 +08:00
zyxucp
4e93efe821 fix 修改异步为同步 2024-04-07 10:49:35 +08:00
zyxucp
8bdbee80a0 fix 修改类型 2024-04-07 10:37:16 +08:00
zyxucp
6bdf5dcc03 fix 修复PG字段报错问题 2024-04-07 10:05:15 +08:00
zeyu xu
0bf0a9d78a fix chat style 2024-04-06 11:50:15 +08:00
zeyu xu
38e9fea601 Merge branch 'main' of github.com:AIDotNet/AntSK 2024-04-06 11:47:59 +08:00
zeyu xu
d2366b3b46 update Semantic Kernel and fix kmsdetaillist style 2024-04-06 11:47:49 +08:00
zyxucp
3aff93083a Update README.md 2024-04-06 11:04:58 +08:00
zeyu xu
eb998199db fix 删除不要的Controller 2024-04-06 00:03:53 +08:00
zeyu xu
1dd794af1b fix 修改安装向量插件 2024-04-06 00:03:17 +08:00
zeyu xu
08c9923e7e update docker-compose.yal 2024-04-05 23:58:45 +08:00
zyxucp
06b109ca87 Merge pull request #62 from AIDotNet/feature_kms
Feature kms
2024-04-05 22:27:21 +08:00
zeyu xu
9b039335c7 fix 修改style 2024-04-05 22:26:37 +08:00
zeyu xu
041378e5fd add 文档搜索测试 2024-04-05 22:16:44 +08:00
zeyu xu
6dc5ae10e3 add 搜索测试布局 2024-04-05 21:19:41 +08:00
zeyu xu
5807f4c283 fix 修改切片详情样式 2024-04-05 21:09:38 +08:00
zyxucp
8ef4445908 Merge pull request #61 from AIDotNet/feature_kms
Feature kms
2024-04-05 20:23:49 +08:00
zeyu xu
8a0609e970 add excel导入 2024-04-05 20:23:03 +08:00
zeyu xu
9f33b5009b add excel 导入 2024-04-05 19:50:58 +08:00
zeyu xu
50e66db8a1 Merge branch 'feature_kms' of github.com:AIDotNet/AntSK into feature_kms 2024-04-05 19:18:26 +08:00
zeyu xu
c3e83b569a fix 升级nuget 2024-04-05 19:18:20 +08:00
zyxucp
85d1c5ea7e add npoi 2024-04-05 19:17:49 +08:00
zeyu xu
ec1d126a02 add excel导入 2024-04-05 19:13:30 +08:00
zyxucp
e857695e70 Update docker-compose.simple.yml 2024-04-05 18:45:56 +08:00
zyxucp
fa9b2051fe Update docker-compose.yml 2024-04-05 18:45:41 +08:00
zyxucp
d450efcffe Merge pull request #60 from AIDotNet/feature_kms
fix 修改提示词上限
2024-04-05 15:51:22 +08:00
zeyu xu
2a6c84c200 fix 修改提示词上限 2024-04-05 15:50:46 +08:00
zyxucp
138a952ace Merge pull request #59 from AIDotNet/feature_kms
Feature kms
2024-04-05 15:41:14 +08:00
zeyu xu
eb6528ecd2 add 修改message结构,减少localstore存储 2024-04-05 15:39:56 +08:00
zeyu xu
2c30bbfa09 fix 细节调整 2024-04-05 15:29:39 +08:00
zeyu xu
c5a78c2135 add modeldownchange 2024-04-05 15:12:29 +08:00
zeyu xu
f03362ee41 fix 修改dropdown Trigger.Click 2024-04-05 15:04:44 +08:00
zeyu xu
fad3167d97 add kms settings 2024-04-05 15:00:37 +08:00
zeyu xu
ad949681dd add change 2024-04-05 14:41:58 +08:00
zeyu xu
27999d76b0 fix 修改知识库函数 2024-04-05 14:26:35 +08:00
zeyu xu
83278352d6 add kms 配置 2024-04-05 14:12:25 +08:00
zeyu xu
fcc56f5fef fix bge embedding 无法切片问题 2024-04-04 00:37:08 +08:00
zyxucp
4ebe2ecc32 fix 修改初始化,增加完成标识 2024-04-02 13:53:32 +08:00
zeyu xu
e684cba527 Merge branch 'main' of github.com:AIDotNet/AntSK 2024-04-02 13:34:38 +08:00
zeyu xu
888dc19ee0 fix bgeembedding 2024-04-02 13:34:24 +08:00
zyxucp
731aea702f fix 修改提示词 2024-04-02 11:17:53 +08:00
zyxucp
09e22bc76a Update README.md 2024-04-02 00:07:08 +08:00
zyxucp
74406d88a0 Merge pull request #58 from AIDotNet/feature_StableDiffusion
fix 修改为静态类
2024-04-01 23:57:12 +08:00
zeyu xu
e5f9d97560 fix 修改为静态类 2024-04-01 23:56:44 +08:00
zyxucp
59e768aaea Merge pull request #57 from AIDotNet/feature_StableDiffusion
Feature stable diffusion
2024-04-01 23:39:22 +08:00
zeyu xu
6a7cb24a5b add sd 2024-04-01 23:08:53 +08:00
zeyu xu
1db40d534c add apptype 2024-04-01 22:14:18 +08:00
zeyu xu
11d6e30f7e add sd function 2024-04-01 22:03:00 +08:00
zeyu xu
9d5214aaae add sdmodel 2024-04-01 21:57:18 +08:00
zeyu xu
010b906271 add sd 2024-04-01 21:35:51 +08:00
zeyu xu
16bf944edf add sd 2024-04-01 21:31:15 +08:00
zeyu xu
5bae5a099a margin 2024-04-01 21:01:29 +08:00
zyxucp
f771ea9521 Merge branch 'main' of https://github.com/AIDotNet/AntSK 2024-04-01 13:54:53 +08:00
zyxucp
994efbf37c update nuget 2024-04-01 13:54:20 +08:00
zyxucp
938cd86c88 Update README.md 2024-03-31 13:24:21 +08:00
zeyu xu
1339cbadbc fix 修改menukey 2024-03-31 13:07:30 +08:00
zeyu xu
bd0ad570ad add 增加使用文档 2024-03-31 13:07:08 +08:00
zeyu xu
234e649a7e fix 优化部分内容 2024-03-31 12:38:17 +08:00
zyxucp
c431dbc842 Update README.md 2024-03-31 00:28:16 +08:00
zyxucp
76283060d9 Update docker-compose.simple.yml 2024-03-30 23:28:52 +08:00
zyxucp
75ba506db4 Update docker-compose.yml 2024-03-30 23:28:33 +08:00
zeyu xu
0c8ad5fe8d add loadding 2024-03-30 19:50:29 +08:00
zeyu xu
68ce0db011 fix 样式修改 2024-03-30 17:35:40 +08:00
zeyu xu
c36de1a1e9 add 选项控制 2024-03-30 17:25:58 +08:00
zeyu xu
44ef759abd fix 修改控件 2024-03-30 14:47:29 +08:00
longdream
0c3d9844be Merge pull request #52 from longdream/main
bge embedding模型添加,bge用的CPU。
2024-03-29 21:51:35 +08:00
longdream
854c62a4ca 合并 2024-03-29 21:50:17 +08:00
longdream
5ed4fd5299 Merge branch 'main' of https://github.com/longdream/AntSK 2024-03-29 20:00:53 +08:00
longdream
af5ec43571 修改设置界面 2024-03-29 20:00:49 +08:00
junlong
d7b56d1590 Merge branch 'main' of https://github.com/longdream/AntSK 2024-03-29 15:34:08 +08:00
longdream
b925f8890b 修改token长度 2024-03-28 23:06:21 +08:00
longdream
5d80ee994a 解决线程冲突问题 2024-03-28 19:04:11 +08:00
longdream
f73bd2dfda 增减embedding 2024-03-27 22:53:45 +08:00
longdream
f340ee1088 embedding封装 2024-03-26 23:14:55 +08:00
longdream
edad2644aa 删除没必要的py文件 2024-03-26 20:48:49 +08:00
longdream
8a56a0393a Merge branch 'main' of https://github.com/longdream/AntSK 2024-03-26 20:48:07 +08:00
junlong
bd5ca06d8f test 2024-03-25 16:55:41 +08:00
junlong
e0985ecec3 Merge branch 'main' of https://github.com/longdream/AntSK 2024-03-25 16:48:21 +08:00
junlong
e56b74d4af 删除chat以外的文件 2024-03-25 16:48:11 +08:00
longdream
849b18f677 Merge branch 'AIDotNet:main' into main 2024-03-22 19:36:20 +08:00
junlong
344128e49d Merge branch 'main' of https://github.com/longdream/AntSK 2024-03-21 19:38:03 +08:00
junlong
56fc9dd517 test 2024-03-21 19:37:56 +08:00
101 changed files with 3964 additions and 565 deletions

4
.gitignore vendored
View File

@@ -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/

View File

@@ -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"]

View File

@@ -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"]

View File

@@ -10,6 +10,8 @@
- **知识库**通过文档Word、PDF、Excel、Txt、Markdown、Json、PPT等形式导入知识库可以进行知识库问答。
- **文生图**:集成**StableDiffusion** 本地模型,可以进行文生图。
- **GPTs 生成**此平台支持创建个性化的GPT模型尝试构建您自己的GPT模型。
- **API接口发布**将内部功能以API的形式对外提供便于开发者将AntSK 集成进其他应用,增强应用智慧。
@@ -49,11 +51,15 @@ https://antsk.ai-dotnet.com/
默认密码test
由于云服务器配置较低,无法运行本地模型,所以把系统设置权限关闭了,大家看看界面即可,要使用本地模型,请下载自行使用
请勿在演示站点上传敏感信息
```
### 其他功能示例
[视频示例](https://www.bilibili.com/video/BV1zH4y1h7Y9/)
[在线文档http://antsk.cn](http://antsk.cn)
## ❓如何开始?
在这里我使用的是Postgres 作为数据存储和向量存储因为Semantic Kernel和Kernel Memory都支持他当然你也可以换成其他的。
@@ -85,7 +91,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.3.0
ports:
- 5000:5000
networks:
@@ -98,6 +104,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 +180,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、选择一个喜欢的模型

View File

@@ -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.3.0
# 如果需要pytorch环境需要使用下面这个镜像镜像比较大
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.2.3.2
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:p0.3.0
ports:
- 5000:5000
networks:

View File

@@ -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.3.0
# 如果需要pytorch环境需要使用下面这个镜像镜像比较大
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.2.3.2
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:p0.3.0
ports:
- 5000:5000
networks:

View File

@@ -0,0 +1,53 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<DocumentationFile>AntSK.Domain.xml</DocumentationFile>
<NoWarn>CA1050,CA1707,CA2007,VSTHRD111,CS1591,RCS1110,CA5394,SKEXP0001,SKEXP0002,SKEXP0003,SKEXP0004,SKEXP0010,SKEXP0011,,SKEXP0012,SKEXP0020,SKEXP0021,SKEXP0022,SKEXP0023,SKEXP0024,SKEXP0025,SKEXP0026,SKEXP0027,SKEXP0028,SKEXP0029,SKEXP0030,SKEXP0031,SKEXP0032,SKEXP0040,SKEXP0041,SKEXP0042,SKEXP0050,SKEXP0051,SKEXP0052,SKEXP0053,SKEXP0054,SKEXP0055,SKEXP0060,SKEXP0061,SKEXP0101,SKEXP0102</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AntDesign.Charts" Version="0.5.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.37.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<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.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.36.240415.2" />
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.Postgres" Version="0.36.240415.2" />
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.Qdrant" Version="0.36.240415.2" />
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.Redis" Version="0.36.240415.2" />
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.AzureAISearch" Version="0.36.240415.2" />
<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>
</Project>

View File

@@ -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="Markdig" Version="0.37.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.148" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.152" />
<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.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="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="$(KMVersion)" />
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.Postgres" Version="$(KMVersion)" />
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.Qdrant" Version="$(KMVersion)" />
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.Redis" Version="$(KMVersion)" />
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.AzureAISearch" Version="$(KMVersion)" />
<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="$(LLamaSharpVersion)" />
<PackageReference Include="LLamaSharp.Backend.Cpu" Version="$(LLamaSharpVersion)" />
<PackageReference Include="LLamaSharp.Backend.Cuda12" Version="$(LLamaSharpVersion)" />
<PackageReference Include="LLamaSharp.kernel-memory" Version="$(LLamaSharpVersion)" />
<PackageReference Include="LLamaSharp.semantic-kernel" Version="$(LLamaSharpVersion)" />
</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>

View File

@@ -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,33 @@
总数
</summary>
</member>
<member name="M:AntSK.Domain.Domain.Other.Bge.BegRerankConfig.LoadModel(System.String,System.String)">
<summary>
模型写死
</summary>
</member>
<member name="M:AntSK.Domain.Domain.Other.Bge.BgeEmbeddingConfig.LoadModel(System.String,System.String)">
<summary>
模型写死
</summary>
</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 +387,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 +891,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.

View File

@@ -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;
}

View 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;
}
}
}

View File

@@ -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.Bge;
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 = BgeEmbeddingConfig.LoadModel(pyDllPath, modelName);
}
public void Dispose()
{
BgeEmbeddingConfig.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 BgeEmbeddingConfig.GetEmbedding(text);
return new Microsoft.KernelMemory.Embedding(embeddings);
}
public int CountTokens(string text)
{
return BgeEmbeddingConfig.TokenCount(text);
}
}
}

View 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 ExcelHSSFWorkbook
//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);
}
}
}

View 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; }
}
}

View File

@@ -0,0 +1,8 @@
<Project>
<!-- See https://aka.ms/dotnet/msbuild/customize for more details on customizing your build -->
<PropertyGroup>
<KMVersion>0.36.240416.1</KMVersion>
<LLamaSharpVersion>0.11.2</LLamaSharpVersion>
</PropertyGroup>
</Project>

View File

@@ -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);
}
}

View File

@@ -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; }

View File

@@ -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);
}

View File

@@ -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&*";
}
}

View File

@@ -8,6 +8,8 @@ namespace AntSK.Domain.Domain.Model.Dto
public string Text { get; set; }
public float Relevance { get; set; }
public double RerankScore { get; set; }
public override string ToString()
{
return $"[file:{SourceName};Relevance:{(Relevance * 100):F2}%]:{Text}";

View File

@@ -21,12 +21,18 @@ namespace AntSK.Domain.Domain.Model.Enum
[Display(Name = "灵积大模型")]
DashScope = 5,
[Display(Name = "LLamaFactory")]
LLamaFactory = 6,
[Display(Name = "Bge Embedding")]
BgeEmbedding = 7,
[Display(Name = "Bge Rerank")]
BgeRerank = 8,
[Display(Name = "StableDiffusion")]
StableDiffusion = 9,
[Display(Name = "模拟输出")]
Mock = 100,
}
/// <summary>
@@ -36,5 +42,7 @@ namespace AntSK.Domain.Domain.Model.Enum
{
Chat = 1,
Embedding = 2,
Image=3,
Rerank=4
}
}

View File

@@ -9,6 +9,7 @@ namespace AntSK.Domain.Domain.Model.Enum
public enum AppType
{
chat = 1,
kms = 2
kms = 2,
img=3
}
}

View 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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -0,0 +1,81 @@
using Newtonsoft.Json;
using Python.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Python.Runtime.Py;
namespace AntSK.Domain.Domain.Other.Bge
{
public static class BegRerankConfig
{
public static dynamic model { get; set; }
static object lockobj = new object();
/// <summary>
/// 模型写死
/// </summary>
public static dynamic LoadModel(string pythondllPath, string modelName)
{
lock (lockobj)
{
if (model == null)
{
if (string.IsNullOrEmpty(Runtime.PythonDLL))
{
Runtime.PythonDLL = pythondllPath;
}
PythonEngine.Initialize();
try
{
using (GIL())// 初始化Python环境的Global Interpreter Lock)
{
dynamic modelscope = Py.Import("modelscope");
dynamic flagEmbedding = Py.Import("FlagEmbedding");
dynamic model_dir = modelscope.snapshot_download(modelName, revision: "master");
dynamic flagReranker = flagEmbedding.FlagReranker(model_dir, use_fp16: true);
model = flagReranker;
return model;
}
}
catch (Exception ex)
{
throw ex;
}
}
else
{
return model;
}
}
}
public static double Rerank(List<string> list)
{
using (GIL())
{
try
{
PyList pyList = new PyList();
foreach (string item in list)
{
pyList.Append(item.ToPython()); // 将C# string转换为Python对象并添加到PyList中
}
PyObject result = model.compute_score(pyList, normalize: true);
return result.As<double>();
}
catch (Exception ex)
{
throw ex;
}
}
}
}
}

View File

@@ -0,0 +1,97 @@
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.Bge
{
public static class BgeEmbeddingConfig
{
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";
if (string.IsNullOrEmpty(Runtime.PythonDLL))
{
Runtime.PythonDLL = pythondllPath;
}
PythonEngine.Initialize();
PythonEngine.BeginAllowThreads();
try
{
using (GIL())// 初始化Python环境的Global Interpreter Lock)
{
dynamic modelscope = Import("modelscope");
//dynamic model_dir = modelscope.snapshot_download("AI-ModelScope/bge-large-zh-v1.5", revision: "master");
dynamic model_dir = modelscope.snapshot_download(modelName, revision: "master");
dynamic HuggingFaceBgeEmbeddingstemp = 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 (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");
}
}
}

View 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);
}
}
}

View File

@@ -0,0 +1,173 @@
using AntSK.Domain.Domain.Interface;
using AntSK.Domain.Domain.Model;
using AntSK.Domain.Utils;
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 Microsoft.SemanticKernel;
using Newtonsoft.Json;
using RestSharp;
using System.Security.Policy;
using System.Text;
using System.Text.RegularExpressions;
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;
private readonly IKernelService _kernelService;
public QAHandler(
string stepName,
IPipelineOrchestrator orchestrator,
IKernelService kernelService,
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;
this._kernelService = kernelService;
}
/// <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();
var kernel = _kernelService.GetKernelByAIModelID(StepName);
var lines = TextChunker.SplitPlainTextLines(content, 299);
var paragraphs = TextChunker.SplitPlainTextParagraphs(lines, 3000);
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用于删除可能的首尾空格
}
}
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);
}
}
}

View File

@@ -1,21 +1,22 @@
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.Domain.Other.Bge;
using AntSK.Domain.Repositories;
using AntSK.Domain.Utils;
using AntSK.LLM.StableDiffusion;
using Markdig;
using Microsoft.KernelMemory;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.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 +24,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 +43,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 +52,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 +69,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 +79,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)
@@ -98,22 +101,87 @@ namespace AntSK.Domain.Domain.Service
})));
}
var dataMsg = new StringBuilder();
if (relevantSourceList.Any())
{
relevantSources?.AddRange(relevantSourceList);
if (!string.IsNullOrEmpty(app.RerankModelID))
{
var rerankModel=_aIModels_Repositories.GetById(app.RerankModelID);
BegRerankConfig.LoadModel(rerankModel.EndPoint, rerankModel.ModelName);
//进行rerank
foreach (var item in relevantSourceList)
{
List<string> rerank = new List<string>();
rerank.Add(questions);
rerank.Add(item.Text);
item.RerankScore = BegRerankConfig.Rerank(rerank);
}
relevantSourceList = relevantSourceList.OrderByDescending(p => p.RerankScore).Take(app.MaxMatchesCount).ToList();
}
bool isSearch = false;
foreach (var item in relevantSourceList)
{
dataMsg.AppendLine(item.ToString());
if (!string.IsNullOrEmpty(app.RerankModelID))
{
//匹配重排后相似度
if (item.RerankScore >= app.Relevance / 100)
{
dataMsg.AppendLine(item.ToString());
isSearch = true;
}
}
else
{
//匹配相似度
if (item.Relevance >= app.Relevance / 100)
{
dataMsg.AppendLine(item.ToString());
isSearch = true;
}
}
}
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)
//处理markdown显示
relevantSources?.AddRange(relevantSourceList);
Dictionary<string, string> fileDic = new Dictionary<string, string>();
foreach (var item in relevantSourceList)
{
yield return content;
if (fileDic.ContainsKey(item.SourceName))
{
item.SourceName = fileDic[item.SourceName];
}
else
{
string fileName = _kmsDetails_Repositories.GetFirst(p => p.FileGuidName == item.SourceName).FileName;
fileDic.Add(item.SourceName, fileName);
item.SourceName = fileName;
}
item.Text = Markdown.ToHtml(item.Text);
}
if (isSearch)
{
//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 +190,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();

View File

@@ -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);

View File

@@ -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;
@@ -26,7 +29,8 @@ namespace AntSK.Domain.Domain.Service
public class KMService(
IKmss_Repositories _kmss_Repositories,
IAIModels_Repositories _aIModels_Repositories,
IMessageService? _message
IMessageService? _message,
IKernelService _kernelService
) : IKMService
{
private MemoryServerless _memory;
@@ -35,20 +39,36 @@ 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);
var chatHttpClient = OpenAIHttpClientHandlerUtil.GetHttpClient(chatModel.EndPoint);
var embeddingHttpClient = OpenAIHttpClientHandlerUtil.GetHttpClient(embedModel.EndPoint);
var searchClientConfig = new SearchClientConfig
SearchClientConfig searchClientConfig;
if (string.IsNullOrEmpty(app.RerankModelID))
{
MaxAskPromptSize = 2048,
MaxMatchesCount = 3,
AnswerTokens = 1000,
EmptyAnswer = KmsConstantcs.KmsSearchNull
};
//不重排直接取查询数
searchClientConfig = new SearchClientConfig
{
MaxAskPromptSize = app.MaxAskPromptSize,
MaxMatchesCount = app.MaxMatchesCount,
AnswerTokens = app.AnswerTokens,
EmptyAnswer = KmsConstantcs.KmsSearchNull
};
}
else
{
//重排取rerank数
searchClientConfig = new SearchClientConfig
{
MaxAskPromptSize = app.MaxAskPromptSize,
MaxMatchesCount = app.RerankCount,
AnswerTokens = app.AnswerTokens,
EmptyAnswer = KmsConstantcs.KmsSearchNull
};
}
var memoryBuild = new KernelMemoryBuilder()
.WithSearchClientConfig(searchClientConfig)
@@ -70,7 +90,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,33 +104,35 @@ 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>();
_memory = memoryBuild.AddSingleton<IKernelService>(_kernelService).Build<MemoryServerless>();
return _memory;
}
//else {
@@ -118,6 +140,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 +177,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 +218,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 +291,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 +306,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 +326,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 +348,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"];

View File

@@ -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:

View File

@@ -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)
@@ -89,9 +92,9 @@ namespace AntSK.Domain.Domain.Service
WorkingDirectory = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location), "llamafactory"),
}
};
process.StartInfo.Environment["CUDA_VISIBLE_DEVICES"] = "0";
process.StartInfo.Environment["CUDA_VISIBLE_DEVICES"] = Environment.GetEnvironmentVariable("CUDA_VISIBLE_DEVICES") ?? "0";
process.StartInfo.Environment["API_PORT"] = "8000";
process.StartInfo.EnvironmentVariables["USE_MODELSCOPE_HUB"] = "1";
process.StartInfo.EnvironmentVariables["USE_MODELSCOPE_HUB"] = Environment.GetEnvironmentVariable("USE_MODELSCOPE_HUB") ?? "1";
process.OutputDataReceived += (sender, eventArgs) =>
{
Console.WriteLine($"{eventArgs.Data}");
@@ -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)

View File

@@ -44,6 +44,10 @@ namespace AntSK.Domain.Repositories
/// </summary>
public string? EmbeddingModelID { get; set; }
public string? RerankModelID { get; set; }
public string? ImageModelID { get; set; }
/// <summary>
/// 温度
/// </summary>
@@ -53,6 +57,7 @@ namespace AntSK.Domain.Repositories
/// <summary>
/// 提示词
/// </summary>
[SugarColumn(ColumnDataType = "varchar(2000)")]
public string? Prompt { get; set; }
/// <summary>
@@ -76,5 +81,31 @@ 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;
[SugarColumn(DefaultValue = "20")]
public int RerankCount { get; set; } = 20;
/// <summary>
/// 回答最大token数
/// </summary>
[SugarColumn(DefaultValue = "2048")]
public int AnswerTokens { get; set; } = 2048;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View 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格式也可以选择PngGif等等
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;
}
}
}

View File

@@ -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()

View File

@@ -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()

View File

@@ -1,10 +0,0 @@
from llmtuner import Evaluator
def main():
evaluator = Evaluator()
evaluator.eval()
if __name__ == "__main__":
main()

View File

@@ -1,9 +0,0 @@
from llmtuner import export_model
def main():
export_model()
if __name__ == "__main__":
main()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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,6 @@ sse-starlette
matplotlib
fire
modelscope
langchain-community
sentence_transformers
FlagEmbedding

View 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="$(KMVersion)" />
<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>

View 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;
}
}
}
}

View File

@@ -0,0 +1,8 @@
<Project>
<!-- See https://aka.ms/dotnet/msbuild/customize for more details on customizing your build -->
<PropertyGroup>
<KMVersion>0.36.240416.1</KMVersion>
<LLamaSharpVersion>0.11.2</LLamaSharpVersion>
</PropertyGroup>
</Project>

View File

@@ -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,8 @@ 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
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -54,6 +57,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

View File

@@ -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>

View File

@@ -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");
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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,34 @@ 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);
}
}
}

View File

@@ -24,45 +24,58 @@
<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 +123,30 @@
}
</SelectOptions>
</Select>
<Button Type="@ButtonType.Link" OnClick="NavigateKmsList">去创建</Button>
</FormItem>
<FormItem Label="Rerank重排模型" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Select DataSource="@_rerankList"
@bind-Value="@context.RerankModelID"
ValueProperty="c=>c.Id"
LabelProperty="c=>'【'+c.AIType.ToString()+'】'+c.ModelDescription">
</Select>
<Button Type="@ButtonType.Link" OnClick="NavigateModelList">去创建</Button>
</FormItem>
<FormItem Label="Rerank数" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<AntDesign.InputNumber @bind-Value="context.RerankCount" PlaceHolder="Rerank数"></AntDesign.InputNumber>
</FormItem>
<FormItem Label="提问最大token数" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<AntDesign.InputNumber @bind-Value="context.MaxAskPromptSize" PlaceHolder="提问最大token数"></AntDesign.InputNumber>
</FormItem>
<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">

View File

@@ -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,9 @@ 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> _rerankList;
private List<AIModels> _imageList;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
@@ -53,7 +56,9 @@ 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();
_rerankList = models.Where(p => p.AIModelType == AIModelType.Rerank).ToList();
_imageList = models.Where(p => p.AIModelType == AIModelType.Image).ToList();
_functionService.SearchMarkedMethods();
foreach (var func in _functionService.Functions)
@@ -87,7 +92,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 +109,7 @@ namespace AntSK.Pages.AppPage
_appModel.NativeFunctionList = string.Join(",", funIds);
}
if (string.IsNullOrEmpty(AppId))
{
//新增
@@ -131,7 +143,26 @@ namespace AntSK.Pages.AppPage
private void NavigateModelList()
{
NavigationManager.NavigateTo("/setting/modellist");
NavigationManager.NavigateTo("/modelmanager/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 = "";
}
}
}

View File

@@ -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>

View File

@@ -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" /> 调试结果
@@ -41,7 +41,14 @@
<Body>
<AntList Bordered DataSource="@_relevantSources" Style="padding:10px;">
<ChildContent Context="item">
<span> <b>@item.SourceName </b> 相似度:<Text Mark> @item.Relevance</Text></span>
<span> <b>@item.SourceName </b> </span>
<br/>
<span>相似度:<Text Mark> @item.Relevance</Text></span>
@if (@item.RerankScore != 0)
{
<br/>
<span> Rerank相关性<Text Mark> @item.RerankScore</Text></span>
}
<Body>
@((MarkupString)(@item.Text))
</Body>

View File

@@ -46,7 +46,7 @@
</GridCol>
<GridCol Span="23">
<div class="chat-bubble received">
@((MarkupString)(item.HtmlAnswers))
@((MarkupString)(item.Context))
</div>
</GridCol>

View File

@@ -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);

View File

@@ -70,7 +70,7 @@ namespace AntSK.Pages
private void NavToAIModel()
{
NavigationManager.NavigateTo("/setting/modellist");
NavigationManager.NavigateTo("/modelmanager/modellist");
}
}
}

View File

@@ -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">

View File

@@ -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))
{
@@ -73,7 +80,7 @@ namespace AntSK.Pages.KmsPage
private void NavigateModelList()
{
NavigationManager.NavigateTo("/setting/modellist");
NavigationManager.NavigateTo("/modelmanager/modellist");
}
}
}

View 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;
}
}

View File

@@ -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>;
}

View File

@@ -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
}
}

View 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>;
}

View File

@@ -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;
}
}
}

View File

@@ -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>

View File

@@ -5,9 +5,9 @@
@using AntSK.LLamaFactory.Model
@using AntSK.LLamaFactory
@using BlazorComponents.Terminal
@page "/setting/model/add"
@page "/setting/model/add/{ModelId}"
@page "/setting/model/addbypath/{ModelPath}"
@page "/modelmanager/model/add"
@page "/modelmanager/model/add/{ModelId}"
@page "/modelmanager/model/addbypath/{ModelPath}"
@using AntSK.Services.Auth
@inherits AuthComponentBase
@using Microsoft.AspNetCore.Authorization
@@ -24,18 +24,35 @@
</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>
@if (context.AIType == AIType.StableDiffusion)
{
<Radio RadioButton Value="@(AIModelType.Image)">图片模型</Radio>
}
else
{
@if (context.AIType != AIType.BgeEmbedding && context.AIType != AIType.BgeRerank)
{
<Radio RadioButton Value="@(AIModelType.Chat)">会话模型</Radio>
}
@if (context.AIType != AIType.LLamaFactory && context.AIType != AIType.Mock && context.AIType != AIType.SparkDesk && context.AIType != AIType.BgeRerank)
{
<Radio RadioButton Value="@(AIModelType.Embedding)">向量模型</Radio>
}
@if (context.AIType == AIType.BgeRerank)
{
<Radio RadioButton Value="@(AIModelType.Rerank)">Rerank重排模型</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 +101,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 +130,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)
@@ -125,8 +145,54 @@
}
</InputGroup>
</FormItem>
<FormItem Label="环境安装" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Button Type="primary" OnClick="PipInstall" >初始化</Button>
}
@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="Python路径" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Popover ContentTemplate="@_content" Title="提示" Style="width:100%">
<Input Placeholder="D:\Programs\Python\Python311\python311.dll" @bind-Value="@context.EndPoint" />
</Popover>
</FormItem>
<FormItem Label="环境安装" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Button Type="primary" OnClick="PipInstall">环境安装</Button>
</FormItem>
<FormItem Label="下载并初始化" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Spin Tip="请等待..." Spinning="@(BgeEmbeddingIsStart)">
<Button Type="primary" Disabled="@(BgeEmbeddingIsStart)" OnClick="BgeEmbedding">@BgeEmbeddingBtnText</Button>
</Spin>
</FormItem>
}
@if (context.AIType == AIType.BgeRerank)
{
<FormItem Label="模型名称" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Select DataSource="@bgeRerankList"
@bind-Value="@context.ModelName"
ValueProperty="c=>c"
LabelProperty="c=>c">
</Select>
</FormItem>
<FormItem Label="Python路径" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Popover ContentTemplate="@_content" Title="提示" Style="width:100%">
<Input Placeholder="D:\Programs\Python\Python311\python311.dll" @bind-Value="@context.EndPoint" />
</Popover>
</FormItem>
<FormItem Label="环境安装" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Button Type="primary" OnClick="PipInstall">环境安装</Button>
</FormItem>
<FormItem Label="下载并初始化" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Spin Tip="请等待..." Spinning="@(BgeRerankIsStart)">
<Button Type="primary" Disabled="@(BgeRerankIsStart)" OnClick="BgeRerank">@BgeRerankBtnText</Button>
</Spin>
</FormItem>
}
@if (context.AIType == AIType.Mock)
@@ -168,3 +234,10 @@
</Modal>
@code
{
RenderFragment _content =
@<div>
<p>在windows上使用 python311.dll文件在linux上使用 libpython3.10.so</p>
</div>;
}

View File

@@ -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.Bge;
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,15 @@ 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 List<string> bgeRerankList = new List<string>() { "Xorbits/bge-reranker-base", "Xorbits/bge-reranker-large", "AI-ModelScope/bge-reranker-v2-m3", "AI-ModelScope/bge-reranker-v2-gemma"};
private bool BgeEmbeddingIsStart = false;
private string BgeEmbeddingBtnText = "初始化";
private bool BgeRerankIsStart = false;
private string BgeRerankBtnText = "初始化";
protected override async Task OnInitializedAsync()
{
try
@@ -75,12 +86,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("---","/")}";
@@ -131,7 +155,7 @@ namespace AntSK.Pages.Setting.AIModel
private void Back()
{
NavigationManager.NavigateTo("/setting/modellist");
NavigationManager.NavigateTo("/modelmanager/modellist");
}
private async Task StartDownload()
@@ -214,7 +238,7 @@ namespace AntSK.Pages.Setting.AIModel
/// <summary>
/// 启动服务
/// </summary>
private void StartLFService()
private async Task StartLFService()
{
if (string.IsNullOrEmpty(_aiModel.ModelName))
{
@@ -248,6 +272,70 @@ namespace AntSK.Pages.Setting.AIModel
_ILLamaFactoryService.PipInstall();
}
}
private async Task BgeEmbedding()
{
if (string.IsNullOrEmpty(_aiModel.ModelName))
{
_ = Message.Error("请输入模型名称!", 2);
return;
}
if (string.IsNullOrEmpty(_aiModel.EndPoint))
{
_ = Message.Error("请输入正确的Python dll或python so路径", 2);
return;
}
BgeEmbeddingIsStart = true;
BgeEmbeddingBtnText = "正在初始化...";
await Task.Run(() =>
{
try
{
BgeEmbeddingConfig.LoadModel(_aiModel.EndPoint, _aiModel.ModelName);
BgeEmbeddingBtnText = "初始化完成";
BgeEmbeddingIsStart = false;
}
catch (System.Exception ex)
{
_ = Message.Error(ex.Message, 2);
BgeEmbeddingIsStart = false;
}
});
}
private async Task BgeRerank()
{
if (string.IsNullOrEmpty(_aiModel.ModelName))
{
_ = Message.Error("请输入模型名称!", 2);
return;
}
if (string.IsNullOrEmpty(_aiModel.EndPoint))
{
_ = Message.Error("请输入正确的Python dll或python so路径", 2);
return;
}
BgeRerankIsStart = true;
BgeRerankBtnText = "正在初始化...";
await Task.Run(() =>
{
try
{
BegRerankConfig.LoadModel(_aiModel.EndPoint, _aiModel.ModelName);
BgeRerankBtnText = "初始化完成";
BgeRerankIsStart = false;
}
catch (System.Exception ex)
{
_ = Message.Error(ex.Message, 2);
BgeRerankIsStart = false;
}
});
}
private async Task CmdLogHandler(string message)
{
await InvokeAsync(() =>
@@ -263,5 +351,31 @@ 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;
case AIType.BgeRerank:
_aiModel.AIModelType = AIModelType.Rerank;
break;
default:
_aiModel.AIModelType = AIModelType.Chat;
break;
}
}
}
}

View File

@@ -1,5 +1,5 @@
@namespace AntSK.Pages.Setting.AIModel
@page "/setting/modeldown"
@page "/modelmanager/modeldown"
@using AntSK.Services.Auth
@inherits AuthComponentBase
@using Microsoft.AspNetCore.Authorization
@@ -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>

View File

@@ -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)
@@ -46,7 +71,12 @@ namespace AntSK.Pages.Setting.AIModel
private void Down(string modelPath)
{
NavigationManager.NavigateTo($"/setting/modeldown/detail/{modelPath}");
NavigationManager.NavigateTo($"/modelmanager/modeldown/detail/{modelPath}");
}
private void OnModelTypeChange(string value)
{
InitData("");
}
}
}

View File

@@ -1,5 +1,5 @@
@namespace AntSK.Pages.Setting.AIModel
@page "/setting/modeldown/detail/{ModelName}/{ModelPath}"
@page "/modelmanager/modeldown/detail/{ModelName}/{ModelPath}"
@using AntSK.Services.Auth
@inherits AuthComponentBase
@using Microsoft.AspNetCore.Authorization

View File

@@ -50,7 +50,7 @@ namespace AntSK.Pages.Setting.AIModel
private void Down(string path)
{
NavigationManager.NavigateTo($"/setting/model/addbypath/{path.Replace("?download=true", "").Replace("/", "---")}");
NavigationManager.NavigateTo($"/modelmanager/model/addbypath/{path.Replace("?download=true", "").Replace("/", "---")}");
}
}
}

View File

@@ -1,7 +1,7 @@
@namespace AntSK.Pages.Setting.AIModel
@using AntSK.Domain.Repositories
@using AntSK.Domain.Domain.Model.Enum
@page "/setting/modellist"
@page "/modelmanager/modellist"
@inject NavigationManager NavigationManager
@using AntSK.Services.Auth
@inherits AuthComponentBase
@@ -39,36 +39,48 @@
delete(async ()=>await Delete(context.Id))
}" Style="width:100%">
<div class="listContent" style="width:100%">
<div class="listContentItem" style="width:20%">
<div class="listContentItem" style="width:15%">
<b>模型描述</b>
<p>@context.ModelDescription</p>
<p title="@context.ModelDescription">@context.ModelDescription</p>
</div>
<div class="listContentItem" style="width:10%">
<b>AI类型</b>
<p>
@if (context.AIType == AIType.OpenAI)
{
<Tag Color="@PresetColor.Yellow.ToString()">OpenAI</Tag>
<Tag Color="@PresetColor.Pink.ToString()">OpenAI</Tag>
}
else if (context.AIType == AIType.AzureOpenAI)
{
<Tag Color="@PresetColor.Green.ToString()">AzureOpenAI</Tag>
<Tag Color="@PresetColor.Red.ToString()">AzureOpenAI</Tag>
}
else if (context.AIType == AIType.LLamaSharp)
{
<Tag Color="@PresetColor.Red.ToString()">LLamaSharp</Tag>
<Tag Color="@PresetColor.Yellow.ToString()">LLamaSharp</Tag>
}
else if (context.AIType == AIType.SparkDesk)
{
<Tag Color="@PresetColor.Orange.ToString()">SparkDesk</Tag>
<Tag Color="@PresetColor.Cyan.ToString()">SparkDesk</Tag>
}
else if (context.AIType == AIType.Mock)
{
<Tag Color="@PresetColor.Cyan.ToString()">Mock</Tag>
<Tag Color="@PresetColor.Green.ToString()">Mock</Tag>
}
else if (context.AIType == AIType.LLamaFactory)
{
<Tag Color="@PresetColor.Cyan.ToString()">LLamaFactory</Tag>
<Tag Color="@PresetColor.Blue.ToString()">LLamaFactory</Tag>
}
else if (context.AIType == AIType.BgeEmbedding)
{
<Tag Color="@PresetColor.Purple.ToString()">BgeEmbedding</Tag>
}
else if (context.AIType == AIType.BgeRerank)
{
<Tag Color="@PresetColor.GeekBlue.ToString()">BgeRerank</Tag>
}
else if (context.AIType == AIType.StableDiffusion)
{
<Tag Color="@PresetColor.Magenta.ToString()">StableDiffusion</Tag>
}
</p>
</div>
@@ -85,15 +97,23 @@
{
<Tag Color="@PresetColor.Green.ToString()">向量模型</Tag>
}
else if (context.AIModelType == AIModelType.Image)
{
<Tag Color="@PresetColor.Lime.ToString()">图片模型</Tag>
}
else if (context.AIModelType == AIModelType.Rerank)
{
<Tag Color="@PresetColor.GeekBlue.ToString()">Rerank重排模型</Tag>
}
</p>
</div>
<div class="listContentItem" style="width:20%">
<div class="listContentItem" style="width:25%">
<b>模型地址</b>
<p>@context.EndPoint</p>
<p title="@context.EndPoint">@context.EndPoint</p>
</div>
<div class="listContentItem" style="width:10%">
<div class="listContentItem" style="width:15%">
<b>模型名称</b>
<p>@context.ModelName</p>
<p title="@context.ModelName">@context.ModelName</p>
</div>
</div>
</ListItem>
@@ -104,7 +124,31 @@
</ChildContent>
</PageContainer>
</div>
<style>
.listContentItem {
width: 20%;
overflow: hidden; /* 防止内容溢出 */
text-overflow: ellipsis; /* 超出部分显示省略号 */
white-space: nowrap; /* 防止内容换行 */
}
/* 为需要显示工具提示的元素设置title属性 */
.listContentItem p[title] {
cursor: pointer; /* 鼠标移动上去时显示小手势 */
}
/* 悬停样式 */
.listContentItem:hover p[title]:before {
content: attr(title); /* 使用title属性的内容 */
position: absolute;
background: #333; /* 工具提示的背景颜色 */
color: #fff; /* 工具提示的文字颜色 */
padding: 4px 8px; /* 工具提示内部的填充 */
border-radius: 4px; /* 工具提示的边框圆角 */
text-align: center; /* 工具提示文字居中对齐 */
z-index: 1000; /* 工具提示在最顶层 */
}
</style>
@code
{
RenderFragment edit(Action clickAction) =>@<a key="edit" @onclick="@clickAction">修改</a>;

View File

@@ -16,6 +16,13 @@ namespace AntSK.Pages.Setting.AIModel
[Inject]
protected IAIModels_Repositories _aIModels_Repositories { get; set; }
[Inject]
protected IApps_Repositories _apps_Repositories{ get; set; }
[Inject]
protected IKmss_Repositories _kmss_Repositories { get; set; }
[Inject] protected MessageService? Message { get; set; }
[Inject]
IConfirmService _confirmService { get; set; }
@@ -44,12 +51,12 @@ namespace AntSK.Pages.Setting.AIModel
public async Task AddModel()
{
NavigationManager.NavigateTo("/setting/model/add");
NavigationManager.NavigateTo("/modelmanager/model/add");
}
public void Edit(string modelid)
{
NavigationManager.NavigateTo("/setting/model/add/" + modelid);
NavigationManager.NavigateTo("/modelmanager/model/add/" + modelid);
}
public async Task Delete(string modelid)
@@ -59,6 +66,16 @@ namespace AntSK.Pages.Setting.AIModel
var result = await _confirmService.Show(content, title, ConfirmButtons.YesNo);
if (result == ConfirmResult.Yes)
{
if (_apps_Repositories.IsAny(p => p.ChatModelID == modelid || p.EmbeddingModelID == modelid))
{
_ = Message.Error("该模型有应用在使用,请先删除应用后才允许删除该模型");
return;
}
if (_kmss_Repositories.IsAny(p => p.ChatModelID == modelid || p.EmbeddingModelID == modelid))
{
_ = Message.Error("该模型有知识库在使用,请先删除知识库后才允许删除该模型");
return;
}
await _aIModels_Repositories.DeleteAsync(modelid);
await InitData("");
}

View File

@@ -0,0 +1,88 @@
@namespace AntSK.Pages.Setting.AIModel
@page "/setting/delkms"
@using AntSK.Services.Auth
@using AntSK.Domain.Options
@using AntSK.Domain.Repositories
@inherits AuthComponentBase
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Roles = "AntSKAdmin")]
<GridContent>
<Card>
<Result Status="error"
Title="删除向量表"
SubTitle="删除向量表将会删除您的所有知识库文件,以及知识库向量。请谨慎操作!"
Style="margin-top: 48px; margin-bottom: 16px;">
<Extra>
<Button Type="primary" OnClick="DelDimensions">删除向量表</Button>
</Extra>
<ChildContent>
<div class="title__b__0">
当您切换不同维度的向量模型时,出现异常:
</div>
<div style="margin-bottom: 16px;">
<Icon Type="close-circle" Theme="outline" Class="error_icon" Style="margin-right: 8px;" />
Npgsql.PostgresException (0x80004005): 22000: expected 2048 dimensions, not 1024
</div>
<div>
<Icon Type="close-circle" Theme="outline" Class="error_icon" Style="margin-right: 8px;" />
您需要删除向量表,然后重建向量维度。
</div>
</ChildContent>
</Result>
</Card>
</GridContent>
<Modal @ref="_modal" Visible="_showAdminPwdVisible" Footer="null" Closable Title="请输入管理员密码" OnCancel="OnCancel" DestroyOnClose>
<Flex Gap="10" Vertical>
<InputGroup>
<InputPassword @bind-Value="@adminPwd" Placeholder="管理员密码" Size="@InputSize.Large" />
</InputGroup>
<InputGroup>
<Button Type="primary" OnClick="DelSubmit">确认</Button>
</InputGroup>
</Flex>
</Modal>
@code {
[Inject] protected MessageService? Message { get; set; }
[Inject] protected IKmsDetails_Repositories kmsDetails_Repositories { get; set; }
[Inject] protected IConfirmService _confirmService { get; set; }
private Modal _modal;
private bool _showAdminPwdVisible = false;
private string adminPwd = "";
public async Task DelDimensions()
{
var content = "删除向量表将会删除您的所有知识库文件,以及知识库向量。请谨慎操作!";
var title = "删除向量表";
var result = await _confirmService.Show(content, title, ConfirmButtons.YesNo);
if (result == ConfirmResult.Yes)
{
_showAdminPwdVisible = true;
}
}
public async Task DelSubmit() {
if (adminPwd != LoginOption.Password)
{
_ = Message.Error("管理员密码错误!");
return;
}
kmsDetails_Repositories.GetDB().Ado.ExecuteCommand("DROP TABLE IF EXISTS \"km-kms\"");
var kmsDetails = await kmsDetails_Repositories.GetListAsync();
foreach (var detail in kmsDetails)
{
kmsDetails_Repositories.Delete(detail);
}
_showAdminPwdVisible = false;
_ = Message.Info("删除成功!");
}
private void OnCancel()
{
_showAdminPwdVisible = false;
}
}

View File

@@ -66,14 +66,19 @@ builder.Services.AddBackgroundTaskBroker().AddHandler<ImportKMSTaskReq, BackGrou
NativeLibraryConfig
.Instance
.WithCuda(false)
.WithLogs(true);
.WithLogCallback((level, message) => {
Console.WriteLine($"[llama {level}]: {message.TrimEnd('\n')}");
});
}
else if (LLamaSharpOption.RunType.ToUpper() == "GPU")
{
NativeLibraryConfig
.Instance
.WithCuda(true)
.WithLogs(true);
.WithAvx(NativeLibraryConfig.AvxLevel.Avx)
.WithLogCallback((level, message) => {
Console.WriteLine($"[llama {level}]: {message.TrimEnd('\n')}");
});
}
}

View File

@@ -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);
}

View File

@@ -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.

View File

@@ -13,5 +13,5 @@
历史聊天记录:{{ConversationSummaryPlugin.SummarizeConversation $history}}
--------------------------
用户问题: {{$questions}}
用户问题: {{$input}}

View 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
}
}
}

View File

@@ -0,0 +1,13 @@
我会给你一段文本,学习它们,并整理学习成果,要求为:
1. 提出最多 25 个问题。
2. 给出每个问题的答案。
3. 答案要详细完整,答案可以包含普通文字、链接、代码、表格、公示、媒体链接等 markdown 元素。
4. 按格式返回多个问题和答案:
Q1: 问题。
A1: 答案。
Q2:
A2:
……
我的文本:"""{{$input}}"""

View File

@@ -35,9 +35,27 @@
}
]
},
{
"path": "/modelmanager",
"name": "模型管理",
"key": "modelmanager",
"icon": "shop",
"children": [
{
"path": "/modelmanager/modellist",
"name": "模型管理",
"key": "modelmanager.modellist"
},
{
"path": "/modelmanager/modeldown",
"name": "模型下载",
"key": "modelmanager.modeldown"
}
]
},
{
"path": "/setting",
"name": "设置",
"name": "系统设置",
"key": "setting",
"icon": "setting",
"children": [
@@ -47,15 +65,16 @@
"key": "setting.user"
},
{
"path": "/setting/modellist",
"name": "模型管理",
"key": "setting.modellist"
},
{
"path": "/setting/modeldown",
"name": "模型下载",
"key": "setting.modeldown"
"path": "/setting/delkms",
"name": "删除向量表",
"key": "setting.delkms"
}
]
},
{
"path": "http://antsk.cn/",
"name": "文档",
"key": "antskdoc",
"icon": "question-circle"
}
]

View File

@@ -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>

View 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);
}
}

View 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 });
}
}
}

View 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
}
}
}

View 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
{
}
}

View 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
}
}
}

Some files were not shown because too many files have changed in this diff Show More