Compare commits
582 Commits
main
...
style/refa
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5ad148b8f9 | ||
![]() |
6b759795d5 | ||
![]() |
bba80f465b | ||
![]() |
735e47f5e5 | ||
![]() |
d354c69493 | ||
![]() |
8f14881aff | ||
![]() |
e53c4fc0ad | ||
![]() |
f9f2e68bd8 | ||
![]() |
7b4d67d72f | ||
![]() |
7446244147 | ||
![]() |
c723bd2c96 | ||
![]() |
73ce8a17a5 | ||
![]() |
6f5e010db5 | ||
![]() |
495d86fd96 | ||
![]() |
42ba4e4f0e | ||
![]() |
6af51701de | ||
![]() |
76104d811c | ||
![]() |
1877433f20 | ||
![]() |
a403fb565d | ||
![]() |
f58b88f319 | ||
![]() |
cd2860deb4 | ||
![]() |
070968a048 | ||
![]() |
ceb18d160f | ||
![]() |
6a63a03cb2 | ||
![]() |
a0a62db6ad | ||
![]() |
253abaf1a3 | ||
![]() |
44cc6157f1 | ||
![]() |
028fc00be6 | ||
![]() |
1aed0fe5d6 | ||
![]() |
300cd675c6 | ||
![]() |
ff1d42bd66 | ||
![]() |
194a99220b | ||
![]() |
926f85ce4f | ||
![]() |
6c6e1e90cd | ||
![]() |
2fbc0c2261 | ||
![]() |
bac1e99557 | ||
![]() |
93e3077f77 | ||
![]() |
fa6858090b | ||
![]() |
61eb655823 | ||
![]() |
6298332950 | ||
![]() |
a1719c49b7 | ||
![]() |
b10a1cd325 | ||
![]() |
aa88028564 | ||
![]() |
3e314843db | ||
![]() |
0d607a8c90 | ||
![]() |
577a948f42 | ||
![]() |
edbfe27eb1 | ||
![]() |
5c98d80fdf | ||
![]() |
89b470d0d5 | ||
![]() |
19dc983d30 | ||
![]() |
e842a46fe2 | ||
![]() |
1573f6f6aa | ||
![]() |
910d5df513 | ||
![]() |
fa01360498 | ||
![]() |
1fe5be532d | ||
![]() |
d67eb907dd | ||
![]() |
83dae7e5bc | ||
![]() |
c6d1b7869d | ||
![]() |
601d267b7a | ||
![]() |
327940a120 | ||
![]() |
582c7ce348 | ||
![]() |
13d3f67746 | ||
![]() |
9c6aafd415 | ||
![]() |
3716ea46b5 | ||
![]() |
3c89b8a698 | ||
![]() |
b188800f16 | ||
![]() |
75a037bc2a | ||
![]() |
5efcdd6fa7 | ||
![]() |
06c4627abb | ||
![]() |
f5267d317e | ||
![]() |
2573950f88 | ||
![]() |
2ba38c6c45 | ||
![]() |
07edda8a85 | ||
![]() |
7791d290c7 | ||
![]() |
8203b23df2 | ||
![]() |
d4c9c76454 | ||
![]() |
a059660ed8 | ||
![]() |
20357beda4 | ||
![]() |
7e39565fd2 | ||
![]() |
27f794e197 | ||
![]() |
a8e8e36756 | ||
![]() |
dbc10425c8 | ||
![]() |
810443c511 | ||
![]() |
f47b5ce63a | ||
![]() |
822c18cb76 | ||
![]() |
66b08e653e | ||
![]() |
5e81150b22 | ||
![]() |
1e62768eed | ||
![]() |
59a9235041 | ||
![]() |
f2bf2e4470 | ||
![]() |
c77b38b97d | ||
![]() |
33349191e9 | ||
![]() |
d4f7ebfd2e | ||
![]() |
ebdf72fffc | ||
![]() |
1f1c61541e | ||
![]() |
f70c23dd7a | ||
![]() |
f498686c3a | ||
![]() |
d13169934d | ||
![]() |
324437b3f1 | ||
![]() |
c6a6c53084 | ||
![]() |
edc2fe050a | ||
![]() |
6fcebf3ecd | ||
![]() |
b754bf80ae | ||
![]() |
a9de7f24a2 | ||
![]() |
6759c6d5e6 | ||
![]() |
920d6d6882 | ||
![]() |
2511968cb4 | ||
![]() |
f684e1c12e | ||
![]() |
be75a1e432 | ||
![]() |
5a679ed396 | ||
![]() |
0cfd676fd6 | ||
![]() |
d997499ecf | ||
![]() |
4d3ffbb6f0 | ||
![]() |
a710858d09 | ||
![]() |
a75cef2c3b | ||
![]() |
392db19ea2 | ||
![]() |
7cb6039833 | ||
![]() |
e041a9e418 | ||
![]() |
281c6dc337 | ||
![]() |
7d7ade26ce | ||
![]() |
6aa2af215b | ||
![]() |
598d307afd | ||
![]() |
39fdcfd7e9 | ||
![]() |
47f638e5aa | ||
![]() |
03b57d1f0a | ||
![]() |
99c84c423e | ||
![]() |
cc2cc56f25 | ||
![]() |
393885ee16 | ||
![]() |
9143d460fa | ||
![]() |
c0ff0cf7cf | ||
![]() |
9c90d98027 | ||
![]() |
0d74466f45 | ||
![]() |
d2e293b9be | ||
![]() |
8fae321b6a | ||
![]() |
a2b42c9431 | ||
![]() |
0a4b256b5a | ||
![]() |
9f7124a79d | ||
![]() |
7a217534d1 | ||
![]() |
a9ed0f0b42 | ||
![]() |
545d2b2622 | ||
![]() |
f114da4e81 | ||
![]() |
f4e3e3fc19 | ||
![]() |
1277941821 | ||
![]() |
f500e6cf5b | ||
![]() |
a3b71830d0 | ||
![]() |
13b7e18a50 | ||
![]() |
5f4bb12a1a | ||
![]() |
781e8e1a4a | ||
![]() |
c721617e19 | ||
![]() |
6b51e81de1 | ||
![]() |
736719745c | ||
![]() |
e0e4a6f819 | ||
![]() |
6ab6b9cc40 | ||
![]() |
52eb18937e | ||
![]() |
aab1ab692a | ||
![]() |
3e7f38d904 | ||
![]() |
94c5e36334 | ||
![]() |
baaa3ae02c | ||
![]() |
623b27583b | ||
![]() |
93e9aeb4e9 | ||
![]() |
391ad7734e | ||
![]() |
c5422af400 | ||
![]() |
65a04ee0be | ||
![]() |
84c35aef6c | ||
![]() |
c2b4845719 | ||
![]() |
cd0f10567f | ||
![]() |
454b755c6b | ||
![]() |
352c1fc370 | ||
![]() |
181eb6038f | ||
![]() |
c32cbeb29a | ||
![]() |
62f8c875c8 | ||
![]() |
baed53bbfa | ||
![]() |
565a0d992a | ||
![]() |
e90a06a7b7 | ||
![]() |
5a0b22dbd4 | ||
![]() |
31445c3782 | ||
![]() |
8e6f5f4bb0 | ||
![]() |
e259b360c2 | ||
![]() |
762dec2dc4 | ||
![]() |
ada7f5c30f | ||
![]() |
6b965eaea3 | ||
![]() |
ea67bc1166 | ||
![]() |
01e8f6066a | ||
![]() |
39effd350e | ||
![]() |
00bfb35759 | ||
![]() |
101d9798f0 | ||
![]() |
ba48754be6 | ||
![]() |
d963df32b9 | ||
![]() |
67ce763377 | ||
![]() |
a32c0ef43c | ||
![]() |
6e03c10285 | ||
![]() |
8f14c422a7 | ||
![]() |
07787366cd | ||
![]() |
8f2d3b6743 | ||
![]() |
e7bc863f26 | ||
![]() |
1d411e195a | ||
![]() |
2a7ae6b0df | ||
![]() |
8f8a3f4318 | ||
![]() |
4b89dba3a5 | ||
![]() |
19c0d1fbf8 | ||
![]() |
94cd4912e1 | ||
![]() |
602f75bb30 | ||
![]() |
c2810de952 | ||
![]() |
1b645c1cc9 | ||
![]() |
ae3482e0b4 | ||
![]() |
76c265f781 | ||
![]() |
b1946c60d8 | ||
![]() |
c1c13cf828 | ||
![]() |
e4a48e28e5 | ||
![]() |
67efcbd6bb | ||
![]() |
7466061e5a | ||
![]() |
b7534b764d | ||
![]() |
eb335ed464 | ||
![]() |
4d9e7c1884 | ||
![]() |
8f7cac6bde | ||
![]() |
d4608f0571 | ||
![]() |
9f27b5bb12 | ||
![]() |
fb9c54e35f | ||
![]() |
dea45682bc | ||
![]() |
a0abd5d077 | ||
![]() |
924dbc128d | ||
![]() |
b76aa11919 | ||
![]() |
7971efd23e | ||
![]() |
b8c2e5359b | ||
![]() |
952847ed29 | ||
![]() |
4e4a8a327b | ||
![]() |
8d1591e5d5 | ||
![]() |
4b8896e034 | ||
![]() |
c2d3464a17 | ||
![]() |
0886c6f224 | ||
![]() |
1ee4c13758 | ||
![]() |
c293aceec1 | ||
![]() |
4d5752fc94 | ||
![]() |
c615ed57b9 | ||
![]() |
020d4baf92 | ||
![]() |
3f8a10613d | ||
![]() |
53fa13f007 | ||
![]() |
d00e1067bf | ||
![]() |
2dd9c64d34 | ||
![]() |
b7c40579b2 | ||
![]() |
c7f8a0fc7b | ||
![]() |
de24d9c145 | ||
![]() |
6357e1516e | ||
![]() |
b83dc5ab99 | ||
![]() |
65285965b6 | ||
![]() |
035c9eb147 | ||
![]() |
91b3aec292 | ||
![]() |
d3a9747bbd | ||
![]() |
6a99fab92f | ||
![]() |
2a590f6d2b | ||
![]() |
117b0f20dd | ||
![]() |
c445f747b7 | ||
![]() |
8ed0963c6b | ||
![]() |
6c47e0b5d1 | ||
![]() |
e99e87269e | ||
![]() |
0a1319548a | ||
![]() |
b1242ba1ac | ||
![]() |
fde0e6c7f9 | ||
![]() |
92153328ea | ||
![]() |
e66ba6ffdd | ||
![]() |
a7e320dc25 | ||
![]() |
5008d9f4a0 | ||
![]() |
912f84777b | ||
![]() |
4c0e4e490a | ||
![]() |
306843fe6a | ||
![]() |
b6a4af4041 | ||
![]() |
cce39b85e9 | ||
![]() |
057d380119 | ||
![]() |
4cf9ff6132 | ||
![]() |
4cfbcd9c79 | ||
![]() |
fcde5b5c9e | ||
![]() |
21b3703bd8 | ||
![]() |
9025e85ca5 | ||
![]() |
bc43e3a9fe | ||
![]() |
319a54aa2f | ||
![]() |
7c2ab21c9c | ||
![]() |
0d08b6cf51 | ||
![]() |
61a70e7a71 | ||
![]() |
bde1261b8c | ||
![]() |
08bb6bf858 | ||
![]() |
1003190dc0 | ||
![]() |
4c516a50b8 | ||
![]() |
8058a1dbe4 | ||
![]() |
8533ded335 | ||
![]() |
1a547b0db9 | ||
![]() |
0b90625e57 | ||
![]() |
e989c1f3aa | ||
![]() |
da15a25cf5 | ||
![]() |
43254ceeb0 | ||
![]() |
faf550164d | ||
![]() |
1a4234347a | ||
![]() |
85947efcfa | ||
![]() |
474ea97fc7 | ||
![]() |
a3becde6d8 | ||
![]() |
c40544a134 | ||
![]() |
4028bb4f58 | ||
![]() |
52268460a1 | ||
![]() |
b64298c458 | ||
![]() |
16dee11589 | ||
![]() |
691dbf9d17 | ||
![]() |
ebebbb684b | ||
![]() |
cee51ac084 | ||
![]() |
ef00ad0417 | ||
![]() |
c37615cd33 | ||
![]() |
a387cfbc9a | ||
![]() |
04fdb4af0f | ||
![]() |
57f9a41e7f | ||
![]() |
eb8b827906 | ||
![]() |
99a9bf6d56 | ||
![]() |
ceae69b773 | ||
![]() |
3c8548c562 | ||
![]() |
8874837dc3 | ||
![]() |
40e171c2c6 | ||
![]() |
824ed7d6c2 | ||
![]() |
4caa8f38bc | ||
![]() |
5d5db7c6c1 | ||
![]() |
ca50522f80 | ||
![]() |
2fd4b6e6d2 | ||
![]() |
c503e8ebc9 | ||
![]() |
245bb02c88 | ||
![]() |
9f08206503 | ||
![]() |
66be03f622 | ||
![]() |
1a92064260 | ||
![]() |
7752f374e5 | ||
![]() |
e7dcc53b55 | ||
![]() |
22766c27c7 | ||
![]() |
c82b641357 | ||
![]() |
1d871dae0d | ||
![]() |
c39be7852f | ||
![]() |
f2a5da918b | ||
![]() |
930425b896 | ||
![]() |
32e4efb524 | ||
![]() |
96c3ec91af | ||
![]() |
f257184b00 | ||
![]() |
581d09895e | ||
![]() |
197f1b3957 | ||
![]() |
207b589458 | ||
![]() |
b5be6bacef | ||
![]() |
bca99cf4f8 | ||
![]() |
0e873223d7 | ||
![]() |
133b487566 | ||
![]() |
a9e8eb1c7e | ||
![]() |
bf2b9bb898 | ||
![]() |
837990cb80 | ||
![]() |
4be2edd934 | ||
![]() |
7d4f8e0082 | ||
![]() |
36ab121b87 | ||
![]() |
7f2980fbc0 | ||
![]() |
ae21d48132 | ||
![]() |
8af8a0f46d | ||
![]() |
4adb61d6c7 | ||
![]() |
7dd7f06f7d | ||
![]() |
074e660a67 | ||
![]() |
06729f6d9d | ||
![]() |
633768cd2a | ||
![]() |
339dfe5e02 | ||
![]() |
22696fa75b | ||
![]() |
2ed73b763d | ||
![]() |
72ef04d3e4 | ||
![]() |
766ac3e255 | ||
![]() |
378a9dd850 | ||
![]() |
c8dc5e4849 | ||
![]() |
1387c6bd1c | ||
![]() |
fda21f6b05 | ||
![]() |
8c25915d2b | ||
![]() |
aba48749da | ||
![]() |
35a66ffe9f | ||
![]() |
3db9174f55 | ||
![]() |
02854b273f | ||
![]() |
fd0a830816 | ||
![]() |
e7fb92e169 | ||
![]() |
9c4e809799 | ||
![]() |
169eb32662 | ||
![]() |
0f4291bd36 | ||
![]() |
14b641557a | ||
![]() |
9c963d6f69 | ||
![]() |
96abeda2e7 | ||
![]() |
62fa90e30e | ||
![]() |
7e378e219c | ||
![]() |
34652010f5 | ||
![]() |
082f6f6a5f | ||
![]() |
6f52edb157 | ||
![]() |
0dcbb34cab | ||
![]() |
0886d7bb8b | ||
![]() |
e65a47cff7 | ||
![]() |
36c01d89c9 | ||
![]() |
6726ca102e | ||
![]() |
e135707f88 | ||
![]() |
f2765b9d31 | ||
![]() |
1e0877dcbf | ||
![]() |
9a65c3391b | ||
![]() |
ca9e23d6ea | ||
![]() |
c4d6f9e179 | ||
![]() |
0cec6195a3 | ||
![]() |
966d42a4db | ||
![]() |
15c33ba7f3 | ||
![]() |
ed7f74c99c | ||
![]() |
1db4139b5a | ||
![]() |
0d85d44de5 | ||
![]() |
f0f1bfa5d9 | ||
![]() |
9161ce481e | ||
![]() |
c760902e72 | ||
![]() |
7c8c15ef1a | ||
![]() |
765eb282f3 | ||
![]() |
0e2b38dddc | ||
![]() |
92e4b3304c | ||
![]() |
c777d55a1c | ||
![]() |
cd27ae4319 | ||
![]() |
bd82c7edac | ||
![]() |
d5043c6628 | ||
![]() |
d9a0584052 | ||
![]() |
3e011109ad | ||
![]() |
bdb990eb90 | ||
![]() |
ae00211691 | ||
![]() |
0ef35a0ee0 | ||
![]() |
9a9d90ad7f | ||
![]() |
606fc7be0c | ||
![]() |
d7def41acc | ||
![]() |
b6a560ce86 | ||
![]() |
25f34f6703 | ||
![]() |
7daa365564 | ||
![]() |
13ccd294cb | ||
![]() |
d357f359ab | ||
![]() |
474cedf653 | ||
![]() |
5d3c88a0b3 | ||
![]() |
ae2c76bda2 | ||
![]() |
c46b5f2fd0 | ||
![]() |
2cb7b73ee7 | ||
![]() |
8d8d5b5235 | ||
![]() |
15acfffd60 | ||
![]() |
18a266eac2 | ||
![]() |
7751070da8 | ||
![]() |
fa8c3d0d7b | ||
![]() |
a567cff809 | ||
![]() |
583b0e9f97 | ||
![]() |
5fddb23516 | ||
![]() |
0e52971997 | ||
![]() |
1387f406a3 | ||
![]() |
ff31f0540a | ||
![]() |
4873e6e2a1 | ||
![]() |
510ce057f7 | ||
![]() |
0e53cc0e8c | ||
![]() |
0b8c896481 | ||
![]() |
15fe635465 | ||
![]() |
f8c3189f4d | ||
![]() |
f215db87e3 | ||
![]() |
67d02212b4 | ||
![]() |
cff9adaf8e | ||
![]() |
cdd2a40086 | ||
![]() |
024028bc52 | ||
![]() |
0ae085b48a | ||
![]() |
2094c54951 | ||
![]() |
f4f11135d3 | ||
![]() |
8e9d7a229d | ||
![]() |
8f49572f85 | ||
![]() |
5aa7696cc3 | ||
![]() |
15dd79e822 | ||
![]() |
4651ab4195 | ||
![]() |
5e3160e6f6 | ||
![]() |
973cd126bb | ||
![]() |
ebaf8766ef | ||
![]() |
d2190e9c3a | ||
![]() |
37f55098fe | ||
![]() |
b1771194cc | ||
![]() |
0279bd8c75 | ||
![]() |
5e077e4ce8 | ||
![]() |
64067e1f20 | ||
![]() |
5295c72ca1 | ||
![]() |
1ecea62052 | ||
![]() |
307af29b65 | ||
![]() |
10190a9aa5 | ||
![]() |
7c5c35600c | ||
![]() |
63b333cdb1 | ||
![]() |
a6776190bd | ||
![]() |
9577cbac27 | ||
![]() |
f6ae13abad | ||
![]() |
f3d501e7d5 | ||
![]() |
2eab8fcc33 | ||
![]() |
bdb81fe20d | ||
![]() |
0f60fe7f2a | ||
![]() |
425f624de5 | ||
![]() |
b1919745e2 | ||
![]() |
9a242bcac9 | ||
![]() |
a6109a60b8 | ||
![]() |
28f7bbf83a | ||
![]() |
cac04c5f3c | ||
![]() |
18f5f9cc37 | ||
![]() |
1787c5c93f | ||
![]() |
f981494613 | ||
![]() |
fbc853af92 | ||
![]() |
1a64c660ba | ||
![]() |
846555af1b | ||
![]() |
bca94854f7 | ||
![]() |
1bd70bd8bf | ||
![]() |
d1dcd39191 | ||
![]() |
35384bda41 | ||
![]() |
89fb6eb648 | ||
![]() |
aa61a890b2 | ||
![]() |
31ece363c3 | ||
![]() |
70a5d78cc5 | ||
![]() |
57f4dfdb6f | ||
![]() |
aa9028a607 | ||
![]() |
d83f94c55c | ||
![]() |
a8c5e0b0b0 | ||
![]() |
177e8cbf73 | ||
![]() |
23828fd15a | ||
![]() |
2cc37ac8e5 | ||
![]() |
c9ee1e9ff2 | ||
![]() |
4f10f5d5f4 | ||
![]() |
c48c84674e | ||
![]() |
1e9fbbf41b | ||
![]() |
4dd144ce43 | ||
![]() |
a387ff1c38 | ||
![]() |
a9e367e6de | ||
![]() |
e2fec587f8 | ||
![]() |
39a6f0943d | ||
![]() |
684896d100 | ||
![]() |
54f911f6cd | ||
![]() |
0e5c16d0c2 | ||
![]() |
b8cd6ea478 | ||
![]() |
fc61fd0f50 | ||
![]() |
2fbfc988c4 | ||
![]() |
99f5fea001 | ||
![]() |
ecd2a1be9f | ||
![]() |
49ee9ca5f1 | ||
![]() |
6d0eef12b1 | ||
![]() |
c1e0a939b0 | ||
![]() |
060a894bd1 | ||
![]() |
c75e02b5b2 | ||
![]() |
fcf43ee845 | ||
![]() |
466f61d044 | ||
![]() |
27ae74af50 | ||
![]() |
8dd941e3d2 | ||
![]() |
dec4bf6b98 | ||
![]() |
e2c33fc40f | ||
![]() |
c74e59d1f4 | ||
![]() |
1fcb902715 | ||
![]() |
c08f98218c | ||
![]() |
c6377f6e38 | ||
![]() |
3cb0a5bd68 | ||
![]() |
95777d23e0 | ||
![]() |
e7dc16fd08 | ||
![]() |
495dec143c | ||
![]() |
4cc6dfa232 | ||
![]() |
d1452d4af4 | ||
![]() |
d68ca56b3a | ||
![]() |
49856d8d17 | ||
![]() |
902de72cc0 | ||
![]() |
76f6b8d104 | ||
![]() |
f111e605c4 | ||
![]() |
b358ed3a5b | ||
![]() |
88dbf639e0 | ||
![]() |
aa8b525b48 | ||
![]() |
c990bc61db | ||
![]() |
6d7588f236 | ||
![]() |
8257c7bf02 | ||
![]() |
946068967b | ||
![]() |
19f5684960 | ||
![]() |
6d62840aff | ||
![]() |
ab868ac979 | ||
![]() |
1d74e693ea | ||
![]() |
fa43d4202f | ||
![]() |
6b29860788 | ||
![]() |
36800eeaba | ||
![]() |
67acd174ac | ||
![]() |
b5edc64b2a | ||
![]() |
d00b2724cc | ||
![]() |
43f87c0b86 | ||
![]() |
7a43f48c95 | ||
![]() |
58a913b09d | ||
![]() |
cd03795f2c | ||
![]() |
36f8b5711d | ||
![]() |
f9c48e9ea9 | ||
![]() |
3b48f8c98e | ||
![]() |
cef1010cb5 | ||
![]() |
cb4875a3a7 | ||
![]() |
bbca708832 | ||
![]() |
05aec43ee3 | ||
![]() |
e8127756e0 | ||
![]() |
792595a46f | ||
![]() |
d7d7281c93 | ||
![]() |
21193c2fbf |
@ -1,11 +1,12 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
cd web && npm install
|
npm add -g pnpm@9.12.2
|
||||||
|
cd web && pnpm install
|
||||||
pipx install poetry
|
pipx install poetry
|
||||||
|
|
||||||
echo 'alias start-api="cd /workspaces/dify/api && poetry run python -m flask run --host 0.0.0.0 --port=5001 --debug"' >> ~/.bashrc
|
echo 'alias start-api="cd /workspaces/dify/api && poetry run python -m flask run --host 0.0.0.0 --port=5001 --debug"' >> ~/.bashrc
|
||||||
echo 'alias start-worker="cd /workspaces/dify/api && poetry run python -m celery -A app.celery worker -P gevent -c 1 --loglevel INFO -Q dataset,generation,mail,ops_trace,app_deletion"' >> ~/.bashrc
|
echo 'alias start-worker="cd /workspaces/dify/api && poetry run python -m celery -A app.celery worker -P gevent -c 1 --loglevel INFO -Q dataset,generation,mail,ops_trace,app_deletion"' >> ~/.bashrc
|
||||||
echo 'alias start-web="cd /workspaces/dify/web && npm run dev"' >> ~/.bashrc
|
echo 'alias start-web="cd /workspaces/dify/web && pnpm dev"' >> ~/.bashrc
|
||||||
echo 'alias start-containers="cd /workspaces/dify/docker && docker-compose -f docker-compose.middleware.yaml -p dify up -d"' >> ~/.bashrc
|
echo 'alias start-containers="cd /workspaces/dify/docker && docker-compose -f docker-compose.middleware.yaml -p dify up -d"' >> ~/.bashrc
|
||||||
|
|
||||||
source /home/vscode/.bashrc
|
source /home/vscode/.bashrc
|
6
.github/workflows/style.yml
vendored
6
.github/workflows/style.yml
vendored
@ -76,16 +76,16 @@ jobs:
|
|||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: yarn
|
cache: pnpm
|
||||||
cache-dependency-path: ./web/package.json
|
cache-dependency-path: ./web/package.json
|
||||||
|
|
||||||
- name: Web dependencies
|
- name: Web dependencies
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
run: yarn install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Web style check
|
- name: Web style check
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
run: yarn run lint
|
run: pnpm run lint
|
||||||
|
|
||||||
|
|
||||||
superlinter:
|
superlinter:
|
||||||
|
6
.github/workflows/tool-test-sdks.yaml
vendored
6
.github/workflows/tool-test-sdks.yaml
vendored
@ -32,10 +32,10 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: ''
|
cache: ''
|
||||||
cache-dependency-path: 'yarn.lock'
|
cache-dependency-path: 'pnpm-lock.yaml'
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: yarn install
|
run: pnpm install
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: yarn test
|
run: pnpm test
|
||||||
|
@ -38,11 +38,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
if: env.FILES_CHANGED == 'true'
|
if: env.FILES_CHANGED == 'true'
|
||||||
run: yarn install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Run npm script
|
- name: Run npm script
|
||||||
if: env.FILES_CHANGED == 'true'
|
if: env.FILES_CHANGED == 'true'
|
||||||
run: npm run auto-gen-i18n
|
run: pnpm run auto-gen-i18n
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
if: env.FILES_CHANGED == 'true'
|
if: env.FILES_CHANGED == 'true'
|
||||||
|
6
.github/workflows/web-tests.yml
vendored
6
.github/workflows/web-tests.yml
vendored
@ -34,13 +34,13 @@ jobs:
|
|||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: yarn
|
cache: pnpm
|
||||||
cache-dependency-path: ./web/package.json
|
cache-dependency-path: ./web/package.json
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
run: yarn install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
run: yarn test
|
run: pnpm test
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -193,3 +193,6 @@ api/.vscode
|
|||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
/.pnpm-store
|
||||||
|
@ -54,10 +54,12 @@ def make_request(method, url, max_retries=SSRF_DEFAULT_MAX_RETRIES, **kwargs):
|
|||||||
if response.status_code not in STATUS_FORCELIST:
|
if response.status_code not in STATUS_FORCELIST:
|
||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
logging.warning(f"Received status code {response.status_code} for URL {url} which is in the force list")
|
logging.warning(
|
||||||
|
f"Received status code {response.status_code} for URL {url} which is in the force list")
|
||||||
|
|
||||||
except httpx.RequestError as e:
|
except httpx.RequestError as e:
|
||||||
logging.warning(f"Request to URL {url} failed on attempt {retries + 1}: {e}")
|
logging.warning(
|
||||||
|
f"Request to URL {url} failed on attempt {retries + 1}: {e}")
|
||||||
|
|
||||||
retries += 1
|
retries += 1
|
||||||
if retries <= max_retries:
|
if retries <= max_retries:
|
||||||
|
@ -20,7 +20,8 @@ from extensions.ext_redis import redis_client
|
|||||||
from models.dataset import Dataset
|
from models.dataset import Dataset
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
|
logging.basicConfig(level=logging.INFO,
|
||||||
|
format="%(asctime)s - %(levelname)s - %(message)s")
|
||||||
logging.getLogger("lindorm").setLevel(logging.WARN)
|
logging.getLogger("lindorm").setLevel(logging.WARN)
|
||||||
|
|
||||||
|
|
||||||
@ -76,7 +77,8 @@ class LindormVectorStore(BaseVector):
|
|||||||
@retry(stop=stop_after_attempt(3), wait=wait_fixed(60))
|
@retry(stop=stop_after_attempt(3), wait=wait_fixed(60))
|
||||||
def __fetch_existing_ids(batch_ids: list[str]) -> set[str]:
|
def __fetch_existing_ids(batch_ids: list[str]) -> set[str]:
|
||||||
try:
|
try:
|
||||||
existing_docs = self._client.mget(index=self._collection_name, body={"ids": batch_ids}, _source=False)
|
existing_docs = self._client.mget(index=self._collection_name, body={
|
||||||
|
"ids": batch_ids}, _source=False)
|
||||||
return {doc["_id"] for doc in existing_docs["docs"] if doc["found"]}
|
return {doc["_id"] for doc in existing_docs["docs"] if doc["found"]}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(f"Error fetching batch {batch_ids}: {e}")
|
logger.exception(f"Error fetching batch {batch_ids}: {e}")
|
||||||
@ -88,7 +90,8 @@ class LindormVectorStore(BaseVector):
|
|||||||
existing_docs = self._client.mget(
|
existing_docs = self._client.mget(
|
||||||
body={
|
body={
|
||||||
"docs": [
|
"docs": [
|
||||||
{"_index": self._collection_name, "_id": id, "routing": routing}
|
{"_index": self._collection_name,
|
||||||
|
"_id": id, "routing": routing}
|
||||||
for id, routing in zip(batch_ids, route_ids)
|
for id, routing in zip(batch_ids, route_ids)
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -117,7 +120,8 @@ class LindormVectorStore(BaseVector):
|
|||||||
for ids_batch, texts_batch, metadatas_batch in zip(
|
for ids_batch, texts_batch, metadatas_batch in zip(
|
||||||
batch(ids, bulk_size),
|
batch(ids, bulk_size),
|
||||||
batch(texts, bulk_size),
|
batch(texts, bulk_size),
|
||||||
batch(metadatas, bulk_size) if metadatas is not None else batch([None] * len(ids), bulk_size),
|
batch(metadatas, bulk_size) if metadatas is not None else batch(
|
||||||
|
[None] * len(ids), bulk_size),
|
||||||
):
|
):
|
||||||
existing_ids_set = __fetch_existing_ids(ids_batch)
|
existing_ids_set = __fetch_existing_ids(ids_batch)
|
||||||
for text, metadata, doc_id in zip(texts_batch, metadatas_batch, ids_batch):
|
for text, metadata, doc_id in zip(texts_batch, metadatas_batch, ids_batch):
|
||||||
@ -139,7 +143,8 @@ class LindormVectorStore(BaseVector):
|
|||||||
"_id": uuids[i],
|
"_id": uuids[i],
|
||||||
"_source": {
|
"_source": {
|
||||||
Field.CONTENT_KEY.value: documents[i].page_content,
|
Field.CONTENT_KEY.value: documents[i].page_content,
|
||||||
Field.VECTOR.value: embeddings[i], # Make sure you pass an array here
|
# Make sure you pass an array here
|
||||||
|
Field.VECTOR.value: embeddings[i],
|
||||||
Field.METADATA_KEY.value: documents[i].metadata,
|
Field.METADATA_KEY.value: documents[i].metadata,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -148,7 +153,8 @@ class LindormVectorStore(BaseVector):
|
|||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
def get_ids_by_metadata_field(self, key: str, value: str):
|
def get_ids_by_metadata_field(self, key: str, value: str):
|
||||||
query = {"query": {"term": {f"{Field.METADATA_KEY.value}.{key}.keyword": value}}}
|
query = {
|
||||||
|
"query": {"term": {f"{Field.METADATA_KEY.value}.{key}.keyword": value}}}
|
||||||
response = self._client.search(index=self._collection_name, body=query)
|
response = self._client.search(index=self._collection_name, body=query)
|
||||||
if response["hits"]["hits"]:
|
if response["hits"]["hits"]:
|
||||||
return [hit["_id"] for hit in response["hits"]["hits"]]
|
return [hit["_id"] for hit in response["hits"]["hits"]]
|
||||||
@ -157,7 +163,8 @@ class LindormVectorStore(BaseVector):
|
|||||||
|
|
||||||
def delete_by_metadata_field(self, key: str, value: str):
|
def delete_by_metadata_field(self, key: str, value: str):
|
||||||
query_str = {"query": {"match": {f"metadata.{key}": f"{value}"}}}
|
query_str = {"query": {"match": {f"metadata.{key}": f"{value}"}}}
|
||||||
results = self._client.search(index=self._collection_name, body=query_str)
|
results = self._client.search(
|
||||||
|
index=self._collection_name, body=query_str)
|
||||||
ids = [hit["_id"] for hit in results["hits"]["hits"]]
|
ids = [hit["_id"] for hit in results["hits"]["hits"]]
|
||||||
if ids:
|
if ids:
|
||||||
self.delete_by_ids(ids)
|
self.delete_by_ids(ids)
|
||||||
@ -167,15 +174,18 @@ class LindormVectorStore(BaseVector):
|
|||||||
if self._client.exists(index=self._collection_name, id=id):
|
if self._client.exists(index=self._collection_name, id=id):
|
||||||
self._client.delete(index=self._collection_name, id=id)
|
self._client.delete(index=self._collection_name, id=id)
|
||||||
else:
|
else:
|
||||||
logger.warning(f"DELETE BY ID: ID {id} does not exist in the index.")
|
logger.warning(
|
||||||
|
f"DELETE BY ID: ID {id} does not exist in the index.")
|
||||||
|
|
||||||
def delete(self) -> None:
|
def delete(self) -> None:
|
||||||
try:
|
try:
|
||||||
if self._client.indices.exists(index=self._collection_name):
|
if self._client.indices.exists(index=self._collection_name):
|
||||||
self._client.indices.delete(index=self._collection_name, params={"timeout": 60})
|
self._client.indices.delete(
|
||||||
|
index=self._collection_name, params={"timeout": 60})
|
||||||
logger.info("Delete index success")
|
logger.info("Delete index success")
|
||||||
else:
|
else:
|
||||||
logger.warning(f"Index '{self._collection_name}' does not exist. No deletion performed.")
|
logger.warning(
|
||||||
|
f"Index '{self._collection_name}' does not exist. No deletion performed.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(f"Error occurred while deleting the index: {e}")
|
logger.exception(f"Error occurred while deleting the index: {e}")
|
||||||
raise e
|
raise e
|
||||||
@ -197,9 +207,11 @@ class LindormVectorStore(BaseVector):
|
|||||||
raise ValueError("All elements in query_vector should be floats")
|
raise ValueError("All elements in query_vector should be floats")
|
||||||
|
|
||||||
top_k = kwargs.get("top_k", 10)
|
top_k = kwargs.get("top_k", 10)
|
||||||
query = default_vector_search_query(query_vector=query_vector, k=top_k, **kwargs)
|
query = default_vector_search_query(
|
||||||
|
query_vector=query_vector, k=top_k, **kwargs)
|
||||||
try:
|
try:
|
||||||
response = self._client.search(index=self._collection_name, body=query)
|
response = self._client.search(
|
||||||
|
index=self._collection_name, body=query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(f"Error executing search: {e}")
|
logger.exception(f"Error executing search: {e}")
|
||||||
raise
|
raise
|
||||||
@ -244,7 +256,8 @@ class LindormVectorStore(BaseVector):
|
|||||||
filters=filters,
|
filters=filters,
|
||||||
routing=routing,
|
routing=routing,
|
||||||
)
|
)
|
||||||
response = self._client.search(index=self._collection_name, body=full_text_query)
|
response = self._client.search(
|
||||||
|
index=self._collection_name, body=full_text_query)
|
||||||
docs = []
|
docs = []
|
||||||
for hit in response["hits"]["hits"]:
|
for hit in response["hits"]["hits"]:
|
||||||
docs.append(
|
docs.append(
|
||||||
@ -262,7 +275,8 @@ class LindormVectorStore(BaseVector):
|
|||||||
with redis_client.lock(lock_name, timeout=20):
|
with redis_client.lock(lock_name, timeout=20):
|
||||||
collection_exist_cache_key = f"vector_indexing_{self._collection_name}"
|
collection_exist_cache_key = f"vector_indexing_{self._collection_name}"
|
||||||
if redis_client.get(collection_exist_cache_key):
|
if redis_client.get(collection_exist_cache_key):
|
||||||
logger.info(f"Collection {self._collection_name} already exists.")
|
logger.info(
|
||||||
|
f"Collection {self._collection_name} already exists.")
|
||||||
return
|
return
|
||||||
if self._client.indices.exists(index=self._collection_name):
|
if self._client.indices.exists(index=self._collection_name):
|
||||||
logger.info("{self._collection_name.lower()} already exists.")
|
logger.info("{self._collection_name.lower()} already exists.")
|
||||||
@ -281,10 +295,13 @@ class LindormVectorStore(BaseVector):
|
|||||||
hnsw_ef_construction = kwargs.pop("hnsw_ef_construction", 500)
|
hnsw_ef_construction = kwargs.pop("hnsw_ef_construction", 500)
|
||||||
ivfpq_m = kwargs.pop("ivfpq_m", dimension)
|
ivfpq_m = kwargs.pop("ivfpq_m", dimension)
|
||||||
nlist = kwargs.pop("nlist", 1000)
|
nlist = kwargs.pop("nlist", 1000)
|
||||||
centroids_use_hnsw = kwargs.pop("centroids_use_hnsw", True if nlist >= 5000 else False)
|
centroids_use_hnsw = kwargs.pop(
|
||||||
|
"centroids_use_hnsw", True if nlist >= 5000 else False)
|
||||||
centroids_hnsw_m = kwargs.pop("centroids_hnsw_m", 24)
|
centroids_hnsw_m = kwargs.pop("centroids_hnsw_m", 24)
|
||||||
centroids_hnsw_ef_construct = kwargs.pop("centroids_hnsw_ef_construct", 500)
|
centroids_hnsw_ef_construct = kwargs.pop(
|
||||||
centroids_hnsw_ef_search = kwargs.pop("centroids_hnsw_ef_search", 100)
|
"centroids_hnsw_ef_construct", 500)
|
||||||
|
centroids_hnsw_ef_search = kwargs.pop(
|
||||||
|
"centroids_hnsw_ef_search", 100)
|
||||||
mapping = default_text_mapping(
|
mapping = default_text_mapping(
|
||||||
dimension,
|
dimension,
|
||||||
method_name,
|
method_name,
|
||||||
@ -303,7 +320,8 @@ class LindormVectorStore(BaseVector):
|
|||||||
centroids_hnsw_ef_search=centroids_hnsw_ef_search,
|
centroids_hnsw_ef_search=centroids_hnsw_ef_search,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
self._client.indices.create(index=self._collection_name.lower(), body=mapping)
|
self._client.indices.create(
|
||||||
|
index=self._collection_name.lower(), body=mapping)
|
||||||
redis_client.set(collection_exist_cache_key, 1, ex=3600)
|
redis_client.set(collection_exist_cache_key, 1, ex=3600)
|
||||||
# logger.info(f"create index success: {self._collection_name}")
|
# logger.info(f"create index success: {self._collection_name}")
|
||||||
|
|
||||||
@ -364,7 +382,8 @@ def default_text_mapping(dimension: int, method_name: str, **kwargs: Any) -> dic
|
|||||||
}
|
}
|
||||||
|
|
||||||
if excludes_from_source:
|
if excludes_from_source:
|
||||||
mapping["mappings"]["_source"] = {"excludes": excludes_from_source} # e.g. {"excludes": ["vector_field"]}
|
# e.g. {"excludes": ["vector_field"]}
|
||||||
|
mapping["mappings"]["_source"] = {"excludes": excludes_from_source}
|
||||||
|
|
||||||
if method_name == "ivfpq" and routing_field is not None:
|
if method_name == "ivfpq" and routing_field is not None:
|
||||||
mapping["settings"]["index"]["knn_routing"] = True
|
mapping["settings"]["index"]["knn_routing"] = True
|
||||||
@ -405,7 +424,8 @@ def default_text_search_query(
|
|||||||
# build complex search_query when either of must/must_not/should/filter is specified
|
# build complex search_query when either of must/must_not/should/filter is specified
|
||||||
if must:
|
if must:
|
||||||
if not isinstance(must, list):
|
if not isinstance(must, list):
|
||||||
raise RuntimeError(f"unexpected [must] clause with {type(filters)}")
|
raise RuntimeError(
|
||||||
|
f"unexpected [must] clause with {type(filters)}")
|
||||||
if query_clause not in must:
|
if query_clause not in must:
|
||||||
must.append(query_clause)
|
must.append(query_clause)
|
||||||
else:
|
else:
|
||||||
@ -415,19 +435,22 @@ def default_text_search_query(
|
|||||||
|
|
||||||
if must_not:
|
if must_not:
|
||||||
if not isinstance(must_not, list):
|
if not isinstance(must_not, list):
|
||||||
raise RuntimeError(f"unexpected [must_not] clause with {type(filters)}")
|
raise RuntimeError(
|
||||||
|
f"unexpected [must_not] clause with {type(filters)}")
|
||||||
boolean_query["must_not"] = must_not
|
boolean_query["must_not"] = must_not
|
||||||
|
|
||||||
if should:
|
if should:
|
||||||
if not isinstance(should, list):
|
if not isinstance(should, list):
|
||||||
raise RuntimeError(f"unexpected [should] clause with {type(filters)}")
|
raise RuntimeError(
|
||||||
|
f"unexpected [should] clause with {type(filters)}")
|
||||||
boolean_query["should"] = should
|
boolean_query["should"] = should
|
||||||
if minimum_should_match != 0:
|
if minimum_should_match != 0:
|
||||||
boolean_query["minimum_should_match"] = minimum_should_match
|
boolean_query["minimum_should_match"] = minimum_should_match
|
||||||
|
|
||||||
if filters:
|
if filters:
|
||||||
if not isinstance(filters, list):
|
if not isinstance(filters, list):
|
||||||
raise RuntimeError(f"unexpected [filter] clause with {type(filters)}")
|
raise RuntimeError(
|
||||||
|
f"unexpected [filter] clause with {type(filters)}")
|
||||||
boolean_query["filter"] = filters
|
boolean_query["filter"] = filters
|
||||||
|
|
||||||
search_query = {"size": k, "query": {"bool": boolean_query}}
|
search_query = {"size": k, "query": {"bool": boolean_query}}
|
||||||
@ -471,8 +494,10 @@ def default_vector_search_query(
|
|||||||
|
|
||||||
if filters is not None:
|
if filters is not None:
|
||||||
# when using filter, transform filter from List[Dict] to Dict as valid format
|
# when using filter, transform filter from List[Dict] to Dict as valid format
|
||||||
filters = {"bool": {"must": filters}} if len(filters) > 1 else filters[0]
|
filters = {"bool": {"must": filters}} if len(
|
||||||
search_query["query"]["knn"][vector_field]["filter"] = filters # filter should be Dict
|
filters) > 1 else filters[0]
|
||||||
|
# filter should be Dict
|
||||||
|
search_query["query"]["knn"][vector_field]["filter"] = filters
|
||||||
if filter_type:
|
if filter_type:
|
||||||
final_ext["lvector"]["filter_type"] = filter_type
|
final_ext["lvector"]["filter_type"] = filter_type
|
||||||
|
|
||||||
@ -489,7 +514,8 @@ class LindormVectorStoreFactory(AbstractVectorFactory):
|
|||||||
else:
|
else:
|
||||||
dataset_id = dataset.id
|
dataset_id = dataset.id
|
||||||
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
||||||
dataset.index_struct = json.dumps(self.gen_index_struct_dict(VectorType.LINDORM, collection_name))
|
dataset.index_struct = json.dumps(
|
||||||
|
self.gen_index_struct_dict(VectorType.LINDORM, collection_name))
|
||||||
lindorm_config = LindormVectorStoreConfig(
|
lindorm_config = LindormVectorStoreConfig(
|
||||||
hosts=dify_config.LINDORM_URL,
|
hosts=dify_config.LINDORM_URL,
|
||||||
username=dify_config.LINDORM_USERNAME,
|
username=dify_config.LINDORM_USERNAME,
|
||||||
|
@ -38,7 +38,6 @@ class AliYuqueDescribeDocumentContentTool(AliYuqueTool, BuiltinTool):
|
|||||||
book_id = index_page.get("data", {}).get("book", {}).get("id")
|
book_id = index_page.get("data", {}).get("book", {}).get("id")
|
||||||
if not book_id:
|
if not book_id:
|
||||||
raise Exception(f"can not parse book_id from {index_page}")
|
raise Exception(f"can not parse book_id from {index_page}")
|
||||||
|
|
||||||
new_params["book_id"] = book_id
|
new_params["book_id"] = book_id
|
||||||
new_params["id"] = doc_id
|
new_params["id"] = doc_id
|
||||||
data = self.request("GET", token, new_params, "/api/v2/repos/{book_id}/docs/{id}")
|
data = self.request("GET", token, new_params, "/api/v2/repos/{book_id}/docs/{id}")
|
||||||
|
@ -49,11 +49,13 @@ class QuestionClassifierNode(LLMNode):
|
|||||||
variable_pool = self.graph_runtime_state.variable_pool
|
variable_pool = self.graph_runtime_state.variable_pool
|
||||||
|
|
||||||
# extract variables
|
# extract variables
|
||||||
variable = variable_pool.get(node_data.query_variable_selector) if node_data.query_variable_selector else None
|
variable = variable_pool.get(
|
||||||
|
node_data.query_variable_selector) if node_data.query_variable_selector else None
|
||||||
query = variable.value if variable else None
|
query = variable.value if variable else None
|
||||||
variables = {"query": query}
|
variables = {"query": query}
|
||||||
# fetch model config
|
# fetch model config
|
||||||
model_instance, model_config = self._fetch_model_config(node_data.model)
|
model_instance, model_config = self._fetch_model_config(
|
||||||
|
node_data.model)
|
||||||
# fetch memory
|
# fetch memory
|
||||||
memory = self._fetch_memory(
|
memory = self._fetch_memory(
|
||||||
node_data_memory=node_data.memory,
|
node_data_memory=node_data.memory,
|
||||||
@ -61,7 +63,8 @@ class QuestionClassifierNode(LLMNode):
|
|||||||
)
|
)
|
||||||
# fetch instruction
|
# fetch instruction
|
||||||
node_data.instruction = node_data.instruction or ""
|
node_data.instruction = node_data.instruction or ""
|
||||||
node_data.instruction = variable_pool.convert_template(node_data.instruction).text
|
node_data.instruction = variable_pool.convert_template(
|
||||||
|
node_data.instruction).text
|
||||||
|
|
||||||
files: Sequence[File] = (
|
files: Sequence[File] = (
|
||||||
self._fetch_files(
|
self._fetch_files(
|
||||||
@ -184,12 +187,15 @@ class QuestionClassifierNode(LLMNode):
|
|||||||
variable_mapping = {"query": node_data.query_variable_selector}
|
variable_mapping = {"query": node_data.query_variable_selector}
|
||||||
variable_selectors = []
|
variable_selectors = []
|
||||||
if node_data.instruction:
|
if node_data.instruction:
|
||||||
variable_template_parser = VariableTemplateParser(template=node_data.instruction)
|
variable_template_parser = VariableTemplateParser(
|
||||||
variable_selectors.extend(variable_template_parser.extract_variable_selectors())
|
template=node_data.instruction)
|
||||||
|
variable_selectors.extend(
|
||||||
|
variable_template_parser.extract_variable_selectors())
|
||||||
for variable_selector in variable_selectors:
|
for variable_selector in variable_selectors:
|
||||||
variable_mapping[variable_selector.variable] = variable_selector.value_selector
|
variable_mapping[variable_selector.variable] = variable_selector.value_selector
|
||||||
|
|
||||||
variable_mapping = {node_id + "." + key: value for key, value in variable_mapping.items()}
|
variable_mapping = {node_id + "." + key: value for key,
|
||||||
|
value in variable_mapping.items()}
|
||||||
|
|
||||||
return variable_mapping
|
return variable_mapping
|
||||||
|
|
||||||
@ -210,7 +216,8 @@ class QuestionClassifierNode(LLMNode):
|
|||||||
context: Optional[str],
|
context: Optional[str],
|
||||||
) -> int:
|
) -> int:
|
||||||
prompt_transform = AdvancedPromptTransform(with_variable_tmpl=True)
|
prompt_transform = AdvancedPromptTransform(with_variable_tmpl=True)
|
||||||
prompt_template = self._get_prompt_template(node_data, query, None, 2000)
|
prompt_template = self._get_prompt_template(
|
||||||
|
node_data, query, None, 2000)
|
||||||
prompt_messages = prompt_transform.get_prompt(
|
prompt_messages = prompt_transform.get_prompt(
|
||||||
prompt_template=prompt_template,
|
prompt_template=prompt_template,
|
||||||
inputs={},
|
inputs={},
|
||||||
@ -223,13 +230,15 @@ class QuestionClassifierNode(LLMNode):
|
|||||||
)
|
)
|
||||||
rest_tokens = 2000
|
rest_tokens = 2000
|
||||||
|
|
||||||
model_context_tokens = model_config.model_schema.model_properties.get(ModelPropertyKey.CONTEXT_SIZE)
|
model_context_tokens = model_config.model_schema.model_properties.get(
|
||||||
|
ModelPropertyKey.CONTEXT_SIZE)
|
||||||
if model_context_tokens:
|
if model_context_tokens:
|
||||||
model_instance = ModelInstance(
|
model_instance = ModelInstance(
|
||||||
provider_model_bundle=model_config.provider_model_bundle, model=model_config.model
|
provider_model_bundle=model_config.provider_model_bundle, model=model_config.model
|
||||||
)
|
)
|
||||||
|
|
||||||
curr_message_tokens = model_instance.get_llm_num_tokens(prompt_messages)
|
curr_message_tokens = model_instance.get_llm_num_tokens(
|
||||||
|
prompt_messages)
|
||||||
|
|
||||||
max_tokens = 0
|
max_tokens = 0
|
||||||
for parameter_rule in model_config.model_schema.parameter_rules:
|
for parameter_rule in model_config.model_schema.parameter_rules:
|
||||||
@ -270,7 +279,8 @@ class QuestionClassifierNode(LLMNode):
|
|||||||
prompt_messages: list[LLMNodeChatModelMessage] = []
|
prompt_messages: list[LLMNodeChatModelMessage] = []
|
||||||
if model_mode == ModelMode.CHAT:
|
if model_mode == ModelMode.CHAT:
|
||||||
system_prompt_messages = LLMNodeChatModelMessage(
|
system_prompt_messages = LLMNodeChatModelMessage(
|
||||||
role=PromptMessageRole.SYSTEM, text=QUESTION_CLASSIFIER_SYSTEM_PROMPT.format(histories=memory_str)
|
role=PromptMessageRole.SYSTEM, text=QUESTION_CLASSIFIER_SYSTEM_PROMPT.format(
|
||||||
|
histories=memory_str)
|
||||||
)
|
)
|
||||||
prompt_messages.append(system_prompt_messages)
|
prompt_messages.append(system_prompt_messages)
|
||||||
user_prompt_message_1 = LLMNodeChatModelMessage(
|
user_prompt_message_1 = LLMNodeChatModelMessage(
|
||||||
@ -311,4 +321,5 @@ class QuestionClassifierNode(LLMNode):
|
|||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise InvalidModelTypeError(f"Model mode {model_mode} not support.")
|
raise InvalidModelTypeError(
|
||||||
|
f"Model mode {model_mode} not support.")
|
||||||
|
@ -68,7 +68,8 @@ def test_executor_with_json_body_and_object_variable():
|
|||||||
system_variables={},
|
system_variables={},
|
||||||
user_inputs={},
|
user_inputs={},
|
||||||
)
|
)
|
||||||
variable_pool.add(["pre_node_id", "object"], {"name": "John Doe", "age": 30, "email": "john@example.com"})
|
variable_pool.add(["pre_node_id", "object"], {
|
||||||
|
"name": "John Doe", "age": 30, "email": "john@example.com"})
|
||||||
|
|
||||||
# Prepare the node data
|
# Prepare the node data
|
||||||
node_data = HttpRequestNodeData(
|
node_data = HttpRequestNodeData(
|
||||||
@ -102,7 +103,8 @@ def test_executor_with_json_body_and_object_variable():
|
|||||||
assert executor.url == "https://api.example.com/data"
|
assert executor.url == "https://api.example.com/data"
|
||||||
assert executor.headers == {"Content-Type": "application/json"}
|
assert executor.headers == {"Content-Type": "application/json"}
|
||||||
assert executor.params == {}
|
assert executor.params == {}
|
||||||
assert executor.json == {"name": "John Doe", "age": 30, "email": "john@example.com"}
|
assert executor.json == {"name": "John Doe",
|
||||||
|
"age": 30, "email": "john@example.com"}
|
||||||
assert executor.data is None
|
assert executor.data is None
|
||||||
assert executor.files is None
|
assert executor.files is None
|
||||||
assert executor.content is None
|
assert executor.content is None
|
||||||
@ -123,7 +125,8 @@ def test_executor_with_json_body_and_nested_object_variable():
|
|||||||
system_variables={},
|
system_variables={},
|
||||||
user_inputs={},
|
user_inputs={},
|
||||||
)
|
)
|
||||||
variable_pool.add(["pre_node_id", "object"], {"name": "John Doe", "age": 30, "email": "john@example.com"})
|
variable_pool.add(["pre_node_id", "object"], {
|
||||||
|
"name": "John Doe", "age": 30, "email": "john@example.com"})
|
||||||
|
|
||||||
# Prepare the node data
|
# Prepare the node data
|
||||||
node_data = HttpRequestNodeData(
|
node_data = HttpRequestNodeData(
|
||||||
@ -157,7 +160,8 @@ def test_executor_with_json_body_and_nested_object_variable():
|
|||||||
assert executor.url == "https://api.example.com/data"
|
assert executor.url == "https://api.example.com/data"
|
||||||
assert executor.headers == {"Content-Type": "application/json"}
|
assert executor.headers == {"Content-Type": "application/json"}
|
||||||
assert executor.params == {}
|
assert executor.params == {}
|
||||||
assert executor.json == {"object": {"name": "John Doe", "age": 30, "email": "john@example.com"}}
|
assert executor.json == {"object": {
|
||||||
|
"name": "John Doe", "age": 30, "email": "john@example.com"}}
|
||||||
assert executor.data is None
|
assert executor.data is None
|
||||||
assert executor.files is None
|
assert executor.files is None
|
||||||
assert executor.content is None
|
assert executor.content is None
|
||||||
|
@ -23,7 +23,8 @@ def test_plain_text_to_dict():
|
|||||||
assert _plain_text_to_dict("aa\n cc:") == {"aa": "", "cc": ""}
|
assert _plain_text_to_dict("aa\n cc:") == {"aa": "", "cc": ""}
|
||||||
assert _plain_text_to_dict("aa:bb\n cc:dd") == {"aa": "bb", "cc": "dd"}
|
assert _plain_text_to_dict("aa:bb\n cc:dd") == {"aa": "bb", "cc": "dd"}
|
||||||
assert _plain_text_to_dict("aa:bb\n cc:dd\n") == {"aa": "bb", "cc": "dd"}
|
assert _plain_text_to_dict("aa:bb\n cc:dd\n") == {"aa": "bb", "cc": "dd"}
|
||||||
assert _plain_text_to_dict("aa:bb\n\n cc : dd\n\n") == {"aa": "bb", "cc": "dd"}
|
assert _plain_text_to_dict("aa:bb\n\n cc : dd\n\n") == {
|
||||||
|
"aa": "bb", "cc": "dd"}
|
||||||
|
|
||||||
|
|
||||||
def test_http_request_node_binary_file(monkeypatch):
|
def test_http_request_node_binary_file(monkeypatch):
|
||||||
@ -189,7 +190,8 @@ def test_http_request_node_form_with_file(monkeypatch):
|
|||||||
|
|
||||||
def attr_checker(*args, **kwargs):
|
def attr_checker(*args, **kwargs):
|
||||||
assert kwargs["data"] == {"name": "test"}
|
assert kwargs["data"] == {"name": "test"}
|
||||||
assert kwargs["files"] == {"file": (None, b"test", "application/octet-stream")}
|
assert kwargs["files"] == {
|
||||||
|
"file": (None, b"test", "application/octet-stream")}
|
||||||
return httpx.Response(200, content=b"")
|
return httpx.Response(200, content=b"")
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
|
@ -318,6 +318,8 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
CONSOLE_API_URL: ${CONSOLE_API_URL:-}
|
CONSOLE_API_URL: ${CONSOLE_API_URL:-}
|
||||||
APP_API_URL: ${APP_API_URL:-}
|
APP_API_URL: ${APP_API_URL:-}
|
||||||
|
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-}
|
||||||
|
MARKETPLACE_URL: ${MARKETPLACE_URL:-}
|
||||||
SENTRY_DSN: ${WEB_SENTRY_DSN:-}
|
SENTRY_DSN: ${WEB_SENTRY_DSN:-}
|
||||||
NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0}
|
NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0}
|
||||||
TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}
|
TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"presets": [
|
|
||||||
"@babel/preset-env"
|
|
||||||
]
|
|
||||||
}
|
|
@ -10,6 +10,10 @@ NEXT_PUBLIC_API_PREFIX=http://localhost:5001/console/api
|
|||||||
# console or api domain.
|
# console or api domain.
|
||||||
# example: http://udify.app/api
|
# example: http://udify.app/api
|
||||||
NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api
|
NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api
|
||||||
|
# The APIFREX for MARKETPLACE
|
||||||
|
NEXT_PUBLIC_MARKETPLACE_API_PREFIX=http://localhost:5002/api
|
||||||
|
# The URL for MARKETPLACE
|
||||||
|
NEXT_PUBLIC_MARKETPLACE_URL_PREFIX=
|
||||||
|
|
||||||
# SENTRY
|
# SENTRY
|
||||||
NEXT_PUBLIC_SENTRY_DSN=
|
NEXT_PUBLIC_SENTRY_DSN=
|
||||||
@ -25,3 +29,6 @@ NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS=60000
|
|||||||
|
|
||||||
# CSP https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
|
# CSP https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
|
||||||
NEXT_PUBLIC_CSP_WHITELIST=
|
NEXT_PUBLIC_CSP_WHITELIST=
|
||||||
|
|
||||||
|
# Github Access Token, used for invoking Github API
|
||||||
|
NEXT_PUBLIC_GITHUB_ACCESS_TOKEN=
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
/**/node_modules/*
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
dist/
|
|
||||||
build/
|
|
||||||
out/
|
|
||||||
.next/
|
|
@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": [
|
|
||||||
"next",
|
|
||||||
"@antfu",
|
|
||||||
"plugin:storybook/recommended"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"@typescript-eslint/consistent-type-definitions": [
|
|
||||||
"error",
|
|
||||||
"type"
|
|
||||||
],
|
|
||||||
"@typescript-eslint/no-var-requires": "off",
|
|
||||||
"no-console": "off",
|
|
||||||
"indent": "off",
|
|
||||||
"@typescript-eslint/indent": [
|
|
||||||
"error",
|
|
||||||
2,
|
|
||||||
{
|
|
||||||
"SwitchCase": 1,
|
|
||||||
"flatTernaryExpressions": false,
|
|
||||||
"ignoredNodes": [
|
|
||||||
"PropertyDefinition[decorators]",
|
|
||||||
"TSUnionType",
|
|
||||||
"FunctionExpression[params]:has(Identifier[decorators])"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"react-hooks/exhaustive-deps": "warn",
|
|
||||||
"react/display-name": "warn"
|
|
||||||
}
|
|
||||||
}
|
|
7
web/.gitignore
vendored
7
web/.gitignore
vendored
@ -44,10 +44,9 @@ package-lock.json
|
|||||||
.pnp.cjs
|
.pnp.cjs
|
||||||
.pnp.loader.mjs
|
.pnp.loader.mjs
|
||||||
.yarn/
|
.yarn/
|
||||||
.yarnrc.yml
|
|
||||||
|
|
||||||
# pmpm
|
|
||||||
pnpm-lock.yaml
|
|
||||||
|
|
||||||
.favorites.json
|
.favorites.json
|
||||||
|
|
||||||
|
# storybook
|
||||||
|
/storybook-static
|
||||||
*storybook.log
|
*storybook.log
|
@ -1,6 +1,3 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
. "$(dirname -- "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
# get the list of modified files
|
# get the list of modified files
|
||||||
files=$(git diff --cached --name-only)
|
files=$(git diff --cached --name-only)
|
||||||
|
|
||||||
@ -50,7 +47,7 @@ fi
|
|||||||
if $web_modified; then
|
if $web_modified; then
|
||||||
echo "Running ESLint on web module"
|
echo "Running ESLint on web module"
|
||||||
cd ./web || exit 1
|
cd ./web || exit 1
|
||||||
npx lint-staged
|
lint-staged
|
||||||
|
|
||||||
echo "Running unit tests check"
|
echo "Running unit tests check"
|
||||||
modified_files=$(git diff --cached --name-only -- utils | grep -v '\.spec\.ts$' || true)
|
modified_files=$(git diff --cached --name-only -- utils | grep -v '\.spec\.ts$' || true)
|
||||||
@ -63,7 +60,7 @@ if $web_modified; then
|
|||||||
# check if the test file exists
|
# check if the test file exists
|
||||||
if [ -f "../$test_file" ]; then
|
if [ -f "../$test_file" ]; then
|
||||||
echo "Detected changes in $file, running corresponding unit tests..."
|
echo "Detected changes in $file, running corresponding unit tests..."
|
||||||
npm run test "../$test_file"
|
pnpm run test "../$test_file"
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Unit tests failed. Please fix the errors before committing."
|
echo "Unit tests failed. Please fix the errors before committing."
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import type { Preview } from '@storybook/react'
|
import type { Preview } from '@storybook/react'
|
||||||
import { withThemeByDataAttribute } from '@storybook/addon-themes';
|
import { withThemeByDataAttribute } from '@storybook/addon-themes'
|
||||||
import I18nServer from '../app/components/i18n-server'
|
import I18nServer from '../app/components/i18n-server'
|
||||||
|
|
||||||
import '../app/styles/globals.css'
|
import '../app/styles/globals.css'
|
||||||
@ -16,12 +16,12 @@ export const decorators = [
|
|||||||
defaultTheme: 'light',
|
defaultTheme: 'light',
|
||||||
attributeName: 'data-theme',
|
attributeName: 'data-theme',
|
||||||
}),
|
}),
|
||||||
Story => {
|
(Story) => {
|
||||||
return <I18nServer>
|
return <I18nServer>
|
||||||
<Story />
|
<Story />
|
||||||
</I18nServer>
|
</I18nServer>
|
||||||
}
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
const preview: Preview = {
|
const preview: Preview = {
|
||||||
parameters: {
|
parameters: {
|
||||||
|
3
web/.vscode/settings.example.json
vendored
3
web/.vscode/settings.example.json
vendored
@ -21,5 +21,6 @@
|
|||||||
"editor.defaultFormatter": "vscode.json-language-features"
|
"editor.defaultFormatter": "vscode.json-language-features"
|
||||||
},
|
},
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
"typescript.enablePromptUseWorkspaceTsdk": true
|
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||||
|
"npm.packageManager": "pnpm"
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@ LABEL maintainer="takatost@gmail.com"
|
|||||||
# RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
|
# RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
|
||||||
|
|
||||||
RUN apk add --no-cache tzdata
|
RUN apk add --no-cache tzdata
|
||||||
|
RUN npm install -g pnpm@9.12.2
|
||||||
|
ENV PNPM_HOME="/pnpm"
|
||||||
|
ENV PATH="$PNPM_HOME:$PATH"
|
||||||
|
|
||||||
|
|
||||||
# install packages
|
# install packages
|
||||||
@ -14,12 +17,12 @@ FROM base AS packages
|
|||||||
WORKDIR /app/web
|
WORKDIR /app/web
|
||||||
|
|
||||||
COPY package.json .
|
COPY package.json .
|
||||||
COPY yarn.lock .
|
COPY pnpm-lock.yaml .
|
||||||
|
|
||||||
# if you located in China, you can use taobao registry to speed up
|
# if you located in China, you can use taobao registry to speed up
|
||||||
# RUN yarn install --frozen-lockfile --registry https://registry.npmmirror.com/
|
# RUN pnpm install --frozen-lockfile --registry https://registry.npmmirror.com/
|
||||||
|
|
||||||
RUN yarn install --frozen-lockfile
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
# build resources
|
# build resources
|
||||||
FROM base AS builder
|
FROM base AS builder
|
||||||
@ -27,7 +30,7 @@ WORKDIR /app/web
|
|||||||
COPY --from=packages /app/web/ .
|
COPY --from=packages /app/web/ .
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN yarn build
|
RUN pnpm build
|
||||||
|
|
||||||
|
|
||||||
# production stage
|
# production stage
|
||||||
@ -38,6 +41,8 @@ ENV EDITION=SELF_HOSTED
|
|||||||
ENV DEPLOY_ENV=PRODUCTION
|
ENV DEPLOY_ENV=PRODUCTION
|
||||||
ENV CONSOLE_API_URL=http://127.0.0.1:5001
|
ENV CONSOLE_API_URL=http://127.0.0.1:5001
|
||||||
ENV APP_API_URL=http://127.0.0.1:5001
|
ENV APP_API_URL=http://127.0.0.1:5001
|
||||||
|
ENV MARKETPLACE_API_URL=http://127.0.0.1:5001
|
||||||
|
ENV MARKETPLACE_URL=http://127.0.0.1:5001
|
||||||
ENV PORT=3000
|
ENV PORT=3000
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
|
||||||
@ -57,8 +62,7 @@ COPY docker/entrypoint.sh ./entrypoint.sh
|
|||||||
|
|
||||||
|
|
||||||
# global runtime packages
|
# global runtime packages
|
||||||
RUN yarn global add pm2 \
|
RUN pnpm add -g pm2 \
|
||||||
&& yarn cache clean \
|
|
||||||
&& mkdir /.pm2 \
|
&& mkdir /.pm2 \
|
||||||
&& chown -R 1001:0 /.pm2 /app/web \
|
&& chown -R 1001:0 /.pm2 /app/web \
|
||||||
&& chmod -R g=u /.pm2 /app/web
|
&& chmod -R g=u /.pm2 /app/web
|
||||||
|
@ -6,14 +6,12 @@ This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next
|
|||||||
|
|
||||||
### Run by source code
|
### Run by source code
|
||||||
|
|
||||||
To start the web frontend service, you will need [Node.js v18.x (LTS)](https://nodejs.org/en) and [NPM version 8.x.x](https://www.npmjs.com/) or [Yarn](https://yarnpkg.com/).
|
To start the web frontend service, you will need [Node.js v18.x (LTS)](https://nodejs.org/en) and [pnpm version 9.12.2](https://pnpm.io).
|
||||||
|
|
||||||
First, install the dependencies:
|
First, install the dependencies:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install
|
pnpm install
|
||||||
# or
|
|
||||||
yarn install --frozen-lockfile
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, configure the environment variables. Create a file named `.env.local` in the current directory and copy the contents from `.env.example`. Modify the values of these environment variables according to your requirements:
|
Then, configure the environment variables. Create a file named `.env.local` in the current directory and copy the contents from `.env.example`. Modify the values of these environment variables according to your requirements:
|
||||||
@ -43,9 +41,7 @@ NEXT_PUBLIC_SENTRY_DSN=
|
|||||||
Finally, run the development server:
|
Finally, run the development server:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev
|
pnpm run dev
|
||||||
# or
|
|
||||||
yarn dev
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||||
@ -59,19 +55,19 @@ You can start editing the file under folder `app`. The page auto-updates as you
|
|||||||
First, build the app for production:
|
First, build the app for production:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build
|
pnpm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, start the server:
|
Then, start the server:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run start
|
pnpm run start
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want to customize the host and port:
|
If you want to customize the host and port:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run start --port=3001 --host=0.0.0.0
|
pnpm run start --port=3001 --host=0.0.0.0
|
||||||
```
|
```
|
||||||
|
|
||||||
## Storybook
|
## Storybook
|
||||||
@ -81,7 +77,7 @@ This project uses [Storybook](https://storybook.js.org/) for UI component develo
|
|||||||
To start the storybook server, run:
|
To start the storybook server, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn storybook
|
pnpm storybook
|
||||||
```
|
```
|
||||||
|
|
||||||
Open [http://localhost:6006](http://localhost:6006) with your browser to see the result.
|
Open [http://localhost:6006](http://localhost:6006) with your browser to see the result.
|
||||||
@ -99,7 +95,7 @@ You can create a test file with a suffix of `.spec` beside the file that to be t
|
|||||||
Run test:
|
Run test:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run test
|
pnpm run test
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are not familiar with writing tests, here is some code to refer to:
|
If you are not familiar with writing tests, here is some code to refer to:
|
||||||
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import Main from '@/app/components/app/log-annotation'
|
import Main from '@/app/components/app/log-annotation'
|
||||||
import { PageType } from '@/app/components/base/features/new-feature-panel/annotation-reply/type'
|
import { PageType } from '@/app/components/base/features/new-feature-panel/annotation-reply/type'
|
||||||
|
|
||||||
export type IProps = {
|
export interface IProps {
|
||||||
params: { appId: string }
|
params: { appId: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { type Locale } from '@/i18n'
|
import type { Locale } from '@/i18n'
|
||||||
import DevelopMain from '@/app/components/develop'
|
import DevelopMain from '@/app/components/develop'
|
||||||
|
|
||||||
export type IDevelopProps = {
|
export type IDevelopProps = {
|
||||||
|
@ -4,7 +4,7 @@ import React from 'react'
|
|||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import Input from '@/app/components/base/input'
|
import Input from '@/app/components/base/input'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
label: string
|
label: string
|
||||||
labelClassName?: string
|
labelClassName?: string
|
||||||
|
@ -8,12 +8,11 @@ import { useBoolean } from 'ahooks'
|
|||||||
import {
|
import {
|
||||||
Cog8ToothIcon,
|
Cog8ToothIcon,
|
||||||
// CommandLineIcon,
|
// CommandLineIcon,
|
||||||
Squares2X2Icon,
|
|
||||||
// eslint-disable-next-line sort-imports
|
|
||||||
PuzzlePieceIcon,
|
|
||||||
DocumentTextIcon,
|
DocumentTextIcon,
|
||||||
PaperClipIcon,
|
PaperClipIcon,
|
||||||
|
PuzzlePieceIcon,
|
||||||
QuestionMarkCircleIcon,
|
QuestionMarkCircleIcon,
|
||||||
|
Squares2X2Icon,
|
||||||
} from '@heroicons/react/24/outline'
|
} from '@heroicons/react/24/outline'
|
||||||
import {
|
import {
|
||||||
Cog8ToothIcon as Cog8ToothSolidIcon,
|
Cog8ToothIcon as Cog8ToothSolidIcon,
|
||||||
|
@ -5,7 +5,6 @@ import { useEffect, useMemo, useRef, useState } from 'react'
|
|||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useDebounceFn } from 'ahooks'
|
import { useDebounceFn } from 'ahooks'
|
||||||
import useSWR from 'swr'
|
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import ExternalAPIPanel from '../../components/datasets/external-api/external-api-panel'
|
import ExternalAPIPanel from '../../components/datasets/external-api/external-api-panel'
|
||||||
@ -28,6 +27,7 @@ import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
|
|||||||
import { useStore as useTagStore } from '@/app/components/base/tag-management/store'
|
import { useStore as useTagStore } from '@/app/components/base/tag-management/store'
|
||||||
import { useAppContext } from '@/context/app-context'
|
import { useAppContext } from '@/context/app-context'
|
||||||
import { useExternalApiPanel } from '@/context/external-api-panel-context'
|
import { useExternalApiPanel } from '@/context/external-api-panel-context'
|
||||||
|
import { useQuery } from '@tanstack/react-query'
|
||||||
|
|
||||||
const Container = () => {
|
const Container = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -47,7 +47,13 @@ const Container = () => {
|
|||||||
defaultTab: 'dataset',
|
defaultTab: 'dataset',
|
||||||
})
|
})
|
||||||
const containerRef = useRef<HTMLDivElement>(null)
|
const containerRef = useRef<HTMLDivElement>(null)
|
||||||
const { data } = useSWR(activeTab === 'dataset' ? null : '/datasets/api-base-info', fetchDatasetApiBaseUrl)
|
const { data } = useQuery(
|
||||||
|
{
|
||||||
|
queryKey: ['datasetApiBaseInfo', activeTab],
|
||||||
|
queryFn: () => fetchDatasetApiBaseUrl('/datasets/api-base-info'),
|
||||||
|
enabled: activeTab !== 'dataset',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
const [keywords, setKeywords] = useState('')
|
const [keywords, setKeywords] = useState('')
|
||||||
const [searchKeywords, setSearchKeywords] = useState('')
|
const [searchKeywords, setSearchKeywords] = useState('')
|
||||||
|
@ -8,12 +8,14 @@ import Header from '@/app/components/header'
|
|||||||
import { EventEmitterContextProvider } from '@/context/event-emitter'
|
import { EventEmitterContextProvider } from '@/context/event-emitter'
|
||||||
import { ProviderContextProvider } from '@/context/provider-context'
|
import { ProviderContextProvider } from '@/context/provider-context'
|
||||||
import { ModalContextProvider } from '@/context/modal-context'
|
import { ModalContextProvider } from '@/context/modal-context'
|
||||||
|
import { TanstackQueryIniter } from '@/context/query-client'
|
||||||
|
|
||||||
const Layout = ({ children }: { children: ReactNode }) => {
|
const Layout = ({ children }: { children: ReactNode }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<GA gaType={GaType.admin} />
|
<GA gaType={GaType.admin} />
|
||||||
<SwrInitor>
|
<SwrInitor>
|
||||||
|
<TanstackQueryIniter>
|
||||||
<AppContextProvider>
|
<AppContextProvider>
|
||||||
<EventEmitterContextProvider>
|
<EventEmitterContextProvider>
|
||||||
<ProviderContextProvider>
|
<ProviderContextProvider>
|
||||||
@ -26,6 +28,7 @@ const Layout = ({ children }: { children: ReactNode }) => {
|
|||||||
</ProviderContextProvider>
|
</ProviderContextProvider>
|
||||||
</EventEmitterContextProvider>
|
</EventEmitterContextProvider>
|
||||||
</AppContextProvider>
|
</AppContextProvider>
|
||||||
|
</TanstackQueryIniter>
|
||||||
</SwrInitor>
|
</SwrInitor>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
18
web/app/(commonLayout)/plugins/page.tsx
Normal file
18
web/app/(commonLayout)/plugins/page.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import PluginPage from '@/app/components/plugins/plugin-page'
|
||||||
|
import PluginsPanel from '@/app/components/plugins/plugin-page/plugins-panel'
|
||||||
|
import Marketplace from '@/app/components/plugins/marketplace'
|
||||||
|
|
||||||
|
const PluginList = async () => {
|
||||||
|
return (
|
||||||
|
<PluginPage
|
||||||
|
plugins={<PluginsPanel />}
|
||||||
|
marketplace={<Marketplace />}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: 'Plugins - Dify',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PluginList
|
14
web/app/(commonLayout)/plugins/test/card/actions.ts
Normal file
14
web/app/(commonLayout)/plugins/test/card/actions.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use server'
|
||||||
|
|
||||||
|
import { revalidatePath } from 'next/cache'
|
||||||
|
|
||||||
|
// Server Actions
|
||||||
|
export async function handleDelete() {
|
||||||
|
// revalidatePath only invalidates the cache when the included path is next visited.
|
||||||
|
revalidatePath('/')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchPluginDetail(org: string, name: string) {
|
||||||
|
// Fetch plugin detail TODO
|
||||||
|
return { org, name }
|
||||||
|
}
|
98
web/app/(commonLayout)/plugins/test/card/page.tsx
Normal file
98
web/app/(commonLayout)/plugins/test/card/page.tsx
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
'use client'
|
||||||
|
import Card from '@/app/components/plugins/card'
|
||||||
|
import { customTool, extensionDallE, modelGPT4, toolNotion } from '@/app/components/plugins/card/card-mock'
|
||||||
|
// import PluginItem from '@/app/components/plugins/plugin-item'
|
||||||
|
import CardMoreInfo from '@/app/components/plugins/card/card-more-info'
|
||||||
|
// import ProviderCard from '@/app/components/plugins/provider-card'
|
||||||
|
import Badge from '@/app/components/base/badge'
|
||||||
|
import InstallBundle from '@/app/components/plugins/install-plugin/install-bundle'
|
||||||
|
|
||||||
|
const PluginList = () => {
|
||||||
|
const pluginList = [toolNotion, extensionDallE, modelGPT4, customTool]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='pb-3 bg-white'>
|
||||||
|
<InstallBundle onClose={() => { }} fromDSLPayload={[
|
||||||
|
// {
|
||||||
|
// type: 'marketplace',
|
||||||
|
// value: {
|
||||||
|
// plugin_unique_identifier: 'langgenius/google:0.0.2@dcb354c9d0fee60e6e9c9eb996e1e485bbef343ba8cd545c0cfb3ec80970f6f1',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
type: 'github',
|
||||||
|
value: {
|
||||||
|
repo: 'YIXIAO0/test',
|
||||||
|
version: '1.11.5',
|
||||||
|
package: 'test.difypkg',
|
||||||
|
github_plugin_unique_identifier: 'yixiao0/test:0.0.1@3592166c87afcf944b4f13f27467a5c8f9e00bd349cb42033a072734a37431b4',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// type: 'marketplace',
|
||||||
|
// value: {
|
||||||
|
// plugin_unique_identifier: 'langgenius/openai:0.0.1@f88fdb98d104466db16a425bfe3af8c1bcad45047a40fb802d98a989ac57a5a3',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
]} />
|
||||||
|
<div className='mx-3 '>
|
||||||
|
{/* <h2 className='my-3'>Dify Plugin list</h2> */}
|
||||||
|
{/* <div className='grid grid-cols-2 gap-3'>
|
||||||
|
{pluginList.map((plugin, index) => (
|
||||||
|
<PluginItem
|
||||||
|
key={index}
|
||||||
|
payload={plugin as any}
|
||||||
|
onDelete={handleDelete}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div> */}
|
||||||
|
|
||||||
|
<h2 className='my-3'>Install Plugin / Package under bundle</h2>
|
||||||
|
<div className='w-[512px] rounded-2xl bg-background-section-burn p-2'>
|
||||||
|
<Card
|
||||||
|
payload={toolNotion as any}
|
||||||
|
descriptionLineRows={1}
|
||||||
|
titleLeft={
|
||||||
|
<Badge className='ml-1' text={toolNotion.version} />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/* <h3 className='my-1'>Installed</h3>
|
||||||
|
<div className='w-[512px] rounded-2xl bg-background-section-burn p-2'>
|
||||||
|
<Card
|
||||||
|
payload={toolNotion as any}
|
||||||
|
descriptionLineRows={1}
|
||||||
|
installed
|
||||||
|
/>
|
||||||
|
</div> */}
|
||||||
|
|
||||||
|
{/* <h3 className='my-1'>Install model provide</h3>
|
||||||
|
<div className='grid grid-cols-2 gap-3'>
|
||||||
|
{pluginList.map((plugin, index) => (
|
||||||
|
<ProviderCard key={index} payload={plugin as any} />
|
||||||
|
))}
|
||||||
|
</div> */}
|
||||||
|
|
||||||
|
<div className='my-3 h-[px] bg-gray-50'></div>
|
||||||
|
<h2 className='my-3'>Marketplace Plugin list</h2>
|
||||||
|
<div className='grid grid-cols-4 gap-3'>
|
||||||
|
{pluginList.map((plugin, index) => (
|
||||||
|
<Card
|
||||||
|
key={index}
|
||||||
|
payload={plugin as any}
|
||||||
|
footer={
|
||||||
|
<CardMoreInfo downloadCount={index % 2 === 0 ? 1234 : 6} tags={index % 2 === 0 ? ['Search', 'Tag that has very very long name', 'Productivity', 'Tag2'] : []} />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// export const metadata = {
|
||||||
|
// title: 'Plugins - Card',
|
||||||
|
// }
|
||||||
|
|
||||||
|
export default PluginList
|
20
web/app/(commonLayout)/plugins/test/other/page.tsx
Normal file
20
web/app/(commonLayout)/plugins/test/other/page.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
'use client'
|
||||||
|
import { useBoolean } from 'ahooks'
|
||||||
|
import UpdatePlugin from '@/app/components/plugins/update-plugin'
|
||||||
|
|
||||||
|
const Page = () => {
|
||||||
|
const [isShowUpdateModal, {
|
||||||
|
setTrue: showUpdateModal,
|
||||||
|
setFalse: hideUpdateModal,
|
||||||
|
}] = useBoolean(false)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div onClick={showUpdateModal}>Show Upgrade</div>
|
||||||
|
{isShowUpdateModal && (
|
||||||
|
<UpdatePlugin onHide={hideUpdateModal} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page
|
22
web/app/(commonLayout)/plugins/test/tools-picker/page.tsx
Normal file
22
web/app/(commonLayout)/plugins/test/tools-picker/page.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
'use client'
|
||||||
|
import React from 'react'
|
||||||
|
import ToolPicker from '@/app/components/workflow/block-selector/tool-picker'
|
||||||
|
|
||||||
|
const ToolsPicker = () => {
|
||||||
|
const [show, setShow] = React.useState(true)
|
||||||
|
return (
|
||||||
|
<div className=' mt-10 ml-10'>
|
||||||
|
<ToolPicker
|
||||||
|
trigger={<div className='inline-block w-[70px]'>Click me</div>}
|
||||||
|
isShow={show}
|
||||||
|
onShowChange={setShow}
|
||||||
|
disabled={false}
|
||||||
|
supportAddCustomTool={true}
|
||||||
|
onSelect={() => { }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ToolsPicker
|
67
web/app/(commonLayout)/plugins/test/update/page.tsx
Normal file
67
web/app/(commonLayout)/plugins/test/update/page.tsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
'use client'
|
||||||
|
import { toolNeko } from '@/app/components/plugins/card/card-mock'
|
||||||
|
import { PluginSource } from '@/app/components/plugins/types'
|
||||||
|
import { useModalContext } from '@/context/modal-context'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const UpdatePlugin = () => {
|
||||||
|
const { setShowUpdatePluginModal } = useModalContext()
|
||||||
|
const handleUpdateFromMarketPlace = () => {
|
||||||
|
setShowUpdatePluginModal({
|
||||||
|
payload: {
|
||||||
|
type: PluginSource.marketplace,
|
||||||
|
marketPlace: {
|
||||||
|
originalPackageInfo: {
|
||||||
|
id: 'langgenius/neko:0.0.1@9e57d693739287c0efdc96847d7ed959ca93f70aa704471f2eb7ed3313821824',
|
||||||
|
payload: toolNeko as any,
|
||||||
|
},
|
||||||
|
targetPackageInfo: {
|
||||||
|
id: 'target_xxx',
|
||||||
|
version: '1.2.3',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onCancelCallback: () => {
|
||||||
|
console.log('canceled')
|
||||||
|
},
|
||||||
|
onSaveCallback: () => {
|
||||||
|
console.log('saved')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleUpdateFromGithub = () => {
|
||||||
|
setShowUpdatePluginModal({
|
||||||
|
payload: {
|
||||||
|
type: PluginSource.github,
|
||||||
|
github: {
|
||||||
|
originalPackageInfo: {
|
||||||
|
id: '111',
|
||||||
|
repo: 'aaa/bbb',
|
||||||
|
version: 'xxx',
|
||||||
|
url: 'aaa/bbb',
|
||||||
|
currVersion: '1.2.3',
|
||||||
|
currPackage: 'pack1',
|
||||||
|
} as any,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onCancelCallback: () => {
|
||||||
|
console.log('canceled')
|
||||||
|
},
|
||||||
|
onSaveCallback: () => {
|
||||||
|
console.log('saved')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>更新组件</div>
|
||||||
|
<div className='flex space-x-1'>
|
||||||
|
<div className='underline cursor-pointer' onClick={handleUpdateFromMarketPlace}>从 Marketplace</div>
|
||||||
|
<div className='underline cursor-pointer' onClick={handleUpdateFromGithub}>从 GitHub</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(UpdatePlugin)
|
@ -8,7 +8,7 @@ import { logout } from '@/service/common'
|
|||||||
import { useAppContext } from '@/context/app-context'
|
import { useAppContext } from '@/context/app-context'
|
||||||
import { LogOut01 } from '@/app/components/base/icons/src/vender/line/general'
|
import { LogOut01 } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
|
|
||||||
export type IAppSelector = {
|
export interface IAppSelector {
|
||||||
isMobile: boolean
|
isMobile: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,11 +6,11 @@ import useSWR from 'swr'
|
|||||||
import Input from '@/app/components/base/input'
|
import Input from '@/app/components/base/input'
|
||||||
import { fetchAnnotationsCount } from '@/service/log'
|
import { fetchAnnotationsCount } from '@/service/log'
|
||||||
|
|
||||||
export type QueryParam = {
|
export interface QueryParam {
|
||||||
keyword?: string
|
keyword?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type IFilterProps = {
|
interface IFilterProps {
|
||||||
appId: string
|
appId: string
|
||||||
queryParams: QueryParam
|
queryParams: QueryParam
|
||||||
setQueryParams: (v: QueryParam) => void
|
setQueryParams: (v: QueryParam) => void
|
||||||
|
@ -27,7 +27,7 @@ import AnnotationFullModal from '@/app/components/billing/annotation-full/modal'
|
|||||||
import { Settings04 } from '@/app/components/base/icons/src/vender/line/general'
|
import { Settings04 } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
import type { App } from '@/types/app'
|
import type { App } from '@/types/app'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
appDetail: App
|
appDetail: App
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import RemoveAnnotationConfirmModal from './remove-annotation-confirm-modal'
|
|||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import useTimestamp from '@/hooks/use-timestamp'
|
import useTimestamp from '@/hooks/use-timestamp'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
list: AnnotationItem[]
|
list: AnnotationItem[]
|
||||||
onRemove: (id: string) => void
|
onRemove: (id: string) => void
|
||||||
onView: (item: AnnotationItem) => void
|
onView: (item: AnnotationItem) => void
|
||||||
|
@ -23,7 +23,7 @@ const FeaturePanel: FC<IFeaturePanelProps> = ({
|
|||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className={cn('rounded-xl border-t-[0.5px] border-l-[0.5px] bg-background-section-burn pb-3', noBodySpacing && '!pb-0', className)}>
|
<div className={cn('rounded-xl border-t-[0.5px] border-l-[0.5px] bg-background-section-burn pb-3', noBodySpacing && 'pb-0', className)}>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className={cn('px-3 pt-2', hasHeaderBottomBorder && 'border-b border-divider-subtle')}>
|
<div className={cn('px-3 pt-2', hasHeaderBottomBorder && 'border-b border-divider-subtle')}>
|
||||||
<div className='flex justify-between items-center h-8'>
|
<div className='flex justify-between items-center h-8'>
|
||||||
|
@ -9,7 +9,7 @@ import { MessageClockCircle } from '@/app/components/base/icons/src/vender/solid
|
|||||||
import I18n from '@/context/i18n'
|
import I18n from '@/context/i18n'
|
||||||
import { LanguagesSupported } from '@/i18n/language'
|
import { LanguagesSupported } from '@/i18n/language'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
showWarning: boolean
|
showWarning: boolean
|
||||||
onShowEditModal: () => void
|
onShowEditModal: () => void
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import ConfirmAddVar from './confirm-add-var'
|
|||||||
import s from './style.module.css'
|
import s from './style.module.css'
|
||||||
import PromptEditorHeightResizeWrap from './prompt-editor-height-resize-wrap'
|
import PromptEditorHeightResizeWrap from './prompt-editor-height-resize-wrap'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import { type PromptVariable } from '@/models/debug'
|
import type { PromptVariable } from '@/models/debug'
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import type { CompletionParams } from '@/types/app'
|
import type { CompletionParams } from '@/types/app'
|
||||||
import { AppType } from '@/types/app'
|
import { AppType } from '@/types/app'
|
||||||
|
@ -3,7 +3,7 @@ import type { FC } from 'react'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
title: string
|
title: string
|
||||||
children: JSX.Element
|
children: JSX.Element
|
||||||
|
@ -23,7 +23,7 @@ import { DEFAULT_VALUE_MAX_LEN } from '@/config'
|
|||||||
|
|
||||||
const TEXT_MAX_LENGTH = 256
|
const TEXT_MAX_LENGTH = 256
|
||||||
|
|
||||||
export type IConfigModalProps = {
|
export interface IConfigModalProps {
|
||||||
isCreate?: boolean
|
isCreate?: boolean
|
||||||
payload?: InputVar
|
payload?: InputVar
|
||||||
isShow: boolean
|
isShow: boolean
|
||||||
|
@ -3,7 +3,7 @@ import type { FC } from 'react'
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import Input from '@/app/components/base/input'
|
import Input from '@/app/components/base/input'
|
||||||
|
|
||||||
export type IConfigStringProps = {
|
export interface IConfigStringProps {
|
||||||
value: number | undefined
|
value: number | undefined
|
||||||
maxLength: number
|
maxLength: number
|
||||||
modelId: string
|
modelId: string
|
||||||
@ -28,7 +28,7 @@ const ConfigString: FC<IConfigStringProps> = ({
|
|||||||
min={1}
|
min={1}
|
||||||
value={value || ''}
|
value={value || ''}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
let value = parseInt(e.target.value, 10)
|
let value = Number.parseInt(e.target.value, 10)
|
||||||
if (value > maxLength)
|
if (value > maxLength)
|
||||||
value = maxLength
|
value = maxLength
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ import type { FC } from 'react'
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useBoolean } from 'ahooks'
|
import { useBoolean } from 'ahooks'
|
||||||
import type { Timeout } from 'ahooks/lib/useRequest/src/types'
|
|
||||||
import { useContext } from 'use-context-selector'
|
import { useContext } from 'use-context-selector'
|
||||||
import produce from 'immer'
|
import produce from 'immer'
|
||||||
import {
|
import {
|
||||||
@ -34,7 +33,7 @@ import { InputVarType } from '@/app/components/workflow/types'
|
|||||||
|
|
||||||
export const ADD_EXTERNAL_DATA_TOOL = 'ADD_EXTERNAL_DATA_TOOL'
|
export const ADD_EXTERNAL_DATA_TOOL = 'ADD_EXTERNAL_DATA_TOOL'
|
||||||
|
|
||||||
type ExternalDataToolParams = {
|
interface ExternalDataToolParams {
|
||||||
key: string
|
key: string
|
||||||
type: string
|
type: string
|
||||||
index: number
|
index: number
|
||||||
@ -44,13 +43,13 @@ type ExternalDataToolParams = {
|
|||||||
icon_background?: string
|
icon_background?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IConfigVarProps = {
|
export interface IConfigVarProps {
|
||||||
promptVariables: PromptVariable[]
|
promptVariables: PromptVariable[]
|
||||||
readonly?: boolean
|
readonly?: boolean
|
||||||
onPromptVariablesChange?: (promptVariables: PromptVariable[]) => void
|
onPromptVariablesChange?: (promptVariables: PromptVariable[]) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
let conflictTimer: Timeout
|
let conflictTimer: number
|
||||||
|
|
||||||
const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVariablesChange }) => {
|
const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVariablesChange }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -107,7 +106,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
|||||||
onPromptVariablesChange?.(newPromptVariables)
|
onPromptVariablesChange?.(newPromptVariables)
|
||||||
}
|
}
|
||||||
const updatePromptKey = (index: number, newKey: string) => {
|
const updatePromptKey = (index: number, newKey: string) => {
|
||||||
clearTimeout(conflictTimer)
|
window.clearTimeout(conflictTimer)
|
||||||
const { isValid, errorKey, errorMessageKey } = checkKeys([newKey], true)
|
const { isValid, errorKey, errorMessageKey } = checkKeys([newKey], true)
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
@ -127,7 +126,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
|||||||
return item
|
return item
|
||||||
})
|
})
|
||||||
|
|
||||||
conflictTimer = setTimeout(() => {
|
conflictTimer = window.setTimeout(() => {
|
||||||
const isKeyExists = promptVariables.some(item => item.key?.trim() === newKey.trim())
|
const isKeyExists = promptVariables.some(item => item.key?.trim() === newKey.trim())
|
||||||
if (isKeyExists) {
|
if (isKeyExists) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
|
@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import type { InputVarType } from '@/app/components/workflow/types'
|
import type { InputVarType } from '@/app/components/workflow/types'
|
||||||
import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon'
|
import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon'
|
||||||
export type ISelectTypeItemProps = {
|
export interface ISelectTypeItemProps {
|
||||||
type: InputVarType
|
type: InputVarType
|
||||||
selected: boolean
|
selected: boolean
|
||||||
onClick: () => void
|
onClick: () => void
|
||||||
|
@ -1,21 +1,25 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React, { useState } from 'react'
|
import React, { useMemo, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useContext } from 'use-context-selector'
|
import { useContext } from 'use-context-selector'
|
||||||
|
import copy from 'copy-to-clipboard'
|
||||||
import produce from 'immer'
|
import produce from 'immer'
|
||||||
import {
|
import {
|
||||||
RiDeleteBinLine,
|
RiDeleteBinLine,
|
||||||
|
RiEqualizer2Line,
|
||||||
RiHammerFill,
|
RiHammerFill,
|
||||||
|
RiInformation2Line,
|
||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
import { useFormattingChangedDispatcher } from '../../../debug/hooks'
|
import { useFormattingChangedDispatcher } from '../../../debug/hooks'
|
||||||
import SettingBuiltInTool from './setting-built-in-tool'
|
import SettingBuiltInTool from './setting-built-in-tool'
|
||||||
import cn from '@/utils/classnames'
|
|
||||||
import Panel from '@/app/components/app/configuration/base/feature-panel'
|
import Panel from '@/app/components/app/configuration/base/feature-panel'
|
||||||
import { InfoCircle } from '@/app/components/base/icons/src/vender/line/general'
|
|
||||||
import OperationBtn from '@/app/components/app/configuration/base/operation-btn'
|
import OperationBtn from '@/app/components/app/configuration/base/operation-btn'
|
||||||
import AppIcon from '@/app/components/base/app-icon'
|
import AppIcon from '@/app/components/base/app-icon'
|
||||||
|
import Button from '@/app/components/base/button'
|
||||||
|
import Indicator from '@/app/components/header/indicator'
|
||||||
import Switch from '@/app/components/base/switch'
|
import Switch from '@/app/components/base/switch'
|
||||||
|
import Toast from '@/app/components/base/toast'
|
||||||
import ConfigContext from '@/context/debug-configuration'
|
import ConfigContext from '@/context/debug-configuration'
|
||||||
import type { AgentTool } from '@/types/app'
|
import type { AgentTool } from '@/types/app'
|
||||||
import { type Collection, CollectionType } from '@/app/components/tools/types'
|
import { type Collection, CollectionType } from '@/app/components/tools/types'
|
||||||
@ -23,7 +27,12 @@ import { MAX_TOOLS_NUM } from '@/config'
|
|||||||
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
|
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import { DefaultToolIcon } from '@/app/components/base/icons/src/public/other'
|
import { DefaultToolIcon } from '@/app/components/base/icons/src/public/other'
|
||||||
import AddToolModal from '@/app/components/tools/add-tool-modal'
|
// import AddToolModal from '@/app/components/tools/add-tool-modal'
|
||||||
|
import ConfigCredential from '@/app/components/tools/setting/build-in/config-credentials'
|
||||||
|
import { updateBuiltInToolCredential } from '@/service/tools'
|
||||||
|
import cn from '@/utils/classnames'
|
||||||
|
import ToolPicker from '@/app/components/workflow/block-selector/tool-picker'
|
||||||
|
import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
|
||||||
|
|
||||||
type AgentToolWithMoreInfo = AgentTool & { icon: any; collection?: Collection } | null
|
type AgentToolWithMoreInfo = AgentTool & { icon: any; collection?: Collection } | null
|
||||||
const AgentTools: FC = () => {
|
const AgentTools: FC = () => {
|
||||||
@ -33,7 +42,13 @@ const AgentTools: FC = () => {
|
|||||||
const formattingChangedDispatcher = useFormattingChangedDispatcher()
|
const formattingChangedDispatcher = useFormattingChangedDispatcher()
|
||||||
|
|
||||||
const [currentTool, setCurrentTool] = useState<AgentToolWithMoreInfo>(null)
|
const [currentTool, setCurrentTool] = useState<AgentToolWithMoreInfo>(null)
|
||||||
|
const currentCollection = useMemo(() => {
|
||||||
|
if (!currentTool) return null
|
||||||
|
const collection = collectionList.find(collection => collection.id === currentTool?.provider_id && collection.type === currentTool?.provider_type)
|
||||||
|
return collection
|
||||||
|
}, [currentTool, collectionList])
|
||||||
const [isShowSettingTool, setIsShowSettingTool] = useState(false)
|
const [isShowSettingTool, setIsShowSettingTool] = useState(false)
|
||||||
|
const [isShowSettingAuth, setShowSettingAuth] = useState(false)
|
||||||
const tools = (modelConfig?.agentConfig?.tools as AgentTool[] || []).map((item) => {
|
const tools = (modelConfig?.agentConfig?.tools as AgentTool[] || []).map((item) => {
|
||||||
const collection = collectionList.find(collection => collection.id === item.provider_id && collection.type === item.provider_type)
|
const collection = collectionList.find(collection => collection.id === item.provider_id && collection.type === item.provider_type)
|
||||||
const icon = collection?.icon
|
const icon = collection?.icon
|
||||||
@ -55,10 +70,39 @@ const AgentTools: FC = () => {
|
|||||||
formattingChangedDispatcher()
|
formattingChangedDispatcher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleToolAuthSetting = (value: any) => {
|
||||||
|
const newModelConfig = produce(modelConfig, (draft) => {
|
||||||
|
const tool = (draft.agentConfig.tools).find((item: any) => item.provider_id === value?.collection?.id && item.tool_name === value?.tool_name)
|
||||||
|
if (tool)
|
||||||
|
(tool as AgentTool).notAuthor = false
|
||||||
|
})
|
||||||
|
setModelConfig(newModelConfig)
|
||||||
|
setIsShowSettingTool(false)
|
||||||
|
formattingChangedDispatcher()
|
||||||
|
}
|
||||||
|
|
||||||
|
const [isDeleting, setIsDeleting] = useState<number>(-1)
|
||||||
|
|
||||||
|
const handleSelectTool = (tool: ToolDefaultValue) => {
|
||||||
|
const newModelConfig = produce(modelConfig, (draft) => {
|
||||||
|
draft.agentConfig.tools.push({
|
||||||
|
provider_id: tool.provider_id,
|
||||||
|
provider_type: tool.provider_type as CollectionType,
|
||||||
|
provider_name: tool.provider_name,
|
||||||
|
tool_name: tool.tool_name,
|
||||||
|
tool_label: tool.tool_label,
|
||||||
|
tool_parameters: tool.params,
|
||||||
|
notAuthor: !tool.is_team_authorization,
|
||||||
|
enabled: true,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
setModelConfig(newModelConfig)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Panel
|
<Panel
|
||||||
className="mt-2"
|
className={cn('mt-2', tools.length === 0 && 'pb-2')}
|
||||||
noBodySpacing={tools.length === 0}
|
noBodySpacing={tools.length === 0}
|
||||||
headerIcon={
|
headerIcon={
|
||||||
<RiHammerFill className='w-4 h-4 text-primary-500' />
|
<RiHammerFill className='w-4 h-4 text-primary-500' />
|
||||||
@ -81,7 +125,14 @@ const AgentTools: FC = () => {
|
|||||||
{tools.length < MAX_TOOLS_NUM && (
|
{tools.length < MAX_TOOLS_NUM && (
|
||||||
<>
|
<>
|
||||||
<div className='ml-3 mr-1 h-3.5 w-px bg-gray-200'></div>
|
<div className='ml-3 mr-1 h-3.5 w-px bg-gray-200'></div>
|
||||||
<OperationBtn type="add" onClick={() => setIsShowChooseTool(true)} />
|
<ToolPicker
|
||||||
|
trigger={<OperationBtn type="add" />}
|
||||||
|
isShow={isShowChooseTool}
|
||||||
|
onShowChange={setIsShowChooseTool}
|
||||||
|
disabled={false}
|
||||||
|
supportAddCustomTool
|
||||||
|
onSelect={handleSelectTool}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -90,72 +141,78 @@ const AgentTools: FC = () => {
|
|||||||
<div className='grid gap-1 grid-cols-1 2xl:grid-cols-2 items-center flex-wrap justify-between'>
|
<div className='grid gap-1 grid-cols-1 2xl:grid-cols-2 items-center flex-wrap justify-between'>
|
||||||
{tools.map((item: AgentTool & { icon: any; collection?: Collection }, index) => (
|
{tools.map((item: AgentTool & { icon: any; collection?: Collection }, index) => (
|
||||||
<div key={index}
|
<div key={index}
|
||||||
className={cn((item.isDeleted || item.notAuthor) ? 'bg-white/50' : 'bg-white', (item.enabled && !item.isDeleted && !item.notAuthor) && 'shadow-xs', index > 1 && 'mt-1', 'group relative flex justify-between items-center last-of-type:mb-0 pl-2.5 py-2 pr-3 w-full rounded-lg border-[0.5px] border-gray-200 ')}
|
className={cn(
|
||||||
|
'group relative flex justify-between items-center last-of-type:mb-0 p-1.5 pr-2 w-full bg-components-panel-on-panel-item-bg rounded-lg border-[0.5px] border-components-panel-border-subtle shadow-xs hover:bg-components-panel-on-panel-item-bg-hover hover:shadow-sm cursor',
|
||||||
|
isDeleting === index && 'hover:bg-state-destructive-hover border-state-destructive-border',
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<div className='grow w-0 flex items-center'>
|
<div className='grow w-0 flex items-center'>
|
||||||
{(item.isDeleted || item.notAuthor)
|
{item.isDeleted && <DefaultToolIcon className='w-5 h-5' />}
|
||||||
? (
|
{!item.isDeleted && (
|
||||||
<DefaultToolIcon className='w-6 h-6' />
|
<div className={cn((item.notAuthor || !item.enabled) && 'opacity-50')}>
|
||||||
)
|
{typeof item.icon === 'string' && <div className='w-5 h-5 bg-cover bg-center rounded-md' style={{ backgroundImage: `url(${item.icon})` }} />}
|
||||||
: (
|
{typeof item.icon !== 'string' && <AppIcon className='rounded-md' size='xs' icon={item.icon?.content} background={item.icon?.background} />}
|
||||||
typeof item.icon === 'string'
|
</div>
|
||||||
? (
|
)}
|
||||||
<div
|
<div
|
||||||
className='w-6 h-6 bg-cover bg-center rounded-md'
|
className={cn(
|
||||||
style={{
|
'grow w-0 ml-1.5 flex items-center system-xs-regular truncate',
|
||||||
backgroundImage: `url(${item.icon})`,
|
item.isDeleted ? 'line-through' : '',
|
||||||
}}
|
(item.isDeleted || item.notAuthor || !item.enabled) ? 'opacity-50' : '',
|
||||||
></div>
|
)}
|
||||||
)
|
|
||||||
: (
|
|
||||||
<AppIcon
|
|
||||||
className='rounded-md'
|
|
||||||
size='tiny'
|
|
||||||
icon={item.icon?.content}
|
|
||||||
background={item.icon?.background}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
<div
|
|
||||||
className={cn((item.isDeleted || item.notAuthor) ? 'line-through opacity-50' : '', 'grow w-0 ml-2 leading-[18px] text-[13px] font-medium text-gray-800 truncate')}
|
|
||||||
>
|
>
|
||||||
<span className='text-gray-800 pr-2'>{item.provider_type === CollectionType.builtIn ? item.provider_name : item.tool_label}</span>
|
<span className='text-text-secondary pr-1.5'>{item.provider_type === CollectionType.builtIn ? item.provider_name : item.tool_label}</span>
|
||||||
|
<span className='text-text-tertiary'>{item.tool_name}</span>
|
||||||
|
{!item.isDeleted && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={t('tools.toolNameUsageTip')}
|
needsDelay
|
||||||
|
popupContent={
|
||||||
|
<div className='w-[180px]'>
|
||||||
|
<div className='mb-1.5 text-text-secondary'>{item.tool_name}</div>
|
||||||
|
<div className='mb-1.5 text-text-tertiary'>{t('tools.toolNameUsageTip')}</div>
|
||||||
|
<div className='text-text-accent cursor-pointer' onClick={() => copy(item.tool_name)}>{t('tools.copyToolName')}</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<span className='text-gray-500'>{item.tool_name}</span>
|
<div className='w-4 h-4'>
|
||||||
|
<div className='hidden group-hover:inline-block ml-0.5'>
|
||||||
|
<RiInformation2Line className='w-4 h-4 text-text-tertiary' />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='shrink-0 ml-1 flex items-center'>
|
<div className='shrink-0 ml-1 flex items-center'>
|
||||||
{(item.isDeleted || item.notAuthor)
|
{item.isDeleted && (
|
||||||
? (
|
<div className='flex items-center mr-2'>
|
||||||
<div className='flex items-center'>
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={t(`tools.${item.isDeleted ? 'toolRemoved' : 'notAuthorized'}`)}
|
popupContent={t('tools.toolRemoved')}
|
||||||
needsDelay
|
needsDelay
|
||||||
>
|
>
|
||||||
<div className='mr-1 p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => {
|
<div className='mr-1 p-1 rounded-md hover:bg-black/5 cursor-pointer'>
|
||||||
if (item.notAuthor)
|
|
||||||
setIsShowChooseTool(true)
|
|
||||||
}}>
|
|
||||||
<AlertTriangle className='w-4 h-4 text-[#F79009]' />
|
<AlertTriangle className='w-4 h-4 text-[#F79009]' />
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
<div
|
||||||
<div className='p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => {
|
className='p-1 rounded-md text-text-tertiary cursor-pointer hover:text-text-destructive'
|
||||||
|
onClick={() => {
|
||||||
const newModelConfig = produce(modelConfig, (draft) => {
|
const newModelConfig = produce(modelConfig, (draft) => {
|
||||||
draft.agentConfig.tools.splice(index, 1)
|
draft.agentConfig.tools.splice(index, 1)
|
||||||
})
|
})
|
||||||
setModelConfig(newModelConfig)
|
setModelConfig(newModelConfig)
|
||||||
formattingChangedDispatcher()
|
formattingChangedDispatcher()
|
||||||
}}>
|
}}
|
||||||
<RiDeleteBinLine className='w-4 h-4 text-gray-500' />
|
onMouseOver={() => setIsDeleting(index)}
|
||||||
|
onMouseLeave={() => setIsDeleting(-1)}
|
||||||
|
>
|
||||||
|
<RiDeleteBinLine className='w-4 h-4' />
|
||||||
</div>
|
</div>
|
||||||
<div className='ml-2 mr-3 w-px h-3.5 bg-gray-200'></div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)}
|
||||||
: (
|
{!item.isDeleted && (
|
||||||
<div className='hidden group-hover:flex items-center'>
|
<div className='hidden group-hover:flex items-center gap-1 mr-2'>
|
||||||
|
{!item.notAuthor && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={t('tools.setBuiltInTools.infoAndSetting')}
|
popupContent={t('tools.setBuiltInTools.infoAndSetting')}
|
||||||
needsDelay
|
needsDelay
|
||||||
@ -164,26 +221,31 @@ const AgentTools: FC = () => {
|
|||||||
setCurrentTool(item)
|
setCurrentTool(item)
|
||||||
setIsShowSettingTool(true)
|
setIsShowSettingTool(true)
|
||||||
}}>
|
}}>
|
||||||
<InfoCircle className='w-4 h-4 text-gray-500' />
|
<RiEqualizer2Line className='w-4 h-4 text-text-tertiary' />
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
)}
|
||||||
<div className='p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => {
|
<div
|
||||||
|
className='p-1 rounded-md text-text-tertiary cursor-pointer hover:text-text-destructive'
|
||||||
|
onClick={() => {
|
||||||
const newModelConfig = produce(modelConfig, (draft) => {
|
const newModelConfig = produce(modelConfig, (draft) => {
|
||||||
draft.agentConfig.tools.splice(index, 1)
|
draft.agentConfig.tools.splice(index, 1)
|
||||||
})
|
})
|
||||||
setModelConfig(newModelConfig)
|
setModelConfig(newModelConfig)
|
||||||
formattingChangedDispatcher()
|
formattingChangedDispatcher()
|
||||||
}}>
|
}}
|
||||||
<RiDeleteBinLine className='w-4 h-4 text-gray-500' />
|
onMouseOver={() => setIsDeleting(index)}
|
||||||
|
onMouseLeave={() => setIsDeleting(-1)}
|
||||||
|
>
|
||||||
|
<RiDeleteBinLine className='w-4 h-4' />
|
||||||
</div>
|
</div>
|
||||||
<div className='ml-2 mr-3 w-px h-3.5 bg-gray-200'></div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={cn((item.isDeleted || item.notAuthor) && 'opacity-50')}>
|
<div className={cn(item.isDeleted && 'opacity-50')}>
|
||||||
|
{!item.notAuthor && (
|
||||||
<Switch
|
<Switch
|
||||||
defaultValue={(item.isDeleted || item.notAuthor) ? false : item.enabled}
|
defaultValue={item.isDeleted ? false : item.enabled}
|
||||||
disabled={(item.isDeleted || item.notAuthor)}
|
disabled={item.isDeleted}
|
||||||
size='md'
|
size='md'
|
||||||
onChange={(enabled) => {
|
onChange={(enabled) => {
|
||||||
const newModelConfig = produce(modelConfig, (draft) => {
|
const newModelConfig = produce(modelConfig, (draft) => {
|
||||||
@ -192,17 +254,23 @@ const AgentTools: FC = () => {
|
|||||||
setModelConfig(newModelConfig)
|
setModelConfig(newModelConfig)
|
||||||
formattingChangedDispatcher()
|
formattingChangedDispatcher()
|
||||||
}} />
|
}} />
|
||||||
|
)}
|
||||||
|
{item.notAuthor && (
|
||||||
|
<Button variant='secondary' size='small' onClick={() => {
|
||||||
|
setCurrentTool(item)
|
||||||
|
setShowSettingAuth(true)
|
||||||
|
}}>
|
||||||
|
{t('tools.notAuthorized')}
|
||||||
|
<Indicator className='ml-2' color='orange' />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div >
|
</div >
|
||||||
</Panel >
|
</Panel >
|
||||||
{isShowChooseTool && (
|
{isShowSettingTool && (
|
||||||
<AddToolModal onHide={() => setIsShowChooseTool(false)} />
|
|
||||||
)}
|
|
||||||
{
|
|
||||||
isShowSettingTool && (
|
|
||||||
<SettingBuiltInTool
|
<SettingBuiltInTool
|
||||||
toolName={currentTool?.tool_name as string}
|
toolName={currentTool?.tool_name as string}
|
||||||
setting={currentTool?.tool_parameters as any}
|
setting={currentTool?.tool_parameters as any}
|
||||||
@ -211,8 +279,23 @@ const AgentTools: FC = () => {
|
|||||||
isModel={currentTool?.collection?.type === CollectionType.model}
|
isModel={currentTool?.collection?.type === CollectionType.model}
|
||||||
onSave={handleToolSettingChange}
|
onSave={handleToolSettingChange}
|
||||||
onHide={() => setIsShowSettingTool(false)}
|
onHide={() => setIsShowSettingTool(false)}
|
||||||
/>)
|
/>
|
||||||
}
|
)}
|
||||||
|
{isShowSettingAuth && (
|
||||||
|
<ConfigCredential
|
||||||
|
collection={currentCollection as any}
|
||||||
|
onCancel={() => setShowSettingAuth(false)}
|
||||||
|
onSaved={async (value) => {
|
||||||
|
await updateBuiltInToolCredential((currentCollection as any).name, value)
|
||||||
|
Toast.notify({
|
||||||
|
type: 'success',
|
||||||
|
message: t('common.api.actionSuccess'),
|
||||||
|
})
|
||||||
|
handleToolAuthSetting(currentTool as any)
|
||||||
|
setShowSettingAuth(false)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3,21 +3,30 @@ import type { FC } from 'react'
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useContext } from 'use-context-selector'
|
import { useContext } from 'use-context-selector'
|
||||||
import cn from '@/utils/classnames'
|
import {
|
||||||
import Drawer from '@/app/components/base/drawer-plus'
|
RiArrowLeftLine,
|
||||||
|
RiCloseLine,
|
||||||
|
} from '@remixicon/react'
|
||||||
|
import Drawer from '@/app/components/base/drawer'
|
||||||
|
import Loading from '@/app/components/base/loading'
|
||||||
|
import ActionButton from '@/app/components/base/action-button'
|
||||||
|
import Icon from '@/app/components/plugins/card/base/card-icon'
|
||||||
|
import OrgInfo from '@/app/components/plugins/card/base/org-info'
|
||||||
|
import Description from '@/app/components/plugins/card/base/description'
|
||||||
|
import TabSlider from '@/app/components/base/tab-slider-plain'
|
||||||
|
|
||||||
|
import Button from '@/app/components/base/button'
|
||||||
import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
|
import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
|
||||||
import { addDefaultValue, toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
|
import { addDefaultValue, toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
|
||||||
import type { Collection, Tool } from '@/app/components/tools/types'
|
import type { Collection, Tool } from '@/app/components/tools/types'
|
||||||
import { CollectionType } from '@/app/components/tools/types'
|
import { CollectionType } from '@/app/components/tools/types'
|
||||||
import { fetchBuiltInToolList, fetchCustomToolList, fetchModelToolList, fetchWorkflowToolList } from '@/service/tools'
|
import { fetchBuiltInToolList, fetchCustomToolList, fetchModelToolList, fetchWorkflowToolList } from '@/service/tools'
|
||||||
import I18n from '@/context/i18n'
|
import I18n from '@/context/i18n'
|
||||||
import Button from '@/app/components/base/button'
|
|
||||||
import Loading from '@/app/components/base/loading'
|
|
||||||
import { DiagonalDividingLine } from '@/app/components/base/icons/src/public/common'
|
|
||||||
import { getLanguage } from '@/i18n/language'
|
import { getLanguage } from '@/i18n/language'
|
||||||
import AppIcon from '@/app/components/base/app-icon'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
|
showBackButton?: boolean
|
||||||
collection: Collection
|
collection: Collection
|
||||||
isBuiltIn?: boolean
|
isBuiltIn?: boolean
|
||||||
isModel?: boolean
|
isModel?: boolean
|
||||||
@ -29,6 +38,7 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const SettingBuiltInTool: FC<Props> = ({
|
const SettingBuiltInTool: FC<Props> = ({
|
||||||
|
showBackButton = false,
|
||||||
collection,
|
collection,
|
||||||
isBuiltIn = true,
|
isBuiltIn = true,
|
||||||
isModel = true,
|
isModel = true,
|
||||||
@ -97,39 +107,26 @@ const SettingBuiltInTool: FC<Props> = ({
|
|||||||
})()
|
})()
|
||||||
|
|
||||||
const infoUI = (
|
const infoUI = (
|
||||||
<div className='pt-2'>
|
<div className=''>
|
||||||
<div className='leading-5 text-sm font-medium text-gray-900'>
|
|
||||||
{t('tools.setBuiltInTools.toolDescription')}
|
|
||||||
</div>
|
|
||||||
<div className='mt-1 leading-[18px] text-xs font-normal text-gray-600'>
|
|
||||||
{currTool?.description[language]}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{infoSchemas.length > 0 && (
|
{infoSchemas.length > 0 && (
|
||||||
<div className='mt-6'>
|
<div className='py-2 space-y-1'>
|
||||||
<div className='flex items-center mb-4 leading-[18px] text-xs font-semibold text-gray-500 uppercase'>
|
|
||||||
<div className='mr-3'>{t('tools.setBuiltInTools.parameters')}</div>
|
|
||||||
<div className='grow w-0 h-px bg-[#f3f4f6]'></div>
|
|
||||||
</div>
|
|
||||||
<div className='space-y-4'>
|
|
||||||
{infoSchemas.map((item: any, index) => (
|
{infoSchemas.map((item: any, index) => (
|
||||||
<div key={index}>
|
<div key={index} className='py-1'>
|
||||||
<div className='flex items-center space-x-2 leading-[18px]'>
|
<div className='flex items-center gap-2'>
|
||||||
<div className='text-[13px] font-semibold text-gray-900'>{item.label[language]}</div>
|
<div className='text-text-secondary code-sm-semibold'>{item.label[language]}</div>
|
||||||
<div className='text-xs font-medium text-gray-500'>{item.type === 'number-input' ? t('tools.setBuiltInTools.number') : t('tools.setBuiltInTools.string')}</div>
|
<div className='text-text-tertiary system-xs-regular'>{item.type === 'number-input' ? t('tools.setBuiltInTools.number') : t('tools.setBuiltInTools.string')}</div>
|
||||||
{item.required && (
|
{item.required && (
|
||||||
<div className='text-xs font-medium text-[#EC4A0A]'>{t('tools.setBuiltInTools.required')}</div>
|
<div className='text-text-warning-secondary system-xs-medium'>{t('tools.setBuiltInTools.required')}</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{item.human_description && (
|
{item.human_description && (
|
||||||
<div className='mt-1 leading-[18px] text-xs font-normal text-gray-600'>
|
<div className='mt-0.5 text-text-tertiary system-xs-regular'>
|
||||||
{item.human_description?.[language]}
|
{item.human_description?.[language]}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -149,61 +146,68 @@ const SettingBuiltInTool: FC<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer
|
||||||
isShow
|
isOpen
|
||||||
onHide={onHide}
|
clickOutsideNotOpen={false}
|
||||||
title={(
|
onClose={onHide}
|
||||||
<div className='flex items-center'>
|
footer={null}
|
||||||
{typeof collection.icon === 'string'
|
mask={false}
|
||||||
? (
|
positionCenter={false}
|
||||||
|
panelClassname={cn('justify-start mt-[64px] mr-2 mb-2 !w-[420px] !max-w-[420px] !p-0 !bg-components-panel-bg rounded-2xl border-[0.5px] border-components-panel-border shadow-xl')}
|
||||||
|
>
|
||||||
|
<>
|
||||||
|
{isLoading && <Loading type='app' />}
|
||||||
|
{!isLoading && (
|
||||||
|
<>
|
||||||
|
{/* header */}
|
||||||
|
<div className='relative p-4 pb-3 border-b border-divider-subtle'>
|
||||||
|
<div className='absolute top-3 right-3'>
|
||||||
|
<ActionButton onClick={onHide}>
|
||||||
|
<RiCloseLine className='w-4 h-4' />
|
||||||
|
</ActionButton>
|
||||||
|
</div>
|
||||||
|
{showBackButton && (
|
||||||
<div
|
<div
|
||||||
className='w-6 h-6 bg-cover bg-center rounded-md flex-shrink-0'
|
className='mb-2 flex items-center gap-1 text-text-accent-secondary system-xs-semibold-uppercase cursor-pointer'
|
||||||
style={{
|
onClick={onHide}
|
||||||
backgroundImage: `url(${collection.icon})`,
|
>
|
||||||
}}
|
<RiArrowLeftLine className='w-4 h-4' />
|
||||||
></div>
|
BACK
|
||||||
)
|
</div>
|
||||||
: (
|
)}
|
||||||
<AppIcon
|
<div className='flex items-center gap-1'>
|
||||||
className='rounded-md'
|
<Icon size='tiny' className='w-6 h-6' src={collection.icon} />
|
||||||
size='tiny'
|
<OrgInfo
|
||||||
icon={(collection.icon as any)?.content}
|
packageNameClassName='w-auto'
|
||||||
background={(collection.icon as any)?.background}
|
orgName={collection.author}
|
||||||
|
packageName={collection.name}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='mt-1 text-text-primary system-md-semibold'>{currTool?.label[language]}</div>
|
||||||
|
{!!currTool?.description[language] && (
|
||||||
|
<Description className='mt-3' text={currTool.description[language]} descriptionLineRows={2}></Description>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className='ml-2 leading-6 text-base font-semibold text-gray-900'>{currTool?.label[language]}</div>
|
|
||||||
{(hasSetting && !readonly) && (<>
|
|
||||||
<DiagonalDividingLine className='mx-4' />
|
|
||||||
<div className='flex space-x-6'>
|
|
||||||
<div
|
|
||||||
className={cn(isInfoActive ? 'text-gray-900 font-semibold' : 'font-normal text-gray-600 cursor-pointer', 'relative text-base')}
|
|
||||||
onClick={() => setCurrType('info')}
|
|
||||||
>
|
|
||||||
{t('tools.setBuiltInTools.info')}
|
|
||||||
{isInfoActive && <div className='absolute left-0 bottom-[-16px] w-full h-0.5 bg-primary-600'></div>}
|
|
||||||
</div>
|
|
||||||
<div className={cn(!isInfoActive ? 'text-gray-900 font-semibold' : 'font-normal text-gray-600 cursor-pointer', 'relative text-base ')}
|
|
||||||
onClick={() => setCurrType('setting')}
|
|
||||||
>
|
|
||||||
{t('tools.setBuiltInTools.setting')}
|
|
||||||
{!isInfoActive && <div className='absolute left-0 bottom-[-16px] w-full h-0.5 bg-primary-600'></div>}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>)}
|
|
||||||
</div>
|
</div>
|
||||||
|
{/* form */}
|
||||||
|
<div className='h-full'>
|
||||||
|
<div className='flex flex-col h-full'>
|
||||||
|
{(hasSetting && !readonly) ? (
|
||||||
|
<TabSlider
|
||||||
|
className='shrink-0 mt-1 px-4'
|
||||||
|
itemClassName='py-3'
|
||||||
|
noBorderBottom
|
||||||
|
value={currType}
|
||||||
|
onChange={(value) => {
|
||||||
|
setCurrType(value)
|
||||||
|
}}
|
||||||
|
options={[
|
||||||
|
{ value: 'info', text: t('tools.setBuiltInTools.parameters')! },
|
||||||
|
{ value: 'setting', text: t('tools.setBuiltInTools.setting')! },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className='p-4 pb-1 text-text-primary system-sm-semibold-uppercase'>{t('tools.setBuiltInTools.parameters')}</div>
|
||||||
)}
|
)}
|
||||||
panelClassName='mt-[65px] !w-[405px]'
|
<div className='grow h-0 overflow-y-auto px-4'>
|
||||||
maxWidthClassName='!max-w-[405px]'
|
|
||||||
height='calc(100vh - 65px)'
|
|
||||||
headerClassName='!border-b-black/5'
|
|
||||||
body={
|
|
||||||
<div className='h-full pt-3'>
|
|
||||||
{isLoading
|
|
||||||
? <div className='flex h-full items-center'>
|
|
||||||
<Loading type='app' />
|
|
||||||
</div>
|
|
||||||
: (<div className='flex flex-col h-full'>
|
|
||||||
<div className='grow h-0 overflow-y-auto px-6'>
|
|
||||||
{isInfoActive ? infoUI : settingUI}
|
{isInfoActive ? infoUI : settingUI}
|
||||||
</div>
|
</div>
|
||||||
{!readonly && !isInfoActive && (
|
{!readonly && !isInfoActive && (
|
||||||
@ -212,12 +216,12 @@ const SettingBuiltInTool: FC<Props> = ({
|
|||||||
<Button className='flex items-center h-8 !px-3 !text-[13px] font-medium' variant='primary' disabled={!isValid} onClick={() => onSave?.(addDefaultValue(tempSetting, formSchemas))}>{t('common.operation.save')}</Button>
|
<Button className='flex items-center h-8 !px-3 !text-[13px] font-medium' variant='primary' disabled={!isValid} onClick={() => onSave?.(addDefaultValue(tempSetting, formSchemas))}>{t('common.operation.save')}</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>)}
|
|
||||||
</div>
|
</div>
|
||||||
}
|
</div>
|
||||||
isShowMask={false}
|
</>
|
||||||
clickOutsideNotOpen={false}
|
)}
|
||||||
/>
|
</>
|
||||||
|
</Drawer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
export default React.memo(SettingBuiltInTool)
|
export default React.memo(SettingBuiltInTool)
|
||||||
|
@ -38,7 +38,7 @@ import ModelName from '@/app/components/header/account-setting/model-provider-pa
|
|||||||
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||||
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||||
|
|
||||||
export type IGetAutomaticResProps = {
|
export interface IGetAutomaticResProps {
|
||||||
mode: AppType
|
mode: AppType
|
||||||
model: Model
|
model: Model
|
||||||
isShow: boolean
|
isShow: boolean
|
||||||
|
@ -11,7 +11,7 @@ import AgentTools from './agent/agent-tools'
|
|||||||
import ConfigContext from '@/context/debug-configuration'
|
import ConfigContext from '@/context/debug-configuration'
|
||||||
import ConfigPrompt from '@/app/components/app/configuration/config-prompt'
|
import ConfigPrompt from '@/app/components/app/configuration/config-prompt'
|
||||||
import ConfigVar from '@/app/components/app/configuration/config-var'
|
import ConfigVar from '@/app/components/app/configuration/config-var'
|
||||||
import { type ModelConfig, type PromptVariable } from '@/models/debug'
|
import type { ModelConfig, PromptVariable } from '@/models/debug'
|
||||||
import type { AppType } from '@/types/app'
|
import type { AppType } from '@/types/app'
|
||||||
import { ModelModeType } from '@/types/app'
|
import { ModelModeType } from '@/types/app'
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ import { useSelectedDatasetsMode } from '@/app/components/workflow/nodes/knowled
|
|||||||
import Switch from '@/app/components/base/switch'
|
import Switch from '@/app/components/base/switch'
|
||||||
import Toast from '@/app/components/base/toast'
|
import Toast from '@/app/components/base/toast'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
datasetConfigs: DatasetConfigs
|
datasetConfigs: DatasetConfigs
|
||||||
onChange: (configs: DatasetConfigs, isRetrievalModeChange?: boolean) => void
|
onChange: (configs: DatasetConfigs, isRetrievalModeChange?: boolean) => void
|
||||||
isInWorkflow?: boolean
|
isInWorkflow?: boolean
|
||||||
|
@ -19,7 +19,7 @@ import {
|
|||||||
getMultipleRetrievalConfig,
|
getMultipleRetrievalConfig,
|
||||||
} from '@/app/components/workflow/nodes/knowledge-retrieval/utils'
|
} from '@/app/components/workflow/nodes/knowledge-retrieval/utils'
|
||||||
|
|
||||||
type ParamsConfigProps = {
|
interface ParamsConfigProps {
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
selectedDatasets: DataSet[]
|
selectedDatasets: DataSet[]
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ import { ModelTypeEnum } from '@/app/components/header/account-setting/model-pro
|
|||||||
import { fetchMembers } from '@/service/common'
|
import { fetchMembers } from '@/service/common'
|
||||||
import type { Member } from '@/models/common'
|
import type { Member } from '@/models/common'
|
||||||
|
|
||||||
type SettingsModalProps = {
|
interface SettingsModalProps {
|
||||||
currentDataset: DataSet
|
currentDataset: DataSet
|
||||||
onCancel: () => void
|
onCancel: () => void
|
||||||
onSave: (newDataset: DataSet) => void
|
onSave: (newDataset: DataSet) => void
|
||||||
|
@ -30,7 +30,7 @@ import { ModelFeatureEnum } from '@/app/components/header/account-setting/model-
|
|||||||
import { useFeatures } from '@/app/components/base/features/hooks'
|
import { useFeatures } from '@/app/components/base/features/hooks'
|
||||||
import type { InputForm } from '@/app/components/base/chat/chat/type'
|
import type { InputForm } from '@/app/components/base/chat/chat/type'
|
||||||
|
|
||||||
type ChatItemProps = {
|
interface ChatItemProps {
|
||||||
modelAndParameter: ModelAndParameter
|
modelAndParameter: ModelAndParameter
|
||||||
}
|
}
|
||||||
const ChatItem: FC<ChatItemProps> = ({
|
const ChatItem: FC<ChatItemProps> = ({
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { createContext, useContext } from 'use-context-selector'
|
|
||||||
import type { ModelAndParameter } from '../types'
|
import type { ModelAndParameter } from '../types'
|
||||||
|
import { createSelectorCtx } from '@/utils/context'
|
||||||
|
|
||||||
export type DebugWithMultipleModelContextType = {
|
export type DebugWithMultipleModelContextType = {
|
||||||
multipleModelConfigs: ModelAndParameter[]
|
multipleModelConfigs: ModelAndParameter[]
|
||||||
@ -9,13 +9,9 @@ export type DebugWithMultipleModelContextType = {
|
|||||||
onDebugWithMultipleModelChange: (singleModelConfig: ModelAndParameter) => void
|
onDebugWithMultipleModelChange: (singleModelConfig: ModelAndParameter) => void
|
||||||
checkCanSend?: () => boolean
|
checkCanSend?: () => boolean
|
||||||
}
|
}
|
||||||
const DebugWithMultipleModelContext = createContext<DebugWithMultipleModelContextType>({
|
const [,useDebugWithMultipleModelContext, DebugWithMultipleModelContext] = createSelectorCtx<DebugWithMultipleModelContextType>()
|
||||||
multipleModelConfigs: [],
|
|
||||||
onMultipleModelConfigsChange: () => {},
|
|
||||||
onDebugWithMultipleModelChange: () => {},
|
|
||||||
})
|
|
||||||
|
|
||||||
export const useDebugWithMultipleModelContext = () => useContext(DebugWithMultipleModelContext)
|
export { useDebugWithMultipleModelContext }
|
||||||
|
|
||||||
type DebugWithMultipleModelContextProviderProps = {
|
type DebugWithMultipleModelContextProviderProps = {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
|
@ -15,7 +15,7 @@ import { useEventEmitterContextContext } from '@/context/event-emitter'
|
|||||||
import { useProviderContext } from '@/context/provider-context'
|
import { useProviderContext } from '@/context/provider-context'
|
||||||
import { useFeatures } from '@/app/components/base/features/hooks'
|
import { useFeatures } from '@/app/components/base/features/hooks'
|
||||||
|
|
||||||
type TextGenerationItemProps = {
|
interface TextGenerationItemProps {
|
||||||
modelAndParameter: ModelAndParameter
|
modelAndParameter: ModelAndParameter
|
||||||
}
|
}
|
||||||
const TextGenerationItem: FC<TextGenerationItemProps> = ({
|
const TextGenerationItem: FC<TextGenerationItemProps> = ({
|
||||||
|
@ -27,10 +27,10 @@ import { useFeatures } from '@/app/components/base/features/hooks'
|
|||||||
import { getLastAnswer } from '@/app/components/base/chat/utils'
|
import { getLastAnswer } from '@/app/components/base/chat/utils'
|
||||||
import type { InputForm } from '@/app/components/base/chat/chat/type'
|
import type { InputForm } from '@/app/components/base/chat/chat/type'
|
||||||
|
|
||||||
type DebugWithSingleModelProps = {
|
interface DebugWithSingleModelProps {
|
||||||
checkCanSend?: () => boolean
|
checkCanSend?: () => boolean
|
||||||
}
|
}
|
||||||
export type DebugWithSingleModelRefType = {
|
export interface DebugWithSingleModelRefType {
|
||||||
handleRestart: () => void
|
handleRestart: () => void
|
||||||
}
|
}
|
||||||
const DebugWithSingleModel = forwardRef<DebugWithSingleModelRefType, DebugWithSingleModelProps>(({
|
const DebugWithSingleModel = forwardRef<DebugWithSingleModelRefType, DebugWithSingleModelProps>(({
|
||||||
|
@ -48,7 +48,7 @@ import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
|||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||||
|
|
||||||
type IDebug = {
|
interface IDebug {
|
||||||
isAPIKeySet: boolean
|
isAPIKeySet: boolean
|
||||||
onSetting: () => void
|
onSetting: () => void
|
||||||
inputs: Inputs
|
inputs: Inputs
|
||||||
|
@ -59,7 +59,7 @@ import {
|
|||||||
useTextGenerationCurrentProviderAndModelAndModelList,
|
useTextGenerationCurrentProviderAndModelAndModelList,
|
||||||
} from '@/app/components/header/account-setting/model-provider-page/hooks'
|
} from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||||
import { fetchCollectionList } from '@/service/tools'
|
import { fetchCollectionList } from '@/service/tools'
|
||||||
import { type Collection } from '@/app/components/tools/types'
|
import type { Collection } from '@/app/components/tools/types'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
import {
|
import {
|
||||||
getMultipleRetrievalConfig,
|
getMultipleRetrievalConfig,
|
||||||
@ -71,6 +71,7 @@ import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
|
|||||||
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
|
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
|
||||||
import NewFeaturePanel from '@/app/components/base/features/new-feature-panel'
|
import NewFeaturePanel from '@/app/components/base/features/new-feature-panel'
|
||||||
import { fetchFileUploadConfig } from '@/service/common'
|
import { fetchFileUploadConfig } from '@/service/common'
|
||||||
|
import { correctProvider } from '@/utils'
|
||||||
|
|
||||||
type PublishConfig = {
|
type PublishConfig = {
|
||||||
modelConfig: ModelConfig
|
modelConfig: ModelConfig
|
||||||
@ -156,7 +157,7 @@ const Configuration: FC = () => {
|
|||||||
const setCompletionParams = (value: FormValue) => {
|
const setCompletionParams = (value: FormValue) => {
|
||||||
const params = { ...value }
|
const params = { ...value }
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
// eslint-disable-next-line ts/no-use-before-define
|
||||||
if ((!params.stop || params.stop.length === 0) && (modeModeTypeRef.current === ModelModeType.completion)) {
|
if ((!params.stop || params.stop.length === 0) && (modeModeTypeRef.current === ModelModeType.completion)) {
|
||||||
params.stop = getTempStop()
|
params.stop = getTempStop()
|
||||||
setTempStop([])
|
setTempStop([])
|
||||||
@ -165,7 +166,7 @@ const Configuration: FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [modelConfig, doSetModelConfig] = useState<ModelConfig>({
|
const [modelConfig, doSetModelConfig] = useState<ModelConfig>({
|
||||||
provider: 'openai',
|
provider: 'langgenius/openai/openai',
|
||||||
model_id: 'gpt-3.5-turbo',
|
model_id: 'gpt-3.5-turbo',
|
||||||
mode: ModelModeType.unset,
|
mode: ModelModeType.unset,
|
||||||
configs: {
|
configs: {
|
||||||
@ -188,7 +189,7 @@ const Configuration: FC = () => {
|
|||||||
|
|
||||||
const isAgent = mode === 'agent-chat'
|
const isAgent = mode === 'agent-chat'
|
||||||
|
|
||||||
const isOpenAI = modelConfig.provider === 'openai'
|
const isOpenAI = modelConfig.provider === 'langgenius/openai/openai'
|
||||||
|
|
||||||
const [collectionList, setCollectionList] = useState<Collection[]>([])
|
const [collectionList, setCollectionList] = useState<Collection[]>([])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -357,7 +358,7 @@ const Configuration: FC = () => {
|
|||||||
const [canReturnToSimpleMode, setCanReturnToSimpleMode] = useState(true)
|
const [canReturnToSimpleMode, setCanReturnToSimpleMode] = useState(true)
|
||||||
const setPromptMode = async (mode: PromptMode) => {
|
const setPromptMode = async (mode: PromptMode) => {
|
||||||
if (mode === PromptMode.advanced) {
|
if (mode === PromptMode.advanced) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
// eslint-disable-next-line ts/no-use-before-define
|
||||||
await migrateToDefaultPrompt()
|
await migrateToDefaultPrompt()
|
||||||
setCanReturnToSimpleMode(true)
|
setCanReturnToSimpleMode(true)
|
||||||
}
|
}
|
||||||
@ -542,8 +543,19 @@ const Configuration: FC = () => {
|
|||||||
if (modelConfig.retriever_resource)
|
if (modelConfig.retriever_resource)
|
||||||
setCitationConfig(modelConfig.retriever_resource)
|
setCitationConfig(modelConfig.retriever_resource)
|
||||||
|
|
||||||
if (modelConfig.annotation_reply)
|
if (modelConfig.annotation_reply) {
|
||||||
setAnnotationConfig(modelConfig.annotation_reply, true)
|
let annotationConfig = modelConfig.annotation_reply
|
||||||
|
if (modelConfig.annotation_reply.enabled) {
|
||||||
|
annotationConfig = {
|
||||||
|
...modelConfig.annotation_reply,
|
||||||
|
embedding_model: {
|
||||||
|
...modelConfig.annotation_reply.embedding_model,
|
||||||
|
embedding_provider_name: correctProvider(modelConfig.annotation_reply.embedding_model.embedding_provider_name),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setAnnotationConfig(annotationConfig, true)
|
||||||
|
}
|
||||||
|
|
||||||
if (modelConfig.sensitive_word_avoidance)
|
if (modelConfig.sensitive_word_avoidance)
|
||||||
setModerationConfig(modelConfig.sensitive_word_avoidance)
|
setModerationConfig(modelConfig.sensitive_word_avoidance)
|
||||||
@ -553,7 +565,7 @@ const Configuration: FC = () => {
|
|||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
modelConfig: {
|
modelConfig: {
|
||||||
provider: model.provider,
|
provider: correctProvider(model.provider),
|
||||||
model_id: model.name,
|
model_id: model.name,
|
||||||
mode: model.mode,
|
mode: model.mode,
|
||||||
configs: {
|
configs: {
|
||||||
@ -595,7 +607,6 @@ const Configuration: FC = () => {
|
|||||||
annotation_reply: modelConfig.annotation_reply,
|
annotation_reply: modelConfig.annotation_reply,
|
||||||
external_data_tools: modelConfig.external_data_tools,
|
external_data_tools: modelConfig.external_data_tools,
|
||||||
dataSets: datasets || [],
|
dataSets: datasets || [],
|
||||||
// eslint-disable-next-line multiline-ternary
|
|
||||||
agentConfig: res.mode === 'agent-chat' ? {
|
agentConfig: res.mode === 'agent-chat' ? {
|
||||||
max_iteration: DEFAULT_AGENT_SETTING.max_iteration,
|
max_iteration: DEFAULT_AGENT_SETTING.max_iteration,
|
||||||
...modelConfig.agent_mode,
|
...modelConfig.agent_mode,
|
||||||
@ -608,6 +619,10 @@ const Configuration: FC = () => {
|
|||||||
...tool,
|
...tool,
|
||||||
isDeleted: res.deleted_tools?.includes(tool.tool_name),
|
isDeleted: res.deleted_tools?.includes(tool.tool_name),
|
||||||
notAuthor: collectionList.find(c => tool.provider_id === c.id)?.is_team_authorization === false,
|
notAuthor: collectionList.find(c => tool.provider_id === c.id)?.is_team_authorization === false,
|
||||||
|
...(tool.provider_type === 'builtin' ? {
|
||||||
|
provider_id: correctProvider(tool.provider_name),
|
||||||
|
provider_name: correctProvider(tool.provider_name),
|
||||||
|
} : {}),
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
} : DEFAULT_AGENT_SETTING,
|
} : DEFAULT_AGENT_SETTING,
|
||||||
@ -625,6 +640,12 @@ const Configuration: FC = () => {
|
|||||||
retrieval_model: RETRIEVE_TYPE.multiWay,
|
retrieval_model: RETRIEVE_TYPE.multiWay,
|
||||||
...modelConfig.dataset_configs,
|
...modelConfig.dataset_configs,
|
||||||
...retrievalConfig,
|
...retrievalConfig,
|
||||||
|
...(retrievalConfig.reranking_model ? {
|
||||||
|
reranking_model: {
|
||||||
|
...retrievalConfig.reranking_model,
|
||||||
|
reranking_provider_name: correctProvider(modelConfig.dataset_configs.reranking_model.reranking_provider_name),
|
||||||
|
},
|
||||||
|
} : {}),
|
||||||
})
|
})
|
||||||
setHasFetchedDetail(true)
|
setHasFetchedDetail(true)
|
||||||
})
|
})
|
||||||
|
@ -23,7 +23,7 @@ import { DEFAULT_VALUE_MAX_LEN } from '@/config'
|
|||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
export type IPromptValuePanelProps = {
|
export interface IPromptValuePanelProps {
|
||||||
appType: AppType
|
appType: AppType
|
||||||
onSend?: () => void
|
onSend?: () => void
|
||||||
inputs: Inputs
|
inputs: Inputs
|
||||||
|
@ -1,124 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import type { FC } from 'react'
|
|
||||||
import React from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { useContext } from 'use-context-selector'
|
|
||||||
import { usePathname, useRouter } from 'next/navigation'
|
|
||||||
import ConfigParamModal from './config-param-modal'
|
|
||||||
import Panel from '@/app/components/app/configuration/base/feature-panel'
|
|
||||||
import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication'
|
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
|
||||||
import { LinkExternal02, Settings04 } from '@/app/components/base/icons/src/vender/line/general'
|
|
||||||
import ConfigContext from '@/context/debug-configuration'
|
|
||||||
import type { EmbeddingModelConfig } from '@/app/components/app/annotation/type'
|
|
||||||
import { fetchAnnotationConfig, updateAnnotationScore } from '@/service/annotation'
|
|
||||||
import type { AnnotationReplyConfig as AnnotationReplyConfigType } from '@/models/debug'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
onEmbeddingChange: (embeddingModel: EmbeddingModelConfig) => void
|
|
||||||
onScoreChange: (score: number, embeddingModel?: EmbeddingModelConfig) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Item: FC<{ title: string; tooltip: string; children: JSX.Element }> = ({
|
|
||||||
title,
|
|
||||||
tooltip,
|
|
||||||
children,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className='flex items-center space-x-1'>
|
|
||||||
<div>{title}</div>
|
|
||||||
<Tooltip
|
|
||||||
popupContent={
|
|
||||||
<div className='max-w-[200px] leading-[18px] text-[13px] font-medium text-gray-800'>{tooltip}</div>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>{children}</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const AnnotationReplyConfig: FC<Props> = ({
|
|
||||||
onEmbeddingChange,
|
|
||||||
onScoreChange,
|
|
||||||
}) => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const router = useRouter()
|
|
||||||
const pathname = usePathname()
|
|
||||||
const matched = pathname.match(/\/app\/([^/]+)/)
|
|
||||||
const appId = (matched?.length && matched[1]) ? matched[1] : ''
|
|
||||||
const {
|
|
||||||
annotationConfig,
|
|
||||||
} = useContext(ConfigContext)
|
|
||||||
|
|
||||||
const [isShowEdit, setIsShowEdit] = React.useState(false)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Panel
|
|
||||||
className="mt-4"
|
|
||||||
headerIcon={
|
|
||||||
<MessageFast className='w-4 h-4 text-[#444CE7]' />
|
|
||||||
}
|
|
||||||
title={t('appDebug.feature.annotation.title')}
|
|
||||||
headerRight={
|
|
||||||
<div className='flex items-center'>
|
|
||||||
<div
|
|
||||||
className='flex items-center rounded-md h-7 px-3 space-x-1 text-gray-700 cursor-pointer hover:bg-gray-200'
|
|
||||||
onClick={() => { setIsShowEdit(true) }}
|
|
||||||
>
|
|
||||||
<Settings04 className="w-[14px] h-[14px]" />
|
|
||||||
<div className='text-xs font-medium'>
|
|
||||||
|
|
||||||
{t('common.operation.params')}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className='ml-1 flex items-center h-7 px-3 space-x-1 leading-[18px] text-xs font-medium text-gray-700 rounded-md cursor-pointer hover:bg-gray-200'
|
|
||||||
onClick={() => {
|
|
||||||
router.push(`/app/${appId}/annotations`)
|
|
||||||
}}>
|
|
||||||
<div>{t('appDebug.feature.annotation.cacheManagement')}</div>
|
|
||||||
<LinkExternal02 className='w-3.5 h-3.5' />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
noBodySpacing
|
|
||||||
/>
|
|
||||||
{isShowEdit && (
|
|
||||||
<ConfigParamModal
|
|
||||||
appId={appId}
|
|
||||||
isShow
|
|
||||||
onHide={() => {
|
|
||||||
setIsShowEdit(false)
|
|
||||||
}}
|
|
||||||
onSave={async (embeddingModel, score) => {
|
|
||||||
const annotationConfig = await fetchAnnotationConfig(appId) as AnnotationReplyConfigType
|
|
||||||
let isEmbeddingModelChanged = false
|
|
||||||
if (
|
|
||||||
embeddingModel.embedding_model_name !== annotationConfig.embedding_model.embedding_model_name
|
|
||||||
|| embeddingModel.embedding_provider_name !== annotationConfig.embedding_model.embedding_provider_name
|
|
||||||
) {
|
|
||||||
await onEmbeddingChange(embeddingModel)
|
|
||||||
isEmbeddingModelChanged = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (score !== annotationConfig.score_threshold) {
|
|
||||||
await updateAnnotationScore(appId, annotationConfig.id, score)
|
|
||||||
if (isEmbeddingModelChanged)
|
|
||||||
onScoreChange(score, embeddingModel)
|
|
||||||
|
|
||||||
else
|
|
||||||
onScoreChange(score)
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsShowEdit(false)
|
|
||||||
}}
|
|
||||||
annotationConfig={annotationConfig}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default React.memo(AnnotationReplyConfig)
|
|
@ -1,45 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import type { FC } from 'react'
|
|
||||||
import React from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import GroupName from '../base/group-name'
|
|
||||||
import Moderation from './moderation'
|
|
||||||
import Annotation from './annotation/config-param'
|
|
||||||
import type { EmbeddingModelConfig } from '@/app/components/app/annotation/type'
|
|
||||||
|
|
||||||
export type ToolboxProps = {
|
|
||||||
showModerationSettings: boolean
|
|
||||||
showAnnotation: boolean
|
|
||||||
onEmbeddingChange: (embeddingModel: EmbeddingModelConfig) => void
|
|
||||||
onScoreChange: (score: number, embeddingModel?: EmbeddingModelConfig) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
const Toolbox: FC<ToolboxProps> = ({
|
|
||||||
showModerationSettings,
|
|
||||||
showAnnotation,
|
|
||||||
onEmbeddingChange,
|
|
||||||
onScoreChange,
|
|
||||||
}) => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='mt-7'>
|
|
||||||
<GroupName name={t('appDebug.feature.toolbox.title')} />
|
|
||||||
{
|
|
||||||
showModerationSettings && (
|
|
||||||
<Moderation />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
{
|
|
||||||
showAnnotation && (
|
|
||||||
<Annotation
|
|
||||||
onEmbeddingChange={onEmbeddingChange}
|
|
||||||
onScoreChange={onScoreChange}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default React.memo(Toolbox)
|
|
@ -21,13 +21,13 @@ import { useToastContext } from '@/app/components/base/toast'
|
|||||||
import AppIcon from '@/app/components/base/app-icon'
|
import AppIcon from '@/app/components/base/app-icon'
|
||||||
|
|
||||||
const systemTypes = ['api']
|
const systemTypes = ['api']
|
||||||
type ExternalDataToolModalProps = {
|
interface ExternalDataToolModalProps {
|
||||||
data: ExternalDataTool
|
data: ExternalDataTool
|
||||||
onCancel: () => void
|
onCancel: () => void
|
||||||
onSave: (externalDataTool: ExternalDataTool) => void
|
onSave: (externalDataTool: ExternalDataTool) => void
|
||||||
onValidateBeforeSave?: (externalDataTool: ExternalDataTool) => boolean
|
onValidateBeforeSave?: (externalDataTool: ExternalDataTool) => boolean
|
||||||
}
|
}
|
||||||
type Provider = {
|
interface Provider {
|
||||||
key: string
|
key: string
|
||||||
name: string
|
name: string
|
||||||
form_schema?: CodeBasedExtensionItem['form_schema']
|
form_schema?: CodeBasedExtensionItem['form_schema']
|
||||||
|
@ -29,7 +29,7 @@ import Tooltip from '@/app/components/base/tooltip'
|
|||||||
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
||||||
import { getRedirection } from '@/utils/app-redirection'
|
import { getRedirection } from '@/utils/app-redirection'
|
||||||
|
|
||||||
type CreateAppDialogProps = {
|
interface CreateAppDialogProps {
|
||||||
show: boolean
|
show: boolean
|
||||||
onSuccess: () => void
|
onSuccess: () => void
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
|
@ -21,6 +21,7 @@ import AppsFull from '@/app/components/billing/apps-full-in-dialog'
|
|||||||
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
||||||
import { getRedirection } from '@/utils/app-redirection'
|
import { getRedirection } from '@/utils/app-redirection'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
import { useMutationCheckDependenciesBeforeImportDSL } from '@/service/use-plugins'
|
||||||
|
|
||||||
type CreateFromDSLModalProps = {
|
type CreateFromDSLModalProps = {
|
||||||
show: boolean
|
show: boolean
|
||||||
@ -43,6 +44,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
|||||||
const [fileContent, setFileContent] = useState<string>()
|
const [fileContent, setFileContent] = useState<string>()
|
||||||
const [currentTab, setCurrentTab] = useState(activeTab)
|
const [currentTab, setCurrentTab] = useState(activeTab)
|
||||||
const [dslUrlValue, setDslUrlValue] = useState(dslUrl)
|
const [dslUrlValue, setDslUrlValue] = useState(dslUrl)
|
||||||
|
const { mutateAsync } = useMutationCheckDependenciesBeforeImportDSL()
|
||||||
|
|
||||||
const readFile = (file: File) => {
|
const readFile = (file: File) => {
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
@ -78,11 +80,21 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
|||||||
let app
|
let app
|
||||||
|
|
||||||
if (currentTab === CreateFromDSLModalTab.FROM_FILE) {
|
if (currentTab === CreateFromDSLModalTab.FROM_FILE) {
|
||||||
|
const leakedData = await mutateAsync({ dslString: fileContent })
|
||||||
|
if (leakedData?.leaked.length) {
|
||||||
|
isCreatingRef.current = false
|
||||||
|
return
|
||||||
|
}
|
||||||
app = await importApp({
|
app = await importApp({
|
||||||
data: fileContent || '',
|
data: fileContent || '',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (currentTab === CreateFromDSLModalTab.FROM_URL) {
|
if (currentTab === CreateFromDSLModalTab.FROM_URL) {
|
||||||
|
const leakedData = await mutateAsync({ url: dslUrlValue })
|
||||||
|
if (leakedData?.leaked.length) {
|
||||||
|
isCreatingRef.current = false
|
||||||
|
return
|
||||||
|
}
|
||||||
app = await importAppFromUrl({
|
app = await importAppFromUrl({
|
||||||
url: dslUrlValue || '',
|
url: dslUrlValue || '',
|
||||||
})
|
})
|
||||||
|
@ -13,7 +13,7 @@ import { useProviderContext } from '@/context/provider-context'
|
|||||||
import AppsFull from '@/app/components/billing/apps-full-in-dialog'
|
import AppsFull from '@/app/components/billing/apps-full-in-dialog'
|
||||||
import type { AppIconType } from '@/types/app'
|
import type { AppIconType } from '@/types/app'
|
||||||
|
|
||||||
export type DuplicateAppModalProps = {
|
export interface DuplicateAppModalProps {
|
||||||
appName: string
|
appName: string
|
||||||
icon_type: AppIconType | null
|
icon_type: AppIconType | null
|
||||||
icon: string
|
icon: string
|
||||||
|
@ -12,7 +12,7 @@ import { PageType } from '@/app/components/base/features/new-feature-panel/annot
|
|||||||
import TabSlider from '@/app/components/base/tab-slider-plain'
|
import TabSlider from '@/app/components/base/tab-slider-plain'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
pageType: PageType
|
pageType: PageType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ export const TIME_PERIOD_LIST = [
|
|||||||
{ value: 'all', name: 'allTime' },
|
{ value: 'all', name: 'allTime' },
|
||||||
]
|
]
|
||||||
|
|
||||||
type IFilterProps = {
|
interface IFilterProps {
|
||||||
isChatMode?: boolean
|
isChatMode?: boolean
|
||||||
appId: string
|
appId: string
|
||||||
queryParams: QueryParam
|
queryParams: QueryParam
|
||||||
|
@ -17,11 +17,11 @@ import Loading from '@/app/components/base/loading'
|
|||||||
import { fetchChatConversations, fetchCompletionConversations } from '@/service/log'
|
import { fetchChatConversations, fetchCompletionConversations } from '@/service/log'
|
||||||
import { APP_PAGE_LIMIT } from '@/config'
|
import { APP_PAGE_LIMIT } from '@/config'
|
||||||
import type { App, AppMode } from '@/types/app'
|
import type { App, AppMode } from '@/types/app'
|
||||||
export type ILogsProps = {
|
export interface ILogsProps {
|
||||||
appDetail: App
|
appDetail: App
|
||||||
}
|
}
|
||||||
|
|
||||||
export type QueryParam = {
|
export interface QueryParam {
|
||||||
period?: number | string
|
period?: number | string
|
||||||
annotation_status?: string
|
annotation_status?: string
|
||||||
keyword?: string
|
keyword?: string
|
||||||
|
@ -13,7 +13,7 @@ import InfiniteScroll from 'react-infinite-scroll-component'
|
|||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import utc from 'dayjs/plugin/utc'
|
import utc from 'dayjs/plugin/utc'
|
||||||
import timezone from 'dayjs/plugin/timezone'
|
import timezone from 'dayjs/plugin/timezone'
|
||||||
import { createContext, useContext } from 'use-context-selector'
|
import { useContext } from 'use-context-selector'
|
||||||
import { useShallow } from 'zustand/react/shallow'
|
import { useShallow } from 'zustand/react/shallow'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import type { ChatItemInTree } from '../../base/chat/types'
|
import type { ChatItemInTree } from '../../base/chat/types'
|
||||||
@ -44,6 +44,8 @@ import Tooltip from '@/app/components/base/tooltip'
|
|||||||
import { CopyIcon } from '@/app/components/base/copy-icon'
|
import { CopyIcon } from '@/app/components/base/copy-icon'
|
||||||
import { buildChatItemTree, getThreadMessages } from '@/app/components/base/chat/utils'
|
import { buildChatItemTree, getThreadMessages } from '@/app/components/base/chat/utils'
|
||||||
import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
|
import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
|
||||||
|
import { correctProvider } from '@/utils'
|
||||||
|
import { createSelectorCtx } from '@/utils/context'
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
@ -61,7 +63,7 @@ type IDrawerContext = {
|
|||||||
appDetail?: App
|
appDetail?: App
|
||||||
}
|
}
|
||||||
|
|
||||||
const DrawerContext = createContext<IDrawerContext>({} as IDrawerContext)
|
const [,, DrawerContext] = createSelectorCtx<IDrawerContext>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Icon component with numbers
|
* Icon component with numbers
|
||||||
@ -324,7 +326,7 @@ function DetailPanel({ detail, onFeedback }: IDetailPanel) {
|
|||||||
})?.name ?? 'custom'
|
})?.name ?? 'custom'
|
||||||
|
|
||||||
const modelName = (detail.model_config as any).model?.name
|
const modelName = (detail.model_config as any).model?.name
|
||||||
const provideName = (detail.model_config as any).model?.provider as any
|
const provideName = correctProvider((detail.model_config as any).model?.provider as any)
|
||||||
const {
|
const {
|
||||||
currentModel,
|
currentModel,
|
||||||
currentProvider,
|
currentProvider,
|
||||||
|
@ -20,7 +20,7 @@ const Progress: FC<IProgressProps> = ({
|
|||||||
className={cn(s.bar, exhausted && s['bar-error'], 'absolute top-0 left-0 right-0 bottom-0')}
|
className={cn(s.bar, exhausted && s['bar-error'], 'absolute top-0 left-0 right-0 bottom-0')}
|
||||||
style={{ width: `${value}%` }}
|
style={{ width: `${value}%` }}
|
||||||
/>
|
/>
|
||||||
{Array(10).fill(0).map((i, k) => (
|
{Array.from({ length: 10 }).fill(0).map((i, k) => (
|
||||||
<div key={k} className={s['bar-item']} />
|
<div key={k} className={s['bar-item']} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -243,7 +243,7 @@ const Chart: React.FC<IChartProps> = ({
|
|||||||
? ''
|
? ''
|
||||||
: <span>{t('appOverview.analysis.tokenUsage.consumed')} Tokens<span className='text-sm'>
|
: <span>{t('appOverview.analysis.tokenUsage.consumed')} Tokens<span className='text-sm'>
|
||||||
<span className='ml-1 text-gray-500'>(</span>
|
<span className='ml-1 text-gray-500'>(</span>
|
||||||
<span className='text-orange-400'>~{sum(statistics.map(item => parseFloat(get(item, 'total_price', '0')))).toLocaleString('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 4 })}</span>
|
<span className='text-orange-400'>~{sum(statistics.map(item => Number.parseFloat(get(item, 'total_price', '0')))).toLocaleString('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 4 })}</span>
|
||||||
<span className='text-gray-500'>)</span>
|
<span className='text-gray-500'>)</span>
|
||||||
</span></span>}
|
</span></span>}
|
||||||
textStyle={{ main: `!text-3xl !font-normal ${sumData === 0 ? '!text-gray-300' : ''}` }} />
|
textStyle={{ main: `!text-3xl !font-normal ${sumData === 0 ? '!text-gray-300' : ''}` }} />
|
||||||
|
@ -22,7 +22,7 @@ import AppContext, { useAppContext } from '@/context/app-context'
|
|||||||
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
||||||
import AppIconPicker from '@/app/components/base/app-icon-picker'
|
import AppIconPicker from '@/app/components/base/app-icon-picker'
|
||||||
|
|
||||||
export type ISettingsModalProps = {
|
export interface ISettingsModalProps {
|
||||||
isChat: boolean
|
isChat: boolean
|
||||||
appInfo: AppDetailResponse & Partial<AppSSO>
|
appInfo: AppDetailResponse & Partial<AppSSO>
|
||||||
isShow: boolean
|
isShow: boolean
|
||||||
@ -31,7 +31,7 @@ export type ISettingsModalProps = {
|
|||||||
onSave?: (params: ConfigParams) => Promise<void>
|
onSave?: (params: ConfigParams) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ConfigParams = {
|
export interface ConfigParams {
|
||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
default_language: string
|
default_language: string
|
||||||
|
@ -2,7 +2,7 @@ import { create } from 'zustand'
|
|||||||
import type { App, AppSSO } from '@/types/app'
|
import type { App, AppSSO } from '@/types/app'
|
||||||
import type { IChatItem } from '@/app/components/base/chat/chat/type'
|
import type { IChatItem } from '@/app/components/base/chat/chat/type'
|
||||||
|
|
||||||
type State = {
|
interface State {
|
||||||
appDetail?: App & Partial<AppSSO>
|
appDetail?: App & Partial<AppSSO>
|
||||||
appSidebarExpand: string
|
appSidebarExpand: string
|
||||||
currentLogItem?: IChatItem
|
currentLogItem?: IChatItem
|
||||||
@ -13,7 +13,7 @@ type State = {
|
|||||||
showAppConfigureFeaturesModal: boolean
|
showAppConfigureFeaturesModal: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type Action = {
|
interface Action {
|
||||||
setAppDetail: (appDetail?: App & Partial<AppSSO>) => void
|
setAppDetail: (appDetail?: App & Partial<AppSSO>) => void
|
||||||
setAppSiderbarExpand: (state: string) => void
|
setAppSiderbarExpand: (state: string) => void
|
||||||
setCurrentLogItem: (item?: IChatItem) => void
|
setCurrentLogItem: (item?: IChatItem) => void
|
||||||
|
@ -25,7 +25,7 @@ import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/aler
|
|||||||
import AppIcon from '@/app/components/base/app-icon'
|
import AppIcon from '@/app/components/base/app-icon'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
|
|
||||||
type SwitchAppModalProps = {
|
interface SwitchAppModalProps {
|
||||||
show: boolean
|
show: boolean
|
||||||
appDetail: App
|
appDetail: App
|
||||||
onSuccess?: () => void
|
onSuccess?: () => void
|
||||||
|
@ -33,7 +33,7 @@ import { useChatContext } from '@/app/components/base/chat/chat/context'
|
|||||||
|
|
||||||
const MAX_DEPTH = 3
|
const MAX_DEPTH = 3
|
||||||
|
|
||||||
export type IGenerationItemProps = {
|
export interface IGenerationItemProps {
|
||||||
isWorkflow?: boolean
|
isWorkflow?: boolean
|
||||||
workflowProcessData?: WorkflowProcess
|
workflowProcessData?: WorkflowProcess
|
||||||
className?: string
|
className?: string
|
||||||
|
@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { RiCloseLine } from '@remixicon/react'
|
import { RiCloseLine } from '@remixicon/react'
|
||||||
import Run from '@/app/components/workflow/run'
|
import Run from '@/app/components/workflow/run'
|
||||||
|
|
||||||
type ILogDetail = {
|
interface ILogDetail {
|
||||||
runID: string
|
runID: string
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import type { QueryParam } from './index'
|
|||||||
import Chip from '@/app/components/base/chip'
|
import Chip from '@/app/components/base/chip'
|
||||||
import Input from '@/app/components/base/input'
|
import Input from '@/app/components/base/input'
|
||||||
|
|
||||||
type IFilterProps = {
|
interface IFilterProps {
|
||||||
queryParams: QueryParam
|
queryParams: QueryParam
|
||||||
setQueryParams: (v: QueryParam) => void
|
setQueryParams: (v: QueryParam) => void
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,11 @@ import { fetchWorkflowLogs } from '@/service/log'
|
|||||||
import { APP_PAGE_LIMIT } from '@/config'
|
import { APP_PAGE_LIMIT } from '@/config'
|
||||||
import type { App, AppMode } from '@/types/app'
|
import type { App, AppMode } from '@/types/app'
|
||||||
|
|
||||||
export type ILogsProps = {
|
export interface ILogsProps {
|
||||||
appDetail: App
|
appDetail: App
|
||||||
}
|
}
|
||||||
|
|
||||||
export type QueryParam = {
|
export interface QueryParam {
|
||||||
status?: string
|
status?: string
|
||||||
keyword?: string
|
keyword?: string
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import Indicator from '@/app/components/header/indicator'
|
|||||||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||||
import useTimestamp from '@/hooks/use-timestamp'
|
import useTimestamp from '@/hooks/use-timestamp'
|
||||||
|
|
||||||
type ILogs = {
|
interface ILogs {
|
||||||
logs?: WorkflowLogsResponse
|
logs?: WorkflowLogsResponse
|
||||||
appDetail?: App
|
appDetail?: App
|
||||||
onRefresh: () => void
|
onRefresh: () => void
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
.action-btn {
|
.action-btn {
|
||||||
@apply inline-flex justify-center items-center cursor-pointer text-text-tertiary
|
@apply inline-flex justify-center items-center cursor-pointer text-text-tertiary hover:text-text-secondary hover:bg-state-base-hover
|
||||||
hover:text-text-secondary
|
|
||||||
hover:bg-state-base-hover
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-btn-disabled {
|
.action-btn-disabled {
|
||||||
@ -29,21 +27,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.action-btn.action-btn-active {
|
.action-btn.action-btn-active {
|
||||||
@apply
|
@apply text-text-accent bg-state-accent-active hover:bg-state-accent-active-alt
|
||||||
text-text-accent
|
|
||||||
bg-state-accent-active
|
|
||||||
hover:bg-state-accent-active-alt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-btn.action-btn-disabled {
|
.action-btn.action-btn-disabled {
|
||||||
@apply
|
@apply text-text-disabled
|
||||||
text-text-disabled
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-btn.action-btn-destructive {
|
.action-btn.action-btn-destructive {
|
||||||
@apply
|
@apply text-text-destructive bg-state-destructive-hover
|
||||||
text-text-destructive
|
|
||||||
bg-state-destructive-hover
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -28,7 +28,7 @@ const actionButtonVariants = cva(
|
|||||||
)
|
)
|
||||||
|
|
||||||
export type ActionButtonProps = {
|
export type ActionButtonProps = {
|
||||||
size?: 'xs' | 'm' | 'l' | 'xl'
|
size?: 'xs' | 's' | 'm' | 'l' | 'xl'
|
||||||
state?: ActionButtonState
|
state?: ActionButtonState
|
||||||
styleCss?: CSSProperties
|
styleCss?: CSSProperties
|
||||||
} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof actionButtonVariants>
|
} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof actionButtonVariants>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.appIcon.xs {
|
.appIcon.xs {
|
||||||
@apply w-3 h-3 text-base;
|
@apply w-5 h-5 text-base;
|
||||||
}
|
}
|
||||||
|
|
||||||
.appIcon.rounded {
|
.appIcon.rounded {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import AudioPlayer from '@/app/components/base/audio-btn/audio'
|
import AudioPlayer from '@/app/components/base/audio-btn/audio'
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
// eslint-disable-next-line ts/consistent-type-definitions
|
||||||
interface AudioPlayerManager {
|
interface AudioPlayerManager {
|
||||||
instance: AudioPlayerManager
|
instance: AudioPlayerManager
|
||||||
}
|
}
|
||||||
@ -12,6 +12,7 @@ export class AudioPlayerManager {
|
|||||||
private audioPlayers: AudioPlayer | null = null
|
private audioPlayers: AudioPlayer | null = null
|
||||||
private msgId: string | undefined
|
private msgId: string | undefined
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
private constructor() {
|
private constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import Toast from '@/app/components/base/toast'
|
|||||||
import { textToAudioStream } from '@/service/share'
|
import { textToAudioStream } from '@/service/share'
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
// eslint-disable-next-line ts/consistent-type-definitions
|
||||||
interface Window {
|
interface Window {
|
||||||
ManagedMediaSource: any
|
ManagedMediaSource: any
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import Tooltip from '@/app/components/base/tooltip'
|
|||||||
import Loading from '@/app/components/base/loading'
|
import Loading from '@/app/components/base/loading'
|
||||||
import { AudioPlayerManager } from '@/app/components/base/audio-btn/audio.player.manager'
|
import { AudioPlayerManager } from '@/app/components/base/audio-btn/audio.player.manager'
|
||||||
|
|
||||||
type AudioBtnProps = {
|
interface AudioBtnProps {
|
||||||
id?: string
|
id?: string
|
||||||
voice?: string
|
voice?: string
|
||||||
value?: string
|
value?: string
|
||||||
|
@ -2,15 +2,15 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: #ffffff;
|
background-color: var(--color-components-chat-input-audio-bg-alt);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
min-width: 240px;
|
min-width: 240px;
|
||||||
max-width: 420px;
|
max-width: 420px;
|
||||||
max-height: 40px;
|
max-height: 40px;
|
||||||
backdrop-filter: blur(5px);
|
backdrop-filter: blur(5px);
|
||||||
border: 1px solid rgba(16, 24, 40, 0.08);
|
border: 1px solid var(--color-components-panel-border-subtle);
|
||||||
box-shadow: 0 1px 2px rgba(9, 9, 11, 0.05);
|
box-shadow: 0 1px 2px var(--color-shadow-shadow-3);
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,8 +19,8 @@
|
|||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-color: #296DFF;
|
background-color: var(--color-components-button-primary-bg);
|
||||||
color: white;
|
color: var(--color-components-chat-input-audio-bg-alt);
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -30,16 +30,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.playButton:hover {
|
.playButton:hover {
|
||||||
background-color: #3367d6;
|
background-color: var(--color-components-button-primary-bg-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.playButton:disabled {
|
.playButton:disabled {
|
||||||
background-color: #bdbdbf;
|
background-color: var(--color-components-button-primary-bg-disabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
.audioControls {
|
.audioControls {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.progressBarContainer {
|
.progressBarContainer {
|
||||||
@ -76,8 +75,8 @@
|
|||||||
|
|
||||||
.timeDisplay {
|
.timeDisplay {
|
||||||
/* position: absolute; */
|
/* position: absolute; */
|
||||||
color: #296DFF;
|
color: var(--color-text-accent-secondary);
|
||||||
border-radius: 2px;
|
font-size: 12px;
|
||||||
order: 0;
|
order: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 50px;
|
width: 50px;
|
||||||
@ -97,7 +96,6 @@
|
|||||||
} */
|
} */
|
||||||
|
|
||||||
.duration {
|
.duration {
|
||||||
background-color: rgba(255, 255, 255, 0.8);
|
|
||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({ src }) => {
|
|||||||
audio.load()
|
audio.load()
|
||||||
|
|
||||||
// Delayed generation of waveform data
|
// Delayed generation of waveform data
|
||||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
// eslint-disable-next-line ts/no-use-before-define
|
||||||
const timer = setTimeout(() => generateWaveformData(src), 1000)
|
const timer = setTimeout(() => generateWaveformData(src), 1000)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -49,4 +49,6 @@ const AutoHeightTextarea = forwardRef<HTMLTextAreaElement, AutoHeightTextareaPro
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AutoHeightTextarea.displayName = 'AutoHeightTextarea'
|
||||||
|
|
||||||
export default AutoHeightTextarea
|
export default AutoHeightTextarea
|
||||||
|
@ -5,22 +5,28 @@ type BadgeProps = {
|
|||||||
className?: string
|
className?: string
|
||||||
text: string
|
text: string
|
||||||
uppercase?: boolean
|
uppercase?: boolean
|
||||||
|
hasRedCornerMark?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const Badge = ({
|
const Badge = ({
|
||||||
className,
|
className,
|
||||||
text,
|
text,
|
||||||
uppercase = true,
|
uppercase = true,
|
||||||
|
hasRedCornerMark,
|
||||||
}: BadgeProps) => {
|
}: BadgeProps) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center px-[5px] h-5 rounded-[5px] border border-divider-deep leading-3 text-text-tertiary',
|
'relative inline-flex items-center px-[5px] h-5 rounded-[5px] border border-divider-deep leading-3 text-text-tertiary',
|
||||||
uppercase ? 'system-2xs-medium-uppercase' : 'system-xs-medium',
|
uppercase ? 'system-2xs-medium-uppercase' : 'system-xs-medium',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{text}
|
{text}
|
||||||
|
{hasRedCornerMark && (
|
||||||
|
<div className='absolute top-[-2px] right-[-2px] w-1.5 h-1.5 border border-components-badge-status-light-error-border-inner bg-components-badge-status-light-error-bg rounded-[2px] shadow-sm'>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
28
web/app/components/base/badge/index.css
Normal file
28
web/app/components/base/badge/index.css
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
@tailwind components;
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.badge {
|
||||||
|
@apply inline-flex justify-center items-center text-text-tertiary border border-divider-deep
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-l {
|
||||||
|
@apply rounded-md gap-1 min-w-6
|
||||||
|
}
|
||||||
|
|
||||||
|
/* m is for the regular button */
|
||||||
|
.badge-m {
|
||||||
|
@apply rounded-md gap-[3px] min-w-5
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-s {
|
||||||
|
@apply rounded-[5px] gap-0.5 min-w-[18px]
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge.badge-warning {
|
||||||
|
@apply text-text-warning border border-text-warning
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge.badge-accent {
|
||||||
|
@apply text-text-accent-secondary border border-text-accent-secondary
|
||||||
|
}
|
||||||
|
}
|
81
web/app/components/base/badge/index.tsx
Normal file
81
web/app/components/base/badge/index.tsx
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import type { CSSProperties, ReactNode } from 'react'
|
||||||
|
import React from 'react'
|
||||||
|
import { type VariantProps, cva } from 'class-variance-authority'
|
||||||
|
import classNames from '@/utils/classnames'
|
||||||
|
import './index.css'
|
||||||
|
|
||||||
|
enum BadgeState {
|
||||||
|
Warning = 'warning',
|
||||||
|
Accent = 'accent',
|
||||||
|
Default = '',
|
||||||
|
}
|
||||||
|
|
||||||
|
const BadgeVariants = cva(
|
||||||
|
'badge',
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
size: {
|
||||||
|
s: 'badge-s',
|
||||||
|
m: 'badge-m',
|
||||||
|
l: 'badge-l',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
size: 'm',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
type BadgeProps = {
|
||||||
|
size?: 's' | 'm' | 'l'
|
||||||
|
iconOnly?: boolean
|
||||||
|
uppercase?: boolean
|
||||||
|
state?: BadgeState
|
||||||
|
styleCss?: CSSProperties
|
||||||
|
children?: ReactNode
|
||||||
|
} & React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof BadgeVariants>
|
||||||
|
|
||||||
|
function getBadgeState(state: BadgeState) {
|
||||||
|
switch (state) {
|
||||||
|
case BadgeState.Warning:
|
||||||
|
return 'badge-warning'
|
||||||
|
case BadgeState.Accent:
|
||||||
|
return 'badge-accent'
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Badge: React.FC<BadgeProps> = ({
|
||||||
|
className,
|
||||||
|
size,
|
||||||
|
state = BadgeState.Default,
|
||||||
|
iconOnly = false,
|
||||||
|
uppercase = false,
|
||||||
|
styleCss,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
BadgeVariants({ size, className }),
|
||||||
|
getBadgeState(state),
|
||||||
|
size === 's'
|
||||||
|
? (iconOnly ? 'p-[3px]' : 'px-[5px] py-[3px]')
|
||||||
|
: size === 'l'
|
||||||
|
? (iconOnly ? 'p-1.5' : 'px-2 py-1')
|
||||||
|
: (iconOnly ? 'p-1' : 'px-[5px] py-[2px]'),
|
||||||
|
uppercase ? 'system-2xs-medium-uppercase' : 'system-2xs-medium',
|
||||||
|
)}
|
||||||
|
style={styleCss}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Badge.displayName = 'Badge'
|
||||||
|
|
||||||
|
export default Badge
|
||||||
|
export { Badge, BadgeState, BadgeVariants }
|
@ -4,7 +4,7 @@ import React from 'react'
|
|||||||
import { RiAddLine } from '@remixicon/react'
|
import { RiAddLine } from '@remixicon/react'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
onClick: () => void
|
onClick: () => void
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
import Textarea from '@/app/components/base/textarea'
|
import Textarea from '@/app/components/base/textarea'
|
||||||
|
|
||||||
type InputProps = {
|
interface InputProps {
|
||||||
form: any
|
form: any
|
||||||
value: string
|
value: string
|
||||||
onChange: (variable: string, value: string) => void
|
onChange: (variable: string, value: string) => void
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import type { RefObject } from 'react'
|
import type { RefObject } from 'react'
|
||||||
import { createContext, useContext } from 'use-context-selector'
|
|
||||||
import type {
|
import type {
|
||||||
Callback,
|
Callback,
|
||||||
ChatConfig,
|
ChatConfig,
|
||||||
@ -15,6 +14,7 @@ import type {
|
|||||||
AppMeta,
|
AppMeta,
|
||||||
ConversationItem,
|
ConversationItem,
|
||||||
} from '@/models/share'
|
} from '@/models/share'
|
||||||
|
import { createSelectorCtx } from '@/utils/context'
|
||||||
|
|
||||||
export type ChatWithHistoryContextValue = {
|
export type ChatWithHistoryContextValue = {
|
||||||
appInfoError?: any
|
appInfoError?: any
|
||||||
@ -51,29 +51,4 @@ export type ChatWithHistoryContextValue = {
|
|||||||
themeBuilder?: ThemeBuilder
|
themeBuilder?: ThemeBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChatWithHistoryContext = createContext<ChatWithHistoryContextValue>({
|
export const [, useChatWithHistoryContext, ChatWithHistoryContext] = createSelectorCtx<ChatWithHistoryContextValue>()
|
||||||
currentConversationId: '',
|
|
||||||
appPrevChatList: [],
|
|
||||||
pinnedConversationList: [],
|
|
||||||
conversationList: [],
|
|
||||||
showConfigPanelBeforeChat: false,
|
|
||||||
newConversationInputs: {},
|
|
||||||
newConversationInputsRef: { current: {} },
|
|
||||||
handleNewConversationInputsChange: () => {},
|
|
||||||
inputsForms: [],
|
|
||||||
handleNewConversation: () => {},
|
|
||||||
handleStartChat: () => {},
|
|
||||||
handleChangeConversation: () => {},
|
|
||||||
handlePinConversation: () => {},
|
|
||||||
handleUnpinConversation: () => {},
|
|
||||||
handleDeleteConversation: () => {},
|
|
||||||
conversationRenaming: false,
|
|
||||||
handleRenameConversation: () => {},
|
|
||||||
handleNewConversationCompleted: () => {},
|
|
||||||
chatShouldReloadKey: '',
|
|
||||||
isMobile: false,
|
|
||||||
isInstalledApp: false,
|
|
||||||
handleFeedback: () => {},
|
|
||||||
currentChatInstanceRef: { current: { handleStop: () => {} } },
|
|
||||||
})
|
|
||||||
export const useChatWithHistoryContext = () => useContext(ChatWithHistoryContext)
|
|
||||||
|
@ -20,7 +20,7 @@ import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
|||||||
import { checkOrSetAccessToken } from '@/app/components/share/utils'
|
import { checkOrSetAccessToken } from '@/app/components/share/utils'
|
||||||
import AppUnavailable from '@/app/components/base/app-unavailable'
|
import AppUnavailable from '@/app/components/base/app-unavailable'
|
||||||
|
|
||||||
type ChatWithHistoryProps = {
|
interface ChatWithHistoryProps {
|
||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
const ChatWithHistory: FC<ChatWithHistoryProps> = ({
|
const ChatWithHistory: FC<ChatWithHistoryProps> = ({
|
||||||
@ -99,7 +99,7 @@ const ChatWithHistory: FC<ChatWithHistoryProps> = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ChatWithHistoryWrapProps = {
|
export interface ChatWithHistoryWrapProps {
|
||||||
installedAppInfo?: InstalledApp
|
installedAppInfo?: InstalledApp
|
||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import Thought from '@/app/components/base/chat/chat/thought'
|
|||||||
import { FileList } from '@/app/components/base/file-uploader'
|
import { FileList } from '@/app/components/base/file-uploader'
|
||||||
import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
|
import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
|
||||||
|
|
||||||
type AgentContentProps = {
|
interface AgentContentProps {
|
||||||
item: ChatItem
|
item: ChatItem
|
||||||
responding?: boolean
|
responding?: boolean
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import type { ChatItem } from '../../types'
|
|||||||
import { Markdown } from '@/app/components/base/markdown'
|
import { Markdown } from '@/app/components/base/markdown'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
type BasicContentProps = {
|
interface BasicContentProps {
|
||||||
item: ChatItem
|
item: ChatItem
|
||||||
}
|
}
|
||||||
const BasicContent: FC<BasicContentProps> = ({
|
const BasicContent: FC<BasicContentProps> = ({
|
||||||
|
@ -23,7 +23,7 @@ import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows
|
|||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import { FileList } from '@/app/components/base/file-uploader'
|
import { FileList } from '@/app/components/base/file-uploader'
|
||||||
|
|
||||||
type AnswerProps = {
|
interface AnswerProps {
|
||||||
item: ChatItem
|
item: ChatItem
|
||||||
question: string
|
question: string
|
||||||
index: number
|
index: number
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user