Compare commits

..

31 Commits
0.2.5 ... 0.2.7

Author SHA1 Message Date
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
39 changed files with 1713 additions and 205 deletions

View File

@@ -10,6 +10,8 @@
- **知识库**通过文档Word、PDF、Excel、Txt、Markdown、Json、PPT等形式导入知识库可以进行知识库问答。
- **文生图**:集成**StableDiffusion** 本地模型,可以进行文生图。
- **GPTs 生成**此平台支持创建个性化的GPT模型尝试构建您自己的GPT模型。
- **API接口发布**将内部功能以API的形式对外提供便于开发者将AntSK 集成进其他应用,增强应用智慧。

View File

@@ -3,9 +3,9 @@ version: '3.8'
services:
antsk:
container_name: antsk
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.2.4
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.2.6
# 如果需要pytorch环境需要使用下面这个镜像镜像比较大
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:p0.2.4
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:p0.2.6
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.4
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.2.6
# 如果需要pytorch环境需要使用下面这个镜像镜像比较大
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:p0.2.4
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:p0.2.6
ports:
- 5000:5000
networks:

View File

@@ -9,7 +9,7 @@
</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" />
@@ -21,9 +21,10 @@
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="Markdig" Version="0.36.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.149" />
<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.5.5" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.6.3" />
<PackageReference Include="Microsoft.SemanticKernel.Core" Version="1.6.3" />

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类型
@@ -104,6 +182,12 @@
模型写死
</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>
避免模型重复加载,本地缓存
@@ -292,6 +376,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>
接口描述

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

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

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

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

@@ -29,6 +29,7 @@ namespace AntSK.Domain.Domain.Model
{
File = 1,
Url = 2,
Text = 3
Text = 3,
Excel=4
}
}

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

