Compare commits
555 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c4030ae43 | ||
|
|
c912ceeee0 | ||
|
|
58c5edbc5e | ||
|
|
3d86fd1125 | ||
|
|
f8c6a05380 | ||
|
|
10b4706094 | ||
|
|
3f7e2d29e1 | ||
|
|
d93e962ae9 | ||
|
|
1da5d5bce1 | ||
|
|
b853ab4851 | ||
|
|
00b37d9600 | ||
|
|
c467a3c427 | ||
|
|
06cdbb14d0 | ||
|
|
115e12257b | ||
|
|
533a47566b | ||
|
|
51ec2db3c3 | ||
|
|
3aa76e0662 | ||
|
|
755d2c2d4f | ||
|
|
bd27048237 | ||
|
|
01063f2d49 | ||
|
|
5a4f038da1 | ||
|
|
dd6e1a6d54 | ||
|
|
52e20396ad | ||
|
|
a8f48929e7 | ||
|
|
ae89fb5ec7 | ||
|
|
48a8670f01 | ||
|
|
2c8efd2eef | ||
|
|
a4acb80151 | ||
|
|
a8f143995d | ||
|
|
e46b02d70b | ||
|
|
31ea75ecba | ||
|
|
e2142deb4a | ||
|
|
a6b11bb33d | ||
|
|
773073b847 | ||
|
|
2bd38b96e7 | ||
|
|
f7bcbcfc95 | ||
|
|
6f5429695c | ||
|
|
547a3b5919 | ||
|
|
358909892c | ||
|
|
6c1bc4be04 | ||
|
|
431c754f42 | ||
|
|
f46faa7679 | ||
|
|
195053cbd7 | ||
|
|
b41d79c247 | ||
|
|
5acab7a46f | ||
|
|
5b83c844a1 | ||
|
|
2325c58092 | ||
|
|
04d16148b5 | ||
|
|
f0f14889c7 | ||
|
|
dedafdd108 | ||
|
|
fad2b4e733 | ||
|
|
032de7a447 | ||
|
|
cb0df4d4af | ||
|
|
c810f85cea | ||
|
|
6700b75684 | ||
|
|
ab15dd6e99 | ||
|
|
13a4419705 | ||
|
|
cf03465e23 | ||
|
|
a441730508 | ||
|
|
6e30886bd2 | ||
|
|
bc2af42724 | ||
|
|
919fc5dea7 | ||
|
|
9ab287fabd | ||
|
|
cf02efc2da | ||
|
|
1c34ad5987 | ||
|
|
4e8039703e | ||
|
|
c2b97c7f82 | ||
|
|
1a621f5cbc | ||
|
|
836f898ffe | ||
|
|
0a9a737709 | ||
|
|
0df8c74ec2 | ||
|
|
5e3ff74eaa | ||
|
|
7c49ff0a6c | ||
|
|
63f5267bca | ||
|
|
e0c35aac06 | ||
|
|
27d52d3331 | ||
|
|
e7b2c6e193 | ||
|
|
7600397b79 | ||
|
|
874b8e5d7f | ||
|
|
3ac18086a1 | ||
|
|
16049c7413 | ||
|
|
7bb7a41bb3 | ||
|
|
6c37ed66b2 | ||
|
|
bc86f96159 | ||
|
|
8eb09fb783 | ||
|
|
eff5f69f0f | ||
|
|
e3f966d4f2 | ||
|
|
015f51b99c | ||
|
|
cd66b61014 | ||
|
|
f0bef7d2fa | ||
|
|
de051b047d | ||
|
|
ed6f5dada2 | ||
|
|
d2e3fde829 | ||
|
|
195551e9c1 | ||
|
|
855103c2a4 | ||
|
|
6150d543d3 | ||
|
|
d968d78982 | ||
|
|
0ec5d1f1cf | ||
|
|
31f44c1758 | ||
|
|
e5f63d605d | ||
|
|
7db62e3dc6 | ||
|
|
4408fa4345 | ||
|
|
c5e952b98e | ||
|
|
bedfeaf53d | ||
|
|
d605fd6685 | ||
|
|
e5e3f7cd8f | ||
|
|
657949694c | ||
|
|
10b6035f84 | ||
|
|
3f9fe27456 | ||
|
|
da3a0681e5 | ||
|
|
57b7948d86 | ||
|
|
40b8bd0439 | ||
|
|
6ed9cc9b70 | ||
|
|
e51bf35217 | ||
|
|
28f88438e7 | ||
|
|
85f4a330d5 | ||
|
|
21d7c719f1 | ||
|
|
4ef398bd57 | ||
|
|
dc70270362 | ||
|
|
97b7211cce | ||
|
|
3e762e13af | ||
|
|
e084317a46 | ||
|
|
531b4473e8 | ||
|
|
aefd0d2775 | ||
|
|
960468edf0 | ||
|
|
07ad1f58b5 | ||
|
|
095428be50 | ||
|
|
87fc8911fa | ||
|
|
58272e1ce8 | ||
|
|
700bbcb63f | ||
|
|
dde1d68876 | ||
|
|
71553a6153 | ||
|
|
d4f8de3e21 | ||
|
|
6cf5dea10d | ||
|
|
05379dfee6 | ||
|
|
5a6d49ff64 | ||
|
|
64ab940a26 | ||
|
|
55982ea36d | ||
|
|
21efcf2479 | ||
|
|
0dc7bfcadb | ||
|
|
22d99091e1 | ||
|
|
7558d3ffdc | ||
|
|
85ae41c44c | ||
|
|
91193850dd | ||
|
|
7cc04e3364 | ||
|
|
3da28090c6 | ||
|
|
1595ef2c0a | ||
|
|
83e3d81de7 | ||
|
|
18437ddda4 | ||
|
|
fd503171a1 | ||
|
|
7022139780 | ||
|
|
1e508e45af | ||
|
|
03d9ec2cad | ||
|
|
86fb48bab7 | ||
|
|
a4bc1e4a55 | ||
|
|
8681e15da5 | ||
|
|
ebc82f8b1b | ||
|
|
3bcd7bd7e1 | ||
|
|
b64d8669b1 | ||
|
|
0489044098 | ||
|
|
17e2062b72 | ||
|
|
4e4f5a698d | ||
|
|
b879d04bcd | ||
|
|
95f918f4c7 | ||
|
|
f0e1ad6088 | ||
|
|
61773af48d | ||
|
|
54cd04c3bf | ||
|
|
cd9f4ae11b | ||
|
|
3f9c748b41 | ||
|
|
d483005531 | ||
|
|
1d2db6a896 | ||
|
|
9a7a263055 | ||
|
|
6beb0b52c7 | ||
|
|
0ea167a204 | ||
|
|
6e6afa2a7c | ||
|
|
7a2a5d86bb | ||
|
|
a1a36c3494 | ||
|
|
4f350081dd | ||
|
|
b3ea0c4e1a | ||
|
|
e72a6acd03 | ||
|
|
9bb8ab89fe | ||
|
|
e78da66d1a | ||
|
|
9ee21fd5e5 | ||
|
|
a22c04c9b2 | ||
|
|
3bb5bfaca7 | ||
|
|
c4bf5ee7e5 | ||
|
|
5e1e688f84 | ||
|
|
80d9bf68f3 | ||
|
|
65f2e3e363 | ||
|
|
68d27ff2bc | ||
|
|
034da30811 | ||
|
|
3db0cdcd19 | ||
|
|
42181a6f1d | ||
|
|
ec8cbf2550 | ||
|
|
9a1bd079da | ||
|
|
4213c4379c | ||
|
|
05cda17e2e | ||
|
|
cda6e54f0b | ||
|
|
51d8ba6408 | ||
|
|
b571c7d22d | ||
|
|
a0c91f565e | ||
|
|
280c750165 | ||
|
|
fec9337fda | ||
|
|
b84f252f2f | ||
|
|
5c998ccce2 | ||
|
|
0e3cfd2cfb | ||
|
|
4040831a23 | ||
|
|
a3a2308659 | ||
|
|
6d43c71d13 | ||
|
|
8315b6f37f | ||
|
|
7bc708e6ae | ||
|
|
e6f2c5c2fe | ||
|
|
5cab781362 | ||
|
|
02d7994bae | ||
|
|
b740957157 | ||
|
|
2480ec1272 | ||
|
|
35c98a0d14 | ||
|
|
0964a5ad5b | ||
|
|
a95131efe9 | ||
|
|
7783cdf3c4 | ||
|
|
7a65f33cb6 | ||
|
|
6efd01db3f | ||
|
|
1e2322b573 | ||
|
|
2cb2241a66 | ||
|
|
64efdd7881 | ||
|
|
be28e32803 | ||
|
|
468422baee | ||
|
|
7b1c6c8c64 | ||
|
|
7ff0ea0bfe | ||
|
|
6bed4356f0 | ||
|
|
73b65f7305 | ||
|
|
0ea52eced9 | ||
|
|
498e9ba9f6 | ||
|
|
125695665b | ||
|
|
0e08b3ae85 | ||
|
|
7cb8f99e7e | ||
|
|
d15cb527d0 | ||
|
|
9cb36174fd | ||
|
|
6265f94ef2 | ||
|
|
09d90b654c | ||
|
|
64e2bca2e6 | ||
|
|
328ece6d73 | ||
|
|
fabb8c2044 | ||
|
|
6ca75df880 | ||
|
|
3d4dfaced1 | ||
|
|
d532bf3bb6 | ||
|
|
e1fd288875 | ||
|
|
91eae9cfa8 | ||
|
|
b0059942d3 | ||
|
|
a716982878 | ||
|
|
3d4e48f9f5 | ||
|
|
1f212d3156 | ||
|
|
7d91ef6ba1 | ||
|
|
2a450b00de | ||
|
|
3a97068248 | ||
|
|
1d9d95899a | ||
|
|
7ae8e52b57 | ||
|
|
f5c195a1d0 | ||
|
|
78a6b662d3 | ||
|
|
5f814eb76c | ||
|
|
d9e5ebb464 | ||
|
|
bce0e9183c | ||
|
|
c40a7bcf22 | ||
|
|
97a7d447ab | ||
|
|
f803b9538b | ||
|
|
1ac34c1702 | ||
|
|
e07b480da1 | ||
|
|
9036af57e3 | ||
|
|
93288f9b5c | ||
|
|
f40dd8b013 | ||
|
|
c6b83d0695 | ||
|
|
592c850198 | ||
|
|
4a3930ac7b | ||
|
|
c05ba0af3e | ||
|
|
630ee51df6 | ||
|
|
d0e75e26c3 | ||
|
|
62c36c3072 | ||
|
|
baef309064 | ||
|
|
d717cbad9c | ||
|
|
5ef0624605 | ||
|
|
af2930a371 | ||
|
|
98f0f9fe84 | ||
|
|
28a23271e9 | ||
|
|
f1ba0bdf10 | ||
|
|
0d5513f374 | ||
|
|
4812cc308c | ||
|
|
584f7faded | ||
|
|
08dcef2d8b | ||
|
|
68218733a2 | ||
|
|
eb64cbf3d4 | ||
|
|
f0e8a55522 | ||
|
|
5ec5a0bde4 | ||
|
|
1cc56dd553 | ||
|
|
64e949a88b | ||
|
|
a2390a7c97 | ||
|
|
559661bb6c | ||
|
|
79326de263 | ||
|
|
3815891b28 | ||
|
|
42d474382a | ||
|
|
fe691f2d44 | ||
|
|
3ee41a8ab1 | ||
|
|
7ca41dff8a | ||
|
|
ba2e86993e | ||
|
|
13878046a2 | ||
|
|
49ff8bf54f | ||
|
|
e9cc5a3993 | ||
|
|
b213964b63 | ||
|
|
bfbed44270 | ||
|
|
9b07d88392 | ||
|
|
3f8ed109f9 | ||
|
|
3f969627a4 | ||
|
|
d92970819a | ||
|
|
23e756fa9b | ||
|
|
5f58126fbf | ||
|
|
dcfd0ffb8f | ||
|
|
17221d056c | ||
|
|
4a9dcfada4 | ||
|
|
bb6c2bb020 | ||
|
|
a8760a34de | ||
|
|
1e432a5782 | ||
|
|
cb861ef2bb | ||
|
|
7cee8fd87a | ||
|
|
8ce0e5d348 | ||
|
|
90bce7c89f | ||
|
|
b840d0bcce | ||
|
|
bfa6d28289 | ||
|
|
f6e6ca9747 | ||
|
|
75f8d39648 | ||
|
|
9a939eba5a | ||
|
|
4e93efe821 | ||
|
|
8bdbee80a0 | ||
|
|
6bdf5dcc03 | ||
|
|
0bf0a9d78a | ||
|
|
38e9fea601 | ||
|
|
d2366b3b46 | ||
|
|
3aff93083a | ||
|
|
eb998199db | ||
|
|
1dd794af1b | ||
|
|
08c9923e7e | ||
|
|
06b109ca87 | ||
|
|
9b039335c7 | ||
|
|
041378e5fd | ||
|
|
6dc5ae10e3 | ||
|
|
5807f4c283 | ||
|
|
8ef4445908 | ||
|
|
8a0609e970 | ||
|
|
9f33b5009b | ||
|
|
50e66db8a1 | ||
|
|
c3e83b569a | ||
|
|
85d1c5ea7e | ||
|
|
ec1d126a02 | ||
|
|
e857695e70 | ||
|
|
fa9b2051fe | ||
|
|
d450efcffe | ||
|
|
2a6c84c200 | ||
|
|
138a952ace | ||
|
|
eb6528ecd2 | ||
|
|
2c30bbfa09 | ||
|
|
c5a78c2135 | ||
|
|
f03362ee41 | ||
|
|
fad3167d97 | ||
|
|
ad949681dd | ||
|
|
27999d76b0 | ||
|
|
83278352d6 | ||
|
|
fcc56f5fef | ||
|
|
4ebe2ecc32 | ||
|
|
e684cba527 | ||
|
|
888dc19ee0 | ||
|
|
731aea702f | ||
|
|
09e22bc76a | ||
|
|
74406d88a0 | ||
|
|
e5f9d97560 | ||
|
|
59e768aaea | ||
|
|
6a7cb24a5b | ||
|
|
1db40d534c | ||
|
|
11d6e30f7e | ||
|
|
9d5214aaae | ||
|
|
010b906271 | ||
|
|
16bf944edf | ||
|
|
5bae5a099a | ||
|
|
f771ea9521 | ||
|
|
994efbf37c | ||
|
|
938cd86c88 | ||
|
|
1339cbadbc | ||
|
|
bd0ad570ad | ||
|
|
234e649a7e | ||
|
|
c431dbc842 | ||
|
|
76283060d9 | ||
|
|
75ba506db4 | ||
|
|
e086ca60df | ||
|
|
04acaa9b12 | ||
|
|
7a824bf18c | ||
|
|
769de2e526 | ||
|
|
c9950609c9 | ||
|
|
ccee6cfea5 | ||
|
|
f626c618be | ||
|
|
3b601a9e3d | ||
|
|
3d5f63d595 | ||
|
|
6933f2f495 | ||
|
|
79c7e8626a | ||
|
|
4a017d311c | ||
|
|
0c8ad5fe8d | ||
|
|
68ce0db011 | ||
|
|
c36de1a1e9 | ||
|
|
44ef759abd | ||
|
|
0c3d9844be | ||
|
|
854c62a4ca | ||
|
|
5ed4fd5299 | ||
|
|
af5ec43571 | ||
|
|
24d685879e | ||
|
|
e801a2ec46 | ||
|
|
d7b56d1590 | ||
|
|
b925f8890b | ||
|
|
5d80ee994a | ||
|
|
da8f955ca2 | ||
|
|
2e04582c5e | ||
|
|
e69994f727 | ||
|
|
d8dc26127d | ||
|
|
f73bd2dfda | ||
|
|
9f08b60348 | ||
|
|
75c2f36b30 | ||
|
|
39c02a6064 | ||
|
|
52c119befd | ||
|
|
23903ded3f | ||
|
|
4799fbac72 | ||
|
|
16a7d55271 | ||
|
|
be0bafcc50 | ||
|
|
defc51a074 | ||
|
|
09709c210d | ||
|
|
8ebb2f54eb | ||
|
|
b831aab115 | ||
|
|
8e322162cc | ||
|
|
6a8a6509b8 | ||
|
|
707dff09f8 | ||
|
|
17c8fca40f | ||
|
|
415f9757e9 | ||
|
|
27394f0699 | ||
|
|
8a9ca40bb6 | ||
|
|
f340ee1088 | ||
|
|
080eb5765e | ||
|
|
36c8ff184a | ||
|
|
0486f67b50 | ||
|
|
aa7e8d545c | ||
|
|
59f6a899a6 | ||
|
|
0fc98d42aa | ||
|
|
edad2644aa | ||
|
|
8a56a0393a | ||
|
|
f4cbf9a40a | ||
|
|
fb5b92f499 | ||
|
|
c286258f2b | ||
|
|
4416651589 | ||
|
|
48a33e8977 | ||
|
|
bd5ca06d8f | ||
|
|
e0985ecec3 | ||
|
|
e56b74d4af | ||
|
|
c417098c2c | ||
|
|
93527215a7 | ||
|
|
0cf3945693 | ||
|
|
ced2a9b2e2 | ||
|
|
987b231c4d | ||
|
|
7a541c1da1 | ||
|
|
74e323158d | ||
|
|
563a7409f6 | ||
|
|
b13b93e04e | ||
|
|
44568c8d65 | ||
|
|
fb277dff80 | ||
|
|
efae890650 | ||
|
|
a146f6059e | ||
|
|
3c67096cd8 | ||
|
|
a993a60f95 | ||
|
|
d3fdc77600 | ||
|
|
b62c56e36f | ||
|
|
7d72911239 | ||
|
|
9e24d7cc67 | ||
|
|
9baa24b496 | ||
|
|
da826525f7 | ||
|
|
62dfab41fd | ||
|
|
04fc811c2c | ||
|
|
8638ecbe29 | ||
|
|
6f1f93fbaf | ||
|
|
dc38d83f89 | ||
|
|
fd780780c5 | ||
|
|
6fd918f33b | ||
|
|
8fcfa8974b | ||
|
|
7e23c32c6c | ||
|
|
7fdfceeea5 | ||
|
|
bf0e62634f | ||
|
|
469ef9aab2 | ||
|
|
f7df26030d | ||
|
|
f61cbe9780 | ||
|
|
56b62cff2a | ||
|
|
0aec21cf03 | ||
|
|
ff4f6be5fc | ||
|
|
964a5022c8 | ||
|
|
849b18f677 | ||
|
|
b8c6a6a626 | ||
|
|
57fc9a9b7e | ||
|
|
068c126a23 | ||
|
|
0ed1662c7b | ||
|
|
a09377814f | ||
|
|
3cc952bb2a | ||
|
|
63c968742b | ||
|
|
a4d6f2a6fd | ||
|
|
d6de64853d | ||
|
|
344128e49d | ||
|
|
56fc9dd517 | ||
|
|
c7c1911eb1 | ||
|
|
dec8b5bef7 | ||
|
|
db7271b519 | ||
|
|
fcbee1f64f | ||
|
|
2d9443a0a1 | ||
|
|
6e3dd00d6f | ||
|
|
7a0656cd81 | ||
|
|
3b89d9e974 | ||
|
|
cd174308cf | ||
|
|
aacef47626 | ||
|
|
fcef01a41f | ||
|
|
7d19b694fa | ||
|
|
966a31b156 | ||
|
|
7538393742 | ||
|
|
3658188be2 | ||
|
|
fcd9fb9079 | ||
|
|
d1168e16d6 | ||
|
|
25a6f00dd2 | ||
|
|
13c474f084 | ||
|
|
8d78270007 | ||
|
|
a94b59c156 | ||
|
|
ae6d61ee6d | ||
|
|
74a7c94619 | ||
|
|
bdd34ac786 | ||
|
|
0e754b4732 | ||
|
|
48a9fcfabf | ||
|
|
7ae2b9ac3b | ||
|
|
a6bfe3c69b | ||
|
|
6b146f4750 | ||
|
|
1387e716d1 | ||
|
|
fadc350047 | ||
|
|
8af4994a7d | ||
|
|
b505b61bfe | ||
|
|
5d086c9383 | ||
|
|
dd0e367dc8 | ||
|
|
7110eea912 | ||
|
|
154e67ef98 | ||
|
|
4a04423373 | ||
|
|
470ea50ebb | ||
|
|
2a30f3f221 | ||
|
|
315f58fdba | ||
|
|
f027682175 | ||
|
|
2618dffcd6 | ||
|
|
ee42d5870b | ||
|
|
27500b1e08 | ||
|
|
4d71a98724 | ||
|
|
b8ba0ab391 | ||
|
|
b589612913 | ||
|
|
ec4b440469 |
7
.gitignore
vendored
@@ -324,10 +324,6 @@ ASALocalRun/
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
*.dll
|
||||
*.pdb
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
**/bin/
|
||||
@@ -337,8 +333,9 @@ ASALocalRun/
|
||||
/AntSK/appsettings.Development.json
|
||||
/AntSK.db
|
||||
**/tmp-memory-files/*
|
||||
**/tmp-memory-vectors/*
|
||||
/src/AntSK/AntSK.db
|
||||
/src/AntSK/appsettings.Development.json
|
||||
/src/AntSK.db
|
||||
/src/AntSK/llama_models
|
||||
/src/AntSK/AntSK.xml
|
||||
/src/AntSK/AntSK.xml
|
||||
@@ -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"]
|
||||
|
||||
17
Dockerfile-py
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["src/AntSK/AntSK.csproj", "AntSK/"]
|
||||
RUN dotnet restore "AntSK/AntSK.csproj"
|
||||
COPY src/ .
|
||||
WORKDIR "/src/AntSK"
|
||||
RUN dotnet build "AntSK.csproj" -c Release -o /app/build
|
||||
RUN dotnet publish "AntSK.csproj" -c Release -o /app/publish
|
||||
|
||||
FROM registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk-base:v1.0.0 AS final
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/publish .
|
||||
|
||||
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
|
||||
ENTRYPOINT ["dotnet", "AntSK.dll"]
|
||||
216
LICENSE
@@ -1,201 +1,79 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
## AntSK 用户协议
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
欢迎使用 AntSK 。请仔细阅读以下协议条款,继续使用本软件即表示您同意本协议内容。
|
||||
|
||||
1. Definitions.
|
||||
**许可协议**
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
本软件采用 Apache License 2.0 许可。除 Apache License 2.0 规定的条款外,您在使用 AntSK 时还应遵守以下附加条款:
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
**一. 商用许可**
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
1. **免费商用**:用户在不修改代码的情况下,可以免费用于商业目的。
|
||||
2. **商业授权**:如果您满足以下任意条件之一,需取得商业授权:
|
||||
1. 对本软件进行二次修改、开发(包括但不限于修改应用名称、logo、代码以及功能)。
|
||||
2. 为企业客户提供多租户服务,且该服务支持 10 人或以上的使用。
|
||||
3. 预装或集成到硬件设备或产品中进行捆绑销售。
|
||||
4. 政府或教育机构的大规模采购项目,特别是涉及安全、数据隐私等敏感需求时。
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
**二. 贡献者协议**
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
作为 AntSK 的贡献者,您应当同意以下条款:
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
1. **许可调整**:生产者有权根据需要对开源协议进行调整,使其更加严格或宽松。
|
||||
2. **商业用途**:您贡献的代码可能会被用于商业用途,包括但不限于云业务运营。
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
**三. 其他条款**
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
1. 本协议条款的解释权归 AntSK 开发者所有。
|
||||
2. 本协议可能根据实际情况进行更新,更新时将通过本软件通知用户。
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
如有任何问题或需申请商业授权,请联系 AntSK 开发团队。
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
除上述特定条件外,其他所有权利和限制均遵循 Apache License 2.0。有关 Apache License 2.0 的详细信息,请访问 http://www.apache.org/licenses/LICENSE-2.0。
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
---
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
根据 Apache 许可证 2.0 版(“许可证”)进行许可;除非符合许可证,否则您不得使用此文件。您可以在以下网址获取许可证副本:
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
除非适用法律要求或书面同意,软件根据许可证分发的内容以“原样”分发,不附带任何明示或暗示的保证或条件。请参阅特定语言管理权限的许可证和许可证下的限制。
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
## AntSK User Agreement
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
Welcome to AntSK, a AI knowledge base. Please read the following agreement carefully. By continuing to use this software, you agree to the terms outlined below.
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
**License Agreement**
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
This software is licensed under the **Apache License 2.0**. In addition to the terms of the Apache License 2.0, the following additional terms apply to the use of AntSK:
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
**I. Commercial Use License**
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
1. **Free Commercial Use**: Users can use the software for commercial purposes without modifying the code.
|
||||
2. **Commercial License Required**: A commercial license is required if any of the following conditions are met:
|
||||
1. You modify, develop, or alter the software, including but not limited to changes to the application name, logo, code, or functionality.
|
||||
2. You provide multi-tenant services to enterprise customers with 10 or more users.
|
||||
3. You pre-install or integrate the software into hardware devices or products and bundle it for sale.
|
||||
4. You are engaging in large-scale procurement for government or educational institutions, especially involving security, data privacy, or other sensitive requirements.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
**II. Contributor Agreement**
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
As a contributor to AntSK, you agree to the following:
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
1. **License Adjustment**: The producer reserves the right to adjust the open-source license as needed, making it stricter or more lenient.
|
||||
2. **Commercial Use**: Any code you contribute may be used for commercial purposes, including but not limited to cloud business operations.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
**III. Other Terms**
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
1. The interpretation of these terms is subject to the discretion of AntSK developers.
|
||||
2. These terms may be updated, and users will be notified through the software when changes occur.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
For any questions or to request a commercial license, please contact the AntSK development team.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Apart from the specific conditions mentioned above, all other rights and restrictions follow the Apache License 2.0. Detailed information about the Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
---
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
215
README.en.md
@@ -1,215 +0,0 @@
|
||||
[简体中文](./README.md) | English
|
||||
# AntSK
|
||||
|
||||
## Based on AI knowledge base/agent created by Net8+AntBlazor+SemanticKernel
|
||||
|
||||
|
||||
|
||||
## Core functions
|
||||
|
||||
|
||||
|
||||
- **Semantic Kernel**: It uses advanced natural language processing technology to accurately understand, process and respond to complex semantic queries, and provides users with accurate information retrieval and recommendation services.
|
||||
|
||||
|
||||
|
||||
- **Kernel Memory**: It has the ability to continuously learn and store knowledge points. AntSK has a long-term memory function to accumulate experience and provide a more personalized interactive experience.
|
||||
|
||||
|
||||
|
||||
- **Knowledge base**: Knowledge base documents can be created by importing knowledge base documents (Word, PDF, Excel, Txt, Markdown, Json, PPT) and other forms.
|
||||
|
||||
|
||||
|
||||
- **API plug-in system**: an open API plug-in system that allows third-party developers or service providers to easily integrate their services into AntSK and continuously enhance application functions.
|
||||
|
||||
|
||||
|
||||
- **Online search**: AntSK can obtain the latest information in real time to ensure that the information received by users is always the most timely and relevant.
|
||||
|
||||
|
||||
|
||||
- **GPTs generation**: This platform supports the creation of personalized GPT models and attempts to build your own GPT models.
|
||||
|
||||
|
||||
|
||||
- **API interface publishing**: internal functions are provided externally in the form of API, so that developers can easily translate Xzy AntSK KnowledgeBase is integrated into other applications to enhance application intelligence.
|
||||
|
||||
- **Model management**: Adapt and manage different models from different vendors.
|
||||
|
||||
|
||||
|
||||
## Application scenarios
|
||||
|
||||
|
||||
|
||||
AntSK is applicable to a variety of business scenarios, such as:
|
||||
|
||||
- Enterprise level knowledge management system
|
||||
|
||||
- Automatic customer service and chat robot
|
||||
|
||||
- Enterprise Search Engine
|
||||
|
||||
- Personalized recommendation system
|
||||
|
||||
- Intelligent assisted writing
|
||||
|
||||
- Education and online learning platform
|
||||
|
||||
- Other interesting AI Apps
|
||||
|
||||
|
||||
|
||||
## Function example
|
||||
|
||||
|
||||
|
||||
First, you need to create a knowledge base
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
In the knowledge base, you can use documents or urls to import
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
Click View to view the document slicing of the knowledge base
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
Then we need to create applications, which can create dialog applications and knowledge bases.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
The application of knowledge base needs to select the existing knowledge base, which can be multiple
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
Then you can ask questions about the knowledge base documents in the dialogue
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
In addition, we can also create dialogue applications, and configure prompt word templates in corresponding applications
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
Let's see the effect
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## How do I get started?
|
||||
|
||||
Login is the default login account and password
|
||||
|
||||
Here I use Postgres as data storage and vector storage, because both the Semantic Kernel and Kernel Memory support it. Of course, you can switch to other ones.
|
||||
|
||||
The model supports openai by default. If you need to use azure openai and need to adjust the dependency injection of SK, you can also use one api for integration.
|
||||
|
||||
The following configuration files need to be configured
|
||||
|
||||
## Using Docker Compose
|
||||
Provided pg version appsettings. json and simplified version (Sqlite+disk) Docker Compose. simple. yml
|
||||
Download Docker Compose.yml from the project root directory, and then place the configuration file appsettings.json and it in a unified directory,
|
||||
The image of PG has been prepared here. You can modify the default account password in Docker Compose.yml, and your appsettings. json database connection needs to be consistent.
|
||||
Then you can enter the directory and execute it
|
||||
```
|
||||
docker compose up - d
|
||||
```
|
||||
To start AntSK
|
||||
|
||||
Some meanings of configuration files
|
||||
|
||||
```
|
||||
|
||||
{
|
||||
"DBConnection": {
|
||||
"DbType": "Sqlite",
|
||||
"ConnectionStrings": "Data Source=AntSK.db;"
|
||||
},
|
||||
"OpenAIOption": {
|
||||
"EndPoint": "http://localhost:5000/llama/",
|
||||
"Key": "NotNull",
|
||||
"Model": "gpt4-turbo",
|
||||
"EmbeddingModel": "text-embedding-ada-002"
|
||||
},
|
||||
"KernelMemory": {
|
||||
"VectorDb": "Disk",
|
||||
"ConnectionString": "Host=;Port=;Database=antsk;Username=;Password=",
|
||||
"TableNamePrefix": "km-"
|
||||
},
|
||||
"LLamaSharp": {
|
||||
"RunType": "GPU",
|
||||
"Chat": "D:\\Code\\AI\\AntBlazor\\model\\qwen1_5-1_8b-chat-q8_0.gguf",
|
||||
"Embedding": "D:\\Code\\AI\\AntBlazor\\model\\qwen1_5-1_8b-chat-q8_0.gguf"
|
||||
},
|
||||
"Login": {
|
||||
"User": "admin",
|
||||
"Password": "xuzeyu"
|
||||
},
|
||||
"BackgroundTaskBroker": {
|
||||
"ImportKMSTask": {
|
||||
"WorkerCount": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
//Supports multiple databases, including SqlSugar, MySql, SqlServer, Sqlite, Oracle, PostgreSQL, Dm, Kdbndp, Oscar, MySqlConnector, Access, OpenGaussian, QuestDB, HG, ClickHouse, GBase, Odbc, OceanBaseForOracle, TDengine, GaussDB, OceanBase, Tidb, Vastbase, PolarDB, Custom
|
||||
DBConnection DbType
|
||||
//Connection string, corresponding strings need to be used according to different DB types
|
||||
DBConnection ConnectionStrings
|
||||
//You can use an online API that conforms to the OpenAI format (domestic models use one API adapter), or you can use AntSK's built-in llama API, with the IP and port being the AntSK startup address
|
||||
OpenAIOption EndPoint
|
||||
//Model key, if using a local model, it can default to Notnull. Chinese cannot be used here
|
||||
OpenAIOption Key
|
||||
//The type of vector storage supports Postgres Disk Memory, where Postgres requires the configuration of ConnectionString
|
||||
KernelMemory VectorDb
|
||||
//The running mode used by the local model is GUP CPU. If using an online API, you can freely use one
|
||||
LLamaSharp RunType
|
||||
//The model path of the local session model should pay attention to distinguishing between Linux and Windows drive letters
|
||||
LLamaSharp Chat
|
||||
//The model path of the local vector model should pay attention to distinguishing between Linux and Windows drive letters
|
||||
LLamaSharp Embedding
|
||||
//Default administrator account password
|
||||
Login
|
||||
//The number of threads for importing asynchronous processing can be higher when using online APIs. Local models suggest 1, otherwise memory overflow and crash may occur
|
||||
BackgroundTaskBroker ImportKMSTask WorkerCount
|
||||
|
||||
```
|
||||
|
||||
|
||||
To learn more or start using**AntSK**, you can follow my public account and join the exchange group.
|
||||
|
||||
|
||||
|
||||
## Contact me
|
||||
|
||||
If you have any questions or suggestions, please follow my public account through the following ways, and send a message to me. We also have an exchange group, which can send messages such as joining the group, and then I will bring you into the exchange group
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
We appreciate your interest in**AntSK**and look forward to working with you to create an intelligent future!
|
||||
227
README.md
@@ -1,100 +1,92 @@
|
||||
中文|[English](https://github.com/xuzeyu91/AntSK/blob/main/README.en.md)
|
||||
[简体中文](./README.zh.md) | English
|
||||
# AntSK
|
||||
## 基于.Net8+AntBlazor+SemanticKernel 打造的AI知识库/智能体
|
||||
## AI Knowledge Base/Intelligent Agent built on .Net8+AntBlazor+SemanticKernel
|
||||
|
||||
## 核心功能
|
||||
## ⭐Core Features
|
||||
|
||||
- **语义内核 (Semantic Kernel)**:采用领先的自然语言处理技术,准确理解、处理和响应复杂的语义查询,为用户提供精确的信息检索和推荐服务。
|
||||
- **Semantic Kernel**: Utilizes advanced natural language processing technology to accurately understand, process, and respond to complex semantic queries, providing users with precise information retrieval and recommendation services.
|
||||
|
||||
- **内存内核 (Kernel Memory)**:具备持续学习和存储知识点的能力,AntSK 拥有长期记忆功能,累积经验,提供更个性化的交互体验。
|
||||
- **Kernel Memory**: Capable of continuous learning and storing knowledge points, AntSK has long-term memory function, accumulates experience, and provides a more personalized interaction experience.
|
||||
|
||||
- **知识库**:通过文档(Word、PDF、Excel、Txt、Markdown、Json、PPT)等形式导入知识库,可以进行知识库文档。
|
||||
- **Knowledge Base**: Import knowledge base through documents (Word, PDF, Excel, Txt, Markdown, Json, PPT) and perform knowledge base Q&A.
|
||||
|
||||
- **GPTs 生成**:此平台支持创建个性化的GPT模型,尝试构建您自己的GPT模型。
|
||||
- **GPT Generation**: This platform supports creating personalized GPT models, enabling users to build their own GPT models.
|
||||
|
||||
- **API接口发布**:将内部功能以API的形式对外提供,便于开发者将AntSK 集成进其他应用,增强应用智慧。
|
||||
- **API Interface Publishing**: Exposes internal functions in the form of APIs, enabling developers to integrate AntSK into other applications and enhance application intelligence.
|
||||
|
||||
- **API插件系统**:开放式API插件系统,允许第三方开发者或服务商轻松将其服务集成到AntSK,不断增强应用功能。
|
||||
- **API Plugin System**: Open API plugin system that allows third-party developers or service providers to easily integrate their services into AntSK, continuously enhancing application functionality.
|
||||
|
||||
- **.Net插件系统**:开放式dll插件系统,允许第三方开发者或服务商轻松将其业务功能通过标准格式的代码生成dll后集成到AntSK,不断增强应用功能。
|
||||
- **.Net Plugin System**: Open dll plugin system that allows third-party developers or service providers to easily integrate their business functions by generating dll in standard format code, continuously enhancing application functionality.
|
||||
|
||||
- **联网搜索**:AntSK,实时获取最新信息,确保用户接受到的资料总是最及时、最相关的。
|
||||
- **Online Search**: AntSK, real-time access to the latest information, ensuring users receive the most timely and relevant data.
|
||||
|
||||
- **模型管理**:适配和管理集成不同厂商的不同模型。并且支持llama.cpp所支持的gguf类型的模型离线运行
|
||||
- **Model Management**: Adapts and manages integration of different models from different manufacturers, models offline running supported by **llamafactory** and **ollama**.
|
||||
|
||||
- **国产信创**:AntSK支持国产模型,和国产数据库,可以在信创条件下运行
|
||||
- **Domestic Innovation**: AntSK supports domestic models and databases and can run under domestic innovation conditions.
|
||||
|
||||
## 应用场景
|
||||
- **Model Fine-Tuning**: Planned based on llamafactory for model fine-tuning.
|
||||
|
||||
AntSK 适用于多种业务场景,例如:
|
||||
- 企业级知识管理系统
|
||||
- 自动客服与聊天机器人
|
||||
- 企业级搜索引擎
|
||||
- 个性化推荐系统
|
||||
- 智能辅助写作
|
||||
- 教育与在线学习平台
|
||||
- 其他有意思的AI App
|
||||
## ⛪Application Scenarios
|
||||
|
||||
## 功能示例
|
||||
AntSK is suitable for various business scenarios, such as:
|
||||
- Enterprise knowledge management system
|
||||
- Automatic customer service and chatbots
|
||||
- Enterprise search engine
|
||||
- Personalized recommendation system
|
||||
- Intelligent writing assistance
|
||||
- Education and online learning platforms
|
||||
- Other interesting AI Apps
|
||||
|
||||
[视频示例](https://www.bilibili.com/video/BV1zH4y1h7Y9/)
|
||||
## ✏️Function Examples
|
||||
### Online Demo
|
||||
[document](http://antsk.cn/)
|
||||
|
||||
首先需要创建知识库
|
||||

|
||||
[demo](https://demo.antsk.cn/)
|
||||
and
|
||||
[demo1](https://antsk.ai-dotnet.com/)
|
||||
|
||||
在知识库里可以使用文档或者url进行导入
|
||||

|
||||
```
|
||||
Default account: test
|
||||
|
||||
点击查看可以查看知识库的文档切片情况
|
||||

|
||||
Default password: test
|
||||
|
||||
然后我们需要创建应用,可以创建对话应用和知识库。
|
||||

|
||||
Due to the low configuration of the cloud server, the local model cannot be run, so the system settings permissions have been closed. You can simply view the interface. If you want to use the local model, please download and use it on your own.
|
||||
```
|
||||
|
||||
知识库应用需要选择已有的知识库,可以选多个
|
||||

|
||||
### Other Function Examples
|
||||
[Video Demonstration](https://www.bilibili.com/video/BV1zH4y1h7Y9/)
|
||||
|
||||
然后再对话中可以对知识库的文档进行提问
|
||||

|
||||
## ❓How to get started?
|
||||
|
||||
另外我们也可以创建对话应用,可以在对应应用中配置提示词模板
|
||||

|
||||
Here I am using Postgres as the data and vector storage because Semantic Kernel and Kernel Memory support it, but you can also use other options.
|
||||
|
||||
下面来看看效果吧
|
||||

|
||||
The model by default supports the local model of openai, azure openai, and llama. If you need to use other models, you can integrate them using one-api.
|
||||
|
||||
## 如何开始?
|
||||
The Login configuration in the configuration file is the default login account and password.
|
||||
|
||||
在这里我使用的是Postgres 作为数据存储和向量存储,因为Semantic Kernel和Kernel Memory都支持他,当然你也可以换成其他的。
|
||||
The following configuration file needs to be configured
|
||||
|
||||
模型默认支持openai、azure openai 和llama支持的gguf本地模型,如果需要使用其他模型,可以使用one-api进行集成。
|
||||
## 1️⃣Using docker-compose
|
||||
|
||||
配置文件中的Login配置是默认的登陆账号和密码
|
||||
Provided the pg version **appsettings.json** and simplified version (Sqlite+disk) **docker-compose.simple.yml**
|
||||
|
||||
需要配置如下的配置文件
|
||||
Download **docker-compose.yml** from the project root directory and place the configuration file **appsettings.json** in the same directory.
|
||||
|
||||
## 使用docker-compose
|
||||
The pg image has already been prepared. You can modify the default username and password in docker-compose.yml, and then the database connection in your **appsettings.json** needs to be consistent.
|
||||
|
||||
提供了pg版本 **appsettings.json** 和 简化版本(Sqlite+disk) **docker-compose.simple.yml**
|
||||
|
||||
从项目根目录下载**docker-compose.yml**,然后把配置文件**appsettings.json**和它放在统一目录,
|
||||
|
||||
这里已经把pg的镜像做好了。在docker-compose.yml中可以修改默认账号密码,然后你的**appsettings.json**的数据库连接需要保持一致。
|
||||
|
||||
然后你可以进入到目录后执行
|
||||
Then you can execute the following command in the directory to start AntSK
|
||||
```
|
||||
docker-compose up -d
|
||||
```
|
||||
来启动AntSK
|
||||
|
||||
## 如何在docker中挂载本地模型,和模型下载的目录
|
||||
## 2️⃣How to mount local models and model download directory in docker
|
||||
```
|
||||
# 非 host 版本, 不使用本机代理
|
||||
# Non-host version, do not use local proxy
|
||||
version: '3.8'
|
||||
services:
|
||||
antsk:
|
||||
container_name: antsk
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.1.5
|
||||
image: registry.cn-hangzhou.aliyuncs.com/AIDotNet/antsk:v0.6.0
|
||||
ports:
|
||||
- 5000:5000
|
||||
networks:
|
||||
@@ -105,33 +97,37 @@ services:
|
||||
environment:
|
||||
- ASPNETCORE_URLS=http://*:5000
|
||||
volumes:
|
||||
- ./appsettings.json:/app/appsettings.json # 本地配置文件 需要放在同级目录
|
||||
- ./appsettings.json:/app/appsettings.json # Local configuration file needs to be placed in the same directory
|
||||
- D://model:/app/model
|
||||
networks:
|
||||
antsk:
|
||||
external: true
|
||||
```
|
||||
以这个为示例,意思是把windows本地D://model的文件夹挂载进 容器内/app/model 如果是这样你的appsettings.json中的模型地址应该配置为
|
||||
```
|
||||
model/xxx.gguf
|
||||
```
|
||||
Taking this as an example, it means mounting the local D://model folder of Windows into the container /app/model. If so, the model address in your appsettings.json should be configured as
|
||||
|
||||
## 配置文件的一些含义
|
||||
[LiteDockerCompose](https://github.com/AIDotNet/AntSK/blob/main/docker-compose.simple.yml)
|
||||
|
||||
The compact version is deployed with sqlite-disk by one click
|
||||
|
||||
[FullDockerCompose](https://github.com/AIDotNet/AntSK/blob/main/docker-compose.yml)
|
||||
|
||||
The full version uses pg+aspire
|
||||
|
||||
|
||||
## 3️⃣Some meanings of configuration file
|
||||
```
|
||||
{
|
||||
"DBConnection": {
|
||||
"DbType": "Sqlite",
|
||||
"DbType": "Sqlite",
|
||||
"ConnectionStrings": "Data Source=AntSK.db;"
|
||||
},
|
||||
"KernelMemory": {
|
||||
"VectorDb": "Disk",
|
||||
"VectorDb": "Disk",
|
||||
"ConnectionString": "Host=;Port=;Database=antsk;Username=;Password=",
|
||||
"TableNamePrefix": "km-"
|
||||
},
|
||||
"LLamaSharp": {
|
||||
"RunType": "GPU",
|
||||
"Chat": "D:\\Code\\AI\\AntBlazor\\model\\qwen1_5-1_8b-chat-q8_0.gguf",
|
||||
"Embedding": "D:\\Code\\AI\\AntBlazor\\model\\qwen1_5-1_8b-chat-q8_0.gguf",
|
||||
"FileDirectory": "D:\\Code\\AI\\AntBlazor\\model\\"
|
||||
"FileDir": {
|
||||
"DirectoryPath": "D:\\git\\AntBlazor\\model"
|
||||
},
|
||||
"Login": {
|
||||
"User": "admin",
|
||||
@@ -145,53 +141,96 @@ model/xxx.gguf
|
||||
}
|
||||
```
|
||||
```
|
||||
//支持多种数据库,具体可以查看SqlSugar,MySql,SqlServer,Sqlite,Oracle,PostgreSQL,Dm,Kdbndp,Oscar,MySqlConnector,Access,OpenGauss,QuestDB,HG,ClickHouse,GBase,Odbc,OceanBaseForOracle,TDengine,GaussDB,OceanBase,Tidb,Vastbase,PolarDB,Custom
|
||||
// Supports various databases, you can check SqlSugar, MySql, SqlServer, Sqlite, Oracle, PostgreSQL, Dm, Kdbndp, Oscar, MySqlConnector, Access, OpenGauss, QuestDB, HG, ClickHouse, GBase, Odbc, OceanBaseForOracle, TDengine, GaussDB, OceanBase, Tidb, Vastbase, PolarDB, Custom
|
||||
DBConnection.DbType
|
||||
//连接字符串,需要根据不同DB类型,用对应的字符串
|
||||
|
||||
// Connection string, need to use the corresponding string according to the different DB types
|
||||
DBConnection.ConnectionStrings
|
||||
|
||||
//向量存储的类型,支持 Postgres Disk Memory ,其中Postgres需要配置 ConnectionString
|
||||
//The type of vector storage, supporting Postgres, Disk, Memory, Qdrant, Redis, AzureAISearch
|
||||
//Postgres and Redis require ConnectionString configuration
|
||||
//The ConnectionString of Qdrant and AzureAISearch uses Endpoint | APIKey
|
||||
KernelMemory.VectorDb
|
||||
|
||||
//本地模型使用的运行方式 GUP CPU ,如果用在线API 这个随意使用一个即可
|
||||
LLamaSharp.RunType
|
||||
//本地会话模型的模型路径 注意区分linux和windows盘符不同
|
||||
LLamaSharp.Chat
|
||||
//本地向量模型的模型路径 注意区分linux和windows盘符不同
|
||||
LLamaSharp.Embedding
|
||||
//本地模型路径,用于在选择llama时可以快速选择目录下的模型,以及保存下载的模型
|
||||
LLamaSharp.FileDirectory
|
||||
//Local model path, used for quick selection of models under llama, as well as saving downloaded models.
|
||||
FileDir.DirectoryPath
|
||||
|
||||
//默认管理员账号密码
|
||||
//Default admin account password
|
||||
Login
|
||||
//导入异步处理的线程数,使用在线API可以高一点,本地模型建议1 否则容易内存溢出崩掉
|
||||
|
||||
//Import asynchronous processing thread count. A higher count can be used for online API, but for local models, 1 is recommended to avoid memory overflow issues.
|
||||
BackgroundTaskBroker.ImportKMSTask.WorkerCount
|
||||
|
||||
```
|
||||
|
||||
## 找不到样式问题解决:
|
||||
AntSK/src/AntSK下执行:
|
||||
## ⚠️Fixing Style Issues:
|
||||
Run the following in AntSK/src/AntSK:
|
||||
```
|
||||
dotnet clean
|
||||
dotnet build
|
||||
dotnet publish "AntSK.csproj"
|
||||
```
|
||||
再去AntSK/src/AntSK/bin/Release/net8.0/publish下
|
||||
Then navigate to AntSK/src/AntSK/bin/Release/net8.0/publish and run:
|
||||
```
|
||||
dotnet AntSK.dll
|
||||
```
|
||||
然后启动就有样式了
|
||||
The styles should now be applied after starting.
|
||||
|
||||
DB我使用的是CodeFirst模式,只要配置好数据库链接,表结构是自动创建的
|
||||
I'm using CodeFirst mode for the database, so as long as the database connection is properly configured, the table structure will be created automatically.
|
||||
|
||||
## ✔️Using llamafactory
|
||||
```
|
||||
1. First, ensure that Python and pip are installed in your environment. This step is not necessary if using an image, such as version v0.2.3.2, which already includes the complete Python environment.
|
||||
2. Go to the model add page and select llamafactory.
|
||||
3. Click "Initialize" to check whether the 'pip install' environment setup is complete.
|
||||
4. Choose a model that you like.
|
||||
5. Click "Start" to begin downloading the model from the tower. This may involve a somewhat lengthy wait.
|
||||
6. After the model has finished downloading, enter http://localhost:8000/ in the request address. The default port is 8000.
|
||||
7. Click "Save" and start chatting.
|
||||
8. Many people ask about the difference between LLamaSharp and llamafactory. In fact, LLamaSharp is a .NET implementation of llama.cpp, but only supports local gguf models, while llamafactory supports a wider variety of models and uses Python implementation. The main difference lies here. Additionally, llamafactory has the ability to fine-tune models, which is an area we will focus on integrating in the future.
|
||||
```
|
||||
|
||||
## 💕 Contributors
|
||||
|
||||
想了解更多信息或开始使用 **AntSK**,可以关注我的公众号以及加入交流群。
|
||||
This project exists thanks to all the people who contribute.
|
||||
|
||||
## 联系我
|
||||
如有任何问题或建议,请通过以下方式关注我的公众号,发消息与我联系,我们也有交流群,可以发送进群等消息,然后我会拉你进交流群
|
||||

|
||||
<a href="https://github.com/AIDotNet/AntSK/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=AIDotNet/AntSK&max=1000&columns=15&anon=1" />
|
||||
</a>
|
||||
|
||||
## 🚨 Use Protocol
|
||||
|
||||
This warehouse follows the [AntSK License](https://github.com/AIDotNet/AntSK?tab=Apache-2.0-1-ov-file) open source protocol.
|
||||
|
||||
This project follows the Apache 2.0 agreement, in addition to the following additional terms
|
||||
|
||||
1. **Free Commercial Use**: Users can use the software for commercial purposes without modifying the code.
|
||||
2. **Commercial License Required**: A commercial license is required if any of the following conditions are met:
|
||||
1. You modify, develop, or alter the software, including but not limited to changes to the application name, logo, code, or functionality.
|
||||
2. You provide multi-tenant services to enterprise customers with 10 or more users.
|
||||
3. You pre-install or integrate the software into hardware devices or products and bundle it for sale.
|
||||
4. You are engaging in large-scale procurement for government or educational institutions, especially involving security, data privacy, or other sensitive requirements.
|
||||
|
||||
3. If you need authorization, you can contact WeChat: **xuzeyu91**
|
||||
|
||||
If you plan to use AntSK in commercial projects, you need to ensure that you follow the following steps:
|
||||
|
||||
1. Copyright statement containing AntSK license. [AntSK License](https://github.com/AIDotNet/AntSK?tab=Apache-2.0-1-ov-file).
|
||||
|
||||
2. If you modify the software source code, you need to clearly indicate these modifications in the source code.
|
||||
|
||||
3. Meet the above requirements
|
||||
|
||||
## 💕 Special thanks
|
||||
Helping enterprise AI application development, we recommend [AntBlazor](https://antblazor.com)
|
||||
|
||||
## ☎️Contact Me
|
||||
If you have any questions or suggestions, please contact me through my official WeChat account. We also have a discussion group where you can send a message to join, and then I will add you to the group.
|
||||
|
||||
Additionally, you can also contact me via email: antskpro@qq.com
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
我们对您在**AntSK**的兴趣表示感谢,并期待与您携手共创智能化的未来!
|
||||
|
||||
We appreciate your interest in **AntSK** and look forward to collaborating with you to create an intelligent future!
|
||||
|
||||
254
README.zh.md
Normal file
@@ -0,0 +1,254 @@
|
||||
中文|[English](./README.md)
|
||||
# AntSK
|
||||
## 使用.Net8+Blazor+SemanticKernel 打造的AI知识库/智能体
|
||||
|
||||
## ⭐核心功能
|
||||
|
||||
- **语义内核 (Semantic Kernel)**:采用领先的自然语言处理技术,准确理解、处理和响应复杂的语义查询,为用户提供精确的信息检索和推荐服务。
|
||||
|
||||
- **内存内核 (Kernel Memory)**:具备持续学习和存储知识点的能力,AntSK 拥有长期记忆功能,累积经验,提供更个性化的交互体验。
|
||||
|
||||
- **知识库**:通过文档(Word、PDF、Excel、Txt、Markdown、Json、PPT)等形式导入知识库,可以进行知识库问答,支持本地bge-embedding 向量模型 ,以及bge-rerank 重排模型。
|
||||
|
||||
- **文生图**:集成**StableDiffusion** 本地模型,可以进行文生图。
|
||||
|
||||
- **GPTs 生成**:此平台支持创建个性化的GPT模型,尝试构建您自己的GPT模型。
|
||||
|
||||
- **API接口发布**:将内部功能以API的形式对外提供,便于开发者将AntSK 集成进其他应用,增强应用智慧。
|
||||
|
||||
- **API插件系统**:开放式API插件系统,允许第三方开发者或服务商轻松将其服务集成到AntSK,不断增强应用功能。
|
||||
|
||||
- **.Net插件系统**:开放式dll插件系统,允许第三方开发者或服务商轻松将其业务功能通过标准格式的代码生成dll后集成到AntSK,不断增强应用功能。
|
||||
|
||||
- **联网搜索**:AntSK,实时获取最新信息,确保用户接受到的资料总是最及时、最相关的。
|
||||
|
||||
- **模型管理**:适配和管理集成不同厂商的不同模型。并且支持**llama.cpp**所支持的gguf类型,以及**llamafactory** 和 **ollama** 所支持的模型离线运行
|
||||
|
||||
- **国产信创**:AntSK支持国产模型,和国产数据库,可以在信创条件下运行
|
||||
|
||||
- **模型微调**:规划中,基于llamafactory进行模型微调
|
||||
|
||||
|
||||
## ⛪应用场景
|
||||
|
||||
AntSK 适用于多种业务场景,例如:
|
||||
- 企业级知识管理系统
|
||||
- 自动客服与聊天机器人
|
||||
- 企业级搜索引擎
|
||||
- 个性化推荐系统
|
||||
- 智能辅助写作
|
||||
- 教育与在线学习平台
|
||||
- 其他有意思的AI App
|
||||
|
||||
## ✏️功能示例
|
||||
### 在线演示
|
||||
|
||||
[体验地址1](https://demo.antsk.cn/)
|
||||
|
||||
和
|
||||
|
||||
[体验地址2](https://antsk.ai-dotnet.com/)
|
||||
```
|
||||
默认账号:test
|
||||
|
||||
默认密码:test
|
||||
|
||||
由于云服务器配置较低,无法运行本地模型,所以把系统设置权限关闭了,大家看看界面即可,要使用本地模型,请下载自行使用
|
||||
|
||||
请勿在演示站点上传敏感信息
|
||||
```
|
||||
|
||||
### 其他功能示例
|
||||
[视频示例](https://www.bilibili.com/video/BV1zH4y1h7Y9/)
|
||||
|
||||
[在线文档:http://antsk.cn](http://antsk.cn)
|
||||
|
||||
## ❓如何开始?
|
||||
|
||||
在这里我使用的是Postgres 作为数据存储和向量存储,因为Semantic Kernel和Kernel Memory都支持他,当然你也可以换成其他的。
|
||||
|
||||
模型默认支持openai、azure openai、讯飞星火、阿里云积、 和llama支持的gguf本地模型 以及llamafactory的本地模型,如果需要使用其他模型,可以使用one-api进行集成。
|
||||
|
||||
配置文件中的Login配置是默认的登录账号和密码
|
||||
|
||||
需要配置如下的配置文件
|
||||
|
||||
## 为了方便体验,我已经把打包好的程序放进了网盘,你只需要安装.net8环境即可运行。
|
||||
[.net8环境 ](https://dotnet.microsoft.com/zh-cn/download/dotnet/8.0)
|
||||
|
||||
[我用夸克网盘分享了「AntSK」](https://pan.quark.cn/s/9462c849cbad)
|
||||
|
||||
|
||||
## 1️⃣使用docker-compose
|
||||
|
||||
提供了pg版本 **appsettings.json** 和 简化版本(**Sqlite+disk**) **docker-compose.simple.yml**
|
||||
|
||||
从项目根目录下载**docker-compose.yml**,然后把配置文件**appsettings.json**和它放在统一目录,
|
||||
|
||||
这里已经把pg的镜像做好了。在docker-compose.yml中可以修改默认账号密码,然后你的**appsettings.json**的数据库连接需要保持一致。
|
||||
|
||||
然后你可以进入到目录后执行
|
||||
```
|
||||
docker-compose up -d
|
||||
```
|
||||
来启动AntSK
|
||||
|
||||
## 2️⃣如何在docker中挂载本地模型,和模型下载的目录
|
||||
```
|
||||
# 非 host 版本, 不使用本机代理
|
||||
version: '3.8'
|
||||
services:
|
||||
antsk:
|
||||
container_name: antsk
|
||||
image: registry.cn-hangzhou.aliyuncs.com/AIDotNet/antsk:v0.6.0
|
||||
ports:
|
||||
- 5000:5000
|
||||
networks:
|
||||
- antsk
|
||||
depends_on:
|
||||
- antskpg
|
||||
restart: always
|
||||
environment:
|
||||
- ASPNETCORE_URLS=http://*:5000
|
||||
volumes:
|
||||
- ./appsettings.json:/app/appsettings.json # 本地配置文件 需要放在同级目录
|
||||
- D://model:/app/model
|
||||
- D://model:/root/.cache/modelscope/hub/AI-ModelScope #使用Llamafactory时需要挂载 否则初始化的环境重启后会丢失
|
||||
networks:
|
||||
antsk:
|
||||
```
|
||||
以这个为示例,意思是把windows本地D://model的文件夹挂载进 容器内/app/model 如果是这样你的appsettings.json中的模型地址应该配置为
|
||||
|
||||
[LiteDockerCompose](https://github.com/AIDotNet/AntSK/blob/main/docker-compose.simple.yml)
|
||||
|
||||
精简版使用sqlite+disk向量模式,简化部署配置
|
||||
|
||||
[FullDockerCompose](https://github.com/AIDotNet/AntSK/blob/main/docker-compose.yml)
|
||||
|
||||
完整版使用pg+aspire 功能更完整,配置文件需要参考如下配置含义进行配置
|
||||
|
||||
|
||||
## 3️⃣配置文件的一些含义
|
||||
```
|
||||
{
|
||||
"DBConnection": {
|
||||
"DbType": "Sqlite",
|
||||
"ConnectionStrings": "Data Source=AntSK.db;"
|
||||
},
|
||||
"KernelMemory": {
|
||||
"VectorDb": "Disk",
|
||||
"ConnectionString": "Host=;Port=;Database=antsk;Username=;Password=",
|
||||
"TableNamePrefix": "km-"
|
||||
},
|
||||
"FileDir": {
|
||||
"DirectoryPath": "D:\\git\\AntBlazor\\model"
|
||||
},
|
||||
"Login": {
|
||||
"User": "admin",
|
||||
"Password": "xuzeyu"
|
||||
},
|
||||
"BackgroundTaskBroker": {
|
||||
"ImportKMSTask": {
|
||||
"WorkerCount": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
//支持多种数据库,具体可以查看SqlSugar,MySql,SqlServer,Sqlite,Oracle,PostgreSQL,Dm,Kdbndp,Oscar,MySqlConnector,Access,OpenGauss,QuestDB,HG,ClickHouse,GBase,Odbc,OceanBaseForOracle,TDengine,GaussDB,OceanBase,Tidb,Vastbase,PolarDB,Custom
|
||||
DBConnection.DbType
|
||||
//连接字符串,需要根据不同DB类型,用对应的字符串
|
||||
DBConnection.ConnectionStrings
|
||||
|
||||
//向量存储的类型,支持 Postgres、Disk、Memory、Qdrant、Redis、AzureAISearch
|
||||
//Postgres、Redis需要配置 ConnectionString
|
||||
//Qdrant 和AzureAISearch 的 ConnectionString 使用 Endpoint|APIKey
|
||||
KernelMemory.VectorDb
|
||||
|
||||
//本地模型路径,用于在选择llama时可以快速选择目录下的模型,以及保存下载的模型
|
||||
FileDir.DirectoryPath
|
||||
|
||||
//默认管理员账号密码
|
||||
Login
|
||||
//导入异步处理的线程数,使用在线API可以高一点,本地模型建议1 否则容易内存溢出崩掉
|
||||
BackgroundTaskBroker.ImportKMSTask.WorkerCount
|
||||
```
|
||||
|
||||
## ⚠️找不到样式问题解决:
|
||||
AntSK/src/AntSK下执行:
|
||||
```
|
||||
dotnet clean
|
||||
dotnet build
|
||||
dotnet publish "AntSK.csproj"
|
||||
```
|
||||
再去AntSK/src/AntSK/bin/Release/net8.0/publish下
|
||||
```
|
||||
dotnet AntSK.dll
|
||||
```
|
||||
然后启动就有样式了
|
||||
|
||||
DB我使用的是CodeFirst模式,只要配置好数据库链接,表结构是自动创建的
|
||||
|
||||
## ✔️使用llamafactory
|
||||
```
|
||||
1、首先需要确保你的环境已经安装了python和pip,如果使用镜像,例如p0.2.4版本已经包含了 python全套环境则无需此步骤
|
||||
2、进入模型添加页面选择llamafactory
|
||||
3、点击初始化,可以检查pip install 环境是否完成
|
||||
4、选择一个喜欢的模型
|
||||
5、点击启动,这会开始从魔塔下载模型,你可能需要有一个较为漫长的等待
|
||||
6、等待模型下载完毕后,在请求地址输入 http://localhost:8000/ 这里默认是使用8000端口
|
||||
7、点击保存,然后就可以开始聊天了
|
||||
8、很多人会问 LLamaSharp与llamafactory有什么区别?其实这两者LLamaSharp是llama.cpp的 dotnet实现,但是只支持本地gguf模型, 而llamafactory 支持的模型种类更多,但使用的是python的实现,其主要差异在这里,另外llamafactory具有模型微调的能力,这也是我们下一步需要重点集成的部分。
|
||||
```
|
||||
|
||||
## 💕 贡献者
|
||||
|
||||
这个项目的存在要感谢所有的贡献者。
|
||||
|
||||
<a href="https://github.com/AIDotNet/AntSK/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=AIDotNet/AntSK&max=1000&columns=15&anon=1" />
|
||||
</a>
|
||||
|
||||
## 🚨 使用协议
|
||||
|
||||
本仓库遵循 [AntSK License](https://github.com/AIDotNet/AntSK?tab=Apache-2.0-1-ov-file) 开源协议。
|
||||
|
||||
除以下附加条款外,该项目遵循Apache 2.0协议
|
||||
|
||||
1. **免费商用**:用户在不修改代码的情况下,可以免费用于商业目的。
|
||||
2. **商业授权**:如果您满足以下任意条件之一,需取得商业授权:
|
||||
1. 对本软件进行二次修改、开发(包括但不限于修改应用名称、logo、代码以及功能)。
|
||||
2. 为企业客户提供多租户服务,且该服务支持 10 人或以上的使用。
|
||||
3. 预装或集成到硬件设备或产品中进行捆绑销售。
|
||||
4. 政府或教育机构的大规模采购项目,特别是涉及安全、数据隐私等敏感需求时。
|
||||
|
||||
3. 如果您需要授权,可以联系微信:xuzeyu91
|
||||
|
||||
如果您打算在商业项目中使用AntSK,您需要确保遵守以下步骤:
|
||||
|
||||
1. 包含AntSK许可证的版权声明。 [AntSK License](https://github.com/AIDotNet/AntSK?tab=Apache-2.0-1-ov-file) 。
|
||||
|
||||
2. 如果您修改了软件源代码,您需要在源代码中明确标明这些修改。
|
||||
|
||||
3. 满足以上要求
|
||||
|
||||
## 💕 特别感谢
|
||||
助力企业级AI应用开发,推荐使用 [AntBlazor](https://antblazor.com)
|
||||
|
||||
|
||||
## ☎️联系我
|
||||
如有任何问题或建议,请通过以下方式关注我的公众号《许泽宇的技术分享》,发消息与我联系,我们也有AIDotnet交流群,可以发送进群等消息,然后我会拉你进交流群
|
||||
|
||||
另外您也可以通过邮箱与我联系:antskpro@qq.com
|
||||
|
||||

|
||||
|
||||
## 🌟 Star History
|
||||
<a href="https://github.com/AIDotNet/AntSK/stargazers" target="_blank" style="display: block" align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=AIDotNet/AntSK&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=AIDotNet/AntSK&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=AIDotNet/AntSK&type=Date" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
@@ -3,7 +3,9 @@ version: '3.8'
|
||||
services:
|
||||
antsk:
|
||||
container_name: antsk
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.2.1
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.6.2
|
||||
# 如果需要pytorch环境需要使用下面这个镜像,镜像比较大
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:p0.6.2
|
||||
ports:
|
||||
- 5000:5000
|
||||
networks:
|
||||
@@ -13,5 +15,7 @@ services:
|
||||
- ASPNETCORE_URLS=http://*:5000
|
||||
volumes:
|
||||
- ./appsettings.json:/app/appsettings.json # 本地配置文件 需要放在同级目录
|
||||
- /AntSK/model:/app/model
|
||||
- /AntSK/model:/root/.cache/modelscope/hub/AI-ModelScope # LLamaFactory模型文件
|
||||
networks:
|
||||
antsk:
|
||||
|
||||
@@ -1,8 +1,22 @@
|
||||
# 非 host 版本, 不使用本机代理
|
||||
version: '3.8'
|
||||
services:
|
||||
aspire-dashboard:
|
||||
container_name: aspire-dashboard
|
||||
image: mcr.microsoft.com/dotnet/aspire-dashboard:8.0
|
||||
networks:
|
||||
- antsk
|
||||
environment:
|
||||
- DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS=true
|
||||
- ASPIRE_ALLOW_UNSECURED_TRANSPORT=true
|
||||
- DASHBOARD_OTLP_AUTHMODE=ApiKey
|
||||
- DASHBOARD_OTLP_PRIMARYAPIKEY=antsk
|
||||
ports:
|
||||
- 18888:18888
|
||||
- 18889:18889
|
||||
restart: unless-stopped
|
||||
antskpg:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/pg:v0.5.0
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/pg:v0.5.0
|
||||
container_name: antskpg
|
||||
restart: always
|
||||
ports: # 生产环境建议不要暴露
|
||||
@@ -18,7 +32,9 @@ services:
|
||||
- ./pg/data:/var/lib/postgresql/data
|
||||
antsk:
|
||||
container_name: antsk
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.2.1
|
||||
image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:v0.6.2
|
||||
# 如果需要pytorch环境需要使用下面这个镜像,镜像比较大
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/xuzeyu91/antsk:p0.6.2
|
||||
ports:
|
||||
- 5000:5000
|
||||
networks:
|
||||
@@ -28,7 +44,15 @@ services:
|
||||
restart: always
|
||||
environment:
|
||||
- ASPNETCORE_URLS=http://*:5000
|
||||
- ASPNETCORE_FORWARDEDHEADERS_ENABLED=true
|
||||
- OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES=true
|
||||
- OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES= true
|
||||
- OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY=in_memory
|
||||
- OTEL_EXPORTER_OTLP_ENDPOINT=http://aspire-dashboard:18889
|
||||
- OTEL_SERVICE_NAME=antsk
|
||||
volumes:
|
||||
- ./appsettings.json:/app/appsettings.json # 本地配置文件 需要放在同级目录
|
||||
- /AntSK/model:/app/model
|
||||
- /AntSK/model:/root/.cache/modelscope/hub/AI-ModelScope # LLamaFactory模型文件
|
||||
networks:
|
||||
antsk:
|
||||
|
||||
14
docs/deploy/_category_.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"position": 3,
|
||||
"label": "部署",
|
||||
"collapsible": true,
|
||||
"collapsed": false,
|
||||
"className": "red",
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"title": "使用案例"
|
||||
},
|
||||
"customProps": {
|
||||
"description": "提供快速使用AntSK的一些案例!"
|
||||
}
|
||||
}
|
||||
56
docs/deploy/settings.md
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# 配置文件的一些含义
|
||||
```
|
||||
{
|
||||
"DBConnection": {
|
||||
"DbType": "Sqlite",
|
||||
"ConnectionStrings": "Data Source=AntSK.db;"
|
||||
},
|
||||
"KernelMemory": {
|
||||
"VectorDb": "Disk",
|
||||
"ConnectionString": "Host=;Port=;Database=antsk;Username=;Password=",
|
||||
"TableNamePrefix": "km-"
|
||||
},
|
||||
"LLamaSharp": {
|
||||
"RunType": "GPU",
|
||||
"Chat": "D:\\Code\\AI\\AntBlazor\\model\\qwen1_5-1_8b-chat-q8_0.gguf",
|
||||
"Embedding": "D:\\Code\\AI\\AntBlazor\\model\\qwen1_5-1_8b-chat-q8_0.gguf",
|
||||
"FileDirectory": "D:\\Code\\AI\\AntBlazor\\model\\"
|
||||
},
|
||||
"Login": {
|
||||
"User": "admin",
|
||||
"Password": "xuzeyu"
|
||||
},
|
||||
"BackgroundTaskBroker": {
|
||||
"ImportKMSTask": {
|
||||
"WorkerCount": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
//支持多种数据库,具体可以查看SqlSugar,MySql,SqlServer,Sqlite,Oracle,PostgreSQL,Dm,Kdbndp,Oscar,MySqlConnector,Access,OpenGauss,QuestDB,HG,ClickHouse,GBase,Odbc,OceanBaseForOracle,TDengine,GaussDB,OceanBase,Tidb,Vastbase,PolarDB,Custom
|
||||
DBConnection.DbType
|
||||
//连接字符串,需要根据不同DB类型,用对应的字符串
|
||||
DBConnection.ConnectionStrings
|
||||
|
||||
//向量存储的类型,支持 Postgres Disk Memory ,其中Postgres需要配置 ConnectionString
|
||||
KernelMemory.VectorDb
|
||||
|
||||
//本地模型使用的运行方式 GUP CPU ,如果用在线API 这个随意使用一个即可
|
||||
LLamaSharp.RunType
|
||||
//本地会话模型的模型路径 注意区分linux和windows盘符不同
|
||||
LLamaSharp.Chat
|
||||
//本地向量模型的模型路径 注意区分linux和windows盘符不同
|
||||
LLamaSharp.Embedding
|
||||
//本地模型路径,用于在选择llama时可以快速选择目录下的模型,以及保存下载的模型
|
||||
LLamaSharp.FileDirectory
|
||||
|
||||
//默认管理员账号密码
|
||||
Login
|
||||
//导入异步处理的线程数,使用在线API可以高一点,本地模型建议1 否则容易内存溢出崩掉
|
||||
BackgroundTaskBroker.ImportKMSTask.WorkerCount
|
||||
```
|
||||
57
docs/deploy/start.md
Normal file
@@ -0,0 +1,57 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# 如何开始?
|
||||
|
||||
在这里我使用的是Postgres 作为数据存储和向量存储,因为Semantic Kernel和Kernel Memory都支持他,当然你也可以换成其他的。
|
||||
|
||||
模型默认支持openai、azure openai 和llama支持的gguf本地模型,如果需要使用其他模型,可以使用one-api进行集成。
|
||||
|
||||
配置文件中的Login配置是默认的登陆账号和密码
|
||||
|
||||
需要配置如下的配置文件
|
||||
|
||||
## 使用docker-compose
|
||||
|
||||
提供了pg版本 **appsettings.json** 和 简化版本(Sqlite+disk) **docker-compose.simple.yml**
|
||||
|
||||
从项目根目录下载**docker-compose.yml**,然后把配置文件**appsettings.json**和它放在统一目录,
|
||||
|
||||
这里已经把pg的镜像做好了。在docker-compose.yml中可以修改默认账号密码,然后你的**appsettings.json**的数据库连接需要保持一致。
|
||||
|
||||
然后你可以进入到目录后执行
|
||||
```
|
||||
docker-compose up -d
|
||||
```
|
||||
来启动AntSK
|
||||
|
||||
## 如何在docker中挂载本地模型,和模型下载的目录
|
||||
```
|
||||
# 非 host 版本, 不使用本机代理
|
||||
version: '3.8'
|
||||
services:
|
||||
antsk:
|
||||
container_name: antsk
|
||||
image: registry.cn-hangzhou.aliyuncs.com/AIDotNet/antsk:v0.1.5
|
||||
ports:
|
||||
- 5000:5000
|
||||
networks:
|
||||
- antsk
|
||||
depends_on:
|
||||
- antskpg
|
||||
restart: always
|
||||
environment:
|
||||
- ASPNETCORE_URLS=http://*:5000
|
||||
volumes:
|
||||
- ./appsettings.json:/app/appsettings.json # 本地配置文件 需要放在同级目录
|
||||
- D://model:/app/model
|
||||
networks:
|
||||
antsk:
|
||||
```
|
||||
以这个为示例,意思是把windows本地D://model的文件夹挂载进 容器内/app/model 如果是这样你的appsettings.json中的模型地址应该配置为
|
||||
```
|
||||
model/xxx.gguf
|
||||
```
|
||||
|
||||
DB我使用的是CodeFirst模式,只要配置好数据库链接,表结构是自动创建的
|
||||
16
docs/deploy/style.md
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# 找不到样式问题解决
|
||||
AntSK/src/AntSK下执行:
|
||||
```
|
||||
dotnet clean
|
||||
dotnet build
|
||||
dotnet publish "AntSK.csproj"
|
||||
```
|
||||
再去AntSK/src/AntSK/bin/Release/net8.0/publish下
|
||||
```
|
||||
dotnet AntSK.dll
|
||||
```
|
||||
然后启动就有样式了
|
||||
14
docs/develop/_category_.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"position": 2,
|
||||
"label": "快速开发",
|
||||
"collapsible": true,
|
||||
"collapsed": false,
|
||||
"className": "red",
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"title": "快速开发"
|
||||
},
|
||||
"customProps": {
|
||||
"description": "快速基于项目二次开发!"
|
||||
}
|
||||
}
|
||||
14
docs/introduce/_category_.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"position": 2,
|
||||
"label": "介绍",
|
||||
"collapsible": true,
|
||||
"collapsed": false,
|
||||
"className": "red",
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"title": "使用案例"
|
||||
},
|
||||
"customProps": {
|
||||
"description": "提供快速使用AntSK的一些案例!"
|
||||
}
|
||||
}
|
||||
BIN
docs/introduce/img/对话效果.png
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
docs/introduce/img/应用.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
docs/introduce/img/应用配置.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
docs/introduce/img/文档切片.png
Normal file
|
After Width: | Height: | Size: 202 KiB |
BIN
docs/introduce/img/知识库.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
docs/introduce/img/知识库详情.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
docs/introduce/img/简单对话.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
docs/introduce/img/问答.png
Normal file
|
After Width: | Height: | Size: 170 KiB |
70
docs/introduce/readme.md
Normal file
@@ -0,0 +1,70 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# AntSK功能介绍
|
||||
## 基于.Net8+AntBlazor+SemanticKernel 打造的AI知识库/智能体
|
||||
|
||||
## 核心功能
|
||||
|
||||
- **语义内核 (Semantic Kernel)**:采用领先的自然语言处理技术,准确理解、处理和响应复杂的语义查询,为用户提供精确的信息检索和推荐服务。
|
||||
|
||||
- **内存内核 (Kernel Memory)**:具备持续学习和存储知识点的能力,AntSK 拥有长期记忆功能,累积经验,提供更个性化的交互体验。
|
||||
|
||||
- **知识库**:通过文档(Word、PDF、Excel、Txt、Markdown、Json、PPT)等形式导入知识库,可以进行知识库问答。
|
||||
|
||||
- **GPTs 生成**:此平台支持创建个性化的GPT模型,尝试构建您自己的GPT模型。
|
||||
|
||||
- **API接口发布**:将内部功能以API的形式对外提供,便于开发者将AntSK 集成进其他应用,增强应用智慧。
|
||||
|
||||
- **API插件系统**:开放式API插件系统,允许第三方开发者或服务商轻松将其服务集成到AntSK,不断增强应用功能。
|
||||
|
||||
- **.Net插件系统**:开放式dll插件系统,允许第三方开发者或服务商轻松将其业务功能通过标准格式的代码生成dll后集成到AntSK,不断增强应用功能。
|
||||
|
||||
- **联网搜索**:AntSK,实时获取最新信息,确保用户接受到的资料总是最及时、最相关的。
|
||||
|
||||
- **模型管理**:适配和管理集成不同厂商的不同模型。并且支持**llama.cpp**所支持的gguf类型,以及**llamafactory**所支持的模型离线运行
|
||||
|
||||
- **国产信创**:AntSK支持国产模型,和国产数据库,可以在信创条件下运行
|
||||
|
||||
- **模型微调**:规划中,基于llamafactory进行模型微调
|
||||
|
||||
|
||||
## 应用场景
|
||||
|
||||
AntSK 适用于多种业务场景,例如:
|
||||
- 企业级知识管理系统
|
||||
- 自动客服与聊天机器人
|
||||
- 企业级搜索引擎
|
||||
- 个性化推荐系统
|
||||
- 智能辅助写作
|
||||
- 教育与在线学习平台
|
||||
- 其他有意思的AI App
|
||||
|
||||
## 功能示例
|
||||
|
||||
[视频示例](https://www.bilibili.com/video/BV1zH4y1h7Y9/)
|
||||
|
||||
首先需要创建知识库
|
||||

|
||||
|
||||
在知识库里可以使用文档或者url进行导入
|
||||

|
||||
|
||||
点击查看可以查看知识库的文档切片情况
|
||||

|
||||
|
||||
然后我们需要创建应用,可以创建对话应用和知识库。
|
||||

|
||||
|
||||
知识库应用需要选择已有的知识库,可以选多个
|
||||

|
||||
|
||||
然后再对话中可以对知识库的文档进行提问
|
||||

|
||||
|
||||
另外我们也可以创建对话应用,可以在对应应用中配置提示词模板
|
||||

|
||||
|
||||
下面来看看效果吧
|
||||

|
||||
BIN
images/gzh.jpg
Normal file
|
After Width: | Height: | Size: 180 KiB |
20
src/AntSK.AppHost/AntSK.AppHost.csproj
Normal file
@@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsAspireHost>true</IsAspireHost>
|
||||
<UserSecretsId>32ac67c8-178a-4eeb-871d-879023582e06</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AntSK\AntSK.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
5
src/AntSK.AppHost/Program.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
var builder = DistributedApplication.CreateBuilder(args);
|
||||
|
||||
builder.AddProject<Projects.AntSK>("antsk");
|
||||
|
||||
builder.Build().Run();
|
||||
8
src/AntSK.AppHost/appsettings.Development.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
9
src/AntSK.AppHost/appsettings.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning",
|
||||
"Aspire.Hosting.Dcp": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/AntSK.AppHost/aspirate-output/docker-compose.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
services:
|
||||
aspire-dashboard:
|
||||
container_name: "aspire-dashboard"
|
||||
image: "mcr.microsoft.com/dotnet/aspire-dashboard:8.0"
|
||||
environment:
|
||||
DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS: "true"
|
||||
ports:
|
||||
- target: 18888
|
||||
published: 18888
|
||||
restart: unless-stopped
|
||||
antsk:
|
||||
container_name: "antsk"
|
||||
image: "antsk:latest"
|
||||
environment:
|
||||
OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES: "true"
|
||||
OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES: "true"
|
||||
OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory"
|
||||
ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true"
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT: "http://aspire-dashboard:18889"
|
||||
OTEL_SERVICE_NAME: "antsk"
|
||||
ports:
|
||||
- target: 8080
|
||||
published: 10000
|
||||
- target: 8443
|
||||
published: 10001
|
||||
restart: unless-stopped
|
||||
17
src/AntSK.AppHost/aspirate-state.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"projectPath": ".",
|
||||
"outputPath": "aspirate-output",
|
||||
"containerImageTags": [
|
||||
"latest"
|
||||
],
|
||||
"containerBuilder": "docker",
|
||||
"outputFormat": "compose",
|
||||
"privateRegistryEmail": "aspir8@aka.ms",
|
||||
"includeDashboard": true,
|
||||
"secrets": {
|
||||
"salt": "fjamZa3pQbM1UyY4",
|
||||
"hash": "QR\u002BSEr3p2SwD/w2oPE21vrWh/EerhNyVyTkr0atIREw=",
|
||||
"secrets": {}
|
||||
},
|
||||
"processAllComponents": true
|
||||
}
|
||||
26
src/AntSK.AppHost/manifest.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"resources": {
|
||||
"antsk": {
|
||||
"type": "project.v0",
|
||||
"path": "../AntSK/AntSK.csproj",
|
||||
"env": {
|
||||
"OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES": "true",
|
||||
"OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES": "true",
|
||||
"OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY": "in_memory",
|
||||
"ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true"
|
||||
},
|
||||
"bindings": {
|
||||
"http": {
|
||||
"scheme": "http",
|
||||
"protocol": "tcp",
|
||||
"transport": "http"
|
||||
},
|
||||
"https": {
|
||||
"scheme": "https",
|
||||
"protocol": "tcp",
|
||||
"transport": "http"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/AntSK.Domain/AntSK - Backup.Domain.csproj
Normal 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>
|
||||
@@ -5,36 +5,48 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<DocumentationFile>AntSK.Domain.xml</DocumentationFile>
|
||||
<NoWarn>CA1050,CA1707,CA2007,VSTHRD111,CS1591,RCS1110,CA5394,SKEXP0001,SKEXP0002,SKEXP0003,SKEXP0004,SKEXP0010,SKEXP0011,,SKEXP0012,SKEXP0020,SKEXP0021,SKEXP0022,SKEXP0023,SKEXP0024,SKEXP0025,SKEXP0026,SKEXP0027,SKEXP0028,SKEXP0029,SKEXP0030,SKEXP0031,SKEXP0032,SKEXP0040,SKEXP0041,SKEXP0042,SKEXP0050,SKEXP0051,SKEXP0052,SKEXP0053,SKEXP0054,SKEXP0055,SKEXP0060,SKEXP0061,SKEXP0101,SKEXP0102</NoWarn>
|
||||
<NoWarn>CA1050,CA1707,CA2007,VSTHRD111,CS1591,RCS1110,CA5394,SKEXP0001,SKEXP0002,SKEXP0003,SKEXP0004,SKEXP0010,SKEXP0011,,SKEXP0012,SKEXP0020,SKEXP0021,SKEXP0022,SKEXP0023,SKEXP0024,SKEXP0025,SKEXP0026,SKEXP0027,SKEXP0028,SKEXP0029,SKEXP0030,SKEXP0031,SKEXP0032,SKEXP0040,SKEXP0041,SKEXP0042,SKEXP0050,SKEXP0051,SKEXP0052,SKEXP0053,SKEXP0054,SKEXP0055,SKEXP0060,SKEXP0061,SKEXP0101,SKEXP0102,KMEXP00</NoWarn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AntDesign.Charts" Version="0.5.1" />
|
||||
<PackageReference Include="AntDesign.ProLayout" Version="0.18.0" />
|
||||
<PackageReference Include="AntDesign.Charts" Version="0.6.0" />
|
||||
<PackageReference Include="AntDesign.ProLayout" Version="1.0.1" />
|
||||
<PackageReference Include="BlazorComponents.Terminal" Version="0.6.0" />
|
||||
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
||||
|
||||
<PackageReference Include="pythonnet" Version="3.0.4" />
|
||||
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
|
||||
|
||||
<PackageReference Include="AutoMapper" Version="8.1.0" />
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||
<PackageReference Include="Markdig" Version="0.36.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.145" />
|
||||
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.118" />
|
||||
<PackageReference Include="RestSharp" Version="110.2.0" />
|
||||
|
||||
<PackageReference Include="Microsoft.SemanticKernel" Version="1.6.2" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Core" Version="1.6.2" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Core" Version="1.6.2-alpha" />
|
||||
<PackageReference Include="Microsoft.KernelMemory.Core" Version="0.34.240313.1" />
|
||||
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.Postgres" Version="0.34.240313.1" />
|
||||
<PackageReference Include="Markdig" Version="0.40.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftVersion)" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.187" />
|
||||
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.119" />
|
||||
<PackageReference Include="RestSharp" Version="$(RestSharpVersion)" />
|
||||
<PackageReference Include="NPOI" Version="2.7.1" />
|
||||
|
||||
<PackageReference Include="LLamaSharp" Version="0.10.0" />
|
||||
<PackageReference Include="LLamaSharp.Backend.Cpu" Version="0.10.0" />
|
||||
<PackageReference Include="LLamaSharp.Backend.Cuda12" Version="0.10.0" />
|
||||
<PackageReference Include="LLamaSharp.kernel-memory" Version="0.10.0" />
|
||||
<PackageReference Include="LLamaSharp.semantic-kernel" Version="0.10.0" />
|
||||
|
||||
|
||||
<PackageReference Include="Microsoft.SemanticKernel" Version="$(SKVersion)" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Core" Version="$(SKVersion)" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Core" Version="$(SKVersion)-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="Serilog" Version="4.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.1-dev-10391" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.4" />
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="8.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.OpenTelemetry" Version="4.1.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AntSk.LLM\AntSK.LLM.csproj" />
|
||||
<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>
|
||||
|
||||
|
||||
@@ -17,6 +17,27 @@
|
||||
<param name="assemblies">程序集集合</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Common.DependencyInjection.InitExtensions.CodeFirst(Microsoft.AspNetCore.Builder.WebApplication)">
|
||||
<summary>
|
||||
使用codefirst创建数据库表
|
||||
</summary>
|
||||
<param name="services"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Common.DependencyInjection.InitExtensions.LoadFun(Microsoft.AspNetCore.Builder.WebApplication)">
|
||||
<summary>
|
||||
加载数据库的插件
|
||||
</summary>
|
||||
<param name="services"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Common.DependencyInjection.InitExtensions.AddAntSKSwagger(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
|
||||
<summary>
|
||||
swagger 初始化
|
||||
</summary>
|
||||
<param name="serviceCollection"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="F:AntSK.Domain.Common.DependencyInjection.ServiceLifetime.Scoped">
|
||||
<summary>
|
||||
作用域
|
||||
@@ -48,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类型
|
||||
@@ -58,11 +157,6 @@
|
||||
模型类型
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Domain.Model.MessageInfo.IsSend">
|
||||
<summary>
|
||||
发送是true 接收是false
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Domain.Model.PageList`1.PageIndex">
|
||||
<summary>
|
||||
当前页,从1开始
|
||||
@@ -78,12 +172,29 @@
|
||||
总数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:AntSK.Domain.Domain.Other.LLamaConfig.dicLLamaWeights">
|
||||
<member name="M:AntSK.Domain.Domain.Other.Bge.BegRerankConfig.LoadModel(System.String,System.String)">
|
||||
<summary>
|
||||
避免模型重复加载,本地缓存
|
||||
模型写死
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Domain.Service.ChatService.SendChatByAppAsync(AntSK.Domain.Repositories.Apps,System.String,System.String)">
|
||||
<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="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,Microsoft.SemanticKernel.ChatCompletion.ChatHistory)">
|
||||
<summary>
|
||||
发送消息
|
||||
</summary>
|
||||
@@ -112,6 +223,20 @@
|
||||
<param name="app"></param>
|
||||
<param name="_kernel"></param>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Domain.Service.KernelService.ImportApiFunction(AntSK.Domain.Repositories.Apps,System.Collections.Generic.List{Microsoft.SemanticKernel.KernelFunction})">
|
||||
<summary>
|
||||
导入API插件
|
||||
</summary>
|
||||
<param name="app"></param>
|
||||
<param name="functions"></param>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Domain.Service.KernelService.ImportNativeFunction(AntSK.Domain.Repositories.Apps,System.Collections.Generic.List{Microsoft.SemanticKernel.KernelFunction})">
|
||||
<summary>
|
||||
导入原生插件
|
||||
</summary>
|
||||
<param name="app"></param>
|
||||
<param name="functions"></param>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Domain.Service.KernelService.RegisterPluginsWithKernel(Microsoft.SemanticKernel.Kernel)">
|
||||
<summary>
|
||||
注册默认插件
|
||||
@@ -127,6 +252,53 @@
|
||||
<param name="history"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Result.Code">
|
||||
<summary>
|
||||
错误码,0是正常返回,异常返回错误码
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Result.Data">
|
||||
<summary>
|
||||
返回数据
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Result.Message">
|
||||
<summary>
|
||||
返回信息详情
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.ResponseResult.Success">
|
||||
<summary>
|
||||
执行成功
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.ResponseResult.Success(System.Object,System.String,System.String)">
|
||||
<summary>
|
||||
执行成功
|
||||
</summary>
|
||||
<param name="data"></param>
|
||||
<param name="code"></param>
|
||||
<param name="message"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.ResponseResult.Error(System.Object,System.String,System.String)">
|
||||
<summary>
|
||||
执行失败
|
||||
</summary>
|
||||
<param name="data"></param>
|
||||
<param name="code"></param>
|
||||
<param name="message"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.ResponseResult.Error(System.String,System.String)">
|
||||
<summary>
|
||||
执行失败
|
||||
</summary>
|
||||
<param name="code"></param>
|
||||
<param name="message"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Options.DBConnectionOption.DbType">
|
||||
<summary>
|
||||
sqlite连接字符串
|
||||
@@ -217,6 +389,11 @@
|
||||
会话模型ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Apps.EmbeddingModelID">
|
||||
<summary>
|
||||
Embedding 模型Id
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Apps.Temperature">
|
||||
<summary>
|
||||
温度
|
||||
@@ -247,6 +424,56 @@
|
||||
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.Chats.UserName">
|
||||
<summary>
|
||||
用户名
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Chats.AppId">
|
||||
<summary>
|
||||
应用ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Chats.Context">
|
||||
<summary>
|
||||
消息内容
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Chats.IsSend">
|
||||
<summary>
|
||||
发送是true 接收是false
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Chats.CreateTime">
|
||||
<summary>
|
||||
创建时间
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Chats.FileName">
|
||||
<summary>
|
||||
文件名
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Funs.Path">
|
||||
<summary>
|
||||
接口描述
|
||||
@@ -724,6 +951,35 @@
|
||||
<param name="stream"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Utils.ConvertUtils.ToQueryString(System.Collections.Generic.Dictionary{System.String,System.String})">
|
||||
<summary>
|
||||
json参数转化querystring参数
|
||||
</summary>
|
||||
<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.ConvertUtils.Unescape(System.String)">
|
||||
<summary>
|
||||
\uxxxx转中文,保留换行符号
|
||||
</summary>
|
||||
<param name="unicodeString"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:AntSK.Domain.Utils.ConvertUtils.IsStream(System.String)">
|
||||
<summary>
|
||||
是否为流式请求
|
||||
</summary>
|
||||
<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.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace AntSK.Domain.Common
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class AntSkFunctionAttribute : Attribute
|
||||
public class AntSKFunctionAttribute : Attribute
|
||||
{
|
||||
// 自定义的ActionAttribute
|
||||
}
|
||||
|
||||
175
src/AntSK.Domain/Common/DependencyInjection/InitExtensions.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using AntSK.Domain.Domain.Model.Constant;
|
||||
using AntSK.Domain.Domain.Service;
|
||||
using AntSK.Domain.Repositories;
|
||||
using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using SqlSugar;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain.Common.DependencyInjection
|
||||
{
|
||||
public static class InitExtensions
|
||||
{
|
||||
private static ILogger _logger;
|
||||
|
||||
public static void InitLog(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
/// <summary>
|
||||
/// 使用codefirst创建数据库表
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <returns></returns>
|
||||
public static WebApplication CodeFirst(this WebApplication app)
|
||||
{
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
// 获取仓储服务
|
||||
var _repository = scope.ServiceProvider.GetRequiredService<IApps_Repositories>();
|
||||
|
||||
// 创建数据库(如果不存在)
|
||||
_repository.GetDB().DbMaintenance.CreateDatabase();
|
||||
|
||||
// 获取当前应用程序域中所有程序集
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
// 在所有程序集中查找具有[SugarTable]特性的类
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
// 获取该程序集中所有具有SugarTable特性的类型
|
||||
var entityTypes = assembly.GetTypes()
|
||||
.Where(type => TypeIsEntity(type));
|
||||
|
||||
// 为每个找到的类型初始化数据库表
|
||||
foreach (var type in entityTypes)
|
||||
{
|
||||
_repository.GetDB().CodeFirst.InitTables(type);
|
||||
}
|
||||
}
|
||||
//安装向量插件
|
||||
_repository.GetDB().Ado.ExecuteCommandAsync($"CREATE EXTENSION IF NOT EXISTS vector;");
|
||||
|
||||
_logger.LogInformation("初始化表结构完成");
|
||||
}
|
||||
return app;
|
||||
}
|
||||
|
||||
public static WebApplication InitDbData(this WebApplication app)
|
||||
{
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
// 初始化字典
|
||||
var _dic_Repository = scope.ServiceProvider.GetRequiredService<IDics_Repositories>();
|
||||
var llamafactoryStart = _dic_Repository.GetFirst(p => p.Type == LLamaFactoryConstantcs.LLamaFactorDic && p.Key == LLamaFactoryConstantcs.IsStartKey);
|
||||
if (llamafactoryStart==null)
|
||||
{
|
||||
llamafactoryStart = new Dics();
|
||||
llamafactoryStart.Id=Guid.NewGuid().ToString();
|
||||
llamafactoryStart.Type = LLamaFactoryConstantcs.LLamaFactorDic;
|
||||
llamafactoryStart.Key = LLamaFactoryConstantcs.IsStartKey;
|
||||
llamafactoryStart.Value = "false";
|
||||
_dic_Repository.Insert(llamafactoryStart);
|
||||
}
|
||||
_logger.LogInformation("初始化数据库初始数据完成");
|
||||
}
|
||||
return app;
|
||||
}
|
||||
/// <summary>
|
||||
/// 加载数据库的插件
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <returns></returns>
|
||||
public static WebApplication LoadFun(this WebApplication app)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
//codefirst 创建表
|
||||
var funRep = scope.ServiceProvider.GetRequiredService<IFuns_Repositories>();
|
||||
var functionService = scope.ServiceProvider.GetRequiredService<FunctionService>();
|
||||
var funs = funRep.GetList();
|
||||
foreach (var fun in funs)
|
||||
{
|
||||
functionService.FuncLoad(fun.Path);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message + " ---- " + ex.StackTrace);
|
||||
}
|
||||
return app;
|
||||
}
|
||||
private static bool TypeIsEntity(Type type)
|
||||
{
|
||||
// 检查类型是否具有SugarTable特性
|
||||
return type.GetCustomAttributes(typeof(SugarTable), inherit: false).Length > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// swagger 初始化
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddAntSKSwagger(this IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddSwaggerGen(c =>
|
||||
{
|
||||
c.SwaggerDoc("v1", new() { Title = "AntSK.Api", Version = "v1" });
|
||||
//添加Api层注释(true表示显示控制器注释)
|
||||
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||
c.IncludeXmlComments(xmlPath, true);
|
||||
//添加Domain层注释(true表示显示控制器注释)
|
||||
var xmlFile1 = $"{Assembly.GetExecutingAssembly().GetName().Name.Replace("Api", "Domain")}.xml";
|
||||
var xmlPath1 = Path.Combine(AppContext.BaseDirectory, xmlFile1);
|
||||
c.IncludeXmlComments(xmlPath1, true);
|
||||
c.DocInclusionPredicate((docName, apiDes) =>
|
||||
{
|
||||
if (!apiDes.TryGetMethodInfo(out MethodInfo method))
|
||||
return false;
|
||||
var version = method.DeclaringType.GetCustomAttributes(true).OfType<ApiExplorerSettingsAttribute>().Select(m => m.GroupName);
|
||||
if (docName == "v1" && !version.Any())
|
||||
return true;
|
||||
var actionVersion = method.GetCustomAttributes(true).OfType<ApiExplorerSettingsAttribute>().Select(m => m.GroupName);
|
||||
if (actionVersion.Any())
|
||||
return actionVersion.Any(v => v == docName);
|
||||
return version.Any(v => v == docName);
|
||||
});
|
||||
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
|
||||
{
|
||||
Description = "Directly enter bearer {token} in the box below (note that there is a space between bearer and token)",
|
||||
Name = "Authorization",
|
||||
In = ParameterLocation.Header,
|
||||
Type = SecuritySchemeType.ApiKey,
|
||||
});
|
||||
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference()
|
||||
{
|
||||
Id = "Bearer",
|
||||
Type = ReferenceType.SecurityScheme
|
||||
}
|
||||
}, Array.Empty<string>()
|
||||
}
|
||||
});
|
||||
});
|
||||
return serviceCollection;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/AntSK.Domain/Common/Embedding/BuilderBgeExtensions.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Microsoft.KernelMemory.AI;
|
||||
using Microsoft.KernelMemory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain.Common.Embedding
|
||||
{
|
||||
public static class BuilderBgeExtensions
|
||||
{
|
||||
public static IKernelMemoryBuilder WithBgeTextEmbeddingGeneration(this IKernelMemoryBuilder builder, HuggingfaceTextEmbeddingGenerator textEmbeddingGenerator)
|
||||
{
|
||||
builder.AddSingleton((ITextEmbeddingGenerator)textEmbeddingGenerator);
|
||||
builder.AddIngestionEmbeddingGenerator(textEmbeddingGenerator);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using Microsoft.KernelMemory.AI;
|
||||
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);
|
||||
}
|
||||
|
||||
public IReadOnlyList<string> GetTokens(string text)
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
822
src/AntSK.Domain/Common/Excel/ExeclHelper.cs
Normal file
@@ -0,0 +1,822 @@
|
||||
using NPOI.HSSF.UserModel;
|
||||
using NPOI.SS.UserModel;
|
||||
using NPOI.SS.Util;
|
||||
using NPOI.XSSF.Streaming;
|
||||
using NPOI.XSSF.UserModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain
|
||||
{
|
||||
public class ExeclHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 将excel导入到datatable
|
||||
/// </summary>
|
||||
/// <param name="filePath">excel路径</param>
|
||||
/// <param name="isColumnName">第一行是否是列名</param>
|
||||
/// <returns>返回datatable</returns>
|
||||
public static DataTable ExcelToDataTable(string filePath, bool isColumnName)
|
||||
{
|
||||
DataTable dataTable = null;
|
||||
FileStream fs = null;
|
||||
DataColumn column = null;
|
||||
DataRow dataRow = null;
|
||||
IWorkbook workbook = null;
|
||||
ISheet sheet = null;
|
||||
IRow row = null;
|
||||
ICell cell = null;
|
||||
int startRow = 0;
|
||||
try
|
||||
{
|
||||
using (fs = File.OpenRead(filePath))
|
||||
{
|
||||
// 2007版本
|
||||
if (filePath.Contains(".xlsx"))
|
||||
workbook = new XSSFWorkbook(fs);
|
||||
// 2003版本
|
||||
else if (filePath.Contains(".xls"))
|
||||
workbook = new HSSFWorkbook(fs);
|
||||
|
||||
if (workbook != null)
|
||||
{
|
||||
sheet = workbook.GetSheetAt(0);//读取第一个sheet,当然也可以循环读取每个sheet
|
||||
dataTable = new DataTable();
|
||||
if (sheet != null)
|
||||
{
|
||||
int rowCount = sheet.LastRowNum;//总行数
|
||||
if (rowCount > 0)
|
||||
{
|
||||
IRow firstRow = sheet.GetRow(0);//第一行
|
||||
int cellCount = firstRow.LastCellNum;//列数
|
||||
|
||||
//构建datatable的列
|
||||
if (isColumnName)
|
||||
{
|
||||
startRow = 1;//如果第一行是列名,则从第二行开始读取
|
||||
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
|
||||
{
|
||||
cell = firstRow.GetCell(i);
|
||||
if (cell != null)
|
||||
{
|
||||
if (cell.StringCellValue != null)
|
||||
{
|
||||
column = new DataColumn(cell.StringCellValue);
|
||||
dataTable.Columns.Add(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
|
||||
{
|
||||
column = new DataColumn("column" + (i + 1));
|
||||
dataTable.Columns.Add(column);
|
||||
}
|
||||
}
|
||||
|
||||
//填充行
|
||||
for (int i = startRow; i <= rowCount; ++i)
|
||||
{
|
||||
row = sheet.GetRow(i);
|
||||
if (row == null) continue;
|
||||
|
||||
dataRow = dataTable.NewRow();
|
||||
for (int j = row.FirstCellNum; j < cellCount; ++j)
|
||||
{
|
||||
cell = row.GetCell(j);
|
||||
if (cell == null)
|
||||
{
|
||||
dataRow[j] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
//CellType(Unknown = -1,Numeric = 0,String = 1,Formula = 2,Blank = 3,Boolean = 4,Error = 5,)
|
||||
switch (cell.CellType)
|
||||
{
|
||||
case CellType.Blank:
|
||||
dataRow[j] = "";
|
||||
break;
|
||||
case CellType.Numeric:
|
||||
short format = cell.CellStyle.DataFormat;
|
||||
//对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
|
||||
if (format == 14 || format == 31 || format == 57 || format == 58)
|
||||
dataRow[j] = cell.DateCellValue;
|
||||
else
|
||||
dataRow[j] = cell.NumericCellValue;
|
||||
break;
|
||||
case CellType.String:
|
||||
dataRow[j] = cell.StringCellValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dataTable.Rows.Add(dataRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataTable;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (fs != null)
|
||||
{
|
||||
fs.Close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将excel导入到datatable
|
||||
/// </summary>
|
||||
/// <param name="stream">流</param>
|
||||
/// <param name="isColumnName">第一行是否是列名</param>
|
||||
/// <returns></returns>
|
||||
public static DataTable ExcelToDataTable(Stream stream, bool isColumnName)
|
||||
{
|
||||
DataTable dataTable = null;
|
||||
DataColumn column = null;
|
||||
DataRow dataRow = null;
|
||||
IWorkbook workbook = new XSSFWorkbook(stream);
|
||||
ISheet sheet = null;
|
||||
IRow row = null;
|
||||
ICell cell = null;
|
||||
int startRow = 0;
|
||||
try
|
||||
{
|
||||
|
||||
if (workbook != null)
|
||||
{
|
||||
sheet = workbook.GetSheetAt(0);//读取第一个sheet,当然也可以循环读取每个sheet
|
||||
dataTable = new DataTable();
|
||||
if (sheet != null)
|
||||
{
|
||||
int rowCount = sheet.LastRowNum;//总行数
|
||||
if (rowCount > 0)
|
||||
{
|
||||
IRow firstRow = sheet.GetRow(0);//第一行
|
||||
int cellCount = firstRow.LastCellNum;//列数
|
||||
|
||||
//构建datatable的列
|
||||
if (isColumnName)
|
||||
{
|
||||
startRow = 1;//如果第一行是列名,则从第二行开始读取
|
||||
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
|
||||
{
|
||||
cell = firstRow.GetCell(i);
|
||||
if (cell != null)
|
||||
{
|
||||
if (cell.StringCellValue != null)
|
||||
{
|
||||
column = new DataColumn(cell.StringCellValue);
|
||||
dataTable.Columns.Add(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
|
||||
{
|
||||
column = new DataColumn("column" + (i + 1));
|
||||
dataTable.Columns.Add(column);
|
||||
}
|
||||
}
|
||||
|
||||
//填充行
|
||||
for (int i = startRow; i <= rowCount; ++i)
|
||||
{
|
||||
row = sheet.GetRow(i);
|
||||
if (row == null) continue;
|
||||
|
||||
dataRow = dataTable.NewRow();
|
||||
for (int j = row.FirstCellNum; j < cellCount; ++j)
|
||||
{
|
||||
cell = row.GetCell(j);
|
||||
if (cell == null)
|
||||
{
|
||||
dataRow[j] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
//CellType(Unknown = -1,Numeric = 0,String = 1,Formula = 2,Blank = 3,Boolean = 4,Error = 5,)
|
||||
switch (cell.CellType)
|
||||
{
|
||||
case CellType.Blank:
|
||||
dataRow[j] = "";
|
||||
break;
|
||||
case CellType.Numeric:
|
||||
short format = cell.CellStyle.DataFormat;
|
||||
//对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
|
||||
if (format == 14 || format == 31 || format == 57 || format == 58)
|
||||
dataRow[j] = cell.DateCellValue;
|
||||
else
|
||||
dataRow[j] = cell.NumericCellValue;
|
||||
break;
|
||||
case CellType.String:
|
||||
dataRow[j] = cell.StringCellValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dataTable.Rows.Add(dataRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dataTable;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// excel转list
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="stream"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<TResult> ExcelToList<TResult>(Stream stream) where TResult : new()
|
||||
{
|
||||
var propertyInfos = typeof(TResult).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CustomAttributes.Count() > 0)
|
||||
.OrderBy(p => p.GetCustomAttribute<ExeclPropertyAttribute>().Order).ToArray();
|
||||
|
||||
List<TResult> list = new List<TResult>();
|
||||
|
||||
IWorkbook workbook = new XSSFWorkbook(stream);
|
||||
ISheet sheet = null;
|
||||
IRow row = null;
|
||||
ICell cell = null;
|
||||
int startRow = 1;
|
||||
try
|
||||
{
|
||||
|
||||
if (workbook != null)
|
||||
{
|
||||
sheet = workbook.GetSheetAt(0);//读取第一个sheet,当然也可以循环读取每个sheet
|
||||
if (sheet != null)
|
||||
{
|
||||
int rowCount = sheet.LastRowNum;//总行数
|
||||
if (rowCount > 0)
|
||||
{
|
||||
IRow firstRow = sheet.GetRow(0);//第一行
|
||||
int cellCount = firstRow.LastCellNum;//列数
|
||||
|
||||
//填充行
|
||||
for (int i = startRow; i <= rowCount; ++i)
|
||||
{
|
||||
row = sheet.GetRow(i);
|
||||
if (row == null) continue;
|
||||
bool emptyRow = true;//是否空行
|
||||
TResult dataModel = new TResult();
|
||||
|
||||
for (int j = row.FirstCellNum; j < cellCount; ++j)
|
||||
{
|
||||
var execlPropertyAttribute = propertyInfos[j].GetCustomAttribute<ExeclPropertyAttribute>();
|
||||
|
||||
cell = row.GetCell(j);
|
||||
if (cell == null)
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (cell.CellType)
|
||||
{
|
||||
case CellType.Blank:
|
||||
propertyInfos[j].SetValue(dataModel, "");
|
||||
break;
|
||||
case CellType.Numeric:
|
||||
short format = cell.CellStyle.DataFormat;
|
||||
//对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
|
||||
if (format == 14 || format == 31 || format == 57 || format == 58)
|
||||
propertyInfos[j].SetValue(dataModel, cell.DateCellValue);
|
||||
else
|
||||
{
|
||||
if (execlPropertyAttribute.CellType == CellType.String)
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, cell.NumericCellValue.ToString());
|
||||
}
|
||||
else
|
||||
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, cell.NumericCellValue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CellType.String:
|
||||
propertyInfos[j].SetValue(dataModel, cell.StringCellValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cell != null && !string.IsNullOrEmpty(cell.ToString().Trim()))
|
||||
{
|
||||
emptyRow = false;
|
||||
}
|
||||
}
|
||||
//非空数据行数据添加到DataTable
|
||||
if (!emptyRow)
|
||||
{
|
||||
list.Add(dataModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static IEnumerable<TResult> ExcelToListFileName<TResult>(Stream stream, string fileName) where TResult : new()
|
||||
{
|
||||
var propertyInfos = typeof(TResult).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CustomAttributes.Count() > 0)
|
||||
.OrderBy(p => p.GetCustomAttribute<ExeclPropertyAttribute>().Order).ToArray();
|
||||
|
||||
List<TResult> list = new List<TResult>();
|
||||
|
||||
IWorkbook workbook = null;
|
||||
if (fileName.Contains(".xlsx"))
|
||||
workbook = new XSSFWorkbook(stream);
|
||||
// 2003版本
|
||||
else if (fileName.Contains(".xls"))
|
||||
workbook = new HSSFWorkbook(stream);
|
||||
ISheet sheet = null;
|
||||
IRow row = null;
|
||||
ICell cell = null;
|
||||
int startRow = 1;
|
||||
try
|
||||
{
|
||||
|
||||
if (workbook != null)
|
||||
{
|
||||
sheet = workbook.GetSheetAt(0);//读取第一个sheet,当然也可以循环读取每个sheet
|
||||
if (sheet != null)
|
||||
{
|
||||
int rowCount = sheet.LastRowNum;//总行数
|
||||
if (rowCount > 0)
|
||||
{
|
||||
IRow firstRow = sheet.GetRow(0);//第一行
|
||||
int cellCount = firstRow.LastCellNum;//列数
|
||||
|
||||
//填充行
|
||||
for (int i = startRow; i <= rowCount; ++i)
|
||||
{
|
||||
row = sheet.GetRow(i);
|
||||
if (row == null) continue;
|
||||
bool emptyRow = true;//是否空行
|
||||
TResult dataModel = new TResult();
|
||||
|
||||
for (int j = row.FirstCellNum; j < cellCount; ++j)
|
||||
{
|
||||
var execlPropertyAttribute = propertyInfos[j].GetCustomAttribute<ExeclPropertyAttribute>();
|
||||
|
||||
cell = row.GetCell(j);
|
||||
if (cell == null)
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (cell.CellType)
|
||||
{
|
||||
case CellType.Blank:
|
||||
propertyInfos[j].SetValue(dataModel, "");
|
||||
break;
|
||||
case CellType.Numeric:
|
||||
short format = cell.CellStyle.DataFormat;
|
||||
//对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
|
||||
if (format == 14 || format == 31 || format == 57 || format == 58)
|
||||
propertyInfos[j].SetValue(dataModel, cell.DateCellValue);
|
||||
else
|
||||
{
|
||||
if (execlPropertyAttribute.CellType == CellType.String)
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, cell.NumericCellValue.ToString());
|
||||
}
|
||||
else
|
||||
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, cell.NumericCellValue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CellType.String:
|
||||
propertyInfos[j].SetValue(dataModel, cell.StringCellValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cell != null && !string.IsNullOrEmpty(cell.ToString().Trim()))
|
||||
{
|
||||
emptyRow = false;
|
||||
}
|
||||
}
|
||||
//非空数据行数据添加到DataTable
|
||||
if (!emptyRow)
|
||||
{
|
||||
list.Add(dataModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// excel转list-根据sheetName得到List
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="sheetName"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<TResult> ExcelToList<TResult>(Stream stream, string sheetName) where TResult : new()
|
||||
{
|
||||
var propertyInfos = typeof(TResult).GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.OrderBy(p => p.GetCustomAttribute<ExeclPropertyAttribute>().Order).ToArray();
|
||||
|
||||
List<TResult> list = new List<TResult>();
|
||||
|
||||
IWorkbook workbook = new XSSFWorkbook(stream);
|
||||
ISheet sheet = null;
|
||||
IRow row = null;
|
||||
ICell cell = null;
|
||||
int startRow = 1;
|
||||
try
|
||||
{
|
||||
|
||||
if (workbook != null)
|
||||
{
|
||||
sheet = workbook.GetSheet(sheetName);//根据sheet读取对应的DataTable
|
||||
if (sheet != null)
|
||||
{
|
||||
int rowCount = sheet.LastRowNum;//总行数
|
||||
if (rowCount > 0)
|
||||
{
|
||||
IRow firstRow = sheet.GetRow(0);//第一行
|
||||
int cellCount = firstRow.LastCellNum;//列数
|
||||
|
||||
//填充行
|
||||
for (int i = startRow; i <= rowCount; ++i)
|
||||
{
|
||||
row = sheet.GetRow(i);
|
||||
if (row == null) continue;
|
||||
bool emptyRow = true;//是否空行
|
||||
|
||||
TResult dataModel = new TResult();
|
||||
|
||||
for (int j = row.FirstCellNum; j < cellCount; ++j)
|
||||
{
|
||||
var execlPropertyAttribute = propertyInfos[j].GetCustomAttribute<ExeclPropertyAttribute>();
|
||||
|
||||
cell = row.GetCell(j);
|
||||
if (cell == null)
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (cell.CellType)
|
||||
{
|
||||
case CellType.Blank:
|
||||
propertyInfos[j].SetValue(dataModel, "");
|
||||
break;
|
||||
case CellType.Numeric:
|
||||
short format = cell.CellStyle.DataFormat;
|
||||
//对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
|
||||
if (format == 14 || format == 31 || format == 57 || format == 58)
|
||||
propertyInfos[j].SetValue(dataModel, cell.DateCellValue);
|
||||
else
|
||||
{
|
||||
if (execlPropertyAttribute.CellType == CellType.String)
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, cell.NumericCellValue.ToString());
|
||||
}
|
||||
else
|
||||
|
||||
{
|
||||
propertyInfos[j].SetValue(dataModel, cell.NumericCellValue);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case CellType.String:
|
||||
propertyInfos[j].SetValue(dataModel, cell.StringCellValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cell != null && !string.IsNullOrEmpty(cell.ToString().Trim()))
|
||||
{
|
||||
emptyRow = false;
|
||||
}
|
||||
}
|
||||
//非空数据行数据添加到DataTable
|
||||
if (!emptyRow)
|
||||
{
|
||||
list.Add(dataModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List导出excel 二进制流
|
||||
/// </summary>
|
||||
/// <typeparam name="T">实体</typeparam>
|
||||
/// <param name="data">List</param>
|
||||
/// <param name="sheetName">sheetname 可不填,默认Sheet0</param>
|
||||
/// <returns></returns>
|
||||
public static byte[] ListToExcel<T>(T[] data, string sheetName = "Sheet0")
|
||||
{
|
||||
IWorkbook workbook = null;
|
||||
IRow row = null;
|
||||
ISheet sheet = null;
|
||||
ICell cell = null;
|
||||
var propertyInfos = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.OrderBy(p => p.GetCustomAttribute<ExeclPropertyAttribute>().Order).ToArray();
|
||||
workbook = new XSSFWorkbook();
|
||||
sheet = workbook.CreateSheet(sheetName);//创建一个名称为Sheet0的表
|
||||
int rowCount = data.Count();//行数
|
||||
int columnCount = propertyInfos.Length;//列数
|
||||
//设置列头
|
||||
row = sheet.CreateRow(0);//excel第一行设为列头
|
||||
for (int c = 0; c < columnCount; c++)
|
||||
{
|
||||
cell = row.CreateCell(c);
|
||||
cell.SetCellValue(propertyInfos[c].GetCustomAttribute<ExeclPropertyAttribute>().DisplayName);
|
||||
}
|
||||
//设置每行每列的单元格,
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
{
|
||||
row = sheet.CreateRow(i + 1);
|
||||
for (int j = 0; j < columnCount; j++)
|
||||
{
|
||||
cell = row.CreateCell(j);//excel第二行开始写入数据
|
||||
cell.SetCellValue(propertyInfos[j].GetValue(data[i])?.ToString());
|
||||
}
|
||||
}
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
{
|
||||
workbook.Write(memoryStream);//向打开的这个xls文件中写入数据
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dt导出excel 二进制流
|
||||
/// </summary>
|
||||
/// <param name="dt">datatable</param>
|
||||
/// <param name="strFile">strFile</param>
|
||||
/// <returns></returns>
|
||||
public static byte[] DataTableToExcel(DataTable dt, string strFile, string sheetName = "Sheet0")
|
||||
{
|
||||
bool result = false;
|
||||
IWorkbook workbook = null;
|
||||
FileStream fs = null;
|
||||
IRow row = null;
|
||||
ISheet sheet = null;
|
||||
ICell cell = null;
|
||||
|
||||
if (dt != null && dt.Rows.Count > 0)
|
||||
{
|
||||
workbook = new XSSFWorkbook();
|
||||
sheet = workbook.CreateSheet(sheetName);//创建一个名称为Sheet0的表
|
||||
int rowCount = dt.Rows.Count;//行数
|
||||
int columnCount = dt.Columns.Count;//列数
|
||||
|
||||
//设置列头
|
||||
row = sheet.CreateRow(0);//excel第一行设为列头
|
||||
for (int c = 0; c < columnCount; c++)
|
||||
{
|
||||
cell = row.CreateCell(c);
|
||||
cell.SetCellValue(dt.Columns[c].ColumnName);
|
||||
}
|
||||
|
||||
//设置每行每列的单元格,
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
{
|
||||
row = sheet.CreateRow(i + 1);
|
||||
for (int j = 0; j < columnCount; j++)
|
||||
{
|
||||
cell = row.CreateCell(j);//excel第二行开始写入数据
|
||||
cell.SetCellValue(dt.Rows[i][j].ToString());
|
||||
}
|
||||
}
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
{
|
||||
workbook.Write(memoryStream);//向打开的这个xls文件中写入数据
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List写入excel
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="strFile">路径</param>
|
||||
/// <param name="sheetName"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ListWriteExcel<T>(T[] data, string strFile, string sheetName = "Sheet0")
|
||||
{
|
||||
bool result = false;
|
||||
IWorkbook workbook = null;
|
||||
FileStream fs = null;
|
||||
IRow row = null;
|
||||
ISheet sheet = null;
|
||||
ICell cell = null;
|
||||
try
|
||||
{
|
||||
var propertyInfos = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.OrderBy(p => p.GetCustomAttribute<ExeclPropertyAttribute>().Order).ToArray();
|
||||
workbook = new XSSFWorkbook();
|
||||
sheet = workbook.CreateSheet(sheetName);//创建一个名称为Sheet0的表
|
||||
int rowCount = data.Count();//行数
|
||||
int columnCount = propertyInfos.Length;//列数
|
||||
//设置列头
|
||||
row = sheet.CreateRow(0);//excel第一行设为列头
|
||||
for (int c = 0; c < columnCount; c++)
|
||||
{
|
||||
cell = row.CreateCell(c);
|
||||
cell.SetCellValue(propertyInfos[c].GetCustomAttribute<ExeclPropertyAttribute>().DisplayName);
|
||||
}
|
||||
//设置每行每列的单元格,
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
{
|
||||
row = sheet.CreateRow(i + 1);
|
||||
for (int j = 0; j < columnCount; j++)
|
||||
{
|
||||
cell = row.CreateCell(j);//excel第二行开始写入数据
|
||||
cell.SetCellValue(propertyInfos[j].GetValue(data[i])?.ToString());
|
||||
}
|
||||
}
|
||||
using (fs = File.OpenWrite(strFile))
|
||||
{
|
||||
workbook.Write(fs);//向打开的这个xls文件中写入数据
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (fs != null)
|
||||
{
|
||||
fs.Close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// dt写入excel
|
||||
/// </summary>
|
||||
/// <param name="dt">datatable</param>
|
||||
/// <param name="strFile">路径</param>
|
||||
/// <returns></returns>
|
||||
public static bool DataTableWriteExcel(DataTable dt, string strFile, string sheetName = "Sheet0")
|
||||
{
|
||||
bool result = false;
|
||||
IWorkbook workbook = null;
|
||||
FileStream fs = null;
|
||||
IRow row = null;
|
||||
ISheet sheet = null;
|
||||
ICell cell = null;
|
||||
try
|
||||
{
|
||||
if (dt != null && dt.Rows.Count > 0)
|
||||
{
|
||||
workbook = new XSSFWorkbook();
|
||||
sheet = workbook.CreateSheet(sheetName);//创建一个名称为Sheet0的表
|
||||
int rowCount = dt.Rows.Count;//行数
|
||||
int columnCount = dt.Columns.Count;//列数
|
||||
|
||||
//设置列头
|
||||
row = sheet.CreateRow(0);//excel第一行设为列头
|
||||
for (int c = 0; c < columnCount; c++)
|
||||
{
|
||||
cell = row.CreateCell(c);
|
||||
cell.SetCellValue(dt.Columns[c].ColumnName);
|
||||
}
|
||||
|
||||
//设置每行每列的单元格,
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
{
|
||||
row = sheet.CreateRow(i + 1);
|
||||
for (int j = 0; j < columnCount; j++)
|
||||
{
|
||||
cell = row.CreateCell(j);//excel第二行开始写入数据
|
||||
cell.SetCellValue(dt.Rows[i][j].ToString());
|
||||
}
|
||||
}
|
||||
using (fs = File.OpenWrite(strFile))
|
||||
{
|
||||
workbook.Write(fs);//向打开的这个xls文件中写入数据
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (fs != null)
|
||||
{
|
||||
fs.Close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置单元格下拉框(除去标题行)
|
||||
/// </summary>
|
||||
/// <param name="workbook"></param>
|
||||
/// <param name="sheet"></param>
|
||||
/// <param name="ddlList"></param>
|
||||
/// <param name="firstcol"></param>
|
||||
/// <param name="lastcol"></param>
|
||||
public static void SetCellDropdownList(IWorkbook workbook, ISheet sheet, List<string> ddlList, string sheetname, int sheetIndex, int firstcol, int lastcol)
|
||||
{
|
||||
|
||||
# region 低版本Excel【HSSFWorkbook】设置下拉框
|
||||
//ISheet sheet2 = workbook.CreateSheet(sheetname);
|
||||
|
||||
////隐藏
|
||||
//workbook.SetSheetHidden(sheetIndex, 1);
|
||||
//int rowIndex = 0;
|
||||
//foreach (var item in ddlList)
|
||||
//{
|
||||
// IRow vrow = sheet2.CreateRow(rowIndex);
|
||||
// vrow.CreateCell(0).SetCellValue(item);
|
||||
|
||||
// rowIndex++;
|
||||
//}
|
||||
|
||||
////创建的下拉项的区域:
|
||||
//var rangeName = sheetname + "Range";
|
||||
//IName range = workbook.CreateName();
|
||||
//range.RefersToFormula = sheetname + "!$A$1:$A$" + rowIndex;
|
||||
//range.NameName = rangeName;
|
||||
//CellRangeAddressList regions = new CellRangeAddressList(1, 65535, firstcol, lastcol);
|
||||
|
||||
//DVConstraint constraint = DVConstraint.CreateFormulaListConstraint(rangeName);
|
||||
//HSSFDataValidation dataValidate = new HSSFDataValidation(regions, constraint);
|
||||
//dataValidate.CreateErrorBox("输入不合法", "请输入或选择下拉列表中的值。");
|
||||
//dataValidate.ShowPromptBox = true;
|
||||
//sheet.AddValidationData(dataValidate);
|
||||
#endregion
|
||||
|
||||
//高版本excel【XSSFWorkbook】 设置下拉框
|
||||
XSSFSheet sheetDDL = (XSSFSheet)workbook.CreateSheet(sheetname);
|
||||
workbook.SetSheetHidden(sheetIndex, 1); //隐藏下拉框数据sheet
|
||||
String[] datas = ddlList.ToArray(); //下拉框数据源
|
||||
XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper(sheetDDL);
|
||||
XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint)dvHelper.CreateExplicitListConstraint(datas);
|
||||
CellRangeAddressList addressList = new CellRangeAddressList(1, 65535, firstcol, lastcol); //下拉设置列
|
||||
XSSFDataValidation validation = (XSSFDataValidation)dvHelper.CreateValidation(dvConstraint, addressList);
|
||||
|
||||
validation.SuppressDropDownArrow = true;
|
||||
validation.ShowErrorBox = true;
|
||||
validation.ShowPromptBox = true;
|
||||
sheet.AddValidationData(validation);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/AntSK.Domain/Common/Excel/ExeclPropertyAttribute.cs
Normal file
@@ -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; }
|
||||
}
|
||||
}
|
||||
73
src/AntSK.Domain/Common/LLamaFactory/ProcessWrapper.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain.Common.LLamaFactory
|
||||
{
|
||||
public class ProcessWrapper(ILogger<ProcessWrapper> _logger)
|
||||
{
|
||||
private Process process;
|
||||
|
||||
public static bool isProcessComplete = false;
|
||||
|
||||
|
||||
public void StartProcess(string arguments, string workingDirectory)
|
||||
{
|
||||
process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "python",
|
||||
Arguments = arguments,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true,
|
||||
WorkingDirectory = workingDirectory
|
||||
}
|
||||
};
|
||||
using (Process start = Process.Start(process.StartInfo))
|
||||
{
|
||||
using (StreamReader reader = start.StandardOutput)
|
||||
{
|
||||
string result = reader.ReadToEnd();
|
||||
if (result != null)
|
||||
{
|
||||
if (result.Contains(":8000"))
|
||||
{
|
||||
isProcessComplete = true;
|
||||
}
|
||||
}
|
||||
_logger.LogInformation(result);
|
||||
}
|
||||
start.WaitForExit();
|
||||
}
|
||||
}
|
||||
|
||||
public string WaitForProcessExit()
|
||||
{
|
||||
process.WaitForExit();
|
||||
return process.StandardOutput.ReadToEnd();
|
||||
}
|
||||
|
||||
public void KillProcess()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!process.HasExited)
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// Process already exited.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
using AntSK.Domain.Domain.Model.Dto;
|
||||
using AntSK.Domain.Domain.Model;
|
||||
using AntSK.Domain.Domain.Model.Dto;
|
||||
using AntSK.Domain.Repositories;
|
||||
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;
|
||||
@@ -11,8 +14,9 @@ namespace AntSK.Domain.Domain.Interface
|
||||
{
|
||||
public interface IChatService
|
||||
{
|
||||
IAsyncEnumerable<StreamingKernelContent> SendChatByAppAsync(Apps app, string questions, string history);
|
||||
IAsyncEnumerable<string> SendChatByAppAsync(Apps app, ChatHistory history);
|
||||
|
||||
IAsyncEnumerable<StreamingKernelContent> SendKmsByAppAsync(Apps app, string questions, string history, List<RelevantSource> relevantSources = null);
|
||||
IAsyncEnumerable<StreamingKernelContent> SendKmsByAppAsync(Apps app, string questions, ChatHistory history, string filePath, List<RelevantSource> relevantSources = null);
|
||||
Task<ChatHistory> GetChatHistory(List<Chats> MessageList, ChatHistory history);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,24 @@
|
||||
using AntSK.Domain.Domain.Model.Dto;
|
||||
using AntDesign;
|
||||
using AntSK.Domain.Domain.Model.Dto;
|
||||
using AntSK.Domain.Repositories;
|
||||
using Microsoft.KernelMemory;
|
||||
|
||||
namespace AntSK.Domain.Domain.Interface
|
||||
{
|
||||
public interface IKMService
|
||||
{
|
||||
MemoryServerless GetMemoryByKMS(string kmsID, SearchClientConfig searchClientConfig = null);
|
||||
Task<List<KMFile>> GetDocumentByFileID(string kmsid, string fileid);
|
||||
MemoryServerless GetMemoryByApp(Apps app);
|
||||
|
||||
MemoryServerless GetMemoryByKMS(string kmsID);
|
||||
|
||||
Task<List<KMFile>> GetDocumentByFileID(string kmsId, string fileId);
|
||||
|
||||
Task<List<RelevantSource>> GetRelevantSourceList(Apps app, string msg);
|
||||
|
||||
List<UploadFileItem> FileList { get; }
|
||||
|
||||
bool BeforeUpload(UploadFileItem file);
|
||||
|
||||
void OnSingleCompleted(UploadInfo fileinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
23
src/AntSK.Domain/Domain/Interface/ILLamaFactoryService.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using AntSK.LLamaFactory.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static AntSK.Domain.Domain.Service.LLamaFactoryService;
|
||||
|
||||
namespace AntSK.Domain.Domain.Interface
|
||||
{
|
||||
public interface ILLamaFactoryService
|
||||
{
|
||||
public event LogMessageHandler LogMessageReceived;
|
||||
Task PipInstall();
|
||||
|
||||
Task PipInstallName(string name);
|
||||
Task StartLLamaFactory(string modelName);
|
||||
|
||||
void KillProcess();
|
||||
|
||||
List<LLamaModel> GetLLamaFactoryModels();
|
||||
}
|
||||
}
|
||||
15
src/AntSK.Domain/Domain/Interface/IOllamaService.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static AntSK.Domain.Domain.Service.OllamaService;
|
||||
|
||||
namespace AntSK.Domain.Domain.Interface
|
||||
{
|
||||
public interface IOllamaService
|
||||
{
|
||||
public event LogMessageHandler LogMessageReceived;
|
||||
Task OllamaPull(string modelName);
|
||||
}
|
||||
}
|
||||
37
src/AntSK.Domain/Domain/Model/Constant/KmsConstantcs.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain.Domain.Model.Constant
|
||||
{
|
||||
public class KmsConstantcs
|
||||
{
|
||||
public const string KmsIdTag = "kmsid";
|
||||
public const string FileIdTag = "fileid";
|
||||
public const string AppIdTag = "appid";
|
||||
public const string KmsIndex = "kms";
|
||||
public const string FileIndex = "kms";
|
||||
public const string KmsSearchNull="知识库未搜索到相关内容";
|
||||
|
||||
public const string KmsPrompt = @"使用<data></data>标记的内容作为你的知识:
|
||||
<data>
|
||||
{{$doc}}
|
||||
</data>
|
||||
--------------------------
|
||||
回答要求:
|
||||
- 如果你不清楚答案,你需要澄清
|
||||
- 避免提及你是从<data></data>获取的知识
|
||||
- 保持答案与<data></data>众描述一致
|
||||
- 使用Markdown语法优化回答格式。
|
||||
- 如果Markdown有图片则正常显示
|
||||
--------------------------
|
||||
|
||||
历史聊天记录:{{ConversationSummaryPlugin.SummarizeConversation $history}}
|
||||
--------------------------
|
||||
用户问题: {{$input}}";
|
||||
|
||||
public const string KMExcelSplit = "*&antsk_excel&*";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain.Domain.Model.Constant
|
||||
{
|
||||
public class LLamaFactoryConstantcs
|
||||
{
|
||||
public const string LLamaFactorDic = "llamafactory";
|
||||
public const string IsStartKey = "isstart";
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,13 @@
|
||||
{
|
||||
public class KMFile
|
||||
{
|
||||
public string DocumentId { get; set; }
|
||||
public string Text { get; set; }
|
||||
|
||||
public string Url { get; set; }
|
||||
public string? Url { get; set; }
|
||||
|
||||
public string LastUpdate { get; set; }
|
||||
|
||||
public string Schema { get; set; }
|
||||
|
||||
public string File { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,4 +18,11 @@
|
||||
public List<string> input { get; set; }
|
||||
}
|
||||
|
||||
public class RerankModel
|
||||
{
|
||||
public string modelId { get; set; }
|
||||
public string query { get; set; }
|
||||
|
||||
public string document { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
namespace AntSK.Domain.Domain.Model.Dto
|
||||
{
|
||||
public class RelevantSource
|
||||
@@ -12,5 +7,12 @@ 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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,38 @@
|
||||
namespace AntSK.Domain.Domain.Model.Enum
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AntSK.Domain.Domain.Model.Enum
|
||||
{
|
||||
/// <summary>
|
||||
/// AI类型
|
||||
/// </summary>
|
||||
public enum AIType
|
||||
{
|
||||
[Display(Name = "Open AI")]
|
||||
OpenAI = 1,
|
||||
|
||||
[Display(Name = "Azure Open AI")]
|
||||
AzureOpenAI = 2,
|
||||
LLamaSharp = 3,
|
||||
|
||||
[Display(Name = "星火大模型")]
|
||||
SparkDesk = 4,
|
||||
Mock = 5,
|
||||
|
||||
[Display(Name = "灵积大模型")]
|
||||
DashScope = 5,
|
||||
|
||||
[Display(Name = "LLamaFactory")]
|
||||
LLamaFactory = 6,
|
||||
[Display(Name = "Bge Embedding")]
|
||||
BgeEmbedding = 7,
|
||||
[Display(Name = "Bge Rerank")]
|
||||
BgeRerank = 8,
|
||||
|
||||
[Display(Name = "Ollama")]
|
||||
Ollama = 10,
|
||||
[Display(Name = "OllamaEmbedding")]
|
||||
OllamaEmbedding = 11,
|
||||
[Display(Name = "模拟输出")]
|
||||
Mock = 100,
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -19,5 +42,6 @@
|
||||
{
|
||||
Chat = 1,
|
||||
Embedding = 2,
|
||||
Rerank=4
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@ namespace AntSK.Domain.Domain.Model.Enum
|
||||
public enum AppType
|
||||
{
|
||||
chat = 1,
|
||||
kms = 2
|
||||
kms = 2,
|
||||
}
|
||||
}
|
||||
|
||||
17
src/AntSK.Domain/Domain/Model/Excel/KMSExcelModel.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain.Domain.Model.Excel
|
||||
{
|
||||
public class KMSExcelModel
|
||||
{
|
||||
[ExeclProperty("问题",0)]
|
||||
public string Question { get; set; }
|
||||
|
||||
[ExeclProperty("答案", 1)]
|
||||
public string Answer { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -11,5 +11,13 @@ namespace AntSK.Domain.Domain.Model.Fun
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public FunType FunType { get; set; }
|
||||
}
|
||||
|
||||
public enum FunType
|
||||
{
|
||||
System=1,
|
||||
Import=2
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
namespace AntSK.Domain.Domain.Model
|
||||
{
|
||||
public class MessageInfo
|
||||
{
|
||||
public string ID { get; set; } = "";
|
||||
public string Context { get; set; } = "";
|
||||
public string HtmlAnswers { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 发送是true 接收是false
|
||||
/// </summary>
|
||||
public bool IsSend { get; set; } = false;
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
85
src/AntSK.Domain/Domain/Model/ResponseResult.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
namespace AntSK.Domain
|
||||
{
|
||||
public class Result
|
||||
{
|
||||
/// <summary>
|
||||
/// 错误码,0是正常返回,异常返回错误码
|
||||
/// </summary>
|
||||
public string Code { get; set; } = "0";
|
||||
/// <summary>
|
||||
/// 返回数据
|
||||
/// </summary>
|
||||
public object Data { get; set; }
|
||||
/// <summary>
|
||||
/// 返回信息详情
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class ResponseResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 执行成功
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Result Success()
|
||||
{
|
||||
return new Result
|
||||
{
|
||||
Data = "",
|
||||
Code = "0",
|
||||
Message = "ok"
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行成功
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="code"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public static Result Success(this object data, string code = "0", string message = "ok")
|
||||
{
|
||||
return new Result
|
||||
{
|
||||
Data = data,
|
||||
Code = code,
|
||||
Message = message
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
/// 执行失败
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="code"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public static Result Error(this object data, string code, string message)
|
||||
{
|
||||
return new Result
|
||||
{
|
||||
Data = data,
|
||||
Code = code,
|
||||
Message = message
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
/// 执行失败
|
||||
/// </summary>
|
||||
/// <param name="code"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public static Result Error(string code, string message)
|
||||
{
|
||||
return new Result
|
||||
{
|
||||
Data = "",
|
||||
Code = code,
|
||||
Message = message
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace AntSK.Domain.Domain.Model.hfmirror
|
||||
public string Author { get; set; }
|
||||
public HfAuthorData AuthorData { get; set; }
|
||||
public int Downloads { get; set; }
|
||||
public bool Gated { get; set; }
|
||||
public object Gated { get; set; }
|
||||
public string Id { get; set; }
|
||||
public DateTime LastModified { get; set; }
|
||||
public int Likes { get; set; }
|
||||
|
||||
@@ -2,26 +2,29 @@
|
||||
using AntSK.Domain.Domain.Interface;
|
||||
using AntSK.Domain.Domain.Model;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace AntSK.Domain.Domain.Other
|
||||
{
|
||||
public class BackGroundTaskHandler : IBackgroundTaskHandler<ImportKMSTaskReq>
|
||||
{
|
||||
private readonly IServiceScopeFactory _scopeFactory;
|
||||
private readonly ILogger<BackGroundTaskHandler> _logger;
|
||||
|
||||
public BackGroundTaskHandler(IServiceScopeFactory scopeFactory)
|
||||
public BackGroundTaskHandler(IServiceScopeFactory scopeFactory, ILogger<BackGroundTaskHandler> logger)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
_logger = logger;
|
||||
}
|
||||
public async Task ExecuteAsync(ImportKMSTaskReq item)
|
||||
{
|
||||
using (var scope = _scopeFactory.CreateScope())
|
||||
{
|
||||
Console.WriteLine("ExecuteAsync.开始执行后台任务");
|
||||
_logger.LogInformation("ExecuteAsync.开始执行后台任务");
|
||||
var importKMSService = scope.ServiceProvider.GetRequiredService<IImportKMSService>();
|
||||
//不能使用异步
|
||||
importKMSService.ImportKMSTask(item);
|
||||
Console.WriteLine("ExecuteAsync.后台任务执行完成");
|
||||
_logger.LogInformation("ExecuteAsync.后台任务执行完成");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
90
src/AntSK.Domain/Domain/Other/Bge/BegRerankConfig.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
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;
|
||||
using AntSK.Domain.Utils;
|
||||
|
||||
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)
|
||||
{
|
||||
PyRunTime.InitRunTime(pythondllPath);
|
||||
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");
|
||||
if (modelName == "BAAI/bge-reranker-v2-minicpm-layerwise")
|
||||
{
|
||||
dynamic flagReranker = flagEmbedding.LayerWiseFlagLLMReranker(model_dir, use_fp16: true);
|
||||
model = flagReranker;
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
|
||||
var res = result.ToString();
|
||||
var res1 = res.Replace("[", "").Replace("]", "").ConvertToDouble();
|
||||
|
||||
return res1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
92
src/AntSK.Domain/Domain/Other/Bge/BgeEmbeddingConfig.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using Microsoft.KernelMemory.AI.OpenAI;
|
||||
using Python.Runtime;
|
||||
using Serilog;
|
||||
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)
|
||||
{
|
||||
PyRunTime.InitRunTime(pythondllPath);
|
||||
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 = DefaultGPTTokenizer.StaticCountTokens(queryStr);
|
||||
return tokenCount1;
|
||||
}
|
||||
|
||||
public static void Dispose()
|
||||
{
|
||||
Log.Information("python dispose");
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/AntSK.Domain/Domain/Other/Bge/PyRunTime.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Python.Runtime;
|
||||
|
||||
namespace AntSK.Domain.Domain.Other.Bge
|
||||
{
|
||||
public static class PyRunTime
|
||||
{
|
||||
static object lockobj = new object();
|
||||
|
||||
static bool isInit = false;
|
||||
|
||||
public static void InitRunTime(string pythonPath)
|
||||
{
|
||||
lock (lockobj)
|
||||
{
|
||||
if (!isInit)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Runtime.PythonDLL))
|
||||
{
|
||||
Runtime.PythonDLL = pythonPath;
|
||||
}
|
||||
PythonEngine.Initialize();
|
||||
PythonEngine.BeginAllowThreads();
|
||||
isInit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
157
src/AntSK.Domain/Domain/Other/KMExcelHandler.cs
Normal file
@@ -0,0 +1,157 @@
|
||||
using AntSK.Domain.Domain.Model.Constant;
|
||||
using AntSK.Domain.Utils;
|
||||
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.AntSKCalculateSHA256(),
|
||||
};
|
||||
newFiles.Add(destFile, destFileDetails);
|
||||
destFileDetails.MarkProcessedBy(this);
|
||||
}
|
||||
|
||||
file.MarkProcessedBy(this);
|
||||
}
|
||||
|
||||
// Add new files to pipeline status
|
||||
foreach (var file in newFiles)
|
||||
{
|
||||
uploadedFile.GeneratedFiles.Add(file.Key, file.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return (true, pipeline);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
using LLama;
|
||||
using LLama.Common;
|
||||
using LLamaSharp.KernelMemory;
|
||||
|
||||
namespace AntSK.Domain.Domain.Other
|
||||
{
|
||||
public static class LLamaConfig
|
||||
{
|
||||
static object lockobj = new object();
|
||||
/// <summary>
|
||||
/// 避免模型重复加载,本地缓存
|
||||
/// </summary>
|
||||
static Dictionary<string, (LLamaWeights, ModelParams)> dicLLamaWeights = new Dictionary<string, (LLamaWeights, ModelParams)>();
|
||||
public static (LLamaWeights, ModelParams) GetLLamaConfig(string modelPath, LLamaSharpConfig config = null)
|
||||
{
|
||||
lock (lockobj)
|
||||
{
|
||||
if (dicLLamaWeights.ContainsKey(modelPath))
|
||||
{
|
||||
return dicLLamaWeights.GetValueOrDefault(modelPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
InferenceParams infParams = new() { AntiPrompts = ["\n\n"] };
|
||||
LLamaSharpConfig lsConfig = new(modelPath) { DefaultInferenceParams = infParams };
|
||||
if (config != null)
|
||||
{
|
||||
lsConfig = config;
|
||||
}
|
||||
var parameters = new ModelParams(lsConfig.ModelPath)
|
||||
{
|
||||
ContextSize = lsConfig?.ContextSize ?? 2048,
|
||||
Seed = lsConfig?.Seed ?? 0,
|
||||
GpuLayerCount = lsConfig?.GpuLayerCount ?? 10,
|
||||
EmbeddingMode = true
|
||||
};
|
||||
var weights = LLamaWeights.LoadFromFile(parameters);
|
||||
dicLLamaWeights.Add(modelPath, (weights, parameters));
|
||||
return (weights, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
173
src/AntSK.Domain/Domain/Other/QAHandler.cs
Normal 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.AntSKCalculateSHA256(),
|
||||
};
|
||||
newFiles.Add(destFile, destFileDetails);
|
||||
destFileDetails.MarkProcessedBy(this);
|
||||
}
|
||||
|
||||
file.MarkProcessedBy(this);
|
||||
}
|
||||
|
||||
// Add new files to pipeline status
|
||||
foreach (var file in newFiles)
|
||||
{
|
||||
uploadedFile.GeneratedFiles.Add(file.Key, file.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return (true, pipeline);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,23 @@
|
||||
using AntSK.Domain.Common.DependencyInjection;
|
||||
using AntSK.Domain.Domain.Interface;
|
||||
using AntSK.Domain.Repositories;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AntSK.Domain.Utils;
|
||||
using Microsoft.KernelMemory;
|
||||
using Markdig;
|
||||
using AntSK.Domain.Domain.Model;
|
||||
using AntSK.Domain.Domain.Model.Constant;
|
||||
using AntSK.Domain.Domain.Model.Dto;
|
||||
using AntSK.Domain.Domain.Other.Bge;
|
||||
using AntSK.Domain.Repositories;
|
||||
using AntSK.Domain.Utils;
|
||||
using AntSK.LLM.StableDiffusion;
|
||||
using Markdig;
|
||||
using Microsoft.KernelMemory;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using ChatHistory = Microsoft.SemanticKernel.ChatCompletion.ChatHistory;
|
||||
|
||||
namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
@@ -20,7 +25,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>
|
||||
@@ -30,73 +36,213 @@ namespace AntSK.Domain.Domain.Service
|
||||
/// <param name="questions"></param>
|
||||
/// <param name="history"></param>
|
||||
/// <returns></returns>
|
||||
public async IAsyncEnumerable<StreamingKernelContent> SendChatByAppAsync(Apps app, string questions, string history)
|
||||
public async IAsyncEnumerable<string> SendChatByAppAsync(Apps app, ChatHistory history)
|
||||
{
|
||||
if (string.IsNullOrEmpty(app.Prompt) || !app.Prompt.Contains("{{$input}}"))
|
||||
{
|
||||
//如果模板为空,给默认提示词
|
||||
app.Prompt = app.Prompt.ConvertToString() + "{{$input}}";
|
||||
}
|
||||
var _kernel = _kernelService.GetKernelByApp(app);
|
||||
var chat = _kernel.GetRequiredService<IChatCompletionService>();
|
||||
var temperature = app.Temperature / 100;//存的是0~100需要缩小
|
||||
OpenAIPromptExecutionSettings settings = new() { Temperature = temperature };
|
||||
if (!string.IsNullOrEmpty(app.ApiFunctionList)|| !string.IsNullOrEmpty(app.NativeFunctionList))//这里还需要加上本地插件的
|
||||
List<string> completionList = new List<string>();
|
||||
if (!string.IsNullOrEmpty(app.ApiFunctionList) || !string.IsNullOrEmpty(app.NativeFunctionList))//这里还需要加上本地插件的
|
||||
{
|
||||
_kernelService.ImportFunctionsByApp(app, _kernel);
|
||||
settings.ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions;
|
||||
settings.ToolCallBehavior = ToolCallBehavior.EnableKernelFunctions;
|
||||
while (true)
|
||||
{
|
||||
ChatMessageContent result = await chat.GetChatMessageContentAsync(history, settings, _kernel);
|
||||
if (result.Content is not null)
|
||||
{
|
||||
string chunkCompletion = result.Content.ConvertToString();
|
||||
completionList.Add(chunkCompletion);
|
||||
foreach (var content in completionList)
|
||||
{
|
||||
yield return content.ConvertToString();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
history.Add(result);
|
||||
|
||||
IEnumerable<FunctionCallContent> functionCalls = FunctionCallContent.GetFunctionCalls(result);
|
||||
if (!functionCalls.Any())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var functionCall in functionCalls)
|
||||
{
|
||||
FunctionResultContent resultContent = await functionCall.InvokeAsync(_kernel);
|
||||
|
||||
history.Add(resultContent.ToChatMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
var func = _kernel.CreateFunctionFromPrompt(app.Prompt, settings);
|
||||
var chatResult = _kernel.InvokeStreamingAsync(function: func, arguments: new KernelArguments() { ["input"] = $"{history}{Environment.NewLine} user:{questions}" });
|
||||
await foreach (var content in chatResult)
|
||||
else
|
||||
{
|
||||
yield return content;
|
||||
var chatResult = chat.GetStreamingChatMessageContentsAsync(history, settings, _kernel);
|
||||
await foreach (var content in chatResult)
|
||||
{
|
||||
yield return content.ConvertToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<StreamingKernelContent> SendKmsByAppAsync(Apps app, string questions, string history, List<RelevantSource> relevantSources = null)
|
||||
public async IAsyncEnumerable<StreamingKernelContent> SendKmsByAppAsync(Apps app, string questions, ChatHistory history, string filePath, List<RelevantSource> relevantSources = null)
|
||||
{
|
||||
relevantSources?.Clear();
|
||||
List<RelevantSource> relevantSourceList = new List<RelevantSource>();
|
||||
|
||||
var _kernel = _kernelService.GetKernelByApp(app);
|
||||
//知识库问答
|
||||
var filters = new List<MemoryFilter>();
|
||||
var kmsidList = app.KmsIdList.Split(",");
|
||||
//只取第一个知识库的配置
|
||||
var _memory = _kMService.GetMemoryByKMS(kmsidList.FirstOrDefault());
|
||||
foreach (var kmsid in kmsidList)
|
||||
if (!string.IsNullOrWhiteSpace(filePath))
|
||||
{
|
||||
filters.Add(new MemoryFilter().ByTag("kmsid", kmsid));
|
||||
}
|
||||
var xlresult = await _memory.SearchAsync(questions, index: "kms", filters: filters);
|
||||
string dataMsg = "";
|
||||
if (xlresult != null)
|
||||
{
|
||||
foreach (var item in xlresult.Results)
|
||||
{
|
||||
foreach (var part in item.Partitions)
|
||||
{
|
||||
dataMsg += $"[file:{item.SourceName};Relevance:{(part.Relevance * 100).ToString("F2")}%]:{part.Text}{Environment.NewLine}";
|
||||
//上传文件问答
|
||||
var memory = _kMService.GetMemoryByApp(app);
|
||||
|
||||
if (relevantSources.IsNotNull())
|
||||
// 匹配GUID的正则表达式
|
||||
string pattern = @"\b[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}\b";
|
||||
|
||||
// 使用正则表达式找到匹配
|
||||
Match match = Regex.Match(filePath, pattern);
|
||||
if (match.Success)
|
||||
{
|
||||
var fileId = match.Value;
|
||||
|
||||
var status = await memory.IsDocumentReadyAsync(fileId, index: KmsConstantcs.KmsIndex);
|
||||
if (!status)
|
||||
{
|
||||
var result = await memory.ImportDocumentAsync(new Document(fileId).AddFile(filePath)
|
||||
.AddTag(KmsConstantcs.AppIdTag, app.Id)
|
||||
.AddTag(KmsConstantcs.FileIdTag, fileId)
|
||||
, index: KmsConstantcs.FileIndex);
|
||||
}
|
||||
|
||||
var filters = new List<MemoryFilter>() {
|
||||
new MemoryFilter().ByTag(KmsConstantcs.AppIdTag, app.Id),
|
||||
new MemoryFilter().ByTag(KmsConstantcs.FileIdTag, fileId)
|
||||
};
|
||||
|
||||
var searchResult = await memory.SearchAsync(questions, index: KmsConstantcs.FileIndex, filters: filters);
|
||||
relevantSourceList.AddRange(searchResult.Results.SelectMany(item => item.Partitions.Select(part => new RelevantSource()
|
||||
{
|
||||
SourceName = item.SourceName,
|
||||
Text = Markdown.ToHtml(part.Text),
|
||||
Relevance = part.Relevance
|
||||
})));
|
||||
app.Prompt = KmsConstantcs.KmsPrompt;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//从知识库问答
|
||||
relevantSourceList = await _kMService.GetRelevantSourceList(app, questions);
|
||||
}
|
||||
|
||||
|
||||
var dataMsg = new StringBuilder();
|
||||
if (relevantSourceList.Any())
|
||||
{
|
||||
if (!string.IsNullOrEmpty(app.RerankModelID))
|
||||
{
|
||||
var rerankModel=_aIModels_Repositories.GetById(app.RerankModelID);
|
||||
BegRerankConfig.LoadModel(rerankModel.EndPoint, rerankModel.ModelName);
|
||||
//进行rerank
|
||||
foreach (var item in relevantSourceList)
|
||||
{
|
||||
List<string> rerank = new List<string>();
|
||||
rerank.Add(questions);
|
||||
rerank.Add(item.Text);
|
||||
item.RerankScore = BegRerankConfig.Rerank(rerank);
|
||||
|
||||
}
|
||||
relevantSourceList = relevantSourceList.OrderByDescending(p => p.RerankScore).Take(app.MaxMatchesCount).ToList();
|
||||
}
|
||||
|
||||
bool isSearch = false;
|
||||
foreach (var item in relevantSourceList)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(app.RerankModelID))
|
||||
{
|
||||
//匹配重排后相似度
|
||||
if (item.RerankScore >= app.Relevance / 100)
|
||||
{
|
||||
string sourceName = item.SourceName;
|
||||
var fileDetail = _kmsDetails_Repositories.GetFirst(p => p.FileGuidName == item.SourceName);
|
||||
if (fileDetail.IsNotNull())
|
||||
{
|
||||
sourceName = fileDetail.FileName;
|
||||
}
|
||||
relevantSources.Add(new RelevantSource() { SourceName = sourceName, Text = Markdown.ToHtml(part.Text), Relevance = part.Relevance });
|
||||
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", "Ask");
|
||||
var chatResult = _kernel.InvokeStreamingAsync(function: jsonFun,
|
||||
arguments: new KernelArguments() { ["doc"] = dataMsg, ["history"] = history, ["questions"] = questions });
|
||||
|
||||
MessageInfo info = null;
|
||||
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
|
||||
{
|
||||
var fileDetail = _kmsDetails_Repositories.GetFirst(p => p.FileGuidName == item.SourceName);
|
||||
if (fileDetail.IsNotNull())
|
||||
{
|
||||
string fileName = fileDetail.FileName;
|
||||
fileDic.Add(item.SourceName, fileName);
|
||||
item.SourceName = fileName;
|
||||
}
|
||||
}
|
||||
item.Text = Markdown.ToHtml(item.Text);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
yield return new StreamingTextContent(KmsConstantcs.KmsSearchNull);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<ChatHistory> GetChatHistory(List<Chats> MessageList, ChatHistory history)
|
||||
{
|
||||
foreach (var item in MessageList)
|
||||
{
|
||||
if (item.IsSend)
|
||||
{
|
||||
history.AddUserMessage(item.Context);
|
||||
}
|
||||
else
|
||||
{
|
||||
history.AddAssistantMessage(item.Context);
|
||||
}
|
||||
}
|
||||
return history;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@ using System.Xml;
|
||||
using AntSK.Domain.Common;
|
||||
using AntSK.Domain.Utils;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.SemanticKernel;
|
||||
using HtmlAgilityPack;
|
||||
using System.Collections.Generic;
|
||||
using Serilog;
|
||||
|
||||
namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
@@ -47,7 +51,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
markedMethods.AddRange(type.GetMethods().Where(m =>
|
||||
{
|
||||
DescriptionAttribute da = (DescriptionAttribute)m.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault();
|
||||
return da != null && da.Description == "AntSK";
|
||||
return da != null && da.Description.Contains( "AntSK");
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -62,7 +66,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
markedMethods.AddRange(type.GetMethods().Where(m =>
|
||||
{
|
||||
DescriptionAttribute da = (DescriptionAttribute)m.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault();
|
||||
return da != null && da.Description == "AntSK";
|
||||
return da != null && da.Description.Contains("AntSK");
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -76,19 +80,10 @@ namespace AntSK.Domain.Domain.Service
|
||||
key = Regex.Replace(key, pattern, "_");
|
||||
_methodCache.TryAdd(key, method);
|
||||
|
||||
var xmlCommentHelper = new XmlCommentHelper();
|
||||
xmlCommentHelper.LoadAll();
|
||||
|
||||
var description = xmlCommentHelper.GetMethodComment(method);
|
||||
var dict = xmlCommentHelper.GetParameterComments(method);
|
||||
|
||||
var parameters = method.GetParameters().Select(x => (x.Name, x.ParameterType, dict[x.Name])).ToArray();
|
||||
var returnType = xmlCommentHelper.GetMethodReturnComment(method);
|
||||
|
||||
if (string.IsNullOrEmpty(description))
|
||||
{
|
||||
description = "导入插件";
|
||||
}
|
||||
var description= method.GetCustomAttribute<DescriptionAttribute>().Description.ConvertToString().Replace("AntSK:","");
|
||||
var returnType = method.ReturnParameter.GetCustomAttribute<DescriptionAttribute>().Description.ConvertToString();
|
||||
var parameters = method.GetParameters().Select(x => (x.Name, x.ParameterType,x.GetCustomAttribute<DescriptionAttribute>()?.Description)).ToArray();
|
||||
// 假设 _methodInfos 是一个已经定义好的字典,用来保存方法的相关信息
|
||||
_methodInfos.TryAdd(key, (description, (method.ReflectedType, returnType), parameters));
|
||||
}
|
||||
}
|
||||
@@ -121,8 +116,8 @@ namespace AntSK.Domain.Domain.Service
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message + " ---- " + ex.StackTrace);
|
||||
Log.Error(ex.Message + " ---- " + ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
using AntSK.Domain.Common.DependencyInjection;
|
||||
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.Extensions.Logging;
|
||||
using Microsoft.KernelMemory;
|
||||
using Microsoft.KernelMemory.Handlers;
|
||||
using System.Text;
|
||||
|
||||
namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
@@ -10,7 +16,8 @@ namespace AntSK.Domain.Domain.Service
|
||||
public class ImportKMSService(
|
||||
IKMService _kMService,
|
||||
IKmsDetails_Repositories _kmsDetails_Repositories,
|
||||
IKmss_Repositories _kmss_Repositories
|
||||
IKmss_Repositories _kmss_Repositories,
|
||||
ILogger<ImportKMSService> _logger
|
||||
) : IImportKMSService
|
||||
{
|
||||
|
||||
@@ -19,18 +26,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("kmsid", req.KmsId)
|
||||
, index: "kms").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);
|
||||
@@ -43,8 +72,16 @@ namespace AntSK.Domain.Domain.Service
|
||||
case ImportType.Url:
|
||||
{
|
||||
//导入url
|
||||
var importResult = _memory.ImportWebPageAsync(req.Url, fileid, new TagCollection() { { "kmsid", req.KmsId } }
|
||||
, index: "kms").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;
|
||||
@@ -54,8 +91,16 @@ namespace AntSK.Domain.Domain.Service
|
||||
case ImportType.Text:
|
||||
//导入文本
|
||||
{
|
||||
var importResult = _memory.ImportTextAsync(req.Text, fileid, new TagCollection() { { "kmsid", req.KmsId } }
|
||||
, index: "kms").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;
|
||||
@@ -63,17 +108,47 @@ 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);
|
||||
//_kmsDetails_Repositories.GetList(p => p.KmsId == req.KmsId);
|
||||
Console.WriteLine("后台导入任务成功:" + req.KmsDetail.DataCount);
|
||||
_logger.LogInformation("后台导入任务成功:" + req.KmsDetail.DataCount);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
req.KmsDetail.Status = Model.Enum.ImportKmsStatus.Fail;
|
||||
_kmsDetails_Repositories.Update(req.KmsDetail);
|
||||
Console.WriteLine("后台导入任务异常:" + ex.Message);
|
||||
_logger.LogError("后台导入任务异常:" + ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,94 @@
|
||||
using AntSK.Domain.Common.DependencyInjection;
|
||||
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;
|
||||
using AntSK.Domain.Domain.Other;
|
||||
using AntSK.Domain.Options;
|
||||
using AntSK.Domain.Repositories;
|
||||
using AntSK.Domain.Utils;
|
||||
using LLama;
|
||||
using LLamaSharp.KernelMemory;
|
||||
using AntSK.OCR;
|
||||
using DocumentFormat.OpenXml.Drawing.Diagrams;
|
||||
using Markdig;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.KernelMemory;
|
||||
using Microsoft.KernelMemory.Configuration;
|
||||
using Microsoft.KernelMemory.ContentStorage.DevTools;
|
||||
using Microsoft.KernelMemory.DataFormats;
|
||||
using Microsoft.KernelMemory.FileSystem.DevTools;
|
||||
using Microsoft.KernelMemory.MemoryStorage;
|
||||
using Microsoft.KernelMemory.MemoryStorage.DevTools;
|
||||
using Microsoft.KernelMemory.Postgres;
|
||||
|
||||
namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
[ServiceDescription(typeof(IKMService), ServiceLifetime.Scoped)]
|
||||
public class KMService(
|
||||
IConfiguration _config,
|
||||
IKmss_Repositories _kmss_Repositories,
|
||||
IAIModels_Repositories _aIModels_Repositories
|
||||
) : IKMService
|
||||
IKmss_Repositories _kmss_Repositories,
|
||||
IAIModels_Repositories _aIModels_Repositories,
|
||||
IMessageService? _message,
|
||||
IKernelService _kernelService
|
||||
) : IKMService
|
||||
{
|
||||
private MemoryServerless _memory;
|
||||
|
||||
public MemoryServerless GetMemoryByKMS(string kmsID, SearchClientConfig searchClientConfig = null)
|
||||
private List<UploadFileItem> _fileList = [];
|
||||
|
||||
public List<UploadFileItem> FileList => _fileList;
|
||||
|
||||
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);
|
||||
SearchClientConfig searchClientConfig;
|
||||
if (string.IsNullOrEmpty(app.RerankModelID))
|
||||
{
|
||||
//不重排直接取查询数
|
||||
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)
|
||||
//.WithCustomTextPartitioningOptions(new TextPartitioningOptions
|
||||
//{
|
||||
// MaxTokensPerLine = app.MaxTokensPerLine,
|
||||
// MaxTokensPerParagraph = kms.MaxTokensPerParagraph,
|
||||
// OverlappingTokens = kms.OverlappingTokens
|
||||
//})
|
||||
;
|
||||
//加载会话模型
|
||||
WithTextGenerationByAIType(memoryBuild, chatModel, chatHttpClient);
|
||||
//加载向量模型
|
||||
WithTextEmbeddingGenerationByAIType(memoryBuild, embedModel, embeddingHttpClient);
|
||||
//加载向量库
|
||||
WithMemoryDbByVectorDB(memoryBuild);
|
||||
|
||||
_memory = memoryBuild.Build<MemoryServerless>();
|
||||
return _memory;
|
||||
}
|
||||
|
||||
public MemoryServerless GetMemoryByKMS(string kmsID)
|
||||
{
|
||||
//if (_memory.IsNull())
|
||||
{
|
||||
@@ -38,42 +102,52 @@ namespace AntSK.Domain.Domain.Service
|
||||
var embeddingHttpClient = OpenAIHttpClientHandlerUtil.GetHttpClient(embedModel.EndPoint);
|
||||
|
||||
//搜索配置
|
||||
if (searchClientConfig.IsNull())
|
||||
{
|
||||
searchClientConfig = new SearchClientConfig
|
||||
{
|
||||
MaxAskPromptSize = 2048,
|
||||
MaxMatchesCount = 3,
|
||||
AnswerTokens = 1000,
|
||||
EmptyAnswer = "知识库未搜索到相关内容"
|
||||
};
|
||||
}
|
||||
//if (searchClientConfig.IsNull())
|
||||
//{
|
||||
// searchClientConfig = new SearchClientConfig
|
||||
// {
|
||||
// MaxAskPromptSize = 2048,
|
||||
// MaxMatchesCount = 3,
|
||||
// AnswerTokens = 1000,
|
||||
// EmptyAnswer = KmsConstantcs.KmsSearchNull
|
||||
// };
|
||||
//}
|
||||
|
||||
var memoryBuild = new KernelMemoryBuilder()
|
||||
.WithSearchClientConfig(searchClientConfig)
|
||||
.WithCustomTextPartitioningOptions(new TextPartitioningOptions
|
||||
{
|
||||
MaxTokensPerLine = kms.MaxTokensPerLine,
|
||||
MaxTokensPerParagraph = kms.MaxTokensPerParagraph,
|
||||
OverlappingTokens = kms.OverlappingTokens
|
||||
});
|
||||
//加载huihu 模型
|
||||
//.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, _config);
|
||||
|
||||
_memory = memoryBuild.Build<MemoryServerless>();
|
||||
WithMemoryDbByVectorDB(memoryBuild);
|
||||
|
||||
_memory = memoryBuild.AddSingleton<IKernelService>(_kernelService).Build<MemoryServerless>();
|
||||
return _memory;
|
||||
}
|
||||
//else {
|
||||
// return _memory;
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
private void WithTextEmbeddingGenerationByAIType(IKernelMemoryBuilder memory, AIModels embedModel, HttpClient embeddingHttpClient)
|
||||
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)
|
||||
{
|
||||
switch (embedModel.AIType)
|
||||
{
|
||||
@@ -84,6 +158,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
EmbeddingModel = embedModel.ModelName
|
||||
}, null, false, embeddingHttpClient);
|
||||
break;
|
||||
|
||||
case Model.Enum.AIType.AzureOpenAI:
|
||||
memory.WithAzureOpenAITextEmbeddingGeneration(new AzureOpenAIConfig()
|
||||
{
|
||||
@@ -94,15 +169,26 @@ namespace AntSK.Domain.Domain.Service
|
||||
APIType = AzureOpenAIConfig.APITypes.EmbeddingGeneration,
|
||||
});
|
||||
break;
|
||||
case Model.Enum.AIType.LLamaSharp:
|
||||
var (weights, parameters) = LLamaConfig.GetLLamaConfig(embedModel.ModelName);
|
||||
var embedder = new LLamaEmbedder(weights, parameters);
|
||||
memory.WithLLamaSharpTextEmbeddingGeneration(new LLamaSharpTextEmbeddingGenerator(embedder));
|
||||
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;
|
||||
case Model.Enum.AIType.OllamaEmbedding:
|
||||
memory.WithOpenAITextEmbeddingGeneration(new OpenAIConfig()
|
||||
{
|
||||
APIKey = "NotNull",
|
||||
EmbeddingModel = embedModel.ModelName
|
||||
}, null, false, embeddingHttpClient);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void WithTextGenerationByAIType(IKernelMemoryBuilder memory, AIModels chatModel, HttpClient chatHttpClient)
|
||||
private void WithTextGenerationByAIType(IKernelMemoryBuilder memory, AIModels chatModel,
|
||||
HttpClient chatHttpClient)
|
||||
{
|
||||
switch (chatModel.AIType)
|
||||
{
|
||||
@@ -113,6 +199,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
TextModel = chatModel.ModelName
|
||||
}, null, chatHttpClient);
|
||||
break;
|
||||
|
||||
case Model.Enum.AIType.AzureOpenAI:
|
||||
memory.WithAzureOpenAITextGeneration(new AzureOpenAIConfig()
|
||||
{
|
||||
@@ -123,20 +210,35 @@ namespace AntSK.Domain.Domain.Service
|
||||
APIType = AzureOpenAIConfig.APITypes.TextCompletion,
|
||||
});
|
||||
break;
|
||||
case Model.Enum.AIType.LLamaSharp:
|
||||
var (weights, parameters) = LLamaConfig.GetLLamaConfig(chatModel.ModelName);
|
||||
var context = weights.CreateContext(parameters);
|
||||
var executor = new StatelessExecutor(weights, parameters);
|
||||
memory.WithLLamaSharpTextGeneration(new LlamaSharpTextGenerator(weights, context, executor));
|
||||
case Model.Enum.AIType.LLamaFactory:
|
||||
|
||||
memory.WithOpenAITextGeneration(new OpenAIConfig()
|
||||
{
|
||||
APIKey = "NotNull",
|
||||
TextModel = chatModel.ModelName
|
||||
}, null, chatHttpClient);
|
||||
break;
|
||||
case Model.Enum.AIType.Ollama:
|
||||
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
|
||||
{
|
||||
ApiKey = chatModel.ModelKey,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void WithMemoryDbByVectorDB(IKernelMemoryBuilder memory, IConfiguration _config)
|
||||
private void WithMemoryDbByVectorDB(IKernelMemoryBuilder memory)
|
||||
{
|
||||
string VectorDb = _config["KernelMemory:VectorDb"].ConvertToString();
|
||||
string ConnectionString = _config["KernelMemory:ConnectionString"].ConvertToString();
|
||||
string TableNamePrefix = _config["KernelMemory:TableNamePrefix"].ConvertToString();
|
||||
string VectorDb = KernelMemoryOption.VectorDb.ConvertToString();
|
||||
string ConnectionString = KernelMemoryOption.ConnectionString.ConvertToString();
|
||||
string TableNamePrefix = KernelMemoryOption.TableNamePrefix.ConvertToString();
|
||||
switch (VectorDb)
|
||||
{
|
||||
case "Postgres":
|
||||
@@ -146,51 +248,137 @@ namespace AntSK.Domain.Domain.Service
|
||||
TableNamePrefix = TableNamePrefix
|
||||
});
|
||||
break;
|
||||
|
||||
case "Disk":
|
||||
memory.WithSimpleFileStorage(new SimpleFileStorageConfig()
|
||||
memory.WithSimpleVectorDb(new SimpleVectorDbConfig()
|
||||
{
|
||||
StorageType = FileSystemTypes.Disk
|
||||
StorageType = FileSystemTypes.Disk,
|
||||
});
|
||||
break;
|
||||
|
||||
case "Memory":
|
||||
memory.WithSimpleFileStorage(new SimpleFileStorageConfig()
|
||||
memory.WithSimpleVectorDb(new SimpleVectorDbConfig()
|
||||
{
|
||||
StorageType = FileSystemTypes.Volatile
|
||||
});
|
||||
break;
|
||||
case "Qdrant":
|
||||
var qdrantConfig = ConnectionString.Split("|");
|
||||
memory.WithQdrantMemoryDb(qdrantConfig[0],qdrantConfig[1]);
|
||||
break;
|
||||
case "Redis":
|
||||
memory.WithRedisMemoryDb(new RedisConfig()
|
||||
{
|
||||
ConnectionString = ConnectionString,
|
||||
});
|
||||
break;
|
||||
case "AzureAISearch":
|
||||
var aisearchConfig = ConnectionString.Split("|");
|
||||
memory.WithAzureAISearchMemoryDb(aisearchConfig[0], aisearchConfig[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<KMFile>> GetDocumentByFileID(string kmsid, string fileid)
|
||||
public async Task<List<KMFile>> GetDocumentByFileID(string kmsId, string fileId)
|
||||
{
|
||||
var _memory = GetMemoryByKMS(kmsid);
|
||||
var memories = await _memory.ListIndexesAsync();
|
||||
var memoryDbs = _memory.Orchestrator.GetMemoryDbs();
|
||||
List<KMFile> docTextList = new List<KMFile>();
|
||||
var memory = GetMemoryByKMS(kmsId);
|
||||
var memories = await memory.ListIndexesAsync();
|
||||
var memoryDbs = memory.Orchestrator.GetMemoryDbs();
|
||||
var docTextList = new List<KMFile>();
|
||||
|
||||
foreach (var memoryIndex in memories)
|
||||
{
|
||||
foreach (var memoryDb in memoryDbs)
|
||||
{
|
||||
|
||||
var items = await memoryDb.GetListAsync(memoryIndex.Name, new List<MemoryFilter>() { new MemoryFilter().ByDocument(fileid) }, 100, true).ToListAsync();
|
||||
foreach (var item in items)
|
||||
var items = await memoryDb.GetListAsync(memoryIndex.Name, new List<MemoryFilter>() { new MemoryFilter().ByDocument(fileId) }, 1000, true).ToListAsync();
|
||||
docTextList.AddRange(items.Select(item => new KMFile()
|
||||
{
|
||||
KMFile file = new KMFile()
|
||||
{
|
||||
Text = item.Payload.FirstOrDefault(p => p.Key == "text").Value.ConvertToString(),
|
||||
Url = item.Payload.FirstOrDefault(p => p.Key == "url").Value.ConvertToString(),
|
||||
LastUpdate = item.Payload.FirstOrDefault(p => p.Key == "last_update").Value.ConvertToString(),
|
||||
Schema = item.Payload.FirstOrDefault(p => p.Key == "schema").Value.ConvertToString(),
|
||||
File = item.Payload.FirstOrDefault(p => p.Key == "file").Value.ConvertToString(),
|
||||
};
|
||||
docTextList.Add(file);
|
||||
}
|
||||
DocumentId = item.GetDocumentId(),
|
||||
Text = item.GetPartitionText(),
|
||||
Url = item.GetWebPageUrl(KmsConstantcs.KmsIndex),
|
||||
LastUpdate = item.GetLastUpdate().LocalDateTime.ToString("yyyy-MM-dd HH:mm:ss"),
|
||||
File = item.GetFileName()
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
return docTextList;
|
||||
}
|
||||
|
||||
public async Task<List<RelevantSource>> GetRelevantSourceList(Apps app ,string msg)
|
||||
{
|
||||
var result = new List<RelevantSource>();
|
||||
if (string.IsNullOrWhiteSpace(app.KmsIdList))
|
||||
return result;
|
||||
var kmsIdList = app.KmsIdList.Split(",");
|
||||
if (!kmsIdList.Any()) return result;
|
||||
|
||||
var memory = GetMemoryByApp(app);
|
||||
|
||||
var filters = kmsIdList.Select(kmsId => new MemoryFilter().ByTag(KmsConstantcs.KmsIdTag, kmsId)).ToList();
|
||||
|
||||
var searchResult = await memory.SearchAsync(msg, index: KmsConstantcs.KmsIndex, filters: filters);
|
||||
if (!searchResult.NoResult)
|
||||
{
|
||||
foreach (var item in searchResult.Results)
|
||||
{
|
||||
result.AddRange(item.Partitions.Select(part => new RelevantSource()
|
||||
{
|
||||
SourceName = item.SourceName,
|
||||
Text = part.Text,
|
||||
Relevance = part.Relevance
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool BeforeUpload(UploadFileItem file)
|
||||
{
|
||||
List<string> types = new List<string>() {
|
||||
"text/plain",
|
||||
"application/msword",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"application/vnd.ms-excel",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"application/vnd.ms-powerpoint",
|
||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||
"application/pdf",
|
||||
"application/json",
|
||||
"text/x-markdown",
|
||||
"text/markdown",
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/tiff"
|
||||
};
|
||||
|
||||
string[] exceptExts = [".md", ".pdf"];
|
||||
var validTypes = types.Contains(file.Type) || exceptExts.Contains(file.Ext);
|
||||
if (!validTypes && file.Ext != ".md")
|
||||
{
|
||||
_message.Error("文件格式错误,请重新选择!");
|
||||
}
|
||||
var IsLt500K = file.Size < 1024 * 1024 * 100;
|
||||
if (!IsLt500K)
|
||||
{
|
||||
_message.Error("文件需不大于100MB!");
|
||||
}
|
||||
|
||||
return validTypes && IsLt500K;
|
||||
}
|
||||
|
||||
public void OnSingleCompleted(UploadInfo fileinfo)
|
||||
{
|
||||
if (fileinfo.File.State == UploadState.Success)
|
||||
{
|
||||
//文件列表
|
||||
_fileList.Add(new UploadFileItem()
|
||||
{
|
||||
FileName = fileinfo.File.FileName,
|
||||
Url = fileinfo.File.Url = fileinfo.File.Response
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,17 +4,16 @@ using AntSK.Domain.Domain.Interface;
|
||||
using AntSK.Domain.Domain.Other;
|
||||
using AntSK.Domain.Repositories;
|
||||
using AntSK.Domain.Utils;
|
||||
using LLama;
|
||||
using LLamaSharp.SemanticKernel.TextCompletion;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Plugins.Core;
|
||||
using Microsoft.SemanticKernel.TextGeneration;
|
||||
using RestSharp;
|
||||
using System;
|
||||
using ServiceLifetime = AntSK.Domain.Common.DependencyInjection.ServiceLifetime;
|
||||
using AntSK.LLM.Mock;
|
||||
using AntSK.Domain.Domain.Model.Enum;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
@@ -26,17 +25,20 @@ namespace AntSK.Domain.Domain.Service
|
||||
private readonly FunctionService _functionService;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private Kernel _kernel;
|
||||
private readonly ILogger<KernelService> _logger;
|
||||
|
||||
public KernelService(
|
||||
IApis_Repositories apis_Repositories,
|
||||
IAIModels_Repositories aIModels_Repositories,
|
||||
FunctionService functionService,
|
||||
IServiceProvider serviceProvider)
|
||||
IServiceProvider serviceProvider,
|
||||
ILogger<KernelService> logger)
|
||||
{
|
||||
_apis_Repositories = apis_Repositories;
|
||||
_aIModels_Repositories = aIModels_Repositories;
|
||||
_functionService = functionService;
|
||||
_serviceProvider = serviceProvider;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -54,7 +56,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);
|
||||
@@ -66,7 +68,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)
|
||||
{
|
||||
@@ -85,18 +98,55 @@ namespace AntSK.Domain.Domain.Service
|
||||
);
|
||||
break;
|
||||
|
||||
case Model.Enum.AIType.LLamaSharp:
|
||||
var (weights, parameters) = LLamaConfig.GetLLamaConfig(chatModel.ModelName);
|
||||
var ex = new StatelessExecutor(weights, parameters);
|
||||
builder.Services.AddKeyedSingleton<ITextGenerationService>("local-llama", new LLamaSharpTextCompletion(ex));
|
||||
case Model.Enum.AIType.SparkDesk:
|
||||
|
||||
var settings = chatModel.ModelKey.Split("|");
|
||||
|
||||
Sdcb.SparkDesk.ModelVersion modelVersion = Sdcb.SparkDesk.ModelVersion.V3_5;
|
||||
|
||||
switch (chatModel.ModelName)
|
||||
{
|
||||
case "V3_5":
|
||||
modelVersion = Sdcb.SparkDesk.ModelVersion.V3_5;
|
||||
break;
|
||||
case "V3":
|
||||
modelVersion = Sdcb.SparkDesk.ModelVersion.V3;
|
||||
break;
|
||||
case "V2":
|
||||
modelVersion = Sdcb.SparkDesk.ModelVersion.V2;
|
||||
break;
|
||||
case "V1_5":
|
||||
modelVersion = Sdcb.SparkDesk.ModelVersion.V1_5;
|
||||
break;
|
||||
}
|
||||
|
||||
SparkDeskOptions options = new SparkDeskOptions { AppId = settings[0], ApiSecret = settings[1], ApiKey = settings[2], ModelVersion = modelVersion };
|
||||
|
||||
builder.Services.AddKeyedSingleton<ITextGenerationService>("spark-desk", new SparkDeskTextCompletion(options, chatModel.Id));
|
||||
builder.Services.AddKeyedSingleton<IChatCompletionService>("spark-desk-chat", new SparkDeskChatCompletion(options, chatModel.Id));
|
||||
break;
|
||||
|
||||
case Model.Enum.AIType.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));
|
||||
case Model.Enum.AIType.DashScope:
|
||||
builder.Services.AddDashScopeChatCompletion(chatModel.ModelKey, chatModel.ModelName);
|
||||
break;
|
||||
|
||||
case Model.Enum.AIType.Mock:
|
||||
builder.Services.AddKeyedSingleton<ITextGenerationService>("mock", new MockTextCompletion());
|
||||
builder.Services.AddKeyedSingleton<IChatCompletionService>("mock-chat", new MockChatCompletion());
|
||||
break;
|
||||
case Model.Enum.AIType.LLamaFactory:
|
||||
builder.AddOpenAIChatCompletion(
|
||||
modelId: chatModel.ModelName,
|
||||
apiKey: "NotNull",
|
||||
httpClient: chatHttpClient
|
||||
);
|
||||
break;
|
||||
case AIType.Ollama:
|
||||
builder.AddOpenAIChatCompletion(
|
||||
modelId: chatModel.ModelName,
|
||||
apiKey: "NotNull",
|
||||
httpClient: chatHttpClient
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -109,13 +159,27 @@ namespace AntSK.Domain.Domain.Service
|
||||
public void ImportFunctionsByApp(Apps app, Kernel _kernel)
|
||||
{
|
||||
//插件不能重复注册,否则会异常
|
||||
if (_kernel.Plugins.Any(p => p.Name == "AntSkFunctions"))
|
||||
if (_kernel.Plugins.Any(p => p.Name == "AntSKFunctions"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<KernelFunction> apiFunctions = new List<KernelFunction>();
|
||||
List<KernelFunction> functions = new List<KernelFunction>();
|
||||
|
||||
//API插件
|
||||
ImportApiFunction(app, functions);
|
||||
//本地函数插件
|
||||
ImportNativeFunction(app, functions);
|
||||
|
||||
_kernel.ImportPluginFromFunctions("AntSKFunctions", functions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导入API插件
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <param name="functions"></param>
|
||||
private void ImportApiFunction(Apps app, List<KernelFunction> functions)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(app.ApiFunctionList))
|
||||
{
|
||||
//开启自动插件调用
|
||||
@@ -124,14 +188,23 @@ namespace AntSK.Domain.Domain.Service
|
||||
|
||||
foreach (var api in apiList)
|
||||
{
|
||||
var returnType = new KernelReturnParameterMetadata() { Description = api.OutputPrompt };
|
||||
switch (api.Method)
|
||||
{
|
||||
case HttpMethodType.Get:
|
||||
apiFunctions.Add(_kernel.CreateFunctionFromMethod((string msg) =>
|
||||
|
||||
var getParametes = new List<KernelParameterMetadata>() {
|
||||
new KernelParameterMetadata("jsonbody"){
|
||||
ParameterType=typeof(string),
|
||||
Description=$"背景文档:{Environment.NewLine}{api.InputPrompt} {Environment.NewLine}提取出对应的json格式字符串,参考如下格式:{Environment.NewLine}{api.Query}"
|
||||
}
|
||||
};
|
||||
functions.Add(_kernel.CreateFunctionFromMethod((string jsonbody) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine(msg);
|
||||
//将json 转换为query参数
|
||||
var queryString = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonbody);
|
||||
RestClient client = new RestClient();
|
||||
RestRequest request = new RestRequest(api.Url, Method.Get);
|
||||
foreach (var header in api.Header.ConvertToString().Split("\n"))
|
||||
@@ -143,13 +216,9 @@ namespace AntSK.Domain.Domain.Service
|
||||
}
|
||||
}
|
||||
//这里应该还要处理一次参数提取,等后面再迭代
|
||||
foreach (var query in api.Query.ConvertToString().Split("\n"))
|
||||
foreach (var q in queryString)
|
||||
{
|
||||
var queryArray = query.Split("=");
|
||||
if (queryArray.Length == 2)
|
||||
{
|
||||
request.AddQueryParameter(queryArray[0], queryArray[1]);
|
||||
}
|
||||
request.AddQueryParameter(q.Key, q.Value);
|
||||
}
|
||||
var result = client.Execute(request);
|
||||
return result.Content;
|
||||
@@ -158,15 +227,21 @@ namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
return "调用失败:" + ex.Message;
|
||||
}
|
||||
}, api.Name, $"{api.Describe}"));
|
||||
}, api.Name, api.Describe, getParametes, returnType));
|
||||
break;
|
||||
|
||||
case HttpMethodType.Post:
|
||||
apiFunctions.Add(_kernel.CreateFunctionFromMethod((string msg) =>
|
||||
//处理json body
|
||||
var postParametes = new List<KernelParameterMetadata>() {
|
||||
new KernelParameterMetadata("jsonbody"){
|
||||
ParameterType=typeof(string),
|
||||
Description=$"背景文档:{Environment.NewLine}{api.InputPrompt} {Environment.NewLine}提取出对应的json格式字符串,参考如下格式:{Environment.NewLine}{api.JsonBody}"
|
||||
}
|
||||
};
|
||||
functions.Add(_kernel.CreateFunctionFromMethod((string jsonBody) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine(msg);
|
||||
_logger.LogInformation(jsonBody);
|
||||
RestClient client = new RestClient();
|
||||
RestRequest request = new RestRequest(api.Url, Method.Post);
|
||||
foreach (var header in api.Header.ConvertToString().Split("\n"))
|
||||
@@ -178,7 +253,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
}
|
||||
}
|
||||
//这里应该还要处理一次参数提取,等后面再迭代
|
||||
request.AddJsonBody(api.JsonBody.ConvertToString());
|
||||
request.AddJsonBody(jsonBody.ConvertToString());
|
||||
var result = client.Execute(request);
|
||||
return result.Content;
|
||||
}
|
||||
@@ -186,19 +261,27 @@ namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
return "调用失败:" + ex.Message;
|
||||
}
|
||||
}, api.Name, $"{api.Describe}"));
|
||||
}, api.Name, api.Describe, postParametes, returnType));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//本地函数插件
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导入原生插件
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <param name="functions"></param>
|
||||
private void ImportNativeFunction(Apps app, List<KernelFunction> functions)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(app.NativeFunctionList))//需要添加判断应用是否开启了本地函数插件
|
||||
{
|
||||
var nativeIdList = app.NativeFunctionList.Split(",");
|
||||
|
||||
_functionService.SearchMarkedMethods();
|
||||
using var scope= _serviceProvider.CreateScope();
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
|
||||
foreach (var func in _functionService.Functions)
|
||||
{
|
||||
@@ -208,11 +291,10 @@ namespace AntSK.Domain.Domain.Service
|
||||
var parameters = methodInfo.Parameters.Select(x => new KernelParameterMetadata(x.ParameterName) { ParameterType = x.ParameterType, Description = x.Description });
|
||||
var returnType = new KernelReturnParameterMetadata() { ParameterType = methodInfo.ReturnType.ParameterType, Description = methodInfo.ReturnType.Description };
|
||||
var target = ActivatorUtilities.CreateInstance(scope.ServiceProvider, func.Value.DeclaringType);
|
||||
apiFunctions.Add(_kernel.CreateFunctionFromMethod(func.Value, target, func.Key, methodInfo.Description, parameters, returnType));
|
||||
functions.Add(_kernel.CreateFunctionFromMethod(func.Value, target, func.Key, methodInfo.Description, parameters, returnType));
|
||||
}
|
||||
}
|
||||
}
|
||||
_kernel.ImportPluginFromFunctions("AntSkFunctions", apiFunctions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -223,7 +305,7 @@ namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
kernel.ImportPluginFromObject(new ConversationSummaryPlugin(), "ConversationSummaryPlugin");
|
||||
//kernel.ImportPluginFromObject(new TimePlugin(), "TimePlugin");
|
||||
kernel.ImportPluginFromPromptDirectory(Path.Combine(RepoFiles.SamplePluginsPath(), "KMSPlugin"));
|
||||
kernel.ImportPluginFromPromptDirectory(System.IO.Path.Combine(RepoFiles.SamplePluginsPath(), "KMSPlugin"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -238,8 +320,8 @@ namespace AntSK.Domain.Domain.Service
|
||||
KernelFunction sunFun = _kernel.Plugins.GetFunction("ConversationSummaryPlugin", "SummarizeConversation");
|
||||
var summary = await _kernel.InvokeAsync(sunFun, new() { ["input"] = $"内容是:{history.ToString()} {Environment.NewLine} 请注意用中文总结" });
|
||||
string his = summary.GetValue<string>();
|
||||
var msg = $"history:{Environment.NewLine}{history.ToString()}{Environment.NewLine} user:{questions}{Environment.NewLine}"; ;
|
||||
var msg = $"history:{Environment.NewLine}{his}{Environment.NewLine} user:{questions}{Environment.NewLine}";
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
210
src/AntSK.Domain/Domain/Service/LLamaFactoryService.cs
Normal file
@@ -0,0 +1,210 @@
|
||||
using AntSK.Domain.Common.DependencyInjection;
|
||||
using AntSK.Domain.Domain.Interface;
|
||||
using AntSK.Domain.Domain.Model.Dto;
|
||||
using AntSK.Domain.Options;
|
||||
using AntSK.Domain.Utils;
|
||||
using AntSK.LLamaFactory.Model;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
[ServiceDescription(typeof(ILLamaFactoryService), ServiceLifetime.Singleton)]
|
||||
public class LLamaFactoryService(ILogger<LLamaFactoryService> _logger) : ILLamaFactoryService
|
||||
{
|
||||
private Process process;
|
||||
|
||||
private readonly object _syncLock = new object();
|
||||
private List<LLamaModel> modelList = new List<LLamaModel>();
|
||||
|
||||
|
||||
public delegate Task LogMessageHandler(string message);
|
||||
public event LogMessageHandler LogMessageReceived;
|
||||
protected virtual async Task OnLogMessageReceived(string message)
|
||||
{
|
||||
LogMessageReceived?.Invoke(message);
|
||||
}
|
||||
|
||||
public async Task PipInstall()
|
||||
{
|
||||
|
||||
var cmdTask = Task.Factory.StartNew(() =>
|
||||
{
|
||||
|
||||
|
||||
process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "pip",
|
||||
Arguments = "install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple",
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory,
|
||||
}
|
||||
};
|
||||
process.OutputDataReceived += (sender, eventArgs) =>
|
||||
{
|
||||
_logger.LogInformation($"{eventArgs.Data}");
|
||||
OnLogMessageReceived(eventArgs.Data);
|
||||
};
|
||||
process.ErrorDataReceived += (sender, eventArgs) =>
|
||||
{
|
||||
_logger.LogInformation($"{eventArgs.Data}");
|
||||
OnLogMessageReceived(eventArgs.Data);
|
||||
};
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
process.WaitForExit();
|
||||
OnLogMessageReceived("--------------------完成--------------------");
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
await cmdTask;
|
||||
}
|
||||
public async Task PipInstallName(string name)
|
||||
{
|
||||
|
||||
var cmdTask = Task.Factory.StartNew(() =>
|
||||
{
|
||||
|
||||
process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "pip",
|
||||
Arguments = $"install {name} -i https://pypi.tuna.tsinghua.edu.cn/simple",
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory,
|
||||
}
|
||||
};
|
||||
process.OutputDataReceived += (sender, eventArgs) =>
|
||||
{
|
||||
Log.Information($"{eventArgs.Data}");
|
||||
OnLogMessageReceived(eventArgs.Data);
|
||||
};
|
||||
process.ErrorDataReceived += (sender, eventArgs) =>
|
||||
{
|
||||
Log.Information($"{eventArgs.Data}");
|
||||
OnLogMessageReceived(eventArgs.Data);
|
||||
};
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
process.WaitForExit();
|
||||
OnLogMessageReceived("--------------------完成--------------------");
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
await cmdTask;
|
||||
}
|
||||
public async Task StartLLamaFactory(string modelName)
|
||||
{
|
||||
var cmdTask = Task.Factory.StartNew(() =>
|
||||
{
|
||||
string templateName = "default";
|
||||
var modelList = GetLLamaFactoryModels();
|
||||
var model = modelList.Where(p => p.ModelScope == modelName).FirstOrDefault();
|
||||
if (model.IsNotNull() && !string.IsNullOrEmpty(model.Template))
|
||||
{
|
||||
templateName = model.Template;
|
||||
}
|
||||
|
||||
process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "python",
|
||||
Arguments = "api_antsk.py --model_name_or_path " + modelName + " --template " + templateName + " ",
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError=true,
|
||||
WorkingDirectory = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location), "llamafactory"),
|
||||
}
|
||||
};
|
||||
process.StartInfo.Environment["CUDA_VISIBLE_DEVICES"] = Environment.GetEnvironmentVariable("CUDA_VISIBLE_DEVICES") ?? "0";
|
||||
process.StartInfo.Environment["API_PORT"] = "8000";
|
||||
process.StartInfo.EnvironmentVariables["USE_MODELSCOPE_HUB"] = Environment.GetEnvironmentVariable("USE_MODELSCOPE_HUB") ?? "1";
|
||||
process.OutputDataReceived += (sender, eventArgs) =>
|
||||
{
|
||||
_logger.LogInformation($"{eventArgs.Data}");
|
||||
OnLogMessageReceived(eventArgs.Data);
|
||||
};
|
||||
process.ErrorDataReceived += (sender, eventArgs) =>
|
||||
{
|
||||
_logger.LogInformation($"{eventArgs.Data}");
|
||||
OnLogMessageReceived(eventArgs.Data);
|
||||
};
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
process.WaitForExit();
|
||||
|
||||
OnLogMessageReceived("--------------------完成--------------------");
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
await cmdTask;
|
||||
}
|
||||
|
||||
private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string WaitForProcessExit()
|
||||
{
|
||||
process.WaitForExit();
|
||||
return process.StandardOutput.ReadToEnd();
|
||||
}
|
||||
|
||||
public void KillProcess()
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
Process[] processes = Process.GetProcesses();
|
||||
foreach (Process process1 in processes)
|
||||
{
|
||||
if (process1.ProcessName.ToLower() == "python")
|
||||
{
|
||||
process1.Kill();
|
||||
_logger.LogInformation("kill python");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
// Process already exited.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public List<LLamaModel> GetLLamaFactoryModels()
|
||||
{
|
||||
if (modelList.Count==0)
|
||||
{
|
||||
string jsonString = File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "modelList.json"));
|
||||
|
||||
// 反序列化 JSON 字符串到相应的 C# 对象
|
||||
var Models = JsonConvert.DeserializeObject<List<LLamaFactoryModel>>(jsonString);
|
||||
foreach (var model in Models)
|
||||
{
|
||||
foreach (var m in model.Models)
|
||||
{
|
||||
modelList.Add(new LLamaModel() { Name = m.Key, ModelScope = m.Value.MODELSCOPE, Template = model.Template });
|
||||
}
|
||||
}
|
||||
}
|
||||
return modelList;
|
||||
}
|
||||
}
|
||||
}
|
||||
74
src/AntSK.Domain/Domain/Service/OllamaService.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using AntSK.Domain.Common.DependencyInjection;
|
||||
using AntSK.Domain.Domain.Interface;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using AntSK.Domain.Utils;
|
||||
|
||||
namespace AntSK.Domain.Domain.Service
|
||||
{
|
||||
[ServiceDescription(typeof(IOllamaService), ServiceLifetime.Singleton)]
|
||||
public class OllamaService : IOllamaService
|
||||
{
|
||||
private Process process;
|
||||
public delegate Task LogMessageHandler(string message);
|
||||
public event LogMessageHandler LogMessageReceived;
|
||||
protected virtual async Task OnLogMessageReceived(string message)
|
||||
{
|
||||
LogMessageReceived?.Invoke(message);
|
||||
}
|
||||
|
||||
public async Task OllamaPull(string modelName)
|
||||
{
|
||||
Console.OutputEncoding = Encoding.UTF8;
|
||||
var cmdTask = Task.Factory.StartNew(() =>
|
||||
{
|
||||
|
||||
var isProcessComplete = false;
|
||||
|
||||
process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "ollama",
|
||||
Arguments = "pull " + modelName,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
}
|
||||
};
|
||||
process.OutputDataReceived += (sender, eventArgs) =>
|
||||
{
|
||||
Log.Information($"{eventArgs.Data.ConvertToString()}");
|
||||
if (!eventArgs.Data.ConvertToString().Contains("The handle is invalid"))
|
||||
{
|
||||
OnLogMessageReceived(eventArgs.Data.ConvertToString());
|
||||
}
|
||||
};
|
||||
process.ErrorDataReceived += (sender, eventArgs) =>
|
||||
{
|
||||
Log.Error($"{eventArgs.Data.ConvertToString()}");
|
||||
if (!eventArgs.Data.ConvertToString().Contains("The handle is invalid"))
|
||||
{
|
||||
OnLogMessageReceived(eventArgs.Data.ConvertToString());
|
||||
}
|
||||
};
|
||||
process.StartInfo.StandardOutputEncoding = Encoding.UTF8;
|
||||
process.StartInfo.StandardErrorEncoding = Encoding.UTF8;
|
||||
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
process.WaitForExit();
|
||||
|
||||
OnLogMessageReceived("--------------------完成--------------------");
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
await cmdTask;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
13
src/AntSK.Domain/Options/FileDirOption.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain.Options
|
||||
{
|
||||
public class FileDirOption
|
||||
{
|
||||
public static string DirectoryPath { get; set; } = Directory.GetCurrentDirectory();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
namespace AntSK.Domain.Options
|
||||
{
|
||||
public class LLamaSharpOption
|
||||
{
|
||||
public static string RunType { get; set; }
|
||||
public static string Chat { get; set; }
|
||||
|
||||
public static string Embedding { get; set; }
|
||||
|
||||
public static string FileDirectory { get; set; } = Directory.GetCurrentDirectory();
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,12 @@ namespace AntSK.Domain.Repositories
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Describe { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Icon { get; set; }
|
||||
public string Icon { get; set; } = "windows";
|
||||
|
||||
/// <summary>
|
||||
/// 类型
|
||||
@@ -38,6 +39,16 @@ namespace AntSK.Domain.Repositories
|
||||
[Required]
|
||||
public string? ChatModelID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Embedding 模型Id
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string? EmbeddingModelID { get; set; }
|
||||
|
||||
public string? RerankModelID { get; set; }
|
||||
|
||||
|
||||
public string? ImageModelID { get; set; }
|
||||
/// <summary>
|
||||
/// 温度
|
||||
/// </summary>
|
||||
@@ -47,6 +58,7 @@ namespace AntSK.Domain.Repositories
|
||||
/// <summary>
|
||||
/// 提示词
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "varchar(2000)")]
|
||||
public string? Prompt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -61,14 +73,41 @@ namespace AntSK.Domain.Repositories
|
||||
[SugarColumn(ColumnDataType = "varchar(1000)")]
|
||||
public string? NativeFunctionList { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 知识库ID列表
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "varchar(1000)")]
|
||||
public string? KmsIdList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// API调用秘钥
|
||||
/// </summary>
|
||||
public string? SecretKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 相似度
|
||||
/// </summary>
|
||||
[SugarColumn(DefaultValue = "60")]
|
||||
public double Relevance { get; set; } = 60f;
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
}
|
||||
41
src/AntSK.Domain/Repositories/AI/Chat/Chats.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using AntSK.Domain.Domain.Model.Enum;
|
||||
using SqlSugar;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
[SugarTable("Chats")]
|
||||
public partial class Chats
|
||||
{
|
||||
[SugarColumn(IsPrimaryKey = true)]
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
/// <summary>
|
||||
/// 应用ID
|
||||
/// </summary>
|
||||
public string AppId { get; set; }
|
||||
/// <summary>
|
||||
/// 消息内容
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "varchar(4000)")]
|
||||
public string Context { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 发送是true 接收是false
|
||||
/// </summary>
|
||||
public bool IsSend { get; set; } = false;
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件名
|
||||
/// </summary>
|
||||
public string? FileName { get; set; }
|
||||
}
|
||||
}
|
||||
11
src/AntSK.Domain/Repositories/AI/Chat/Chats_Repositories.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
using AntSK.Domain.Common.DependencyInjection;
|
||||
using AntSK.Domain.Repositories.Base;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
[ServiceDescription(typeof(IChats_Repositories), ServiceLifetime.Scoped)]
|
||||
public class Chats_Repositories : Repository<Chats>, IChats_Repositories
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using AntSK.Domain.Repositories.Base;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
public interface IChats_Repositories : IRepository<Chats>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace AntSK.Domain.Repositories
|
||||
/// 图标
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Icon { get; set; }
|
||||
public string Icon { get; set; } = "question-circle";
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
16
src/AntSK.Domain/Repositories/Setting/Dic/Dics.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using AntSK.Domain.Domain.Model.Enum;
|
||||
using SqlSugar;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
[SugarTable("Dics")]
|
||||
public partial class Dics
|
||||
{
|
||||
[SugarColumn(IsPrimaryKey = true)]
|
||||
public string Id { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string Key { get; set; }
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
using AntSK.Domain.Common.DependencyInjection;
|
||||
using AntSK.Domain.Repositories.Base;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
[ServiceDescription(typeof(IDics_Repositories), ServiceLifetime.Scoped)]
|
||||
public class Dics_Repositories : Repository<Dics>, IDics_Repositories
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using AntSK.Domain.Repositories.Base;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
public interface IDics_Repositories : IRepository<Dics>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,10 @@
|
||||
namespace AntSK.Domain.Utils
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
|
||||
namespace AntSK.Domain.Utils
|
||||
{
|
||||
public static class ConvertUtils
|
||||
{
|
||||
@@ -231,5 +237,83 @@
|
||||
{
|
||||
return $"{Environment.NewLine}```json{Environment.NewLine}{s}{Environment.NewLine}```{Environment.NewLine}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// json参数转化querystring参数
|
||||
/// </summary>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToQueryString(this Dictionary<string, string> parameters)
|
||||
{
|
||||
var nameValueCollection = HttpUtility.ParseQueryString(string.Empty);
|
||||
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
nameValueCollection[param.Key] = param.Value;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// \uxxxx转中文,保留换行符号
|
||||
/// </summary>
|
||||
/// <param name="unicodeString"></param>
|
||||
/// <returns></returns>
|
||||
public static string Unescape(this string value)
|
||||
{
|
||||
if (value.IsNull())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Formatting formatting = Formatting.None;
|
||||
|
||||
object jsonObj = JsonConvert.DeserializeObject(value);
|
||||
string unescapeValue = JsonConvert.SerializeObject(jsonObj, formatting);
|
||||
return unescapeValue;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex.ToString());
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 是否为流式请求
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsStream(this string value)
|
||||
{
|
||||
// 正则表达式忽略空格的情况
|
||||
string pattern = @"\s*""stream""\s*:\s*true\s*";
|
||||
|
||||
// 使用正则表达式匹配
|
||||
bool contains = Regex.IsMatch(value, pattern);
|
||||
return contains;
|
||||
}
|
||||
|
||||
public static string AntSKCalculateSHA256(this BinaryData binaryData)
|
||||
{
|
||||
byte[] byteArray = SHA256.HashData(binaryData.ToMemory().Span);
|
||||
return Convert.ToHexString(byteArray).ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
39
src/AntSK.Domain/Utils/ImageUtils.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.Domain.Utils
|
||||
{
|
||||
public class ImageUtils
|
||||
{
|
||||
public static string BitmapToBase64(Bitmap bitmap)
|
||||
{
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
{
|
||||
// 保存为JPEG格式,也可以选择Png,Gif等等
|
||||
bitmap.Save(memoryStream, ImageFormat.Jpeg);
|
||||
|
||||
// 获取内存流的字节数组
|
||||
byte[] imageBytes = memoryStream.ToArray();
|
||||
|
||||
// 将字节转换为Base64字符串
|
||||
string base64String = Convert.ToBase64String(imageBytes);
|
||||
return base64String;
|
||||
}
|
||||
}
|
||||
public static List<string> BitmapListToBase64(Bitmap[] bitmaps)
|
||||
{
|
||||
List<string> base64Strings = new List<string>();
|
||||
|
||||
foreach (Bitmap bitmap in bitmaps)
|
||||
{
|
||||
base64Strings.Add(BitmapToBase64(bitmap));
|
||||
}
|
||||
return base64Strings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using Serilog;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AntSK.Domain.Utils
|
||||
{
|
||||
@@ -15,12 +17,19 @@ namespace AntSK.Domain.Utils
|
||||
UriBuilder uriBuilder;
|
||||
Regex regex = new Regex(@"(https?)://([^/:]+)(:\d+)?/(.*)");
|
||||
Match match = regex.Match(_endPoint);
|
||||
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development" && request.Content != null)
|
||||
string guid = Guid.NewGuid().ToString();
|
||||
var mediaType = request.Content.Headers.ContentType.MediaType;
|
||||
string requestBody = (await request.Content.ReadAsStringAsync()).Unescape();
|
||||
var uncaseBody = new StringContent(requestBody, Encoding.UTF8, mediaType);
|
||||
request.Content = uncaseBody;
|
||||
|
||||
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT").ConvertToString() == "Development")
|
||||
{
|
||||
string requestBody = await request.Content.ReadAsStringAsync();
|
||||
//生产环境根据环境变量可去关闭日志
|
||||
//便于调试查看请求prompt
|
||||
Console.WriteLine(requestBody);
|
||||
Log.Information("{Message}", $"【模型服务接口调用-{guid},host:{_endPoint}】:{Environment.NewLine}{requestBody}");
|
||||
}
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
string xieyi = match.Groups[1].Value;
|
||||
@@ -70,7 +79,11 @@ namespace AntSK.Domain.Utils
|
||||
|
||||
// 接着,调用基类的 SendAsync 方法将你的修改后的请求发出去
|
||||
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
|
||||
|
||||
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT").ConvertToString() == "Development")
|
||||
{
|
||||
string responseContent = requestBody.IsStream() ? response.Content.ReadAsStringAsync().Result : response.Content.ReadAsStringAsync().Result.Unescape();
|
||||
Log.Information("{Message}", $"【模型服务接口返回-{guid},host:{_endPoint}】:{Environment.NewLine}{responseContent}");
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -82,7 +95,7 @@ namespace AntSK.Domain.Utils
|
||||
{
|
||||
var handler = new OpenAIHttpClientHandler(endPoint.ConvertToString());
|
||||
var httpClient = new HttpClient(handler);
|
||||
httpClient.Timeout = TimeSpan.FromMinutes(5);
|
||||
httpClient.Timeout = TimeSpan.FromMinutes(10);
|
||||
return httpClient;
|
||||
}
|
||||
}
|
||||
|
||||
55
src/AntSK.LLM/AntSK.LLM.csproj
Normal file
@@ -0,0 +1,55 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SemanticKernel" Version="$(SKVersion)" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftVersion)" />
|
||||
<PackageReference Include="RestSharp" Version="$(RestSharpVersion)" />
|
||||
<PackageReference Include="Cnblogs.KernelMemory.AI.DashScope" Version="0.3.0" />
|
||||
<PackageReference Include="Cnblogs.SemanticKernel.Connectors.DashScope" Version="0.3.2" />
|
||||
<PackageReference Include="Sdcb.SparkDesk" Version="3.0.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="OllamaEmbeddingModelList.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="OllamaModelList.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<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>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
17
src/AntSK.LLM/LLamaFactory/LLMFactoryOptions.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Sdcb.SparkDesk;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.LLM.LLamaFactory
|
||||
{
|
||||
public class LLMFactoryOptions
|
||||
{
|
||||
|
||||
public string ModelPath { get; set; }
|
||||
|
||||
public string ModelName { get; set; }
|
||||
}
|
||||
}
|
||||
48
src/AntSK.LLM/LLamaFactory/LLMFactoryTextCompletion.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using AntSK.LLM.SparkDesk;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
using Microsoft.SemanticKernel.TextGeneration;
|
||||
using Sdcb.SparkDesk;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Unicode;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
using RestSharp;
|
||||
using System.Text.Json.Nodes;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace AntSK.LLM.LLamaFactory
|
||||
{
|
||||
public class LLMFactoryTextCompletion : ITextGenerationService, IAIService
|
||||
{
|
||||
private readonly Dictionary<string, object?> _attributes = new();
|
||||
private string _chatId;
|
||||
private readonly LLMFactoryOptions _options;
|
||||
|
||||
public IReadOnlyDictionary<string, object?> Attributes => _attributes;
|
||||
|
||||
public LLMFactoryTextCompletion(LLMFactoryOptions options, string chatId)
|
||||
{
|
||||
_options = options;
|
||||
_chatId = chatId;
|
||||
}
|
||||
|
||||
public Task<IReadOnlyList<TextContent>> GetTextContentsAsync(string prompt, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
}
|
||||
|
||||
public IAsyncEnumerable<StreamingTextContent> GetStreamingTextContentsAsync(string prompt, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
55
src/AntSK.LLM/Mock/MockChatCompletion.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using AntSK.LLM.SparkDesk;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Sdcb.SparkDesk;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Unicode;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.LLM.Mock
|
||||
{
|
||||
public class MockChatCompletion : IChatCompletionService
|
||||
{
|
||||
private readonly Dictionary<string, object?> _attributes = new();
|
||||
private readonly SparkDeskClient _client;
|
||||
private string _chatId;
|
||||
private readonly SparkDeskOptions _options;
|
||||
|
||||
private static readonly JsonSerializerOptions _jsonSerializerOptions = new()
|
||||
{
|
||||
NumberHandling = JsonNumberHandling.AllowReadingFromString,
|
||||
Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
|
||||
};
|
||||
|
||||
public IReadOnlyDictionary<string, object?> Attributes => _attributes;
|
||||
|
||||
public MockChatCompletion()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<ChatMessageContent>> GetChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
string result = $"这是一条Mock数据,便于聊天测试,你的消息是:{chatHistory.LastOrDefault().ToString()}";
|
||||
return [new(AuthorRole.Assistant, result.ToString())];
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<StreamingChatMessageContent> GetStreamingChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
string result = $"这是一条Mock数据,便于聊天测试,你的消息是:{chatHistory.LastOrDefault().ToString()}";
|
||||
foreach (var c in result)
|
||||
{
|
||||
yield return new StreamingChatMessageContent(AuthorRole.Assistant, c.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/AntSK.LLM/OllamaEmbeddingModelList.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
nomic-embed-text:v1.5
|
||||
mxbai-embed-large:335m
|
||||
all-minilm:22m
|
||||
all-minilm:33m
|
||||
snowflake-arctic-embed:22m
|
||||
snowflake-arctic-embed:33m
|
||||
snowflake-arctic-embed:110m
|
||||
snowflake-arctic-embed:137m
|
||||
snowflake-arctic-embed:335m
|
||||
bge-m3
|
||||
bge-large:335m
|
||||
paraphrase-multilingual:278m
|
||||
111
src/AntSK.LLM/OllamaModelList.txt
Normal file
@@ -0,0 +1,111 @@
|
||||
gemma2
|
||||
gemma2:27b
|
||||
gemma:2b
|
||||
gemma:7b
|
||||
llama3
|
||||
llama3:70b
|
||||
yi:6b
|
||||
yi:9B
|
||||
yi:34B
|
||||
qwen2:0.5b
|
||||
qwen2:1.5b
|
||||
qwen2:7b
|
||||
qwen2:72b
|
||||
qwen:0.5b
|
||||
qwen:1.8b
|
||||
qwen:4b
|
||||
qwen:7b
|
||||
qwen:14b
|
||||
qwen:32b
|
||||
qwen:72b
|
||||
qwen:110b
|
||||
deepseek-coder:1.3b
|
||||
deepseek-coder:6.7b
|
||||
deepseek-coder:33b
|
||||
deepseek-coder-v2:16b
|
||||
deepseek-coder-v2:236b
|
||||
deepseek-r1:1.5b
|
||||
deepseek-r1:7b
|
||||
deepseek-r1:8b
|
||||
deepseek-r1:14b
|
||||
deepseek-r1:32b
|
||||
deepseek-r1:70b
|
||||
phi:2.7b
|
||||
phi3:mini
|
||||
phi3:medium
|
||||
phi3:medium-128k
|
||||
aya:8b
|
||||
aya:35b
|
||||
mistral:7b
|
||||
mixtral:8x22b
|
||||
mixtral:8x7b
|
||||
codegemma:2b
|
||||
codegemma:7b
|
||||
command-r:35b
|
||||
llava
|
||||
gemma:2b
|
||||
gemma:7b
|
||||
llama2:7b
|
||||
llama2:13b
|
||||
llama2:70b
|
||||
llama2-chinese:7b
|
||||
llama2-chinese:13b
|
||||
llama3.1:8b
|
||||
llama3.1:70b
|
||||
llama3.1:405b
|
||||
codellama:7b
|
||||
codellama:13b
|
||||
codellama:34b
|
||||
codellama:70b
|
||||
dolphin-mistral:7b
|
||||
dolphin-mixtral:8x22b
|
||||
dolphin-mixtral:8x7b
|
||||
llama2-uncensored:7b
|
||||
llama2-uncensored:70b
|
||||
tinyllama:1.1b
|
||||
openchat:7b
|
||||
orca-mini:3b
|
||||
orca-mini:7b
|
||||
orca-mini:13b
|
||||
orca-mini:70b
|
||||
mistral-openorca:7b
|
||||
dolphin-llama3:8b
|
||||
dolphin-llama3:70b
|
||||
starcoder:1b
|
||||
starcoder:3b
|
||||
starcoder:7b
|
||||
starcoder:15b
|
||||
starcoder2:3b
|
||||
starcoder2:7b
|
||||
starcoder2:15b
|
||||
zephyr:7b
|
||||
zephyr:141b
|
||||
nous-hermes2:10.7b
|
||||
nous-hermes2:34b
|
||||
vicuna:7b
|
||||
vicuna:13b
|
||||
vicuna:33b
|
||||
wizard-vicuna-uncensored:7b
|
||||
wizard-vicuna-uncensored:13b
|
||||
wizard-vicuna-uncensored:30b
|
||||
wizardlm2:7b
|
||||
codestral:22b
|
||||
tinydolphin:1.1b
|
||||
openhermes:v2.5
|
||||
neural-chat:7b
|
||||
codeqwen:7b
|
||||
phind-codellama:34b
|
||||
nous-hermes:7b
|
||||
nous-hermes:13b
|
||||
nous-hermes:13b
|
||||
starling-lm:7b
|
||||
llama3-gradient:8b
|
||||
llama3-gradient:70b
|
||||
yarn-llama2:7b
|
||||
yarn-llama2:13b
|
||||
llava-llama3:8b
|
||||
llama-pro:instruct
|
||||
everythinglm:13b
|
||||
llava-phi3:3.8b
|
||||
mistrallite:7b
|
||||
notus:7b
|
||||
231
src/AntSK.LLM/SparkDesk/SparkDeskChatCompletion.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Sdcb.SparkDesk;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Unicode;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntSK.LLM.SparkDesk
|
||||
{
|
||||
public class SparkDeskChatCompletion : IChatCompletionService
|
||||
{
|
||||
private readonly Dictionary<string, object?> _attributes = new();
|
||||
private readonly SparkDeskClient _client;
|
||||
private string _chatId;
|
||||
private readonly SparkDeskOptions _options;
|
||||
|
||||
private static readonly JsonSerializerOptions _jsonSerializerOptions = new()
|
||||
{
|
||||
NumberHandling = JsonNumberHandling.AllowReadingFromString,
|
||||
Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
|
||||
};
|
||||
|
||||
public IReadOnlyDictionary<string, object?> Attributes => _attributes;
|
||||
|
||||
public SparkDeskChatCompletion(SparkDeskOptions options, string chatId)
|
||||
{
|
||||
_options = options;
|
||||
_chatId = chatId;
|
||||
_client = new(options.AppId, options.ApiKey, options.ApiSecret);
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<ChatMessageContent>> GetChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
var parameters = new ChatRequestParameters
|
||||
{
|
||||
ChatId = _chatId,
|
||||
};
|
||||
|
||||
OpenAIPromptExecutionSettings chatExecutionSettings = OpenAIPromptExecutionSettings.FromExecutionSettings(executionSettings);
|
||||
|
||||
parameters.Temperature = (float)chatExecutionSettings.Temperature;
|
||||
parameters.MaxTokens = chatExecutionSettings.MaxTokens ?? parameters.MaxTokens;
|
||||
|
||||
IList<KernelFunctionMetadata> functions = kernel?.Plugins.GetFunctionsMetadata().Where(x => x.PluginName == "AntSKFunctions").ToList() ?? [];
|
||||
var functionDefs = functions.Select(func => new FunctionDef(func.Name, func.Description, func.Parameters.Select(p => new FunctionParametersDef(p.Name, p.ParameterType?.IsClass == true ? "object" : "string", p.Description, p.IsRequired)).ToList())).ToList();
|
||||
|
||||
List<ChatMessage> messages = GetSparkMessage(chatHistory);
|
||||
|
||||
var result = await _client.ChatAsync(_options.ModelVersion, messages.ToArray(), parameters, functionDefs.Count > 0 ? [.. functionDefs] : null, cancellationToken: cancellationToken);
|
||||
|
||||
if (result.FunctionCall != null)
|
||||
{
|
||||
var func = functions.Where(x => x.Name == result.FunctionCall.Name).FirstOrDefault();
|
||||
|
||||
if (func == null)
|
||||
{
|
||||
return new List<ChatMessageContent> { new(AuthorRole.Assistant, $"插件{result.FunctionCall.Name}未注册") }.AsReadOnly();
|
||||
}
|
||||
|
||||
if (kernel.Plugins.TryGetFunction(func.PluginName, func.Name, out var function))
|
||||
{
|
||||
var arguments = new KernelArguments();
|
||||
|
||||
var JsonElement = JsonDocument.Parse(result.FunctionCall.Arguments).RootElement;
|
||||
foreach (var parameter in func.Parameters)
|
||||
{
|
||||
var error = "";
|
||||
try
|
||||
{
|
||||
if (JsonElement.TryGetProperty(parameter.Name, out var property))
|
||||
{
|
||||
arguments.Add(parameter.Name, property.Deserialize(parameter.ParameterType!, _jsonSerializerOptions));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = $"参数{parameter.Name}解析错误:{ex.Message}";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
{
|
||||
return new List<ChatMessageContent> { new(AuthorRole.Assistant, error) }.AsReadOnly();
|
||||
|
||||
}
|
||||
}
|
||||
var functionResult = await function.InvokeAsync(kernel, arguments, cancellationToken);
|
||||
messages = [ ChatMessage.FromUser(messages.LastOrDefault().Content),
|
||||
ChatMessage.FromSystem($@"
|
||||
执行函数调用成功
|
||||
函数描述:{func.Description}
|
||||
函数执行结果:{functionResult}
|
||||
"),
|
||||
ChatMessage.FromUser("请根据函数调用结果回答我的问题,不要超出函数调用结果的返回,以及不要有多余描述:")];
|
||||
|
||||
|
||||
var callResult = await _client.ChatAsync(_options.ModelVersion, messages.ToArray(), parameters, null);
|
||||
ChatMessageContent chatMessageContent = new(AuthorRole.Assistant, callResult.Text.ToString(), modelId: "SparkDesk");
|
||||
|
||||
return new List<ChatMessageContent> { chatMessageContent }.AsReadOnly();
|
||||
|
||||
}
|
||||
return new List<ChatMessageContent> { new(AuthorRole.Assistant, "未找到插件") }.AsReadOnly();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
ChatMessageContent chatMessageContent = new(AuthorRole.Assistant, result.Text.ToString(), modelId: "SparkDesk");
|
||||
|
||||
return new List<ChatMessageContent> { chatMessageContent }.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async IAsyncEnumerable<StreamingChatMessageContent> GetStreamingChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
var parameters = new ChatRequestParameters
|
||||
{
|
||||
ChatId = _chatId,
|
||||
};
|
||||
OpenAIPromptExecutionSettings chatExecutionSettings = OpenAIPromptExecutionSettings.FromExecutionSettings(executionSettings);
|
||||
|
||||
parameters.Temperature = (float)chatExecutionSettings.Temperature;
|
||||
parameters.MaxTokens = chatExecutionSettings.MaxTokens ?? parameters.MaxTokens;
|
||||
|
||||
IList<KernelFunctionMetadata> functions = kernel?.Plugins.GetFunctionsMetadata().Where(x => x.PluginName == "AntSKFunctions").ToList() ?? [];
|
||||
var functionDefs = functions.Select(func => new FunctionDef(func.Name, func.Description, func.Parameters.Select(p => new FunctionParametersDef(p.Name, p.ParameterType?.IsClass == true ? "object" : "string", p.Description, p.IsRequired)).ToList())).ToList();
|
||||
List<ChatMessage> messages = GetSparkMessage(chatHistory);
|
||||
await foreach (StreamedChatResponse msg in _client.ChatAsStreamAsync(_options.ModelVersion, messages.ToArray(), parameters, functionDefs.Count > 0 ? [.. functionDefs] : null, cancellationToken: cancellationToken))
|
||||
{
|
||||
|
||||
yield return new StreamingChatMessageContent(AuthorRole.Assistant, msg);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private static List<ChatMessage> GetSparkMessage(ChatHistory chatHistory)
|
||||
{
|
||||
List<ChatMessage> messages = new List<ChatMessage>();
|
||||
foreach (var msg in chatHistory.ToList())
|
||||
{
|
||||
string role = "";
|
||||
if (msg.Role == AuthorRole.User)
|
||||
{
|
||||
role = "user";
|
||||
}
|
||||
else if (msg.Role == AuthorRole.System)
|
||||
{
|
||||
role = "system";
|
||||
}
|
||||
else
|
||||
{
|
||||
role = "assistant";
|
||||
}
|
||||
messages.Add(new ChatMessage(role, msg.ToString()));
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
|
||||
private static string? ProcessFunctionResult(object functionResult, ToolCallBehavior? toolCallBehavior)
|
||||
{
|
||||
if (functionResult is string stringResult)
|
||||
{
|
||||
return stringResult;
|
||||
}
|
||||
|
||||
if (functionResult is ChatMessageContent chatMessageContent)
|
||||
{
|
||||
return chatMessageContent.ToString();
|
||||
}
|
||||
|
||||
return JsonSerializer.Serialize(functionResult, _jsonSerializerOptions);
|
||||
}
|
||||
|
||||
public static Dictionary<string, object> ParseJsonElement(JsonElement element, string propertyName)
|
||||
{
|
||||
Dictionary<string, object> dict = new();
|
||||
|
||||
switch (element.ValueKind)
|
||||
{
|
||||
case JsonValueKind.Object:
|
||||
foreach (JsonProperty property in element.EnumerateObject())
|
||||
{
|
||||
dict.Add(property.Name, ParseJsonElement(property.Value, property.Name));
|
||||
}
|
||||
break;
|
||||
|
||||
case JsonValueKind.Array:
|
||||
List<object> list = new List<object>();
|
||||
foreach (JsonElement arrayElement in element.EnumerateArray())
|
||||
{
|
||||
list.Add(ParseJsonElement(arrayElement, ""));
|
||||
}
|
||||
dict.Add(propertyName, list);
|
||||
break;
|
||||
|
||||
case JsonValueKind.String:
|
||||
dict.Add(propertyName, element.GetString());
|
||||
break;
|
||||
|
||||
case JsonValueKind.Number:
|
||||
dict.Add(propertyName, element.GetInt32());
|
||||
break;
|
||||
|
||||
case JsonValueKind.True:
|
||||
case JsonValueKind.False:
|
||||
dict.Add(propertyName, element.GetBoolean());
|
||||
break;
|
||||
|
||||
default:
|
||||
dict.Add(propertyName, "Unsupported value type");
|
||||
break;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,11 +67,11 @@ namespace AntSK.LLM.SparkDesk
|
||||
parameters.Temperature = (float)chatExecutionSettings.Temperature;
|
||||
parameters.MaxTokens = chatExecutionSettings.MaxTokens ?? parameters.MaxTokens;
|
||||
|
||||
IList<KernelFunctionMetadata> functions = kernel?.Plugins.GetFunctionsMetadata().Where(x => x.PluginName == "AntSkFunctions").ToList() ?? [];
|
||||
var functionDefs = functions.Select(func => new FunctionDef(func.Name, func.Description, func.Parameters.Select(p => new FunctionParametersDef(p.Name, p.ParameterType?.IsClass == true ? "object" : "string", func.Description, p.IsRequired)).ToList())).ToList();
|
||||
IList<KernelFunctionMetadata> functions = kernel?.Plugins.GetFunctionsMetadata().Where(x => x.PluginName == "AntSKFunctions").ToList() ?? [];
|
||||
var functionDefs = functions.Select(func => new FunctionDef(func.Name, func.Description, func.Parameters.Select(p => new FunctionParametersDef(p.Name, p.ParameterType?.IsClass == true ? "object" : "string", p.Description, p.IsRequired)).ToList())).ToList();
|
||||
|
||||
//var messages = GetHistories(prompt);
|
||||
var messages = new ChatMessage[] { new ChatMessage("user", prompt) };
|
||||
var messages = new ChatMessage[] { new ChatMessage("user", prompt) };
|
||||
|
||||
return GetStreamingMessageAsync(messages, parameters, functionDefs, cancellationToken);
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace AntSK.LLM.SparkDesk
|
||||
{
|
||||
error = $"参数{parameter.Name}解析错误:{ex.Message}";
|
||||
}
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
{
|
||||
yield return new(error);
|
||||
@@ -118,12 +118,13 @@ namespace AntSK.LLM.SparkDesk
|
||||
|
||||
var result = (await function.InvokeAsync(kernel, arguments, cancellationToken)).GetValue<object>() ?? string.Empty;
|
||||
var stringResult = ProcessFunctionResult(result, chatExecutionSettings.ToolCallBehavior);
|
||||
messages = [.. messages, ChatMessage.FromUser($"""
|
||||
function call result:
|
||||
{stringResult}
|
||||
""")];
|
||||
messages = [ChatMessage.FromSystem($"""
|
||||
用户意图{func.Description}结果是:{stringResult}
|
||||
|
||||
functionDefs.RemoveAll(x => x.Name == msg.FunctionCall.Name);
|
||||
请结合用户的提问回复:
|
||||
"""), ChatMessage.FromUser(prompt)];
|
||||
|
||||
functionDefs.Clear();
|
||||
|
||||
await foreach (var content in GetStreamingMessageAsync(messages, parameters, functionDefs, cancellationToken))
|
||||
{
|
||||