@@ -1,4 +1,5 @@
using Python.Runtime;
using Microsoft.KernelMemory.AI.OpenAI.GPT3;
using Python.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -37,7 +38,7 @@ namespace AntSK.Domain.Domain.Other
dynamic modelscope = Py.Import("modelscope");
//dynamic model_dir = modelscope.snapshot_download("AI-ModelScope/bge-large-zh-v1.5", revision: "master");
dynamic model_dir = modelscope.snapshot_download(modelName, revision: "master");
dynamic HuggingFaceBgeEmbeddingstemp = Py.Import("langchain.embeddings");
dynamic HuggingFaceBgeEmbeddingstemp = Py.Import("langchain_community.embeddings.huggingface");
dynamic HuggingFaceBgeEmbeddings = HuggingFaceBgeEmbeddingstemp.HuggingFaceBgeEmbeddings;
string model_name = model_dir;
dynamic model_kwargs = new PyDict();
@@ -72,12 +73,18 @@ namespace AntSK.Domain.Domain.Other
public static int TokenCount(string queryStr)
{
using (Py.GIL())
{
PyObject queryResult = model.client.tokenize(queryStr);
int len = (int)(queryResult.Length());
return len;
}
//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()

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

@@ -80,11 +80,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)
@@ -104,20 +105,43 @@ namespace AntSK.Domain.Domain.Service
var dataMsg = new StringBuilder();
if (relevantSourceList.Any())
{
bool isSearch=false;
foreach (var item in relevantSourceList)
{
//匹配相似度
if (item.Relevance >= app.Relevance/100)
{
dataMsg.AppendLine(item.ToString());
isSearch=true;
}
}
//处理markdown显示
relevantSources?.AddRange(relevantSourceList);
foreach (var item in relevantSourceList)
{
dataMsg.AppendLine(item.ToString());
item.Text = Markdown.ToHtml(item.Text);
}
KernelFunction jsonFun = _kernel.Plugins.GetFunction("KMSPlugin", "Ask1");
var chatResult = _kernel.InvokeStreamingAsync(function: jsonFun,
arguments: new KernelArguments() { ["doc"] = dataMsg, ["history"] = string.Join("\n", history.Select(x => x.Role + ": " + x.Content)), ["questions"] = questions });
await foreach (var content in chatResult)
if (isSearch)
{
yield return content;
//KernelFunction jsonFun = _kernel.Plugins.GetFunction("KMSPlugin", "Ask1");
var temperature = app.Temperature / 100;//存的是0~100需要缩小
OpenAIPromptExecutionSettings settings = new() { Temperature = temperature };
var func = _kernel.CreateFunctionFromPrompt(app.Prompt, settings);
var chatResult = _kernel.InvokeStreamingAsync(function: func,
arguments: new KernelArguments() { ["doc"] = dataMsg.ToString(), ["history"] = string.Join("\n", history.Select(x => x.Role + ": " + x.Content)), ["input"] = questions });
await foreach (var content in chatResult)
{
yield return content;
}
}
else
{
yield return new StreamingTextContent(KmsConstantcs.KmsSearchNull);
}
}
else
{
@@ -135,7 +159,7 @@ namespace AntSK.Domain.Domain.Service
var _kernel = _kernelService.GetKernelByApp(app);
var temperature = app.Temperature / 100; //存的是0~100需要缩小
OpenAIPromptExecutionSettings settings = new() { Temperature = temperature };
var func = _kernel.CreateFunctionFromPrompt("你是一个StableDiffusion提示词助手,需要将用户问题转化为StableDiffusion的英文提示词并返回,请注意只返回提示词不要有其他多余内容,用户的问题是:{{$input}}", settings);
var func = _kernel.CreateFunctionFromPrompt("Translate this into English:{{$input}}", settings);
var chatResult = await _kernel.InvokeAsync(function: func, arguments: args);
if (chatResult.IsNotNull())
{

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
{
@@ -56,7 +60,7 @@ namespace AntSK.Domain.Domain.Service
//导入文本
{
var importResult = _memory.ImportTextAsync(req.Text, fileid, new TagCollection() { { KmsConstantcs.KmsIdTag, req.KmsId } }
, index: KmsConstantcs.KmsIndex).Result;
, index: KmsConstantcs.KmsIndex).Result;
//查询文档数量
var docTextList = _kMService.GetDocumentByFileID(km.Id, fileid).Result;
req.KmsDetail.Url = req.Url;
@@ -64,6 +68,37 @@ 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

@@ -36,7 +36,7 @@ namespace AntSK.Domain.Domain.Service
public List<UploadFileItem> FileList => _fileList;
public MemoryServerless GetMemory(Apps app)
public MemoryServerless GetMemoryByApp(Apps app)
{
var chatModel = _aIModels_Repositories.GetFirst(p => p.Id == app.ChatModelID);
var embedModel = _aIModels_Repositories.GetFirst(p => p.Id == app.EmbeddingModelID);
@@ -45,9 +45,9 @@ namespace AntSK.Domain.Domain.Service
var searchClientConfig = new SearchClientConfig
{
MaxAskPromptSize = 2048,
MaxMatchesCount = 3,
AnswerTokens = 1000,
MaxAskPromptSize = app.MaxAskPromptSize,
MaxMatchesCount = app.MaxMatchesCount,
AnswerTokens = app.AnswerTokens,
EmptyAnswer = KmsConstantcs.KmsSearchNull
};
@@ -71,7 +71,7 @@ namespace AntSK.Domain.Domain.Service
return _memory;
}
public MemoryServerless GetMemoryByKMS(string kmsID, SearchClientConfig searchClientConfig = null)
public MemoryServerless GetMemoryByKMS(string kmsID)
{
//if (_memory.IsNull())
{
@@ -85,19 +85,19 @@ 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,
@@ -277,15 +277,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();
@@ -297,7 +297,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
}));
}

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

@@ -54,6 +54,7 @@ namespace AntSK.Domain.Repositories
/// <summary>
/// 提示词
/// </summary>
[SugarColumn(ColumnDataType = "varchar(2000)")]
public string? Prompt { get; set; }
/// <summary>
@@ -77,5 +78,28 @@ namespace AntSK.Domain.Repositories
/// API调用秘钥
/// </summary>
public string? SecretKey { get; set; }
/// <summary>
/// 相似度
/// </summary>
[SugarColumn(DefaultValue = "70")]
public double Relevance { get; set; } = 70;
/// <summary>
/// 提问最大token数
/// </summary>
[SugarColumn(DefaultValue = "2048")]
public int MaxAskPromptSize { get; set; } = 2048;
/// <summary>
/// 向量匹配数
/// </summary>
[SugarColumn(DefaultValue = "3")]
public int MaxMatchesCount { get; set; } = 3;
/// <summary>
/// 回答最大token数
/// </summary>
[SugarColumn(DefaultValue = "2048")]
public int AnswerTokens { get; set; } = 2048;
}
}

View File

@@ -15,4 +15,6 @@ fastapi
sse-starlette
matplotlib
fire
modelscope
modelscope
langchain-community
sentence_transformers

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

@@ -24,7 +24,7 @@
<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>
<Radio RadioButton Value="@AppType.img.ToString()">做图应用</Radio>
@@ -52,6 +52,14 @@
</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>
}
else
{
@@ -66,17 +74,6 @@
}
@if (@context.Type == AppType.chat.ToString())
{
<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">
<Select Mode="multiple"
@bind-Values="apiIds"
@@ -125,6 +122,19 @@
}
</SelectOptions>
</Select>
<Button Type="@ButtonType.Link" OnClick="NavigateKmsList">去创建</Button>
</FormItem>
<FormItem Label="提问最大token数" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<AntDesign.InputNumber @bind-Value="context.MaxAskPromptSize" PlaceHolder="提问最大token数"></AntDesign.InputNumber>
</FormItem>
<FormItem Label="回答最大token数" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<AntDesign.InputNumber @bind-Value="context.AnswerTokens" PlaceHolder="回答最大token数"></AntDesign.InputNumber>
</FormItem>
<FormItem Label="向量匹配数" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<AntDesign.InputNumber @bind-Value="context.MaxMatchesCount" PlaceHolder="向量匹配数"></AntDesign.InputNumber>
</FormItem>
<FormItem Label="最低相似度(%" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Slider TValue="double" Style="display: inline-block;width: 300px; " Min="0" Max="100" DefaultValue="70" @bind-Value="@context.Relevance" />
</FormItem>
}
<FormItem Label=" " Style="margin-top:32px" WrapperCol="LayoutModel._submitFormLayout.WrapperCol">

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;
@@ -89,7 +90,14 @@ namespace AntSK.Pages.AppPage
}
_appModel.KmsIdList = string.Join(",", kmsIds);
}
if (_appModel.Type == AppType.kms.ToString())
{
if (string.IsNullOrEmpty(_appModel.Prompt)|| !_appModel.Prompt.Contains("{{$doc}}") || !_appModel.Prompt.Contains("{{$input}}"))
{
_ = Message.Error("知识库提示词必须包含 {{$doc}} 和 {{$input}}", 2);
return;
}
}
if (apiIds.IsNotNull())
{
_appModel.ApiFunctionList = string.Join(",", apiIds);
@@ -99,7 +107,7 @@ namespace AntSK.Pages.AppPage
_appModel.NativeFunctionList = string.Join(",", funIds);
}
if (string.IsNullOrEmpty(AppId))
{
//新增
@@ -135,6 +143,25 @@ namespace AntSK.Pages.AppPage
{
NavigationManager.NavigateTo("/setting/modellist");
}
private void NavigateKmsList()
{
NavigationManager.NavigateTo("/KmsList");
}
private void OnAppTypeChange(string value)
{
if (value == AppType.kms.ToString() && string.IsNullOrEmpty( _appModel.Prompt))
{
_appModel.Prompt = KmsConstantcs.KmsPrompt;
}
if (value == AppType.chat.ToString())
{
_appModel.Prompt = "";
}
}
}
}

View File

@@ -60,7 +60,7 @@
}
else if (context.Type == AppType.img.ToString())
{
<Tag Color="@PresetColor.Lime.ToString()">做图应用</Tag>
<Tag Color="@PresetColor.Red.ToString()">做图应用</Tag>
}
</DescriptionTemplate>
</CardMeta>

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

@@ -181,11 +181,11 @@ namespace AntSK.Pages.ChatPage.Components
var base64= await _chatService.SendImgByAppAsync(app, questions);
if (string.IsNullOrEmpty(base64))
{
info.HtmlAnswers = "生成失败";
info.Context = "生成失败";
}
else
{
info.HtmlAnswers = $"<img src=\"data:image/jpeg;base64,{base64}\" alt=\"Base64 Image\" />";
info.Context = $"<img src=\"data:image/jpeg;base64,{base64}\" alt=\"Base64 Image\" />";
}
MessageList.Add(info);
}
@@ -208,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);
@@ -243,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);
@@ -264,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

@@ -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,112 @@
@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"
@@ -153,9 +165,30 @@
</Upload>
</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">
支持excel文件。
</p>
</Upload>
</Modal>
@code {
RenderFragment _fileUpload(Action clickAction) =>@<MenuItem>
<a target="_blank" rel="noopener noreferrer" @onclick="@clickAction">
文件导入
@@ -174,6 +207,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

@@ -30,6 +30,9 @@ namespace AntSK.Pages.KmsPage
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;
@@ -212,19 +215,47 @@ 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
});
}
_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 +287,5 @@ namespace AntSK.Pages.KmsPage
await InvokeAsync(StateHasChanged);
}
}
#endregion File
}
}

View File

@@ -8,16 +8,36 @@
<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>
<AvatarTemplate>
</AvatarTemplate>
<TitleTemplate>
<a>@context.LastUpdate</a>
</TitleTemplate>
<DescriptionTemplate>
<Paragraph class="item" Ellipsis Style=" white-space: nowrap; ">
<!--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

@@ -24,11 +24,10 @@
</FormItem>
<FormItem Label="AI类型" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<EnumRadioGroup @bind-Value="context.AIType" ButtonStyle="RadioButtonStyle.Solid"> </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">
<RadioGroup @bind-Value="context.AIModelType">
@if (context.AIType == AIType.StableDiffusion)
{
<Radio RadioButton Value="@(AIModelType.Image)">图片模型</Radio>
@@ -39,7 +38,7 @@
{
<Radio RadioButton Value="@(AIModelType.Chat)">会话模型</Radio>
}
@if (context.AIType != AIType.LLamaFactory && context.AIType != AIType.Mock)
@if (context.AIType != AIType.LLamaFactory && context.AIType != AIType.Mock && context.AIType != AIType.SparkDesk)
{
<Radio RadioButton Value="@(AIModelType.Embedding)">向量模型</Radio>
}
@@ -127,6 +126,9 @@
<FormItem Label="请求地址" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Input Placeholder="http://localhost:8080/" @bind-Value="@context.EndPoint" />
</FormItem>
<FormItem Label="环境安装" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Button Type="primary" OnClick="PipInstall">环境安装</Button>
</FormItem>
<FormItem Label="llama factory服务" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<InputGroup>
@if (!llamaFactoryIsStart)
@@ -138,10 +140,7 @@
<Button OnClick="StopLFService" Disabled="@(!llamaFactoryIsStart)">停止</Button>
}
</InputGroup>
</FormItem>
<FormItem Label="环境安装" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Button Type="primary" OnClick="PipInstall">初始化</Button>
</FormItem>
</FormItem>
}
@if (context.AIType == AIType.BgeEmbedding)
@@ -156,6 +155,9 @@
<FormItem Label="PythonDll路径" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Input Placeholder="D:\Programs\Python\Python311\python311.dll" @bind-Value="@context.EndPoint" />
</FormItem>
<FormItem Label="环境安装" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Button Type="primary" OnClick="PipInstall">环境安装</Button>
</FormItem>
<FormItem Label="下载并初始化" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
<Spin Tip="请等待..." Spinning="@(BgeIsStart)" >
<Button Type="primary" Disabled="@(BgeIsStart)" OnClick="BgeDownload">@BgeBtnText</Button>

View File

@@ -233,7 +233,7 @@ namespace AntSK.Pages.Setting.AIModel
/// <summary>
/// 启动服务
/// </summary>
private void StartLFService()
private async Task StartLFService()
{
if (string.IsNullOrEmpty(_aiModel.ModelName))
{
@@ -264,7 +264,7 @@ namespace AntSK.Pages.Setting.AIModel
{
_logModalVisible = true;
_ILLamaFactoryService.LogMessageReceived += CmdLogHandler;
await _ILLamaFactoryService.PipInstall();
_ILLamaFactoryService.PipInstall();
}
}
@@ -314,9 +314,27 @@ namespace AntSK.Pages.Setting.AIModel
_logModalVisible = false;
}
private void AITypeModelChange()
{
private void AITypeChange(AIType aiType)
{
switch (aiType)
{
case AIType.LLamaFactory:
_aiModel.EndPoint = "http://localhost:8080/";
_aiModel.AIModelType=AIModelType.Chat;
break;
case AIType.StableDiffusion:
_aiModel.AIModelType = AIModelType.Image;
break;
case AIType.Mock:
_aiModel.AIModelType = AIModelType.Chat;
break ;
case AIType.BgeEmbedding:
_aiModel.AIModelType = AIModelType.Embedding;
break;
default:
_aiModel.AIModelType = AIModelType.Chat;
break;
}
}
}
}

View File

@@ -10,7 +10,7 @@
<PageContainer Title="模型列表">
<Content>
<RadioGroup @bind-Value="@_modelType">
<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>

View File

@@ -48,5 +48,10 @@ namespace AntSK.Pages.Setting.AIModel
{
NavigationManager.NavigateTo($"/setting/modeldown/detail/{modelPath}");
}
private void OnModelTypeChange(string value)
{
InitData("");
}
}
}

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

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