mirror of
https://github.com/langgenius/dify.git
synced 2026-01-19 11:45:05 +08:00
Compare commits
1049 Commits
1.10.0-rc1
...
fix/not-sh
| Author | SHA1 | Date | |
|---|---|---|---|
| 8cd97eba32 | |||
| ab66f30e1d | |||
| 566dc9b4a8 | |||
| 641395b3ec | |||
| db60150f30 | |||
| b964c713bd | |||
| 7b4d49a79c | |||
| 0ad08f523b | |||
| f4ca5938ec | |||
| 38437efec0 | |||
| 52553a66ba | |||
| a87c2d7e20 | |||
| 08cff0045d | |||
| 195a507b40 | |||
| d7ec013665 | |||
| dc9675d2d8 | |||
| 06fe17c93e | |||
| 5ec4695e4a | |||
| bb60db7078 | |||
| e3e8eafd32 | |||
| eff6a55960 | |||
| a7f0933e55 | |||
| eaf1177cd4 | |||
| 297b5280f0 | |||
| 4aac48ed61 | |||
| 192af8df9f | |||
| 9822445c1e | |||
| 018e32e355 | |||
| 41b720502f | |||
| a157af724f | |||
| cc0d864599 | |||
| 4a6a1b9855 | |||
| 7ccc268ced | |||
| 6483d20f56 | |||
| 61237e8037 | |||
| aae601f233 | |||
| 701520ffd0 | |||
| 596e3409b7 | |||
| 38dd285656 | |||
| 0248c8cb8c | |||
| 88b3c0b7a6 | |||
| 3ae7787011 | |||
| c357ec0f7c | |||
| 763f91fcea | |||
| 62d53399ae | |||
| c3215a8f94 | |||
| d65c1218ae | |||
| 83723212af | |||
| 84c2a9dc3b | |||
| 87d7df3ed4 | |||
| 586f9d8d89 | |||
| b656b7a0dd | |||
| 0fdf7b23c6 | |||
| 369e3eb97f | |||
| f58eef74b3 | |||
| 2fd083629d | |||
| 755685a89a | |||
| 23b29b1d21 | |||
| 4b01ef2b48 | |||
| 05d273d643 | |||
| 5481b42257 | |||
| fa83f2e2fa | |||
| 5e4d2f9501 | |||
| fdfe724438 | |||
| b0b373d2fb | |||
| f63cc9e069 | |||
| 8c9c336b64 | |||
| 2dac103463 | |||
| 17dfb3654f | |||
| 98ad18ba81 | |||
| 53bb1bb937 | |||
| 93806148cd | |||
| adf0d94a9a | |||
| d17932d723 | |||
| 3cbb288a25 | |||
| 99e2eaa6ee | |||
| 6006380723 | |||
| 55ad1fe1f0 | |||
| 0383fce821 | |||
| 85610651c0 | |||
| 768e1b9da3 | |||
| a6d172f111 | |||
| 5817c07db6 | |||
| 2f5da1f6aa | |||
| 130cfaf2a4 | |||
| f840b7db0c | |||
| aac2184069 | |||
| f03631ff9e | |||
| e207894d7e | |||
| 8512a7d3ad | |||
| 46614cc6f5 | |||
| b39acd0bad | |||
| 48b88b90f5 | |||
| 851fe246a7 | |||
| ff61c22f36 | |||
| e6eae8568f | |||
| 6d5c34564b | |||
| 4c5fa00c50 | |||
| 910e6d17d3 | |||
| 275696edba | |||
| 1348e32015 | |||
| f5b2735dd5 | |||
| 8d39ec1da5 | |||
| 0f6cbf25d3 | |||
| 0e98794d49 | |||
| 1419430015 | |||
| 5d25643f54 | |||
| e24b04b30f | |||
| a8c4870349 | |||
| bdb9d676b1 | |||
| 0beebab605 | |||
| 15f3e46c49 | |||
| 61d2f70927 | |||
| 228cd1cdbe | |||
| e0ed17a2e6 | |||
| 07aa2ca9cf | |||
| 5fdfba6b00 | |||
| fbf9984d85 | |||
| 2296bb162b | |||
| 06f0c3c886 | |||
| 483890b207 | |||
| 390107f97e | |||
| 5ba0b85738 | |||
| 39335b8038 | |||
| 5fb356fd33 | |||
| c458c28c62 | |||
| 055fb22b9b | |||
| f2eb095960 | |||
| d5cfb26db6 | |||
| a514bde428 | |||
| 87ce813175 | |||
| 336b26569b | |||
| a432fcfd5e | |||
| 0ed4ec5cd0 | |||
| add6dff789 | |||
| c469da2020 | |||
| 55aad3718d | |||
| c6c388fbda | |||
| d3d606799d | |||
| c1ae681b6c | |||
| f11ea5ae97 | |||
| e112357e91 | |||
| 1b8ec6710a | |||
| 4663af8a60 | |||
| 91ac660f81 | |||
| 3c829a1c28 | |||
| f9ce6b6a6e | |||
| afe8c85b99 | |||
| bc5cd4405b | |||
| be36aedac1 | |||
| 9e6f3e9161 | |||
| 52537c9e6b | |||
| 8d229f26d0 | |||
| 504c794e8a | |||
| cab8c6c5a7 | |||
| 5bba422c0b | |||
| 870779534f | |||
| f956c2edcd | |||
| 2a29dd3534 | |||
| b1831bc582 | |||
| 3e979a5ded | |||
| 7011a5029e | |||
| d7cbbbca8e | |||
| 21d082f3da | |||
| 2cdf2b2e05 | |||
| ec2dd750f1 | |||
| 066595f3aa | |||
| f81bbee6b6 | |||
| 4855e87876 | |||
| e47aaad396 | |||
| df421796bb | |||
| fe5702784e | |||
| eba4042a62 | |||
| 3bed0346d7 | |||
| 3a09f43f70 | |||
| 232fb66edd | |||
| a3f736f6e5 | |||
| d9d42b2d8c | |||
| 0a30018330 | |||
| 128410902c | |||
| 9b6f580365 | |||
| afb3548e45 | |||
| e1cb85cee1 | |||
| 2007828404 | |||
| f5b4366bd8 | |||
| cd7e6ca010 | |||
| 2ac6f00efb | |||
| f461f56886 | |||
| ba16cbccf0 | |||
| 08a1f241ca | |||
| a5509fbe5a | |||
| 98a03b0593 | |||
| f72818bed5 | |||
| 0c5101fb3c | |||
| 84febd5e94 | |||
| b5ad9a58f7 | |||
| 8a90a9bd5d | |||
| 6f8e217580 | |||
| 891a76f2fa | |||
| 3c85363392 | |||
| a863e9f674 | |||
| 6a2a7aca9b | |||
| 18393d2e27 | |||
| de48a1c7e9 | |||
| 3d5620dfb3 | |||
| da2982ba98 | |||
| 0108b28305 | |||
| 573c8f909c | |||
| 3a5170716b | |||
| e4cc8f7010 | |||
| 23913b8640 | |||
| 0d0a4cfaa1 | |||
| 04d8d16d8a | |||
| 0d2a74b8cb | |||
| ae42edb8d7 | |||
| e903cd8073 | |||
| 31cca291b7 | |||
| ed6c9625e8 | |||
| 08c517dd99 | |||
| 69a6556f52 | |||
| e34eebfb0b | |||
| ef3e904839 | |||
| df5fb6dca9 | |||
| 2f65d0439c | |||
| 5cdca9cafe | |||
| 67019d128b | |||
| 697ee496b7 | |||
| 7f5e27d001 | |||
| 1f128729f4 | |||
| a562e6db89 | |||
| c23fe3b67f | |||
| 95da3a4cf1 | |||
| bfecc73de9 | |||
| b4e9dddbca | |||
| 10218cfe8d | |||
| e00da7a1d8 | |||
| 469ce0f23d | |||
| 23bf0a6812 | |||
| 605085bddf | |||
| dbc45f0d74 | |||
| 6175f8c16f | |||
| 7e94056507 | |||
| 1429b30e84 | |||
| 5ef9156242 | |||
| 6f865b96a2 | |||
| b7e56a23a0 | |||
| 5b8ad3ac4b | |||
| e0b7f48b6b | |||
| ff70e14de2 | |||
| 244517e6e7 | |||
| cd08f98bff | |||
| b752c0654e | |||
| e07d7ee4fc | |||
| c476f06388 | |||
| 5f13402c6e | |||
| 8dcd82290c | |||
| 86eb618b84 | |||
| e1ea82475d | |||
| 08515957f1 | |||
| 8503099d65 | |||
| c04a89d5b1 | |||
| 8d225264fa | |||
| 26901b2c87 | |||
| b56acb825f | |||
| f1e17ad134 | |||
| b8e4580074 | |||
| 935c126abd | |||
| b4105fcc9c | |||
| 5f65fb1b62 | |||
| 986d6eed36 | |||
| e0f83d06d8 | |||
| f42cfe8075 | |||
| a7b2f9aef0 | |||
| c867584049 | |||
| ac2c8344f2 | |||
| 8c662e04e0 | |||
| e1d0c29711 | |||
| 50c77ad405 | |||
| 880496db0b | |||
| 057da6c31b | |||
| c0a8b89e93 | |||
| a8a956b5f1 | |||
| ff02e1cb8f | |||
| d78719a6f8 | |||
| da6d65b072 | |||
| 8d1a8eac51 | |||
| e34fe3d10a | |||
| 8d79b24883 | |||
| 03520a5a81 | |||
| d43b2c62f5 | |||
| 07d7965e3b | |||
| e4d72f3442 | |||
| c93c264c5a | |||
| 77017522b8 | |||
| aa309964e5 | |||
| 754baf8d02 | |||
| b98dd22491 | |||
| 7c460eb6e7 | |||
| e2e2090e0c | |||
| c8fc1deca6 | |||
| 6dd14ca2be | |||
| ec6f4ee9df | |||
| 9d117fa2f9 | |||
| e8319f01e0 | |||
| c3f3b79b79 | |||
| 327eac09e7 | |||
| cf75e2f053 | |||
| 12c47d80af | |||
| 5c6916354e | |||
| 6d2b2d7810 | |||
| 1fa5b1755f | |||
| 5dad4793e6 | |||
| 04054954c5 | |||
| 672843dcab | |||
| 4f8cdabef0 | |||
| e792e91777 | |||
| d5cb9f0193 | |||
| 171cc88a0d | |||
| 031c2ad899 | |||
| 463f5a34c6 | |||
| 5c98f1a5aa | |||
| a0e999e438 | |||
| e0cc990fa5 | |||
| 5b3112a137 | |||
| 35fb9099e3 | |||
| c51c032334 | |||
| 5825c101c9 | |||
| 4c1bf96b14 | |||
| 69daf4a027 | |||
| 3bc9ddb006 | |||
| ea2862e435 | |||
| ca3d96e5f4 | |||
| d6dea67947 | |||
| b8f9747849 | |||
| 0e70e72594 | |||
| 0e419a7a16 | |||
| 0ac5e53c2e | |||
| 44b0039e8b | |||
| becdca24df | |||
| f634a4488f | |||
| fc2656b4b7 | |||
| d6a4cbc6cc | |||
| 1e2ee61f6a | |||
| ab9a177c90 | |||
| 8b28ed589c | |||
| 3b1211d6bc | |||
| 7bd3f2b932 | |||
| b78ab0bd69 | |||
| 84cad5969e | |||
| 35ef874867 | |||
| 47579c86e6 | |||
| 32619bd05e | |||
| 6a500edf4d | |||
| be7fa93ffc | |||
| 3bcd470ec6 | |||
| 73825c59e4 | |||
| 5f76975e12 | |||
| 3ddb3d2bff | |||
| a70eda6c45 | |||
| 42cdc55db1 | |||
| a76d0a09b6 | |||
| 51f0f21a47 | |||
| 073e847524 | |||
| 3e601c4ef5 | |||
| fba468e8ad | |||
| f40b212b04 | |||
| 37eee7be24 | |||
| 99942b26e6 | |||
| d4cda69b0e | |||
| e145dba487 | |||
| e908ecab8f | |||
| b8af4aead1 | |||
| d40f0e645c | |||
| 4b77ced4ad | |||
| b84b0c8ba8 | |||
| f47b32b26d | |||
| 102a42d24c | |||
| 00eb47384a | |||
| 2041650cca | |||
| a0873a956f | |||
| df049564e8 | |||
| b93be49530 | |||
| 57756b18e4 | |||
| 8ad9ab40df | |||
| 4f54ac6ed6 | |||
| 3263a6a5f5 | |||
| 506e5e0bc8 | |||
| c768f8fdd1 | |||
| d45ce48932 | |||
| 3e3ae989f0 | |||
| 786f2d9bf6 | |||
| 85377d13fc | |||
| 51e04b45ec | |||
| bd6c2e519c | |||
| 3f0b35d72e | |||
| 78c867b9a3 | |||
| f213c8f393 | |||
| 1b3f4f1f2a | |||
| c59c696df2 | |||
| 8993a91f12 | |||
| 02c5989612 | |||
| ac42ba880a | |||
| 56f573ecfb | |||
| 2560d3edae | |||
| 351615fb98 | |||
| 11ed86f2a8 | |||
| b01c18ae7f | |||
| 84a3fe85c8 | |||
| 3efc6c5050 | |||
| 42a0534299 | |||
| eec193488d | |||
| 021bc57cd4 | |||
| 022eda9e8b | |||
| 2067092f52 | |||
| 000db07d29 | |||
| 98ae34acd5 | |||
| 698e94856e | |||
| 99ffe43e91 | |||
| 498222371c | |||
| 26288e71d3 | |||
| 19fb466074 | |||
| cd4eb9c3f1 | |||
| 4ef0a3818f | |||
| 77d6dbb3d0 | |||
| e3b8926aef | |||
| efb84ff03d | |||
| 1846a7de73 | |||
| 40d025052d | |||
| bb2914652a | |||
| e6a03f7a58 | |||
| 386ee7b07b | |||
| 788f9de843 | |||
| 5947e38ea0 | |||
| e151c2ee8c | |||
| a093a48675 | |||
| 27b1a51572 | |||
| a867040b88 | |||
| 2e3442f74c | |||
| 43d7a538dc | |||
| c5c06c18f1 | |||
| 972eaa5948 | |||
| 87b23a1fac | |||
| 07174cf52c | |||
| d3fe6fd303 | |||
| 87ca20c047 | |||
| 07494459cc | |||
| 812fbab57b | |||
| afdfc8c609 | |||
| 66f0e1209a | |||
| f0e4885926 | |||
| 1dc2d7f4a2 | |||
| 9193bc3143 | |||
| 3b032f086d | |||
| 746838e276 | |||
| 5ea306850e | |||
| a6be3fdcd0 | |||
| a7a5c6f4cb | |||
| f53b658964 | |||
| 70bf321fd7 | |||
| 35eafd239d | |||
| 3f2baf0131 | |||
| a5a6969db3 | |||
| c176494405 | |||
| 6fbff78b9c | |||
| 0738c2ef54 | |||
| 984e4564f8 | |||
| bc927868f4 | |||
| a0758dc2fc | |||
| 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
|
||||
|
||||
cd web && npm install
|
||||
npm add -g pnpm@9.12.2
|
||||
cd web && pnpm install
|
||||
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-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 stop-containers="cd /workspaces/dify/docker && docker-compose -f docker-compose.middleware.yaml -p dify down"' >> ~/.bashrc
|
||||
|
||||
|
||||
6
.github/workflows/style.yml
vendored
6
.github/workflows/style.yml
vendored
@ -71,16 +71,16 @@ jobs:
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
with:
|
||||
node-version: 20
|
||||
cache: yarn
|
||||
cache: pnpm
|
||||
cache-dependency-path: ./web/package.json
|
||||
|
||||
- name: Web dependencies
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
run: yarn install --frozen-lockfile
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Web style check
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
run: yarn run lint
|
||||
run: pnpm run lint
|
||||
|
||||
docker-compose-template:
|
||||
name: Docker Compose Template
|
||||
|
||||
6
.github/workflows/tool-test-sdks.yaml
vendored
6
.github/workflows/tool-test-sdks.yaml
vendored
@ -32,10 +32,10 @@ jobs:
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: ''
|
||||
cache-dependency-path: 'yarn.lock'
|
||||
cache-dependency-path: 'pnpm-lock.yaml'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: yarn install
|
||||
run: pnpm install
|
||||
|
||||
- name: Test
|
||||
run: yarn test
|
||||
run: pnpm test
|
||||
|
||||
@ -38,11 +38,11 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
if: env.FILES_CHANGED == 'true'
|
||||
run: yarn install --frozen-lockfile
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Run npm script
|
||||
if: env.FILES_CHANGED == 'true'
|
||||
run: npm run auto-gen-i18n
|
||||
run: pnpm run auto-gen-i18n
|
||||
|
||||
- name: Create Pull Request
|
||||
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'
|
||||
with:
|
||||
node-version: 20
|
||||
cache: yarn
|
||||
cache: pnpm
|
||||
cache-dependency-path: ./web/package.json
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
run: yarn install --frozen-lockfile
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Run tests
|
||||
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/
|
||||
.vscode
|
||||
|
||||
# pnpm
|
||||
/.pnpm-store
|
||||
|
||||
@ -61,17 +61,20 @@ def make_request(method, url, max_retries=SSRF_DEFAULT_MAX_RETRIES, **kwargs):
|
||||
if response.status_code not in STATUS_FORCELIST:
|
||||
return response
|
||||
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:
|
||||
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}")
|
||||
if max_retries == 0:
|
||||
raise
|
||||
|
||||
retries += 1
|
||||
if retries <= max_retries:
|
||||
time.sleep(BACKOFF_FACTOR * (2 ** (retries - 1)))
|
||||
raise MaxRetriesExceededError(f"Reached maximum retries ({max_retries}) for URL {url}")
|
||||
raise MaxRetriesExceededError(
|
||||
f"Reached maximum retries ({max_retries}) for URL {url}")
|
||||
|
||||
|
||||
def get(url, max_retries=SSRF_DEFAULT_MAX_RETRIES, **kwargs):
|
||||
|
||||
@ -17,7 +17,8 @@ from extensions.ext_redis import redis_client
|
||||
from models.dataset import Dataset
|
||||
|
||||
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)
|
||||
|
||||
ROUTING_FIELD = "routing_field"
|
||||
@ -134,7 +135,8 @@ class LindormVectorStore(BaseVector):
|
||||
self._client.delete(index=self._collection_name, id=id, params=params)
|
||||
self.refresh()
|
||||
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:
|
||||
if self._using_ugc:
|
||||
@ -145,7 +147,8 @@ class LindormVectorStore(BaseVector):
|
||||
self.refresh()
|
||||
else:
|
||||
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")
|
||||
else:
|
||||
logger.warning(f"Index '{self._collection_name}' does not exist. No deletion performed.")
|
||||
@ -168,7 +171,8 @@ class LindormVectorStore(BaseVector):
|
||||
raise ValueError("All elements in query_vector should be floats")
|
||||
|
||||
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:
|
||||
params = {}
|
||||
if self._using_ugc:
|
||||
@ -220,7 +224,8 @@ class LindormVectorStore(BaseVector):
|
||||
routing=routing,
|
||||
routing_field=self._routing_field,
|
||||
)
|
||||
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 = []
|
||||
for hit in response["hits"]["hits"]:
|
||||
docs.append(
|
||||
@ -238,7 +243,8 @@ class LindormVectorStore(BaseVector):
|
||||
with redis_client.lock(lock_name, timeout=20):
|
||||
collection_exist_cache_key = f"vector_indexing_{self._collection_name}"
|
||||
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
|
||||
if self._client.indices.exists(index=self._collection_name):
|
||||
logger.info(f"{self._collection_name.lower()} already exists.")
|
||||
@ -258,10 +264,13 @@ class LindormVectorStore(BaseVector):
|
||||
hnsw_ef_construction = kwargs.pop("hnsw_ef_construction", 500)
|
||||
ivfpq_m = kwargs.pop("ivfpq_m", dimension)
|
||||
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_ef_construct = kwargs.pop("centroids_hnsw_ef_construct", 500)
|
||||
centroids_hnsw_ef_search = kwargs.pop("centroids_hnsw_ef_search", 100)
|
||||
centroids_hnsw_ef_construct = kwargs.pop(
|
||||
"centroids_hnsw_ef_construct", 500)
|
||||
centroids_hnsw_ef_search = kwargs.pop(
|
||||
"centroids_hnsw_ef_search", 100)
|
||||
mapping = default_text_mapping(
|
||||
dimension,
|
||||
method_name,
|
||||
@ -281,7 +290,8 @@ class LindormVectorStore(BaseVector):
|
||||
using_ugc=self._using_ugc,
|
||||
**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)
|
||||
# logger.info(f"create index success: {self._collection_name}")
|
||||
|
||||
@ -347,7 +357,8 @@ def default_text_mapping(dimension: int, method_name: str, **kwargs: Any) -> dic
|
||||
}
|
||||
|
||||
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 using_ugc and method_name == "ivfpq":
|
||||
mapping["settings"]["index"]["knn_routing"] = True
|
||||
@ -385,7 +396,8 @@ def default_text_search_query(
|
||||
# build complex search_query when either of must/must_not/should/filter is specified
|
||||
if must:
|
||||
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:
|
||||
must.append(query_clause)
|
||||
else:
|
||||
@ -395,19 +407,22 @@ def default_text_search_query(
|
||||
|
||||
if must_not:
|
||||
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
|
||||
|
||||
if should:
|
||||
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
|
||||
if minimum_should_match != 0:
|
||||
boolean_query["minimum_should_match"] = minimum_should_match
|
||||
|
||||
if filters:
|
||||
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
|
||||
|
||||
search_query = {"size": k, "query": {"bool": boolean_query}}
|
||||
|
||||
@ -50,7 +50,7 @@ class WordExtractor(BaseExtractor):
|
||||
|
||||
self.web_path = self.file_path
|
||||
# TODO: use a better way to handle the file
|
||||
self.temp_file = tempfile.NamedTemporaryFile() # noqa: SIM115
|
||||
self.temp_file = tempfile.NamedTemporaryFile()
|
||||
self.temp_file.write(r.content)
|
||||
self.file_path = self.temp_file.name
|
||||
elif not os.path.isfile(self.file_path):
|
||||
|
||||
@ -38,7 +38,6 @@ class AliYuqueDescribeDocumentContentTool(AliYuqueTool, BuiltinTool):
|
||||
book_id = index_page.get("data", {}).get("book", {}).get("id")
|
||||
if not book_id:
|
||||
raise Exception(f"can not parse book_id from {index_page}")
|
||||
|
||||
new_params["book_id"] = book_id
|
||||
new_params["id"] = doc_id
|
||||
data = self.request("GET", token, new_params, "/api/v2/repos/{book_id}/docs/{id}")
|
||||
|
||||
@ -44,11 +44,13 @@ class QuestionClassifierNode(LLMNode):
|
||||
variable_pool = self.graph_runtime_state.variable_pool
|
||||
|
||||
# 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
|
||||
variables = {"query": query}
|
||||
# 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
|
||||
memory = self._fetch_memory(
|
||||
node_data_memory=node_data.memory,
|
||||
@ -56,7 +58,8 @@ class QuestionClassifierNode(LLMNode):
|
||||
)
|
||||
# fetch instruction
|
||||
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 = (
|
||||
self._fetch_files(
|
||||
@ -178,12 +181,15 @@ class QuestionClassifierNode(LLMNode):
|
||||
variable_mapping = {"query": node_data.query_variable_selector}
|
||||
variable_selectors = []
|
||||
if node_data.instruction:
|
||||
variable_template_parser = VariableTemplateParser(template=node_data.instruction)
|
||||
variable_selectors.extend(variable_template_parser.extract_variable_selectors())
|
||||
variable_template_parser = VariableTemplateParser(
|
||||
template=node_data.instruction)
|
||||
variable_selectors.extend(
|
||||
variable_template_parser.extract_variable_selectors())
|
||||
for variable_selector in variable_selectors:
|
||||
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
|
||||
|
||||
@ -204,7 +210,8 @@ class QuestionClassifierNode(LLMNode):
|
||||
context: Optional[str],
|
||||
) -> int:
|
||||
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_template=prompt_template,
|
||||
inputs={},
|
||||
@ -217,13 +224,15 @@ class QuestionClassifierNode(LLMNode):
|
||||
)
|
||||
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:
|
||||
model_instance = ModelInstance(
|
||||
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
|
||||
for parameter_rule in model_config.model_schema.parameter_rules:
|
||||
@ -264,7 +273,8 @@ class QuestionClassifierNode(LLMNode):
|
||||
prompt_messages: list[LLMNodeChatModelMessage] = []
|
||||
if model_mode == ModelMode.CHAT:
|
||||
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)
|
||||
user_prompt_message_1 = LLMNodeChatModelMessage(
|
||||
@ -305,4 +315,5 @@ class QuestionClassifierNode(LLMNode):
|
||||
)
|
||||
|
||||
else:
|
||||
raise InvalidModelTypeError(f"Model mode {model_mode} not support.")
|
||||
raise InvalidModelTypeError(
|
||||
f"Model mode {model_mode} not support.")
|
||||
|
||||
@ -10,7 +10,6 @@ from collections.abc import Generator, Mapping
|
||||
from datetime import datetime
|
||||
from hashlib import sha256
|
||||
from typing import Any, Optional, Union, cast
|
||||
from zoneinfo import available_timezones
|
||||
|
||||
from flask import Response, stream_with_context
|
||||
from flask_restful import fields # type: ignore
|
||||
|
||||
@ -68,7 +68,8 @@ def test_executor_with_json_body_and_object_variable():
|
||||
system_variables={},
|
||||
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
|
||||
node_data = HttpRequestNodeData(
|
||||
@ -123,7 +124,8 @@ def test_executor_with_json_body_and_nested_object_variable():
|
||||
system_variables={},
|
||||
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
|
||||
node_data = HttpRequestNodeData(
|
||||
|
||||
@ -18,6 +18,14 @@ from models.enums import UserFrom
|
||||
from models.workflow import WorkflowNodeExecutionStatus, WorkflowType
|
||||
|
||||
|
||||
def test_plain_text_to_dict():
|
||||
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\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):
|
||||
data = HttpRequestNodeData(
|
||||
title="test",
|
||||
@ -183,7 +191,8 @@ def test_http_request_node_form_with_file(monkeypatch):
|
||||
|
||||
def attr_checker(*args, **kwargs):
|
||||
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"")
|
||||
|
||||
monkeypatch.setattr(
|
||||
|
||||
@ -443,6 +443,8 @@ services:
|
||||
environment:
|
||||
CONSOLE_API_URL: ${CONSOLE_API_URL:-}
|
||||
APP_API_URL: ${APP_API_URL:-}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-}
|
||||
MARKETPLACE_URL: ${MARKETPLACE_URL:-}
|
||||
SENTRY_DSN: ${WEB_SENTRY_DSN:-}
|
||||
NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0}
|
||||
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.
|
||||
# example: http://udify.app/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
|
||||
NEXT_PUBLIC_SENTRY_DSN=
|
||||
@ -26,5 +30,7 @@ NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS=60000
|
||||
# CSP https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
|
||||
NEXT_PUBLIC_CSP_WHITELIST=
|
||||
|
||||
# Github Access Token, used for invoking Github API
|
||||
NEXT_PUBLIC_GITHUB_ACCESS_TOKEN=
|
||||
# The maximum number of top-k value for RAG.
|
||||
NEXT_PUBLIC_TOP_K_MAX_VALUE=10
|
||||
|
||||
@ -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,12 +44,11 @@ package-lock.json
|
||||
.pnp.cjs
|
||||
.pnp.loader.mjs
|
||||
.yarn/
|
||||
.yarnrc.yml
|
||||
|
||||
# pmpm
|
||||
pnpm-lock.yaml
|
||||
|
||||
.favorites.json
|
||||
|
||||
# storybook
|
||||
/storybook-static
|
||||
*storybook.log
|
||||
|
||||
# mise
|
||||
|
||||
@ -1,6 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
# get the list of modified files
|
||||
files=$(git diff --cached --name-only)
|
||||
|
||||
@ -50,7 +47,7 @@ fi
|
||||
if $web_modified; then
|
||||
echo "Running ESLint on web module"
|
||||
cd ./web || exit 1
|
||||
npx lint-staged
|
||||
lint-staged
|
||||
|
||||
echo "Running unit tests check"
|
||||
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
|
||||
if [ -f "../$test_file" ]; then
|
||||
echo "Detected changes in $file, running corresponding unit tests..."
|
||||
npm run test "../$test_file"
|
||||
pnpm run test "../$test_file"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Unit tests failed. Please fix the errors before committing."
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
import type { StorybookConfig } from '@storybook/nextjs'
|
||||
|
||||
const config: StorybookConfig = {
|
||||
// stories: ['../stories/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
|
||||
stories: ['../app/components/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
|
||||
addons: [
|
||||
'@storybook/addon-onboarding',
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-essentials',
|
||||
'@chromatic-com/storybook',
|
||||
'@storybook/addon-interactions',
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/nextjs',
|
||||
options: {},
|
||||
},
|
||||
staticDirs: ['../public'],
|
||||
// stories: ['../stories/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
|
||||
stories: ['../app/components/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
|
||||
addons: [
|
||||
'@storybook/addon-onboarding',
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-essentials',
|
||||
'@chromatic-com/storybook',
|
||||
'@storybook/addon-interactions',
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/nextjs',
|
||||
options: {},
|
||||
},
|
||||
staticDirs: ['../public'],
|
||||
}
|
||||
export default config
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React from '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 '../app/styles/globals.css'
|
||||
@ -8,30 +8,30 @@ import '../app/styles/markdown.scss'
|
||||
import './storybook.css'
|
||||
|
||||
export const decorators = [
|
||||
withThemeByDataAttribute({
|
||||
themes: {
|
||||
light: 'light',
|
||||
dark: 'dark',
|
||||
},
|
||||
defaultTheme: 'light',
|
||||
attributeName: 'data-theme',
|
||||
}),
|
||||
Story => {
|
||||
return <I18nServer>
|
||||
<Story />
|
||||
</I18nServer>
|
||||
}
|
||||
];
|
||||
withThemeByDataAttribute({
|
||||
themes: {
|
||||
light: 'light',
|
||||
dark: 'dark',
|
||||
},
|
||||
defaultTheme: 'light',
|
||||
attributeName: 'data-theme',
|
||||
}),
|
||||
(Story) => {
|
||||
return <I18nServer>
|
||||
<Story />
|
||||
</I18nServer>
|
||||
},
|
||||
]
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i,
|
||||
},
|
||||
},
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default preview
|
||||
|
||||
3
web/.vscode/settings.example.json
vendored
3
web/.vscode/settings.example.json
vendored
@ -21,5 +21,6 @@
|
||||
"editor.defaultFormatter": "vscode.json-language-features"
|
||||
},
|
||||
"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 apk add --no-cache tzdata
|
||||
RUN npm install -g pnpm@9.12.2
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
|
||||
|
||||
# install packages
|
||||
@ -14,12 +17,12 @@ FROM base AS packages
|
||||
WORKDIR /app/web
|
||||
|
||||
COPY package.json .
|
||||
COPY yarn.lock .
|
||||
COPY pnpm-lock.yaml .
|
||||
|
||||
# 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
|
||||
FROM base AS builder
|
||||
@ -27,7 +30,8 @@ WORKDIR /app/web
|
||||
COPY --from=packages /app/web/ .
|
||||
COPY . .
|
||||
|
||||
RUN yarn build
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
RUN pnpm build
|
||||
|
||||
|
||||
# production stage
|
||||
@ -38,6 +42,8 @@ ENV EDITION=SELF_HOSTED
|
||||
ENV DEPLOY_ENV=PRODUCTION
|
||||
ENV CONSOLE_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 NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
@ -57,8 +63,7 @@ COPY docker/entrypoint.sh ./entrypoint.sh
|
||||
|
||||
|
||||
# global runtime packages
|
||||
RUN yarn global add pm2 \
|
||||
&& yarn cache clean \
|
||||
RUN pnpm add -g pm2 \
|
||||
&& mkdir /.pm2 \
|
||||
&& chown -R 1001:0 /.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
|
||||
|
||||
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:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
# or
|
||||
yarn install --frozen-lockfile
|
||||
pnpm install
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
Then, start the server:
|
||||
|
||||
```bash
|
||||
npm run start
|
||||
pnpm run start
|
||||
```
|
||||
|
||||
If you want to customize the host and port:
|
||||
|
||||
```bash
|
||||
npm run start --port=3001 --host=0.0.0.0
|
||||
pnpm run start --port=3001 --host=0.0.0.0
|
||||
```
|
||||
|
||||
## Storybook
|
||||
@ -81,7 +77,7 @@ This project uses [Storybook](https://storybook.js.org/) for UI component develo
|
||||
To start the storybook server, run:
|
||||
|
||||
```bash
|
||||
yarn storybook
|
||||
pnpm storybook
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```bash
|
||||
npm run test
|
||||
pnpm run test
|
||||
```
|
||||
|
||||
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 { PageType } from '@/app/components/base/features/new-feature-panel/annotation-reply/type'
|
||||
|
||||
export type IProps = {
|
||||
export interface IProps {
|
||||
params: { appId: string }
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { type Locale } from '@/i18n'
|
||||
import type { Locale } from '@/i18n'
|
||||
import DevelopMain from '@/app/components/develop'
|
||||
|
||||
export type IDevelopProps = {
|
||||
|
||||
@ -46,7 +46,7 @@ export default function ChartView({ appId }: IChartViewProps) {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='flex flex-row items-center mt-8 mb-4 text-gray-900 text-base'>
|
||||
<div className='flex flex-row items-center mt-8 mb-4 system-xl-semibold text-text-primary'>
|
||||
<span className='mr-3'>{t('appOverview.analysis.title')}</span>
|
||||
<SimpleSelect
|
||||
items={Object.entries(TIME_PERIOD_MAPPING).map(([k, v]) => ({ value: k, name: t(`appLog.filter.period.${v.name}`) }))}
|
||||
|
||||
@ -12,7 +12,7 @@ const Overview = async ({
|
||||
params: { appId },
|
||||
}: IDevelopProps) => {
|
||||
return (
|
||||
<div className="h-full px-4 sm:px-16 py-6 overflow-scroll">
|
||||
<div className="h-full px-4 sm:px-12 py-6 overflow-scroll bg-chatbot-bg">
|
||||
<ApikeyInfoPanel />
|
||||
<TracingPanel />
|
||||
<CardView appId={appId} />
|
||||
|
||||
@ -1,20 +1,18 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiEqualizer2Line,
|
||||
} from '@remixicon/react'
|
||||
import type { PopupProps } from './config-popup'
|
||||
import ConfigPopup from './config-popup'
|
||||
import cn from '@/utils/classnames'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { Settings04 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
|
||||
const I18N_PREFIX = 'app.tracing'
|
||||
|
||||
type Props = {
|
||||
readOnly: boolean
|
||||
className?: string
|
||||
@ -28,7 +26,6 @@ const ConfigBtn: FC<Props> = ({
|
||||
controlShowPopup,
|
||||
...popupProps
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [open, doSetOpen] = useState(false)
|
||||
const openRef = useRef(open)
|
||||
const setOpen = useCallback((v: boolean) => {
|
||||
@ -50,21 +47,6 @@ const ConfigBtn: FC<Props> = ({
|
||||
if (popupProps.readOnly && !hasConfigured)
|
||||
return null
|
||||
|
||||
const triggerContent = hasConfigured
|
||||
? (
|
||||
<div className={cn(className, 'p-1 rounded-md hover:bg-black/5 cursor-pointer')}>
|
||||
<Settings04 className='w-4 h-4 text-gray-500' />
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<Button variant='primary'
|
||||
className={cn(className, '!h-8 !px-3 select-none')}
|
||||
>
|
||||
<Settings04 className='mr-1 w-4 h-4' />
|
||||
<span className='text-[13px]'>{t(`${I18N_PREFIX}.config`)}</span>
|
||||
</Button>
|
||||
)
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
@ -72,11 +54,13 @@ const ConfigBtn: FC<Props> = ({
|
||||
placement='bottom-end'
|
||||
offset={{
|
||||
mainAxis: 12,
|
||||
crossAxis: hasConfigured ? 8 : 0,
|
||||
crossAxis: hasConfigured ? 8 : 49,
|
||||
}}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={handleTrigger}>
|
||||
{triggerContent}
|
||||
<div className={cn(className, 'p-1 rounded-md')}>
|
||||
<RiEqualizer2Line className='w-4 h-4 text-text-tertiary' />
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[11]'>
|
||||
<ConfigPopup {...popupProps} />
|
||||
|
||||
@ -11,6 +11,8 @@ import ProviderConfigModal from './provider-config-modal'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
const I18N_PREFIX = 'app.tracing'
|
||||
|
||||
@ -77,7 +79,6 @@ const ConfigPopup: FC<PopupProps> = ({
|
||||
className='ml-3'
|
||||
defaultValue={enabled}
|
||||
onChange={onStatusChange}
|
||||
size='l'
|
||||
disabled={providerAllNotConfigured}
|
||||
/>
|
||||
)
|
||||
@ -106,15 +107,15 @@ const ConfigPopup: FC<PopupProps> = ({
|
||||
)
|
||||
|
||||
return (
|
||||
<div className='w-[420px] p-4 rounded-2xl bg-white border-[0.5px] border-black/5 shadow-lg'>
|
||||
<div className='w-[420px] p-4 rounded-2xl bg-components-panel-bg border-[0.5px] border-components-panel-border shadow-xl'>
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='flex items-center'>
|
||||
<TracingIcon size='md' className='mr-2' />
|
||||
<div className='leading-[120%] text-[18px] font-semibold text-gray-900'>{t(`${I18N_PREFIX}.tracing`)}</div>
|
||||
<div className='text-text-primary title-2xl-semibold'>{t(`${I18N_PREFIX}.tracing`)}</div>
|
||||
</div>
|
||||
<div className='flex items-center'>
|
||||
<Indicator color={enabled ? 'green' : 'gray'} />
|
||||
<div className='ml-1.5 text-xs font-semibold text-gray-500 uppercase'>
|
||||
<div className={cn('ml-1 system-xs-semibold-uppercase text-text-tertiary', enabled && 'text-util-colors-green-green-600')}>
|
||||
{t(`${I18N_PREFIX}.${enabled ? 'enabled' : 'disabled'}`)}
|
||||
</div>
|
||||
{!readOnly && (
|
||||
@ -130,19 +131,18 @@ const ConfigPopup: FC<PopupProps> = ({
|
||||
: switchContent}
|
||||
</>
|
||||
)}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='mt-2 leading-4 text-xs font-normal text-gray-500'>
|
||||
<div className='mt-2 system-xs-regular text-text-tertiary'>
|
||||
{t(`${I18N_PREFIX}.tracingDescription`)}
|
||||
</div>
|
||||
<div className='mt-3 h-px bg-gray-100'></div>
|
||||
<div className='mt-3'>
|
||||
<Divider className='my-3' />
|
||||
<div className='relative'>
|
||||
{(providerAllConfigured || providerAllNotConfigured)
|
||||
? (
|
||||
<>
|
||||
<div className='leading-4 text-xs font-medium text-gray-500 uppercase'>{t(`${I18N_PREFIX}.configProviderTitle.${providerAllConfigured ? 'configured' : 'notConfigured'}`)}</div>
|
||||
<div className='system-xs-medium-uppercase text-text-tertiary'>{t(`${I18N_PREFIX}.configProviderTitle.${providerAllConfigured ? 'configured' : 'notConfigured'}`)}</div>
|
||||
<div className='mt-2 space-y-2'>
|
||||
{langSmithPanel}
|
||||
{langfusePanel}
|
||||
@ -151,11 +151,11 @@ const ConfigPopup: FC<PopupProps> = ({
|
||||
)
|
||||
: (
|
||||
<>
|
||||
<div className='leading-4 text-xs font-medium text-gray-500 uppercase'>{t(`${I18N_PREFIX}.configProviderTitle.configured`)}</div>
|
||||
<div className='system-xs-medium-uppercase text-text-tertiary'>{t(`${I18N_PREFIX}.configProviderTitle.configured`)}</div>
|
||||
<div className='mt-2'>
|
||||
{langSmithConfig ? langSmithPanel : langfusePanel}
|
||||
</div>
|
||||
<div className='mt-3 leading-4 text-xs font-medium text-gray-500 uppercase'>{t(`${I18N_PREFIX}.configProviderTitle.moreProvider`)}</div>
|
||||
<div className='mt-3 system-xs-medium-uppercase text-text-tertiary'>{t(`${I18N_PREFIX}.configProviderTitle.moreProvider`)}</div>
|
||||
<div className='mt-2'>
|
||||
{!langSmithConfig ? langSmithPanel : langfusePanel}
|
||||
</div>
|
||||
|
||||
@ -26,7 +26,7 @@ const Field: FC<Props> = ({
|
||||
return (
|
||||
<div className={cn(className)}>
|
||||
<div className='flex py-[7px]'>
|
||||
<div className={cn(labelClassName, 'flex items-center h-[18px] text-[13px] font-medium text-gray-900')}>{label} </div>
|
||||
<div className={cn(labelClassName, 'flex items-center h-[18px] text-[13px] font-medium text-text-primary')}>{label} </div>
|
||||
{isRequired && <span className='ml-0.5 text-xs font-semibold text-[#D92D20]'>*</span>}
|
||||
</div>
|
||||
<Input
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import {
|
||||
RiArrowDownDoubleLine,
|
||||
} from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { useBoolean } from 'ahooks'
|
||||
@ -8,7 +11,6 @@ import type { LangFuseConfig, LangSmithConfig } from './type'
|
||||
import { TracingProvider } from './type'
|
||||
import TracingIcon from './tracing-icon'
|
||||
import ConfigButton from './config-button'
|
||||
import cn from '@/utils/classnames'
|
||||
import { LangfuseIcon, LangsmithIcon } from '@/app/components/base/icons/src/public/tracing'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
import { fetchTracingConfig as doFetchTracingConfig, fetchTracingStatus, updateTracingStatus } from '@/service/apps'
|
||||
@ -16,6 +18,8 @@ import type { TracingStatus } from '@/models/app'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
const I18N_PREFIX = 'app.tracing'
|
||||
|
||||
@ -27,7 +31,7 @@ const Title = ({
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className={cn(className, 'flex items-center text-lg font-semibold text-gray-900')}>
|
||||
<div className={cn('flex items-center system-xl-semibold text-text-primary', className)}>
|
||||
{t('common.appMenus.overview')}
|
||||
</div>
|
||||
)
|
||||
@ -135,43 +139,68 @@ const Panel: FC = () => {
|
||||
return (
|
||||
<div className={cn('mb-3 flex justify-between items-center')}>
|
||||
<Title className='h-[41px]' />
|
||||
<div className='flex items-center p-2 rounded-xl border-[0.5px] border-gray-200 shadow-xs cursor-pointer hover:bg-gray-100' onClick={showPopup}>
|
||||
{!inUseTracingProvider
|
||||
? <>
|
||||
<TracingIcon size='md' className='mr-2' />
|
||||
<div className='leading-5 text-sm font-semibold text-gray-700'>{t(`${I18N_PREFIX}.title`)}</div>
|
||||
</>
|
||||
: <InUseProviderIcon className='ml-1 h-4' />}
|
||||
|
||||
{hasConfiguredTracing && (
|
||||
<div className='ml-4 mr-1 flex items-center'>
|
||||
<Indicator color={enabled ? 'green' : 'gray'} />
|
||||
<div className='ml-1.5 text-xs font-semibold text-gray-500 uppercase'>
|
||||
{t(`${I18N_PREFIX}.${enabled ? 'enabled' : 'disabled'}`)}
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center p-2 rounded-xl bg-background-default-dodge border-t border-l-[0.5px] border-effects-highlight shadow-xs cursor-pointer hover:bg-background-default-lighter hover:border-effects-highlight-lightmode-off',
|
||||
controlShowPopup && 'bg-background-default-lighter border-effects-highlight-lightmode-off',
|
||||
)}
|
||||
onClick={showPopup}
|
||||
>
|
||||
{!inUseTracingProvider && (
|
||||
<>
|
||||
<TracingIcon size='md' />
|
||||
<div className='mx-2 system-sm-semibold text-text-secondary'>{t(`${I18N_PREFIX}.title`)}</div>
|
||||
<div className='flex items-center' onClick={e => e.stopPropagation()}>
|
||||
<ConfigButton
|
||||
appId={appId}
|
||||
readOnly={readOnly}
|
||||
hasConfigured={false}
|
||||
enabled={enabled}
|
||||
onStatusChange={handleTracingEnabledChange}
|
||||
chosenProvider={inUseTracingProvider}
|
||||
onChooseProvider={handleChooseProvider}
|
||||
langSmithConfig={langSmithConfig}
|
||||
langFuseConfig={langFuseConfig}
|
||||
onConfigUpdated={handleTracingConfigUpdated}
|
||||
onConfigRemoved={handleTracingConfigRemoved}
|
||||
controlShowPopup={controlShowPopup}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Divider type='vertical' className='h-3.5' />
|
||||
<div className='p-1 rounded-md'>
|
||||
<RiArrowDownDoubleLine className='w-4 h-4 text-text-tertiary' />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{hasConfiguredTracing && (
|
||||
<div className='ml-2 w-px h-3.5 bg-gray-200'></div>
|
||||
<>
|
||||
<div className='ml-4 mr-1 flex items-center'>
|
||||
<Indicator color={enabled ? 'green' : 'gray'} />
|
||||
<div className='ml-1.5 system-xs-semibold-uppercase text-text-tertiary'>
|
||||
{t(`${I18N_PREFIX}.${enabled ? 'enabled' : 'disabled'}`)}
|
||||
</div>
|
||||
</div>
|
||||
<InUseProviderIcon className='ml-1 h-4' />
|
||||
<Divider type='vertical' className='h-3.5' />
|
||||
<div className='flex items-center' onClick={e => e.stopPropagation()}>
|
||||
<ConfigButton
|
||||
appId={appId}
|
||||
readOnly={readOnly}
|
||||
hasConfigured
|
||||
className='ml-2'
|
||||
enabled={enabled}
|
||||
onStatusChange={handleTracingEnabledChange}
|
||||
chosenProvider={inUseTracingProvider}
|
||||
onChooseProvider={handleChooseProvider}
|
||||
langSmithConfig={langSmithConfig}
|
||||
langFuseConfig={langFuseConfig}
|
||||
onConfigUpdated={handleTracingConfigUpdated}
|
||||
onConfigRemoved={handleTracingConfigRemoved}
|
||||
controlShowPopup={controlShowPopup}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className='flex items-center' onClick={e => e.stopPropagation()}>
|
||||
<ConfigButton
|
||||
appId={appId}
|
||||
readOnly={readOnly}
|
||||
hasConfigured
|
||||
className='ml-2'
|
||||
enabled={enabled}
|
||||
onStatusChange={handleTracingEnabledChange}
|
||||
chosenProvider={inUseTracingProvider}
|
||||
onChooseProvider={handleChooseProvider}
|
||||
langSmithConfig={langSmithConfig}
|
||||
langFuseConfig={langFuseConfig}
|
||||
onConfigUpdated={handleTracingConfigUpdated}
|
||||
onConfigRemoved={handleTracingConfigRemoved}
|
||||
controlShowPopup={controlShowPopup}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -17,6 +17,7 @@ import { LinkExternal02 } from '@/app/components/base/icons/src/vender/line/gene
|
||||
import Confirm from '@/app/components/base/confirm'
|
||||
import { addTracingConfig, removeTracingConfig, updateTracingConfig } from '@/service/apps'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
|
||||
type Props = {
|
||||
appId: string
|
||||
@ -152,11 +153,11 @@ const ProviderConfigModal: FC<Props> = ({
|
||||
? (
|
||||
<PortalToFollowElem open>
|
||||
<PortalToFollowElemContent className='w-full h-full z-[60]'>
|
||||
<div className='fixed inset-0 flex items-center justify-center bg-black/[.25]'>
|
||||
<div className='mx-2 w-[640px] max-h-[calc(100vh-120px)] bg-white shadow-xl rounded-2xl overflow-y-auto'>
|
||||
<div className='fixed inset-0 flex items-center justify-center bg-background-overlay'>
|
||||
<div className='mx-2 w-[640px] max-h-[calc(100vh-120px)] bg-components-panel-bg shadow-xl rounded-2xl overflow-y-auto'>
|
||||
<div className='px-8 pt-8'>
|
||||
<div className='flex justify-between items-center mb-4'>
|
||||
<div className='text-xl font-semibold text-gray-900'>{t(`${I18N_PREFIX}.title`)}{t(`app.tracing.${type}.title`)}</div>
|
||||
<div className='title-2xl-semibold text-text-primary'>{t(`${I18N_PREFIX}.title`)}{t(`app.tracing.${type}.title`)}</div>
|
||||
</div>
|
||||
|
||||
<div className='space-y-4'>
|
||||
@ -230,16 +231,16 @@ const ProviderConfigModal: FC<Props> = ({
|
||||
{isEdit && (
|
||||
<>
|
||||
<Button
|
||||
className='h-9 text-sm font-medium text-gray-700'
|
||||
className='h-9 text-sm font-medium text-text-secondary'
|
||||
onClick={showRemoveConfirm}
|
||||
>
|
||||
<span className='text-[#D92D20]'>{t('common.operation.remove')}</span>
|
||||
</Button>
|
||||
<div className='mx-3 w-px h-[18px] bg-gray-200'></div>
|
||||
<Divider className='mx-3 h-[18px]'/>
|
||||
</>
|
||||
)}
|
||||
<Button
|
||||
className='mr-2 h-9 text-sm font-medium text-gray-700'
|
||||
className='mr-2 h-9 text-sm font-medium text-text-secondary'
|
||||
onClick={onCancel}
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
@ -256,9 +257,9 @@ const ProviderConfigModal: FC<Props> = ({
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className='border-t-[0.5px] border-t-black/5'>
|
||||
<div className='flex justify-center items-center py-3 bg-gray-50 text-xs text-gray-500'>
|
||||
<Lock01 className='mr-1 w-3 h-3 text-gray-500' />
|
||||
<div className='border-t-[0.5px] border-divider-regular'>
|
||||
<div className='flex justify-center items-center py-3 bg-background-section-burn text-xs text-text-tertiary'>
|
||||
<Lock01 className='mr-1 w-3 h-3 text-text-tertiary' />
|
||||
{t('common.modelProvider.encrypted.front')}
|
||||
<a
|
||||
className='text-primary-600 mx-1'
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
import {
|
||||
RiEqualizer2Line,
|
||||
} from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { TracingProvider } from './type'
|
||||
import cn from '@/utils/classnames'
|
||||
import { LangfuseIconBig, LangsmithIconBig } from '@/app/components/base/icons/src/public/tracing'
|
||||
import { Settings04 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { Eye as View } from '@/app/components/base/icons/src/vender/solid/general'
|
||||
|
||||
const I18N_PREFIX = 'app.tracing'
|
||||
@ -61,34 +63,37 @@ const ProviderPanel: FC<Props> = ({
|
||||
}, [hasConfigured, isChosen, onChoose, readOnly])
|
||||
return (
|
||||
<div
|
||||
className={cn(isChosen ? 'border-primary-400' : 'border-transparent', !isChosen && hasConfigured && !readOnly && 'cursor-pointer', 'px-4 py-3 rounded-xl border-[1.5px] bg-gray-100')}
|
||||
className={cn(
|
||||
'px-4 py-3 rounded-xl border-[1.5px] bg-background-section-burn',
|
||||
isChosen ? 'bg-background-section border-components-option-card-option-selected-border' : 'border-transparent',
|
||||
!isChosen && hasConfigured && !readOnly && 'cursor-pointer',
|
||||
)}
|
||||
onClick={handleChosen}
|
||||
>
|
||||
<div className={'flex justify-between items-center space-x-1'}>
|
||||
<div className='flex items-center'>
|
||||
<Icon className='h-6' />
|
||||
{isChosen && <div className='ml-1 flex items-center h-4 px-1 rounded-[4px] border border-primary-500 leading-4 text-xs font-medium text-primary-500 uppercase '>{t(`${I18N_PREFIX}.inUse`)}</div>}
|
||||
{isChosen && <div className='ml-1 flex items-center h-4 px-1 rounded-[4px] border border-text-accent-secondary system-2xs-medium-uppercase text-text-accent-secondary'>{t(`${I18N_PREFIX}.inUse`)}</div>}
|
||||
</div>
|
||||
{!readOnly && (
|
||||
<div className={'flex justify-between items-center space-x-1'}>
|
||||
{hasConfigured && (
|
||||
<div className='flex px-2 items-center h-6 bg-white rounded-md border-[0.5px] border-gray-200 shadow-xs cursor-pointer text-gray-700 space-x-1' onClick={viewBtnClick} >
|
||||
<div className='flex px-2 items-center h-6 bg-components-button-secondary-bg rounded-md border-[0.5px] border-components-button-secondary-border shadow-xs cursor-pointer text-text-secondary space-x-1' onClick={viewBtnClick} >
|
||||
<View className='w-3 h-3'/>
|
||||
<div className='text-xs font-medium'>{t(`${I18N_PREFIX}.view`)}</div>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className='flex px-2 items-center h-6 bg-white rounded-md border-[0.5px] border-gray-200 shadow-xs cursor-pointer text-gray-700 space-x-1'
|
||||
className='flex px-2 items-center h-6 bg-components-button-secondary-bg rounded-md border-[0.5px] border-components-button-secondary-border shadow-xs cursor-pointer text-text-secondary space-x-1'
|
||||
onClick={handleConfigBtnClick}
|
||||
>
|
||||
<Settings04 className='w-3 h-3' />
|
||||
<RiEqualizer2Line className='w-3 h-3' />
|
||||
<div className='text-xs font-medium'>{t(`${I18N_PREFIX}.config`)}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
<div className='mt-2 leading-4 text-xs font-normal text-gray-500'>
|
||||
<div className='mt-2 system-xs-regular text-text-tertiary'>
|
||||
{t(`${I18N_PREFIX}.${type}.description`)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,45 +0,0 @@
|
||||
'use client'
|
||||
import { ChevronDoubleDownIcon } from '@heroicons/react/20/solid'
|
||||
import type { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import React, { useCallback } from 'react'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
|
||||
const I18N_PREFIX = 'app.tracing'
|
||||
|
||||
type Props = {
|
||||
isFold: boolean
|
||||
onFoldChange: (isFold: boolean) => void
|
||||
}
|
||||
|
||||
const ToggleFoldBtn: FC<Props> = ({
|
||||
isFold,
|
||||
onFoldChange,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const handleFoldChange = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
|
||||
e.stopPropagation()
|
||||
onFoldChange(!isFold)
|
||||
}, [isFold, onFoldChange])
|
||||
return (
|
||||
// text-[0px] to hide spacing between tooltip elements
|
||||
<div className='shrink-0 cursor-pointer text-[0px]' onClick={handleFoldChange}>
|
||||
<Tooltip
|
||||
popupContent={t(`${I18N_PREFIX}.${isFold ? 'expand' : 'collapse'}`)}
|
||||
>
|
||||
{isFold && (
|
||||
<div className='p-1 rounded-md text-gray-500 hover:text-gray-800 hover:bg-black/5'>
|
||||
<ChevronDoubleDownIcon className='w-4 h-4' />
|
||||
</div>
|
||||
)}
|
||||
{!isFold && (
|
||||
<div className='p-2 rounded-lg text-gray-500 border-[0.5px] border-gray-200 hover:text-gray-800 hover:bg-black/5'>
|
||||
<ChevronDoubleDownIcon className='w-4 h-4 transform rotate-180' />
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(ToggleFoldBtn)
|
||||
@ -26,7 +26,7 @@ import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
|
||||
import { useStore as useTagStore } from '@/app/components/base/tag-management/store'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { useExternalApiPanel } from '@/context/external-api-panel-context'
|
||||
// eslint-disable-next-line import/order
|
||||
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import Input from '@/app/components/base/input'
|
||||
|
||||
|
||||
20
web/app/(commonLayout)/plugins/page.tsx
Normal file
20
web/app/(commonLayout)/plugins/page.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
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'
|
||||
import { getLocaleOnServer } from '@/i18n/server'
|
||||
|
||||
const PluginList = async () => {
|
||||
const locale = await getLocaleOnServer()
|
||||
return (
|
||||
<PluginPage
|
||||
plugins={<PluginsPanel />}
|
||||
marketplace={<Marketplace locale={locale} pluginTypeSwitchClassName='top-[60px]' searchBoxAutoAnimate={false} />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const metadata = {
|
||||
title: 'Plugins - Dify',
|
||||
}
|
||||
|
||||
export default PluginList
|
||||
@ -8,7 +8,7 @@ import { logout } from '@/service/common'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { LogOut01 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
|
||||
export type IAppSelector = {
|
||||
export interface IAppSelector {
|
||||
isMobile: boolean
|
||||
}
|
||||
|
||||
|
||||
@ -60,18 +60,18 @@ export default function AppBasic({ icon, icon_background, name, isExternal, type
|
||||
return (
|
||||
<div className="flex items-start p-1">
|
||||
{icon && icon_background && iconType === 'app' && (
|
||||
<div className='flex-shrink-0 mr-3'>
|
||||
<div className='shrink-0 mr-3'>
|
||||
<AppIcon icon={icon} background={icon_background} />
|
||||
</div>
|
||||
)}
|
||||
{iconType !== 'app'
|
||||
&& <div className='flex-shrink-0 mr-3'>
|
||||
&& <div className='shrink-0 mr-3'>
|
||||
{ICON_MAP[iconType]}
|
||||
</div>
|
||||
|
||||
}
|
||||
{mode === 'expand' && <div className="group">
|
||||
<div className={`flex flex-row items-center text-sm font-semibold text-gray-700 group-hover:text-gray-900 break-all ${textStyle?.main ?? ''}`}>
|
||||
<div className={`flex flex-row items-center text-sm font-semibold text-text-secondary group-hover:text-text-primary break-all ${textStyle?.main ?? ''}`}>
|
||||
{name}
|
||||
{hoverTip
|
||||
&& <Tooltip
|
||||
@ -86,7 +86,7 @@ export default function AppBasic({ icon, icon_background, name, isExternal, type
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<div className={`text-xs font-normal text-gray-500 group-hover:text-gray-700 break-all ${textStyle?.extra ?? ''}`}>{type}</div>
|
||||
<div className={`text-xs font-normal text-text-tertiary group-hover:text-text-secondary break-all ${textStyle?.extra ?? ''}`}>{type}</div>
|
||||
<div className='text-text-tertiary system-2xs-medium-uppercase'>{isExternal ? t('dataset.externalTag') : ''}</div>
|
||||
</div>}
|
||||
</div>
|
||||
|
||||
@ -6,11 +6,11 @@ import useSWR from 'swr'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { fetchAnnotationsCount } from '@/service/log'
|
||||
|
||||
export type QueryParam = {
|
||||
export interface QueryParam {
|
||||
keyword?: string
|
||||
}
|
||||
|
||||
type IFilterProps = {
|
||||
interface IFilterProps {
|
||||
appId: string
|
||||
queryParams: QueryParam
|
||||
setQueryParams: (v: QueryParam) => void
|
||||
|
||||
@ -9,7 +9,7 @@ import ActionButton from '@/app/components/base/action-button'
|
||||
import useTimestamp from '@/hooks/use-timestamp'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
list: AnnotationItem[]
|
||||
onRemove: (id: string) => void
|
||||
onView: (item: AnnotationItem) => void
|
||||
|
||||
@ -23,7 +23,7 @@ const FeaturePanel: FC<IFeaturePanelProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
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 */}
|
||||
<div className={cn('px-3 pt-2', hasHeaderBottomBorder && 'border-b border-divider-subtle')}>
|
||||
<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 { LanguagesSupported } from '@/i18n/language'
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
showWarning: boolean
|
||||
onShowEditModal: () => void
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ import ConfirmAddVar from './confirm-add-var'
|
||||
import s from './style.module.css'
|
||||
import PromptEditorHeightResizeWrap from './prompt-editor-height-resize-wrap'
|
||||
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 type { CompletionParams } from '@/types/app'
|
||||
import { AppType } from '@/types/app'
|
||||
|
||||
@ -3,7 +3,7 @@ import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
className?: string
|
||||
title: string
|
||||
children: JSX.Element
|
||||
|
||||
@ -23,7 +23,7 @@ import { DEFAULT_VALUE_MAX_LEN } from '@/config'
|
||||
|
||||
const TEXT_MAX_LENGTH = 256
|
||||
|
||||
export type IConfigModalProps = {
|
||||
export interface IConfigModalProps {
|
||||
isCreate?: boolean
|
||||
payload?: InputVar
|
||||
isShow: boolean
|
||||
|
||||
@ -3,7 +3,7 @@ import type { FC } from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import Input from '@/app/components/base/input'
|
||||
|
||||
export type IConfigStringProps = {
|
||||
export interface IConfigStringProps {
|
||||
value: number | undefined
|
||||
maxLength: number
|
||||
modelId: string
|
||||
@ -28,7 +28,7 @@ const ConfigString: FC<IConfigStringProps> = ({
|
||||
min={1}
|
||||
value={value || ''}
|
||||
onChange={(e) => {
|
||||
let value = parseInt(e.target.value, 10)
|
||||
let value = Number.parseInt(e.target.value, 10)
|
||||
if (value > maxLength)
|
||||
value = maxLength
|
||||
|
||||
|
||||
@ -3,7 +3,6 @@ import type { FC } from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import type { Timeout } from 'ahooks/lib/useRequest/src/types'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import produce from 'immer'
|
||||
import {
|
||||
@ -34,7 +33,7 @@ import { InputVarType } from '@/app/components/workflow/types'
|
||||
|
||||
export const ADD_EXTERNAL_DATA_TOOL = 'ADD_EXTERNAL_DATA_TOOL'
|
||||
|
||||
type ExternalDataToolParams = {
|
||||
interface ExternalDataToolParams {
|
||||
key: string
|
||||
type: string
|
||||
index: number
|
||||
@ -44,13 +43,13 @@ type ExternalDataToolParams = {
|
||||
icon_background?: string
|
||||
}
|
||||
|
||||
export type IConfigVarProps = {
|
||||
export interface IConfigVarProps {
|
||||
promptVariables: PromptVariable[]
|
||||
readonly?: boolean
|
||||
onPromptVariablesChange?: (promptVariables: PromptVariable[]) => void
|
||||
}
|
||||
|
||||
let conflictTimer: Timeout
|
||||
let conflictTimer: number
|
||||
|
||||
const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVariablesChange }) => {
|
||||
const { t } = useTranslation()
|
||||
@ -107,7 +106,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
||||
onPromptVariablesChange?.(newPromptVariables)
|
||||
}
|
||||
const updatePromptKey = (index: number, newKey: string) => {
|
||||
clearTimeout(conflictTimer)
|
||||
window.clearTimeout(conflictTimer)
|
||||
const { isValid, errorKey, errorMessageKey } = checkKeys([newKey], true)
|
||||
if (!isValid) {
|
||||
Toast.notify({
|
||||
@ -127,7 +126,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
||||
return item
|
||||
})
|
||||
|
||||
conflictTimer = setTimeout(() => {
|
||||
conflictTimer = window.setTimeout(() => {
|
||||
const isKeyExists = promptVariables.some(item => item.key?.trim() === newKey.trim())
|
||||
if (isKeyExists) {
|
||||
Toast.notify({
|
||||
|
||||
@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import cn from '@/utils/classnames'
|
||||
import type { InputVarType } from '@/app/components/workflow/types'
|
||||
import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon'
|
||||
export type ISelectTypeItemProps = {
|
||||
export interface ISelectTypeItemProps {
|
||||
type: InputVarType
|
||||
selected: boolean
|
||||
onClick: () => void
|
||||
|
||||
@ -1,21 +1,25 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import produce from 'immer'
|
||||
import {
|
||||
RiDeleteBinLine,
|
||||
RiEqualizer2Line,
|
||||
RiHammerFill,
|
||||
RiInformation2Line,
|
||||
} from '@remixicon/react'
|
||||
import { useFormattingChangedDispatcher } from '../../../debug/hooks'
|
||||
import SettingBuiltInTool from './setting-built-in-tool'
|
||||
import cn from '@/utils/classnames'
|
||||
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 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 Toast from '@/app/components/base/toast'
|
||||
import ConfigContext from '@/context/debug-configuration'
|
||||
import type { AgentTool } from '@/types/app'
|
||||
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 Tooltip from '@/app/components/base/tooltip'
|
||||
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
|
||||
const AgentTools: FC = () => {
|
||||
@ -33,9 +42,19 @@ const AgentTools: FC = () => {
|
||||
const formattingChangedDispatcher = useFormattingChangedDispatcher()
|
||||
|
||||
const [currentTool, setCurrentTool] = useState<AgentToolWithMoreInfo>(null)
|
||||
const currentCollection = useMemo(() => {
|
||||
if (!currentTool) return null
|
||||
const collection = collectionList.find(collection => collection.id.split('/').pop() === currentTool?.provider_id.split('/').pop() && collection.type === currentTool?.provider_type)
|
||||
return collection
|
||||
}, [currentTool, collectionList])
|
||||
const [isShowSettingTool, setIsShowSettingTool] = useState(false)
|
||||
const [isShowSettingAuth, setShowSettingAuth] = useState(false)
|
||||
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.split('/').pop() === item.provider_id.split('/').pop()
|
||||
&& collection.type === item.provider_type,
|
||||
)
|
||||
const icon = collection?.icon
|
||||
return {
|
||||
...item,
|
||||
@ -55,10 +74,39 @@ const AgentTools: FC = () => {
|
||||
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 (
|
||||
<>
|
||||
<Panel
|
||||
className="mt-2"
|
||||
className={cn('mt-2', tools.length === 0 && 'pb-2')}
|
||||
noBodySpacing={tools.length === 0}
|
||||
headerIcon={
|
||||
<RiHammerFill className='w-4 h-4 text-primary-500' />
|
||||
@ -81,7 +129,14 @@ const AgentTools: FC = () => {
|
||||
{tools.length < MAX_TOOLS_NUM && (
|
||||
<>
|
||||
<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>
|
||||
@ -90,72 +145,77 @@ const AgentTools: FC = () => {
|
||||
<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) => (
|
||||
<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'>
|
||||
{(item.isDeleted || item.notAuthor)
|
||||
? (
|
||||
<DefaultToolIcon className='w-6 h-6' />
|
||||
)
|
||||
: (
|
||||
typeof item.icon === 'string'
|
||||
? (
|
||||
<div
|
||||
className='w-6 h-6 bg-cover bg-center rounded-md'
|
||||
style={{
|
||||
backgroundImage: `url(${item.icon})`,
|
||||
}}
|
||||
></div>
|
||||
)
|
||||
: (
|
||||
<AppIcon
|
||||
className='rounded-md'
|
||||
size='tiny'
|
||||
icon={item.icon?.content}
|
||||
background={item.icon?.background}
|
||||
/>
|
||||
))}
|
||||
{item.isDeleted && <DefaultToolIcon className='w-5 h-5' />}
|
||||
{!item.isDeleted && (
|
||||
<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} />}
|
||||
</div>
|
||||
)}
|
||||
<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')}
|
||||
className={cn(
|
||||
'grow w-0 ml-1.5 flex items-center system-xs-regular truncate',
|
||||
(item.isDeleted || item.notAuthor || !item.enabled) ? 'opacity-50' : '',
|
||||
)}
|
||||
>
|
||||
<span className='text-gray-800 pr-2'>{item.provider_type === CollectionType.builtIn ? item.provider_name : item.tool_label}</span>
|
||||
<Tooltip
|
||||
popupContent={t('tools.toolNameUsageTip')}
|
||||
>
|
||||
<span className='text-gray-500'>{item.tool_name}</span>
|
||||
</Tooltip>
|
||||
<span className='text-text-secondary system-xs-medium pr-1.5'>{item.provider_type === CollectionType.builtIn ? item.provider_name.split('/').pop() : item.tool_label}</span>
|
||||
<span className='text-text-tertiary'>{item.tool_name}</span>
|
||||
{!item.isDeleted && (
|
||||
<Tooltip
|
||||
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>
|
||||
}
|
||||
>
|
||||
<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>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='shrink-0 ml-1 flex items-center'>
|
||||
{(item.isDeleted || item.notAuthor)
|
||||
? (
|
||||
<div className='flex items-center'>
|
||||
<Tooltip
|
||||
popupContent={t(`tools.${item.isDeleted ? 'toolRemoved' : 'notAuthorized'}`)}
|
||||
needsDelay
|
||||
>
|
||||
<div className='mr-1 p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => {
|
||||
if (item.notAuthor)
|
||||
setIsShowChooseTool(true)
|
||||
}}>
|
||||
<AlertTriangle className='w-4 h-4 text-[#F79009]' />
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
<div className='p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => {
|
||||
{item.isDeleted && (
|
||||
<div className='flex items-center mr-2'>
|
||||
<Tooltip
|
||||
popupContent={t('tools.toolRemoved')}
|
||||
needsDelay
|
||||
>
|
||||
<div className='mr-1 p-1 rounded-md hover:bg-black/5 cursor-pointer'>
|
||||
<AlertTriangle className='w-4 h-4 text-[#F79009]' />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div
|
||||
className='p-1 rounded-md text-text-tertiary cursor-pointer hover:text-text-destructive'
|
||||
onClick={() => {
|
||||
const newModelConfig = produce(modelConfig, (draft) => {
|
||||
draft.agentConfig.tools.splice(index, 1)
|
||||
})
|
||||
setModelConfig(newModelConfig)
|
||||
formattingChangedDispatcher()
|
||||
}}>
|
||||
<RiDeleteBinLine className='w-4 h-4 text-gray-500' />
|
||||
</div>
|
||||
<div className='ml-2 mr-3 w-px h-3.5 bg-gray-200'></div>
|
||||
}}
|
||||
onMouseOver={() => setIsDeleting(index)}
|
||||
onMouseLeave={() => setIsDeleting(-1)}
|
||||
>
|
||||
<RiDeleteBinLine className='w-4 h-4' />
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<div className='hidden group-hover:flex items-center'>
|
||||
</div>
|
||||
)}
|
||||
{!item.isDeleted && (
|
||||
<div className='hidden group-hover:flex items-center gap-1 mr-2'>
|
||||
{!item.notAuthor && (
|
||||
<Tooltip
|
||||
popupContent={t('tools.setBuiltInTools.infoAndSetting')}
|
||||
needsDelay
|
||||
@ -164,55 +224,81 @@ const AgentTools: FC = () => {
|
||||
setCurrentTool(item)
|
||||
setIsShowSettingTool(true)
|
||||
}}>
|
||||
<InfoCircle className='w-4 h-4 text-gray-500' />
|
||||
<RiEqualizer2Line className='w-4 h-4 text-text-tertiary' />
|
||||
</div>
|
||||
</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) => {
|
||||
draft.agentConfig.tools.splice(index, 1)
|
||||
})
|
||||
setModelConfig(newModelConfig)
|
||||
formattingChangedDispatcher()
|
||||
}}>
|
||||
<RiDeleteBinLine className='w-4 h-4 text-gray-500' />
|
||||
</div>
|
||||
<div className='ml-2 mr-3 w-px h-3.5 bg-gray-200'></div>
|
||||
}}
|
||||
onMouseOver={() => setIsDeleting(index)}
|
||||
onMouseLeave={() => setIsDeleting(-1)}
|
||||
>
|
||||
<RiDeleteBinLine className='w-4 h-4' />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={cn(item.isDeleted && 'opacity-50')}>
|
||||
{!item.notAuthor && (
|
||||
<Switch
|
||||
defaultValue={item.isDeleted ? false : item.enabled}
|
||||
disabled={item.isDeleted}
|
||||
size='md'
|
||||
onChange={(enabled) => {
|
||||
const newModelConfig = produce(modelConfig, (draft) => {
|
||||
(draft.agentConfig.tools[index] as any).enabled = enabled
|
||||
})
|
||||
setModelConfig(newModelConfig)
|
||||
formattingChangedDispatcher()
|
||||
}} />
|
||||
)}
|
||||
{item.notAuthor && (
|
||||
<Button variant='secondary' size='small' onClick={() => {
|
||||
setCurrentTool(item)
|
||||
setShowSettingAuth(true)
|
||||
}}>
|
||||
{t('tools.notAuthorized')}
|
||||
<Indicator className='ml-2' color='orange' />
|
||||
</Button>
|
||||
)}
|
||||
<div className={cn((item.isDeleted || item.notAuthor) && 'opacity-50')}>
|
||||
<Switch
|
||||
defaultValue={(item.isDeleted || item.notAuthor) ? false : item.enabled}
|
||||
disabled={(item.isDeleted || item.notAuthor)}
|
||||
size='md'
|
||||
onChange={(enabled) => {
|
||||
const newModelConfig = produce(modelConfig, (draft) => {
|
||||
(draft.agentConfig.tools[index] as any).enabled = enabled
|
||||
})
|
||||
setModelConfig(newModelConfig)
|
||||
formattingChangedDispatcher()
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div >
|
||||
</Panel >
|
||||
{isShowChooseTool && (
|
||||
<AddToolModal onHide={() => setIsShowChooseTool(false)} />
|
||||
{isShowSettingTool && (
|
||||
<SettingBuiltInTool
|
||||
toolName={currentTool?.tool_name as string}
|
||||
setting={currentTool?.tool_parameters as any}
|
||||
collection={currentTool?.collection as Collection}
|
||||
isBuiltIn={currentTool?.collection?.type === CollectionType.builtIn}
|
||||
isModel={currentTool?.collection?.type === CollectionType.model}
|
||||
onSave={handleToolSettingChange}
|
||||
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)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{
|
||||
isShowSettingTool && (
|
||||
<SettingBuiltInTool
|
||||
toolName={currentTool?.tool_name as string}
|
||||
setting={currentTool?.tool_parameters as any}
|
||||
collection={currentTool?.collection as Collection}
|
||||
isBuiltIn={currentTool?.collection?.type === CollectionType.builtIn}
|
||||
isModel={currentTool?.collection?.type === CollectionType.model}
|
||||
onSave={handleToolSettingChange}
|
||||
onHide={() => setIsShowSettingTool(false)}
|
||||
/>)
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -3,21 +3,30 @@ import type { FC } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import cn from '@/utils/classnames'
|
||||
import Drawer from '@/app/components/base/drawer-plus'
|
||||
import {
|
||||
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 { addDefaultValue, toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
|
||||
import type { Collection, Tool } from '@/app/components/tools/types'
|
||||
import { CollectionType } from '@/app/components/tools/types'
|
||||
import { fetchBuiltInToolList, fetchCustomToolList, fetchModelToolList, fetchWorkflowToolList } from '@/service/tools'
|
||||
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 AppIcon from '@/app/components/base/app-icon'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
showBackButton?: boolean
|
||||
collection: Collection
|
||||
isBuiltIn?: boolean
|
||||
isModel?: boolean
|
||||
@ -29,6 +38,7 @@ type Props = {
|
||||
}
|
||||
|
||||
const SettingBuiltInTool: FC<Props> = ({
|
||||
showBackButton = false,
|
||||
collection,
|
||||
isBuiltIn = true,
|
||||
isModel = true,
|
||||
@ -96,39 +106,38 @@ const SettingBuiltInTool: FC<Props> = ({
|
||||
return valid
|
||||
})()
|
||||
|
||||
const infoUI = (
|
||||
<div className='pt-2'>
|
||||
<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>
|
||||
const getType = (type: string) => {
|
||||
if (type === 'number-input')
|
||||
return t('tools.setBuiltInTools.number')
|
||||
if (type === 'text-input')
|
||||
return t('tools.setBuiltInTools.string')
|
||||
if (type === 'file')
|
||||
return t('tools.setBuiltInTools.file')
|
||||
return type
|
||||
}
|
||||
|
||||
const infoUI = (
|
||||
<div className=''>
|
||||
{infoSchemas.length > 0 && (
|
||||
<div className='mt-6'>
|
||||
<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) => (
|
||||
<div key={index}>
|
||||
<div className='flex items-center space-x-2 leading-[18px]'>
|
||||
<div className='text-[13px] font-semibold text-gray-900'>{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>
|
||||
{item.required && (
|
||||
<div className='text-xs font-medium text-[#EC4A0A]'>{t('tools.setBuiltInTools.required')}</div>
|
||||
)}
|
||||
<div className='py-2 space-y-1'>
|
||||
{infoSchemas.map((item: any, index) => (
|
||||
<div key={index} className='py-1'>
|
||||
<div className='flex items-center gap-2'>
|
||||
<div className='text-text-secondary code-sm-semibold'>{item.label[language]}</div>
|
||||
<div className='text-text-tertiary system-xs-regular'>
|
||||
{getType(item.type)}
|
||||
</div>
|
||||
{item.human_description && (
|
||||
<div className='mt-1 leading-[18px] text-xs font-normal text-gray-600'>
|
||||
{item.human_description?.[language]}
|
||||
</div>
|
||||
{item.required && (
|
||||
<div className='text-text-warning-secondary system-xs-medium'>{t('tools.setBuiltInTools.required')}</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{item.human_description && (
|
||||
<div className='mt-0.5 text-text-tertiary system-xs-regular'>
|
||||
{item.human_description?.[language]}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -149,75 +158,82 @@ const SettingBuiltInTool: FC<Props> = ({
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
isShow
|
||||
onHide={onHide}
|
||||
title={(
|
||||
<div className='flex items-center'>
|
||||
{typeof collection.icon === 'string'
|
||||
? (
|
||||
<div
|
||||
className='w-6 h-6 bg-cover bg-center rounded-md flex-shrink-0'
|
||||
style={{
|
||||
backgroundImage: `url(${collection.icon})`,
|
||||
}}
|
||||
></div>
|
||||
)
|
||||
: (
|
||||
<AppIcon
|
||||
className='rounded-md'
|
||||
size='tiny'
|
||||
icon={(collection.icon as any)?.content}
|
||||
background={(collection.icon as any)?.background}
|
||||
/>
|
||||
)}
|
||||
|
||||
<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>}
|
||||
isOpen
|
||||
clickOutsideNotOpen={false}
|
||||
onClose={onHide}
|
||||
footer={null}
|
||||
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>
|
||||
<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>
|
||||
)}
|
||||
panelClassName='mt-[65px] !w-[405px]'
|
||||
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}
|
||||
</div>
|
||||
{!readonly && !isInfoActive && (
|
||||
<div className='mt-2 shrink-0 flex justify-end py-4 px-6 space-x-2 rounded-b-[10px] bg-gray-50 border-t border-black/5'>
|
||||
<Button className='flex items-center h-8 !px-3 !text-[13px] font-medium !text-gray-700' onClick={onHide}>{t('common.operation.cancel')}</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>
|
||||
{showBackButton && (
|
||||
<div
|
||||
className='mb-2 flex items-center gap-1 text-text-accent-secondary system-xs-semibold-uppercase cursor-pointer'
|
||||
onClick={onHide}
|
||||
>
|
||||
<RiArrowLeftLine className='w-4 h-4' />
|
||||
BACK
|
||||
</div>
|
||||
)}
|
||||
</div>)}
|
||||
</div>
|
||||
}
|
||||
isShowMask={false}
|
||||
clickOutsideNotOpen={false}
|
||||
/>
|
||||
<div className='flex items-center gap-1'>
|
||||
<Icon size='tiny' className='w-6 h-6' src={collection.icon} />
|
||||
<OrgInfo
|
||||
packageNameClassName='w-auto'
|
||||
orgName={collection.author}
|
||||
packageName={collection.name.split('/').pop() || ''}
|
||||
/>
|
||||
</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>
|
||||
{/* 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>
|
||||
)}
|
||||
<div className='grow h-0 overflow-y-auto px-4'>
|
||||
{isInfoActive ? infoUI : settingUI}
|
||||
</div>
|
||||
{!readonly && !isInfoActive && (
|
||||
<div className='mt-2 shrink-0 flex justify-end py-4 px-6 space-x-2 rounded-b-[10px] bg-components-panel-bg border-t border-divider-regular'>
|
||||
<Button className='flex items-center h-8 !px-3 !text-[13px] font-medium !text-gray-700' onClick={onHide}>{t('common.operation.cancel')}</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>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</Drawer>
|
||||
)
|
||||
}
|
||||
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 { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
|
||||
export type IGetAutomaticResProps = {
|
||||
export interface IGetAutomaticResProps {
|
||||
mode: AppType
|
||||
model: Model
|
||||
isShow: boolean
|
||||
|
||||
@ -12,7 +12,7 @@ import AgentTools from './agent/agent-tools'
|
||||
import ConfigContext from '@/context/debug-configuration'
|
||||
import ConfigPrompt from '@/app/components/app/configuration/config-prompt'
|
||||
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 { ModelModeType } from '@/types/app'
|
||||
|
||||
|
||||
@ -140,11 +140,11 @@ const ParamsConfig = ({
|
||||
/>
|
||||
|
||||
<div className='mt-6 flex justify-end'>
|
||||
<Button className='mr-2 flex-shrink-0' onClick={() => {
|
||||
<Button className='mr-2 shrink-0' onClick={() => {
|
||||
setTempDataSetConfigs(datasetConfigs)
|
||||
setRerankSettingModalOpen(false)
|
||||
}}>{t('common.operation.cancel')}</Button>
|
||||
<Button variant='primary' className='flex-shrink-0' onClick={handleSave} >{t('common.operation.save')}</Button>
|
||||
<Button variant='primary' className='shrink-0' onClick={handleSave} >{t('common.operation.save')}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
|
||||
@ -33,7 +33,7 @@ import { ModelTypeEnum } from '@/app/components/header/account-setting/model-pro
|
||||
import { fetchMembers } from '@/service/common'
|
||||
import type { Member } from '@/models/common'
|
||||
|
||||
type SettingsModalProps = {
|
||||
interface SettingsModalProps {
|
||||
currentDataset: DataSet
|
||||
onCancel: () => void
|
||||
onSave: (newDataset: DataSet) => void
|
||||
|
||||
@ -31,7 +31,7 @@ import { useFeatures } from '@/app/components/base/features/hooks'
|
||||
import type { InputForm } from '@/app/components/base/chat/chat/type'
|
||||
import { getLastAnswer } from '@/app/components/base/chat/utils'
|
||||
|
||||
type ChatItemProps = {
|
||||
interface ChatItemProps {
|
||||
modelAndParameter: ModelAndParameter
|
||||
}
|
||||
const ChatItem: FC<ChatItemProps> = ({
|
||||
|
||||
@ -15,7 +15,7 @@ import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { useFeatures } from '@/app/components/base/features/hooks'
|
||||
|
||||
type TextGenerationItemProps = {
|
||||
interface TextGenerationItemProps {
|
||||
modelAndParameter: ModelAndParameter
|
||||
}
|
||||
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 type { InputForm } from '@/app/components/base/chat/chat/type'
|
||||
|
||||
type DebugWithSingleModelProps = {
|
||||
interface DebugWithSingleModelProps {
|
||||
checkCanSend?: () => boolean
|
||||
}
|
||||
export type DebugWithSingleModelRefType = {
|
||||
export interface DebugWithSingleModelRefType {
|
||||
handleRestart: () => void
|
||||
}
|
||||
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 { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
|
||||
type IDebug = {
|
||||
interface IDebug {
|
||||
isAPIKeySet: boolean
|
||||
onSetting: () => void
|
||||
inputs: Inputs
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
/* eslint-disable multiline-ternary */
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
|
||||
@ -59,7 +59,7 @@ import {
|
||||
useTextGenerationCurrentProviderAndModelAndModelList,
|
||||
} from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
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 {
|
||||
getMultipleRetrievalConfig,
|
||||
@ -71,6 +71,8 @@ import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
|
||||
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
|
||||
import NewFeaturePanel from '@/app/components/base/features/new-feature-panel'
|
||||
import { fetchFileUploadConfig } from '@/service/common'
|
||||
import { correctProvider } from '@/utils'
|
||||
import PluginDependency from '@/app/components/workflow/plugin-dependency'
|
||||
|
||||
type PublishConfig = {
|
||||
modelConfig: ModelConfig
|
||||
@ -156,7 +158,7 @@ const Configuration: FC = () => {
|
||||
const setCompletionParams = (value: FormValue) => {
|
||||
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)) {
|
||||
params.stop = getTempStop()
|
||||
setTempStop([])
|
||||
@ -165,7 +167,7 @@ const Configuration: FC = () => {
|
||||
}
|
||||
|
||||
const [modelConfig, doSetModelConfig] = useState<ModelConfig>({
|
||||
provider: 'openai',
|
||||
provider: 'langgenius/openai/openai',
|
||||
model_id: 'gpt-3.5-turbo',
|
||||
mode: ModelModeType.unset,
|
||||
configs: {
|
||||
@ -188,7 +190,7 @@ const Configuration: FC = () => {
|
||||
|
||||
const isAgent = mode === 'agent-chat'
|
||||
|
||||
const isOpenAI = modelConfig.provider === 'openai'
|
||||
const isOpenAI = modelConfig.provider === 'langgenius/openai/openai'
|
||||
|
||||
const [collectionList, setCollectionList] = useState<Collection[]>([])
|
||||
useEffect(() => {
|
||||
@ -361,7 +363,7 @@ const Configuration: FC = () => {
|
||||
const [canReturnToSimpleMode, setCanReturnToSimpleMode] = useState(true)
|
||||
const setPromptMode = async (mode: PromptMode) => {
|
||||
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()
|
||||
setCanReturnToSimpleMode(true)
|
||||
}
|
||||
@ -547,8 +549,19 @@ const Configuration: FC = () => {
|
||||
if (modelConfig.retriever_resource)
|
||||
setCitationConfig(modelConfig.retriever_resource)
|
||||
|
||||
if (modelConfig.annotation_reply)
|
||||
setAnnotationConfig(modelConfig.annotation_reply, true)
|
||||
if (modelConfig.annotation_reply) {
|
||||
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)
|
||||
setModerationConfig(modelConfig.sensitive_word_avoidance)
|
||||
@ -558,7 +571,7 @@ const Configuration: FC = () => {
|
||||
|
||||
const config = {
|
||||
modelConfig: {
|
||||
provider: model.provider,
|
||||
provider: correctProvider(model.provider),
|
||||
model_id: model.name,
|
||||
mode: model.mode,
|
||||
configs: {
|
||||
@ -600,7 +613,6 @@ const Configuration: FC = () => {
|
||||
annotation_reply: modelConfig.annotation_reply,
|
||||
external_data_tools: modelConfig.external_data_tools,
|
||||
dataSets: datasets || [],
|
||||
// eslint-disable-next-line multiline-ternary
|
||||
agentConfig: res.mode === 'agent-chat' ? {
|
||||
max_iteration: DEFAULT_AGENT_SETTING.max_iteration,
|
||||
...modelConfig.agent_mode,
|
||||
@ -611,8 +623,12 @@ const Configuration: FC = () => {
|
||||
}).map((tool: any) => {
|
||||
return {
|
||||
...tool,
|
||||
isDeleted: res.deleted_tools?.includes(tool.tool_name),
|
||||
isDeleted: res.deleted_tools?.some((deletedTool: any) => deletedTool.id === tool.id && deletedTool.tool_name === tool.tool_name),
|
||||
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,
|
||||
@ -633,6 +649,12 @@ const Configuration: FC = () => {
|
||||
retrieval_model: RETRIEVE_TYPE.multiWay,
|
||||
...modelConfig.dataset_configs,
|
||||
...retrievalConfig,
|
||||
...(retrievalConfig.reranking_model ? {
|
||||
reranking_model: {
|
||||
...retrievalConfig.reranking_model,
|
||||
reranking_provider_name: correctProvider(modelConfig.dataset_configs.reranking_model.reranking_provider_name),
|
||||
},
|
||||
} : {}),
|
||||
})
|
||||
setHasFetchedDetail(true)
|
||||
})
|
||||
@ -1020,6 +1042,7 @@ const Configuration: FC = () => {
|
||||
onAutoAddPromptVariable={handleAddPromptVariable}
|
||||
/>
|
||||
)}
|
||||
<PluginDependency />
|
||||
</>
|
||||
</FeaturesProvider>
|
||||
</ConfigContext.Provider>
|
||||
|
||||
@ -23,7 +23,7 @@ import { DEFAULT_VALUE_MAX_LEN } from '@/config'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
export type IPromptValuePanelProps = {
|
||||
export interface IPromptValuePanelProps {
|
||||
appType: AppType
|
||||
onSend?: () => void
|
||||
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'
|
||||
|
||||
const systemTypes = ['api']
|
||||
type ExternalDataToolModalProps = {
|
||||
interface ExternalDataToolModalProps {
|
||||
data: ExternalDataTool
|
||||
onCancel: () => void
|
||||
onSave: (externalDataTool: ExternalDataTool) => void
|
||||
onValidateBeforeSave?: (externalDataTool: ExternalDataTool) => boolean
|
||||
}
|
||||
type Provider = {
|
||||
interface Provider {
|
||||
key: string
|
||||
name: string
|
||||
form_schema?: CodeBasedExtensionItem['form_schema']
|
||||
|
||||
@ -25,6 +25,7 @@ import AppsFull from '@/app/components/billing/apps-full-in-dialog'
|
||||
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
||||
import { getRedirection } from '@/utils/app-redirection'
|
||||
import cn from '@/utils/classnames'
|
||||
import { usePluginDependencies } from '@/app/components/workflow/plugin-dependency/hooks'
|
||||
|
||||
type CreateFromDSLModalProps = {
|
||||
show: boolean
|
||||
@ -50,6 +51,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
||||
const [showErrorModal, setShowErrorModal] = useState(false)
|
||||
const [versions, setVersions] = useState<{ importedVersion: string; systemVersion: string }>()
|
||||
const [importId, setImportId] = useState<string>()
|
||||
const { handleCheckPluginDependencies } = usePluginDependencies()
|
||||
|
||||
const readFile = (file: File) => {
|
||||
const reader = new FileReader()
|
||||
@ -114,6 +116,8 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
||||
children: status === DSLImportStatus.COMPLETED_WITH_WARNINGS && t('app.newApp.appCreateDSLWarning'),
|
||||
})
|
||||
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||
if (app_id)
|
||||
await handleCheckPluginDependencies(app_id)
|
||||
getRedirection(isCurrentWorkspaceEditor, { id: app_id }, push)
|
||||
}
|
||||
else if (status === DSLImportStatus.PENDING) {
|
||||
@ -132,6 +136,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
catch (e) {
|
||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
}
|
||||
@ -158,6 +163,8 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
||||
type: 'success',
|
||||
message: t('app.newApp.appCreated'),
|
||||
})
|
||||
if (app_id)
|
||||
await handleCheckPluginDependencies(app_id)
|
||||
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||
getRedirection(isCurrentWorkspaceEditor, { id: app_id }, push)
|
||||
}
|
||||
@ -165,6 +172,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
catch (e) {
|
||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
}
|
||||
@ -268,7 +276,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
||||
>
|
||||
<div className='flex pb-4 flex-col items-start gap-2 self-stretch'>
|
||||
<div className='text-text-primary title-2xl-semi-bold'>{t('app.newApp.appCreateDSLErrorTitle')}</div>
|
||||
<div className='flex flex-grow flex-col text-text-secondary system-md-regular'>
|
||||
<div className='flex grow flex-col text-text-secondary system-md-regular'>
|
||||
<div>{t('app.newApp.appCreateDSLErrorPart1')}</div>
|
||||
<div>{t('app.newApp.appCreateDSLErrorPart2')}</div>
|
||||
<br />
|
||||
|
||||
@ -13,7 +13,7 @@ import { useProviderContext } from '@/context/provider-context'
|
||||
import AppsFull from '@/app/components/billing/apps-full-in-dialog'
|
||||
import type { AppIconType } from '@/types/app'
|
||||
|
||||
export type DuplicateAppModalProps = {
|
||||
export interface DuplicateAppModalProps {
|
||||
appName: string
|
||||
icon_type: AppIconType | null
|
||||
icon: string
|
||||
|
||||
@ -79,6 +79,9 @@ const HandThumbIconWithCount: FC<{ count: number; iconType: 'up' | 'down' }> = (
|
||||
}
|
||||
|
||||
const statusTdRender = (statusCount: StatusCount) => {
|
||||
if (!statusCount)
|
||||
return null
|
||||
|
||||
if (statusCount.partial_success + statusCount.failed === 0) {
|
||||
return (
|
||||
<div className='inline-flex items-center gap-1 system-xs-semibold-uppercase'>
|
||||
|
||||
@ -27,8 +27,8 @@ const APIKeyInfoPanel: FC = () => {
|
||||
return null
|
||||
|
||||
return (
|
||||
<div className={cn('bg-[#EFF4FF] border-[#D1E0FF]', 'mb-6 relative rounded-2xl shadow-md border p-8 ')}>
|
||||
<div className={cn('text-[24px] text-gray-800 font-semibold', isCloud ? 'flex items-center h-8 space-x-1' : 'leading-8 mb-6')}>
|
||||
<div className={cn('bg-components-panel-bg border-components-panel-border', 'mb-6 relative rounded-2xl shadow-md border p-8 ')}>
|
||||
<div className={cn('text-[24px] text-text-primary font-semibold', isCloud ? 'flex items-center h-8 space-x-1' : 'leading-8 mb-6')}>
|
||||
{isCloud && <em-emoji id={'😀'} />}
|
||||
{isCloud
|
||||
? (
|
||||
@ -42,11 +42,11 @@ const APIKeyInfoPanel: FC = () => {
|
||||
)}
|
||||
</div>
|
||||
{isCloud && (
|
||||
<div className='mt-1 text-sm text-gray-600 font-normal'>{t(`appOverview.apiKeyInfo.cloud.${'trial'}.description`)}</div>
|
||||
<div className='mt-1 text-sm text-text-tertiary font-normal'>{t(`appOverview.apiKeyInfo.cloud.${'trial'}.description`)}</div>
|
||||
)}
|
||||
<Button
|
||||
variant='primary'
|
||||
className='space-x-2'
|
||||
className='mt-2 space-x-2'
|
||||
onClick={() => setShowAccountSettingModal({ payload: 'provider' })}
|
||||
>
|
||||
<div className='text-sm font-medium'>{t('appOverview.apiKeyInfo.setAPIBtn')}</div>
|
||||
@ -65,7 +65,7 @@ const APIKeyInfoPanel: FC = () => {
|
||||
<div
|
||||
onClick={() => setIsShow(false)}
|
||||
className='absolute right-4 top-4 flex items-center justify-center w-8 h-8 cursor-pointer '>
|
||||
<RiCloseLine className='w-4 h-4 text-gray-500' />
|
||||
<RiCloseLine className='w-4 h-4 text-text-tertiary' />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import s from './style.module.css'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
export type IProgressProps = {
|
||||
className?: string
|
||||
value: number // percent
|
||||
}
|
||||
|
||||
const Progress: FC<IProgressProps> = ({
|
||||
className,
|
||||
value,
|
||||
}) => {
|
||||
const exhausted = value === 100
|
||||
return (
|
||||
<div className={cn(className, 'relative grow h-2 flex bg-gray-200 rounded-md overflow-hidden')}>
|
||||
<div
|
||||
className={cn(s.bar, exhausted && s['bar-error'], 'absolute top-0 left-0 right-0 bottom-0')}
|
||||
style={{ width: `${value}%` }}
|
||||
/>
|
||||
{Array(10).fill(0).map((i, k) => (
|
||||
<div key={k} className={s['bar-item']} />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(Progress)
|
||||
@ -1,16 +0,0 @@
|
||||
.bar {
|
||||
background: linear-gradient(90deg, rgba(41, 112, 255, 0.9) 0%, rgba(21, 94, 239, 0.9) 100%);
|
||||
}
|
||||
|
||||
.bar-error {
|
||||
background: linear-gradient(90deg, rgba(240, 68, 56, 0.72) 0%, rgba(217, 45, 32, 0.9) 100%);
|
||||
}
|
||||
|
||||
.bar-item {
|
||||
width: 10%;
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.bar-item:last-of-type {
|
||||
border-right: 0;
|
||||
}
|
||||
@ -1,6 +1,9 @@
|
||||
'use client'
|
||||
import type { HTMLProps } from 'react'
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import {
|
||||
RiLoopLeftLine,
|
||||
} from '@remixicon/react'
|
||||
import {
|
||||
Cog8ToothIcon,
|
||||
DocumentTextIcon,
|
||||
@ -16,24 +19,25 @@ import style from './style.module.css'
|
||||
import type { ConfigParams } from './settings'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import AppBasic from '@/app/components/app-sidebar/basic'
|
||||
import { asyncRunSafe, randomString } from '@/utils'
|
||||
import { asyncRunSafe } from '@/utils'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Tag from '@/app/components/base/tag'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import CopyFeedback from '@/app/components/base/copy-feedback'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import Confirm from '@/app/components/base/confirm'
|
||||
import ShareQRCode from '@/app/components/base/qrcode'
|
||||
import SecretKeyButton from '@/app/components/develop/secret-key/secret-key-button'
|
||||
import type { AppDetailResponse } from '@/models/app'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import type { AppSSO } from '@/types/app'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
export type IAppCardProps = {
|
||||
className?: string
|
||||
appInfo: AppDetailResponse & Partial<AppSSO>
|
||||
cardType?: 'api' | 'webapp'
|
||||
customBgColor?: string
|
||||
onChangeStatus: (val: boolean) => Promise<void>
|
||||
onSaveSiteConfig?: (params: ConfigParams) => Promise<void>
|
||||
onGenerateCode?: () => Promise<void>
|
||||
@ -46,7 +50,6 @@ const EmbedIcon = ({ className = '' }: HTMLProps<HTMLDivElement>) => {
|
||||
function AppCard({
|
||||
appInfo,
|
||||
cardType = 'webapp',
|
||||
customBgColor,
|
||||
onChangeStatus,
|
||||
onSaveSiteConfig,
|
||||
onGenerateCode,
|
||||
@ -92,10 +95,6 @@ function AppCard({
|
||||
const appUrl = `${app_base_url}/${appMode}/${access_token}`
|
||||
const apiUrl = appInfo?.api_base_url
|
||||
|
||||
let bgColor = 'bg-primary-50 bg-opacity-40'
|
||||
if (cardType === 'api')
|
||||
bgColor = 'bg-purple-50'
|
||||
|
||||
const genClickFuncByName = (opName: string) => {
|
||||
switch (opName) {
|
||||
case t('appOverview.overview.appInfo.preview'):
|
||||
@ -133,11 +132,8 @@ function AppCard({
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
`shadow-xs border-[0.5px] rounded-lg border-gray-200 ${className ?? ''}`}
|
||||
>
|
||||
<div className={`px-6 py-5 ${customBgColor ?? bgColor} rounded-lg`}>
|
||||
<div className={cn('rounded-xl border-effects-highlight border-t border-l-[0.5px] bg-background-default', className)}>
|
||||
<div className={cn('px-6 py-5')}>
|
||||
<div className="mb-2.5 flex flex-row items-start justify-between">
|
||||
<AppBasic
|
||||
iconType={cardType}
|
||||
@ -161,23 +157,20 @@ function AppCard({
|
||||
</div>
|
||||
<div className="flex flex-col justify-center py-2">
|
||||
<div className="py-1">
|
||||
<div className="pb-1 text-xs text-gray-500">
|
||||
<div className="pb-1 text-xs text-text-tertiary">
|
||||
{isApp
|
||||
? t('appOverview.overview.appInfo.accessibleAddress')
|
||||
: t('appOverview.overview.apiInfo.accessibleAddress')}
|
||||
</div>
|
||||
<div className="w-full h-9 pl-2 pr-0.5 py-0.5 bg-black bg-opacity-2 rounded-lg border border-black border-opacity-5 justify-start items-center inline-flex">
|
||||
<div className="w-full h-9 px-2 py-0.5 bg-components-input-bg-normal rounded-lg justify-start items-center inline-flex">
|
||||
<div className="h-4 px-2 justify-start items-start gap-2 flex flex-1 min-w-0">
|
||||
<div className="text-gray-700 text-xs font-medium text-ellipsis overflow-hidden whitespace-nowrap">
|
||||
<div className="text-text-secondary system-xs-medium truncate">
|
||||
{isApp ? appUrl : apiUrl}
|
||||
</div>
|
||||
</div>
|
||||
<Divider type="vertical" className="!h-3.5 shrink-0 !mx-0.5" />
|
||||
{isApp && <ShareQRCode content={isApp ? appUrl : apiUrl} selectorId={randomString(8)} className={'hover:bg-gray-200'} />}
|
||||
<CopyFeedback
|
||||
content={isApp ? appUrl : apiUrl}
|
||||
className={'hover:bg-gray-200'}
|
||||
/>
|
||||
<Divider type="vertical" className="!h-3.5 shrink-0" />
|
||||
{isApp && <ShareQRCode content={isApp ? appUrl : apiUrl} />}
|
||||
<CopyFeedback content={isApp ? appUrl : apiUrl}/>
|
||||
{/* button copy link/ button regenerate */}
|
||||
{showConfirmDelete && (
|
||||
<Confirm
|
||||
@ -196,22 +189,16 @@ function AppCard({
|
||||
<Tooltip
|
||||
popupContent={t('appOverview.overview.appInfo.regenerate') || ''}
|
||||
>
|
||||
<div
|
||||
className="w-8 h-8 ml-0.5 cursor-pointer hover:bg-gray-200 rounded-lg"
|
||||
onClick={() => setShowConfirmDelete(true)}
|
||||
>
|
||||
<div
|
||||
className={
|
||||
`w-full h-full ${style.refreshIcon} ${genLoading ? style.generateLogo : ''}`}
|
||||
></div>
|
||||
</div>
|
||||
<ActionButton onClick={() => setShowConfirmDelete(true)}>
|
||||
<RiLoopLeftLine className={cn('w-4 h-4', genLoading && 'animate-spin')} />
|
||||
</ActionButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={'pt-2 flex flex-row items-center flex-wrap gap-y-2'}>
|
||||
{!isApp && <SecretKeyButton className='flex-shrink-0 !h-8 bg-white mr-2' textCls='!text-gray-700 font-medium' iconCls='stroke-[1.2px]' appId={appInfo.id} />}
|
||||
{!isApp && <SecretKeyButton className='shrink-0 !h-8 mr-2' textCls='!text-text-secondary font-medium' iconCls='stroke-[1.2px]' appId={appInfo.id} />}
|
||||
{OPERATIONS_MAP[cardType].map((op) => {
|
||||
const disabled
|
||||
= op.opName === t('appOverview.overview.appInfo.settings.entry')
|
||||
|
||||
@ -216,8 +216,8 @@ const Chart: React.FC<IChartProps> = ({
|
||||
return `<div style='color:#6B7280;font-size:12px'>${params.name}</div>
|
||||
<div style='font-size:14px;color:#1F2A37'>${valueFormatter((params.data as any)[yField])}
|
||||
${!CHART_TYPE_CONFIG[chartType].showTokens
|
||||
? ''
|
||||
: `<span style='font-size:12px'>
|
||||
? ''
|
||||
: `<span style='font-size:12px'>
|
||||
<span style='margin-left:4px;color:#6B7280'>(</span>
|
||||
<span style='color:#FF8A4C'>~$${get(params.data, 'total_price', 0)}</span>
|
||||
<span style='color:#6B7280'>)</span>
|
||||
@ -231,7 +231,7 @@ const Chart: React.FC<IChartProps> = ({
|
||||
const sumData = isAvg ? (sum(yData) / yData.length) : sum(yData)
|
||||
|
||||
return (
|
||||
<div className={`flex flex-col w-full px-6 py-4 border-[0.5px] rounded-lg border-gray-200 shadow-xs ${className ?? ''}`}>
|
||||
<div className={`flex flex-col w-full px-6 py-4 rounded-xl bg-components-chart-bg shadow-xs ${className ?? ''}`}>
|
||||
<div className='mb-3'>
|
||||
<Basic name={title} type={timePeriod} hoverTip={explanation} />
|
||||
</div>
|
||||
@ -242,11 +242,11 @@ const Chart: React.FC<IChartProps> = ({
|
||||
type={!CHART_TYPE_CONFIG[chartType].showTokens
|
||||
? ''
|
||||
: <span>{t('appOverview.analysis.tokenUsage.consumed')} Tokens<span className='text-sm'>
|
||||
<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-gray-500'>)</span>
|
||||
<span className='ml-1 text-text-tertiary'>(</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-text-tertiary'>)</span>
|
||||
</span></span>}
|
||||
textStyle={{ main: `!text-3xl !font-normal ${sumData === 0 ? '!text-gray-300' : ''}` }} />
|
||||
textStyle={{ main: `!text-3xl !font-normal ${sumData === 0 ? '!text-text-quaternary' : ''}` }} />
|
||||
</div>
|
||||
<ReactECharts option={options} style={{ height: 160 }} />
|
||||
</div>
|
||||
|
||||
@ -21,7 +21,7 @@ type IShareLinkProps = {
|
||||
}
|
||||
|
||||
const StepNum: FC<{ children: React.ReactNode }> = ({ children }) =>
|
||||
<div className='h-7 w-7 flex justify-center items-center flex-shrink-0 mr-3 text-primary-600 bg-primary-50 rounded-2xl'>
|
||||
<div className='h-7 w-7 flex justify-center items-center shrink-0 mr-3 text-text-accent bg-util-colors-blue-blue-50 rounded-2xl'>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@ -54,27 +54,27 @@ const CustomizeModal: FC<IShareLinkProps> = ({
|
||||
className='!max-w-2xl w-[640px]'
|
||||
closable={true}
|
||||
>
|
||||
<div className='w-full mt-4 px-6 py-5 border-gray-200 rounded-lg border-[0.5px]'>
|
||||
<Tag bordered={true} hideBg={true} className='text-primary-600 border-primary-600 uppercase'>{t(`${prefixCustomize}.way`)} 1</Tag>
|
||||
<p className='my-2 text-base font-medium text-gray-800'>{t(`${prefixCustomize}.way1.name`)}</p>
|
||||
<div className='w-full mt-4 px-6 py-5 border-components-panel-border rounded-lg border-[0.5px]'>
|
||||
<Tag bordered={true} hideBg={true} className='text-text-accent-secondary border-text-accent-secondary uppercase'>{t(`${prefixCustomize}.way`)} 1</Tag>
|
||||
<p className='my-2 system-sm-medium text-text-secondary'>{t(`${prefixCustomize}.way1.name`)}</p>
|
||||
<div className='flex py-4'>
|
||||
<StepNum>1</StepNum>
|
||||
<div className='flex flex-col'>
|
||||
<div className='text-gray-900'>{t(`${prefixCustomize}.way1.step1`)}</div>
|
||||
<div className='text-gray-500 text-xs mt-1 mb-2'>{t(`${prefixCustomize}.way1.step1Tip`)}</div>
|
||||
<div className='text-text-primary'>{t(`${prefixCustomize}.way1.step1`)}</div>
|
||||
<div className='text-text-tertiary text-xs mt-1 mb-2'>{t(`${prefixCustomize}.way1.step1Tip`)}</div>
|
||||
<a href={`https://github.com/langgenius/${isChatApp ? 'webapp-conversation' : 'webapp-text-generator'}`} target='_blank' rel='noopener noreferrer'>
|
||||
<Button><GithubIcon className='text-gray-800 mr-2' />{t(`${prefixCustomize}.way1.step1Operation`)}</Button>
|
||||
<Button><GithubIcon className='text-text-secondary mr-2' />{t(`${prefixCustomize}.way1.step1Operation`)}</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex pt-4'>
|
||||
<StepNum>2</StepNum>
|
||||
<div className='flex flex-col'>
|
||||
<div className='text-gray-900'>{t(`${prefixCustomize}.way1.step3`)}</div>
|
||||
<div className='text-gray-500 text-xs mt-1 mb-2'>{t(`${prefixCustomize}.way1.step2Tip`)}</div>
|
||||
<div className='text-text-primary'>{t(`${prefixCustomize}.way1.step3`)}</div>
|
||||
<div className='text-text-tertiary text-xs mt-1 mb-2'>{t(`${prefixCustomize}.way1.step2Tip`)}</div>
|
||||
<a href="https://vercel.com/docs/concepts/deployments/git/vercel-for-github" target='_blank' rel='noopener noreferrer'>
|
||||
<Button>
|
||||
<div className='mr-1.5 border-solid border-t-0 border-r-[7px] border-l-[7px] border-b-[12px] border-r-transparent border-b-black border-l-transparent border-t-transparent'></div>
|
||||
<div className='mr-1.5 border-solid border-t-0 border-r-[7px] border-l-[7px] border-b-[12px] border-r-transparent border-text-primary border-l-transparent border-t-transparent'></div>
|
||||
<span>{t(`${prefixCustomize}.way1.step2Operation`)}</span>
|
||||
</Button>
|
||||
</a>
|
||||
@ -83,9 +83,9 @@ const CustomizeModal: FC<IShareLinkProps> = ({
|
||||
<div className='flex py-4'>
|
||||
<StepNum>3</StepNum>
|
||||
<div className='flex flex-col w-full overflow-hidden'>
|
||||
<div className='text-gray-900'>{t(`${prefixCustomize}.way1.step3`)}</div>
|
||||
<div className='text-gray-500 text-xs mt-1 mb-2'>{t(`${prefixCustomize}.way1.step3Tip`)}</div>
|
||||
<pre className='overflow-x-scroll box-border py-3 px-4 bg-gray-100 text-xs font-medium rounded-lg select-text'>
|
||||
<div className='text-text-primary'>{t(`${prefixCustomize}.way1.step3`)}</div>
|
||||
<div className='text-text-tertiary text-xs mt-1 mb-2'>{t(`${prefixCustomize}.way1.step3Tip`)}</div>
|
||||
<pre className='overflow-x-scroll box-border py-3 px-4 bg-background-section text-xs font-medium rounded-lg select-text text-text-secondary border-[0.5px] border-components-panel-border'>
|
||||
NEXT_PUBLIC_APP_ID={`'${appId}'`} <br />
|
||||
NEXT_PUBLIC_APP_KEY={'\'<Web API Key From Dify>\''} <br />
|
||||
NEXT_PUBLIC_API_URL={`'${api_base_url}'`}
|
||||
@ -94,9 +94,9 @@ const CustomizeModal: FC<IShareLinkProps> = ({
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className='w-full mt-4 px-6 py-5 border-gray-200 rounded-lg border-[0.5px]'>
|
||||
<Tag bordered={true} hideBg={true} className='text-primary-600 border-primary-600 uppercase'>{t(`${prefixCustomize}.way`)} 2</Tag>
|
||||
<p className='mt-2 text-base font-medium text-gray-800'>{t(`${prefixCustomize}.way2.name`)}</p>
|
||||
<div className='w-full mt-4 px-6 py-5 border-components-panel-border rounded-lg border-[0.5px]'>
|
||||
<Tag bordered={true} hideBg={true} className='text-text-accent-secondary border-text-accent-secondary uppercase'>{t(`${prefixCustomize}.way`)} 2</Tag>
|
||||
<p className='my-2 system-sm-medium text-text-secondary'>{t(`${prefixCustomize}.way2.name`)}</p>
|
||||
<Button
|
||||
className='mt-2'
|
||||
onClick={() =>
|
||||
@ -109,8 +109,8 @@ const CustomizeModal: FC<IShareLinkProps> = ({
|
||||
)
|
||||
}
|
||||
>
|
||||
<span className='text-sm text-gray-800'>{t(`${prefixCustomize}.way2.operation`)}</span>
|
||||
<ArrowTopRightOnSquareIcon className='w-4 h-4 ml-1 text-gray-800 shrink-0' />
|
||||
<span className='text-sm text-text-secondary'>{t(`${prefixCustomize}.way2.operation`)}</span>
|
||||
<ArrowTopRightOnSquareIcon className='w-4 h-4 ml-1 text-text-secondary shrink-0' />
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
@ -1,15 +1,19 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiClipboardFill,
|
||||
RiClipboardLine,
|
||||
} from '@remixicon/react'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import style from './style.module.css'
|
||||
import cn from '@/utils/classnames'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import copyStyle from '@/app/components/base/copy-btn/style.module.css'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { IS_CE_EDITION } from '@/config'
|
||||
import type { SiteInfo } from '@/models/share'
|
||||
import { useThemeContext } from '@/app/components/base/chat/embedded-chatbot/theme/theme-context'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
siteInfo?: SiteInfo
|
||||
@ -35,12 +39,12 @@ const OPTION_MAP = {
|
||||
`<script>
|
||||
window.difyChatbotConfig = {
|
||||
token: '${token}'${isTestEnv
|
||||
? `,
|
||||
? `,
|
||||
isDev: true`
|
||||
: ''}${IS_CE_EDITION
|
||||
? `,
|
||||
: ''}${IS_CE_EDITION
|
||||
? `,
|
||||
baseUrl: '${url}'`
|
||||
: ''}
|
||||
: ''}
|
||||
}
|
||||
</script>
|
||||
<script
|
||||
@ -119,7 +123,7 @@ const Embedded = ({ siteInfo, isShow, onClose, appBaseUrl, accessToken, classNam
|
||||
wrapperClassName={className}
|
||||
closable={true}
|
||||
>
|
||||
<div className="mb-4 mt-8 text-gray-900 text-[14px] font-medium leading-tight">
|
||||
<div className="mb-4 mt-8 text-text-primary system-sm-medium">
|
||||
{t(`${prefixEmbedded}.explanation`)}
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center justify-between gap-y-2">
|
||||
@ -143,30 +147,37 @@ const Embedded = ({ siteInfo, isShow, onClose, appBaseUrl, accessToken, classNam
|
||||
{option === 'chromePlugin' && (
|
||||
<div className="w-full mt-6">
|
||||
<div className={cn('gap-2 py-3 justify-center items-center inline-flex w-full rounded-lg',
|
||||
'bg-primary-600 hover:bg-primary-600/75 hover:shadow-md cursor-pointer text-white hover:shadow-sm flex-shrink-0')}>
|
||||
'bg-primary-600 hover:bg-primary-600/75 cursor-pointer text-white hover:shadow-sm flex-shrink-0')}>
|
||||
<div className={`w-4 h-4 relative ${style.pluginInstallIcon}`}></div>
|
||||
<div className="text-white text-sm font-medium font-['Inter'] leading-tight" onClick={navigateToChromeUrl}>{t(`${prefixEmbedded}.chromePlugin`)}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={cn('w-full bg-gray-100 rounded-lg flex-col justify-start items-start inline-flex',
|
||||
<div className={cn('w-full bg-background-section border-[0.5px] border-components-panel-border rounded-lg flex-col justify-start items-start inline-flex',
|
||||
'mt-6')}>
|
||||
<div className="inline-flex items-center self-stretch justify-start gap-2 py-1 pl-3 pr-1 border border-black rounded-tl-lg rounded-tr-lg bg-gray-50 border-opacity-5">
|
||||
<div className="grow shrink basis-0 text-slate-700 text-[13px] font-medium leading-none">
|
||||
<div className="inline-flex items-center self-stretch justify-start gap-2 py-1 pl-3 pr-1 rounded-t-lg bg-background-section-burn">
|
||||
<div className="grow shrink-0 text-text-secondary system-sm-medium">
|
||||
{t(`${prefixEmbedded}.${option}`)}
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-1 p-2 rounded-lg">
|
||||
<Tooltip
|
||||
popupContent={(isCopied[option] ? t(`${prefixEmbedded}.copied`) : t(`${prefixEmbedded}.copy`)) || ''}
|
||||
>
|
||||
<div className="w-8 h-8 rounded-lg cursor-pointer hover:bg-gray-100">
|
||||
<div onClick={onClickCopy} className={`w-full h-full ${copyStyle.copyIcon} ${isCopied[option] ? copyStyle.copied : ''}`}></div>
|
||||
<Tooltip
|
||||
popupContent={
|
||||
(isCopied[option]
|
||||
? t(`${prefixEmbedded}.copied`)
|
||||
: t(`${prefixEmbedded}.copy`)) || ''
|
||||
}
|
||||
>
|
||||
<ActionButton>
|
||||
<div
|
||||
onClick={onClickCopy}
|
||||
>
|
||||
{isCopied[option] && <RiClipboardFill className='w-4 h-4' />}
|
||||
{!isCopied[option] && <RiClipboardLine className='w-4 h-4' />}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</ActionButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="flex items-start justify-start w-full gap-2 p-3 overflow-x-auto">
|
||||
<div className="grow shrink basis-0 text-slate-700 text-[13px] leading-tight font-mono">
|
||||
<div className="grow shrink basis-0 text-text-secondary text-[13px] leading-tight font-mono">
|
||||
<pre className='select-text'>{OPTION_MAP[option].getContent(appBaseUrl, accessToken, themeBuilder.theme?.primaryColor ?? '#1C64F2', isTestEnv)}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -5,7 +5,6 @@ import { ChevronRightIcon } from '@heroicons/react/20/solid'
|
||||
import Link from 'next/link'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { useContextSelector } from 'use-context-selector'
|
||||
import s from './style.module.css'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Input from '@/app/components/base/input'
|
||||
@ -21,6 +20,8 @@ import Tooltip from '@/app/components/base/tooltip'
|
||||
import AppContext, { useAppContext } from '@/context/app-context'
|
||||
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
||||
import AppIconPicker from '@/app/components/base/app-icon-picker'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
export type ISettingsModalProps = {
|
||||
isChat: boolean
|
||||
@ -195,9 +196,9 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
||||
title={t(`${prefixSettings}.title`)}
|
||||
isShow={isShow}
|
||||
onClose={onHide}
|
||||
className={`${s.settingsModal}`}
|
||||
className='max-w-[520px]'
|
||||
>
|
||||
<div className={`mt-6 font-medium ${s.settingTitle} text-gray-900`}>{t(`${prefixSettings}.webName`)}</div>
|
||||
<div className={cn('mt-6 system-sm-semibold text-text-secondary')}>{t(`${prefixSettings}.webName`)}</div>
|
||||
<div className='flex mt-2'>
|
||||
<AppIcon size='large'
|
||||
onClick={() => { setShowAppIconPicker(true) }}
|
||||
@ -214,8 +215,8 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
||||
placeholder={t('app.appNamePlaceholder') || ''}
|
||||
/>
|
||||
</div>
|
||||
<div className={`mt-6 font-medium ${s.settingTitle} text-gray-900 `}>{t(`${prefixSettings}.webDesc`)}</div>
|
||||
<p className={`mt-1 ${s.settingsTip} text-gray-500`}>{t(`${prefixSettings}.webDescTip`)}</p>
|
||||
<div className={cn('mt-6 system-sm-semibold text-text-secondary')}>{t(`${prefixSettings}.webDesc`)}</div>
|
||||
<p className={cn('mt-1 body-xs-regular text-text-tertiary')}>{t(`${prefixSettings}.webDescTip`)}</p>
|
||||
<Textarea
|
||||
className='mt-2'
|
||||
value={inputInfo.desc}
|
||||
@ -225,36 +226,36 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
||||
{isChatBot && (
|
||||
<div className='w-full mt-4'>
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className={`font-medium ${s.settingTitle} text-gray-900 `}>{t('app.answerIcon.title')}</div>
|
||||
<div className={cn('system-sm-semibold text-text-secondary')}>{t('app.answerIcon.title')}</div>
|
||||
<Switch
|
||||
defaultValue={inputInfo.use_icon_as_answer_icon}
|
||||
onChange={v => setInputInfo({ ...inputInfo, use_icon_as_answer_icon: v })}
|
||||
/>
|
||||
</div>
|
||||
<p className='body-xs-regular text-gray-500'>{t('app.answerIcon.description')}</p>
|
||||
<p className='body-xs-regular text-text-tertiary'>{t('app.answerIcon.description')}</p>
|
||||
</div>
|
||||
)}
|
||||
<div className={`mt-6 mb-2 font-medium ${s.settingTitle} text-gray-900 `}>{t(`${prefixSettings}.language`)}</div>
|
||||
<div className={cn('mt-6 mb-2 system-sm-semibold text-text-secondary')}>{t(`${prefixSettings}.language`)}</div>
|
||||
<SimpleSelect
|
||||
items={languages.filter(item => item.supported)}
|
||||
defaultValue={language}
|
||||
onSelect={item => setLanguage(item.value as Language)}
|
||||
/>
|
||||
<div className='w-full mt-8'>
|
||||
<p className='system-xs-medium text-gray-500'>{t(`${prefixSettings}.workflow.title`)}</p>
|
||||
<p className='system-xs-medium text-text-tertiary'>{t(`${prefixSettings}.workflow.title`)}</p>
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='font-medium system-sm-semibold flex-grow text-gray-900'>{t(`${prefixSettings}.workflow.subTitle`)}</div>
|
||||
<div className='font-medium system-sm-semibold grow text-text-primary'>{t(`${prefixSettings}.workflow.subTitle`)}</div>
|
||||
<Switch
|
||||
disabled={!(appInfo.mode === 'workflow' || appInfo.mode === 'advanced-chat')}
|
||||
defaultValue={inputInfo.show_workflow_steps}
|
||||
onChange={v => setInputInfo({ ...inputInfo, show_workflow_steps: v })}
|
||||
/>
|
||||
</div>
|
||||
<p className='body-xs-regular text-gray-500'>{t(`${prefixSettings}.workflow.showDesc`)}</p>
|
||||
<p className='body-xs-regular text-text-tertiary'>{t(`${prefixSettings}.workflow.showDesc`)}</p>
|
||||
</div>
|
||||
|
||||
{isChat && <> <div className={`mt-8 font-medium ${s.settingTitle} text-gray-900`}>{t(`${prefixSettings}.chatColorTheme`)}</div>
|
||||
<p className={`mt-1 ${s.settingsTip} text-gray-500`}>{t(`${prefixSettings}.chatColorThemeDesc`)}</p>
|
||||
{isChat && <> <div className={cn('mt-8 system-sm-semibold text-text-secondary')}>{t(`${prefixSettings}.chatColorTheme`)}</div>
|
||||
<p className='mt-1 body-xs-regular text-text-tertiary'>{t(`${prefixSettings}.chatColorThemeDesc`)}</p>
|
||||
<Input
|
||||
className='mt-2 h-10'
|
||||
value={inputInfo.chatColorTheme ?? ''}
|
||||
@ -262,14 +263,14 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
||||
placeholder='E.g #A020F0'
|
||||
/>
|
||||
<div className="mt-1 flex justify-between items-center">
|
||||
<p className={`ml-2 ${s.settingsTip} text-gray-500`}>{t(`${prefixSettings}.chatColorThemeInverted`)}</p>
|
||||
<p className='ml-2 body-xs-regular text-text-tertiary'>{t(`${prefixSettings}.chatColorThemeInverted`)}</p>
|
||||
<Switch defaultValue={inputInfo.chatColorThemeInverted} onChange={v => setInputInfo({ ...inputInfo, chatColorThemeInverted: v })}></Switch>
|
||||
</div>
|
||||
</>}
|
||||
{systemFeatures.enable_web_sso_switch_component && <div className='w-full mt-8'>
|
||||
<p className='system-xs-medium text-gray-500'>{t(`${prefixSettings}.sso.label`)}</p>
|
||||
<p className='system-xs-medium text-text-tertiary'>{t(`${prefixSettings}.sso.label`)}</p>
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='font-medium system-sm-semibold flex-grow text-gray-900'>{t(`${prefixSettings}.sso.title`)}</div>
|
||||
<div className='system-sm-semibold grow text-text-secondary'>{t(`${prefixSettings}.sso.title`)}</div>
|
||||
<Tooltip
|
||||
disabled={systemFeatures.sso_enforced_for_web}
|
||||
popupContent={
|
||||
@ -280,31 +281,31 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
||||
<Switch disabled={!systemFeatures.sso_enforced_for_web || !isCurrentWorkspaceEditor} defaultValue={systemFeatures.sso_enforced_for_web && inputInfo.enable_sso} onChange={v => setInputInfo({ ...inputInfo, enable_sso: v })}></Switch>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<p className='body-xs-regular text-gray-500'>{t(`${prefixSettings}.sso.description`)}</p>
|
||||
<p className='body-xs-regular text-text-tertiary'>{t(`${prefixSettings}.sso.description`)}</p>
|
||||
</div>}
|
||||
{!isShowMore && <div className='w-full cursor-pointer mt-8' onClick={() => setIsShowMore(true)}>
|
||||
<div className='flex justify-between'>
|
||||
<div className={`font-medium ${s.settingTitle} flex-grow text-gray-900`}>{t(`${prefixSettings}.more.entry`)}</div>
|
||||
<div className='flex-shrink-0 w-4 h-4 text-gray-500'>
|
||||
<div className='system-sm-semibold text-text-secondary'>{t(`${prefixSettings}.more.entry`)}</div>
|
||||
<div className='shrink-0 w-4 h-4 text-text-tertiary'>
|
||||
<ChevronRightIcon />
|
||||
</div>
|
||||
</div>
|
||||
<p className={`mt-1 ${s.policy} text-gray-500`}>{t(`${prefixSettings}.more.copyright`)} & {t(`${prefixSettings}.more.privacyPolicy`)}</p>
|
||||
<p className='mt-1 body-xs-regular text-text-tertiary'>{t(`${prefixSettings}.more.copyright`)} & {t(`${prefixSettings}.more.privacyPolicy`)}</p>
|
||||
</div>}
|
||||
{isShowMore && <>
|
||||
<hr className='w-full mt-6' />
|
||||
<div className={`mt-6 font-medium ${s.settingTitle} text-gray-900`}>{t(`${prefixSettings}.more.copyright`)}</div>
|
||||
<Divider className='my-6' />
|
||||
<div className='system-sm-semibold text-text-secondary'>{t(`${prefixSettings}.more.copyright`)}</div>
|
||||
<Input
|
||||
className='mt-2 h-10'
|
||||
value={inputInfo.copyright}
|
||||
onChange={onChange('copyright')}
|
||||
placeholder={t(`${prefixSettings}.more.copyRightPlaceholder`) as string}
|
||||
/>
|
||||
<div className={`mt-8 font-medium ${s.settingTitle} text-gray-900`}>{t(`${prefixSettings}.more.privacyPolicy`)}</div>
|
||||
<p className={`mt-1 ${s.settingsTip} text-gray-500`}>
|
||||
<div className='mt-8 system-sm-semibold text-text-secondary'>{t(`${prefixSettings}.more.privacyPolicy`)}</div>
|
||||
<p className='mt-1 body-xs-regular text-text-tertiary'>
|
||||
<Trans
|
||||
i18nKey={`${prefixSettings}.more.privacyPolicyTip`}
|
||||
components={{ privacyPolicyLink: <Link href={'https://docs.dify.ai/user-agreement/privacy-policy'} target='_blank' rel='noopener noreferrer' className='text-primary-600' /> }}
|
||||
components={{ privacyPolicyLink: <Link href={'https://docs.dify.ai/user-agreement/privacy-policy'} target='_blank' rel='noopener noreferrer' className='text-text-accent' /> }}
|
||||
/>
|
||||
</p>
|
||||
<Input
|
||||
@ -313,8 +314,8 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
||||
onChange={onChange('privacyPolicy')}
|
||||
placeholder={t(`${prefixSettings}.more.privacyPolicyPlaceholder`) as string}
|
||||
/>
|
||||
<div className={`mt-8 font-medium ${s.settingTitle} text-gray-900`}>{t(`${prefixSettings}.more.customDisclaimer`)}</div>
|
||||
<p className={`mt-1 ${s.settingsTip} text-gray-500`}>{t(`${prefixSettings}.more.customDisclaimerTip`)}</p>
|
||||
<div className='mt-8 system-sm-semibold text-text-secondary'>{t(`${prefixSettings}.more.customDisclaimer`)}</div>
|
||||
<p className='mt-1 body-xs-regular text-text-tertiary'>{t(`${prefixSettings}.more.customDisclaimerTip`)}</p>
|
||||
<Input
|
||||
className='mt-2 h-10'
|
||||
value={inputInfo.customDisclaimer}
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
.settingsModal {
|
||||
max-width: 32.5rem !important;
|
||||
}
|
||||
|
||||
.settingTitle {
|
||||
line-height: 21px;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.settingsTip {
|
||||
line-height: 1.125rem;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.policy {
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.125rem;
|
||||
}
|
||||
@ -2,7 +2,7 @@ import { create } from 'zustand'
|
||||
import type { App, AppSSO } from '@/types/app'
|
||||
import type { IChatItem } from '@/app/components/base/chat/chat/type'
|
||||
|
||||
type State = {
|
||||
interface State {
|
||||
appDetail?: App & Partial<AppSSO>
|
||||
appSidebarExpand: string
|
||||
currentLogItem?: IChatItem
|
||||
@ -13,7 +13,7 @@ type State = {
|
||||
showAppConfigureFeaturesModal: boolean
|
||||
}
|
||||
|
||||
type Action = {
|
||||
interface Action {
|
||||
setAppDetail: (appDetail?: App & Partial<AppSSO>) => void
|
||||
setAppSiderbarExpand: (state: string) => 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 { useStore as useAppStore } from '@/app/components/app/store'
|
||||
|
||||
type SwitchAppModalProps = {
|
||||
interface SwitchAppModalProps {
|
||||
show: boolean
|
||||
appDetail: App
|
||||
onSuccess?: () => void
|
||||
|
||||
@ -33,7 +33,7 @@ import { useChatContext } from '@/app/components/base/chat/chat/context'
|
||||
|
||||
const MAX_DEPTH = 3
|
||||
|
||||
export type IGenerationItemProps = {
|
||||
export interface IGenerationItemProps {
|
||||
isWorkflow?: boolean
|
||||
workflowProcessData?: WorkflowProcess
|
||||
className?: string
|
||||
|
||||
@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { RiCloseLine } from '@remixicon/react'
|
||||
import Run from '@/app/components/workflow/run'
|
||||
|
||||
type ILogDetail = {
|
||||
interface ILogDetail {
|
||||
runID: string
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import type { QueryParam } from './index'
|
||||
import Chip from '@/app/components/base/chip'
|
||||
import Input from '@/app/components/base/input'
|
||||
|
||||
type IFilterProps = {
|
||||
interface IFilterProps {
|
||||
queryParams: QueryParam
|
||||
setQueryParams: (v: QueryParam) => void
|
||||
}
|
||||
|
||||
@ -2,9 +2,7 @@
|
||||
|
||||
@layer components {
|
||||
.action-btn {
|
||||
@apply inline-flex justify-center items-center cursor-pointer text-text-tertiary
|
||||
hover:text-text-secondary
|
||||
hover:bg-state-base-hover
|
||||
@apply inline-flex justify-center items-center cursor-pointer text-text-tertiary hover:text-text-secondary hover:bg-state-base-hover
|
||||
}
|
||||
|
||||
.action-btn-disabled {
|
||||
@ -29,21 +27,15 @@
|
||||
}
|
||||
|
||||
.action-btn.action-btn-active {
|
||||
@apply
|
||||
text-text-accent
|
||||
bg-state-accent-active
|
||||
hover:bg-state-accent-active-alt
|
||||
@apply text-text-accent bg-state-accent-active hover:bg-state-accent-active-alt
|
||||
}
|
||||
|
||||
.action-btn.action-btn-disabled {
|
||||
@apply
|
||||
text-text-disabled
|
||||
@apply text-text-disabled
|
||||
}
|
||||
|
||||
.action-btn.action-btn-destructive {
|
||||
@apply
|
||||
text-text-destructive
|
||||
bg-state-destructive-hover
|
||||
@apply text-text-destructive bg-state-destructive-hover
|
||||
}
|
||||
|
||||
}
|
||||
@ -28,7 +28,7 @@ const actionButtonVariants = cva(
|
||||
)
|
||||
|
||||
export type ActionButtonProps = {
|
||||
size?: 'xs' | 'm' | 'l' | 'xl'
|
||||
size?: 'xs' | 's' | 'm' | 'l' | 'xl'
|
||||
state?: ActionButtonState
|
||||
styleCss?: CSSProperties
|
||||
} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof actionButtonVariants>
|
||||
|
||||
23
web/app/components/base/app-icon/style.module.css
Normal file
23
web/app/components/base/app-icon/style.module.css
Normal file
@ -0,0 +1,23 @@
|
||||
.appIcon {
|
||||
@apply flex items-center justify-center relative w-9 h-9 text-lg rounded-lg grow-0 shrink-0;
|
||||
}
|
||||
|
||||
.appIcon.large {
|
||||
@apply w-10 h-10;
|
||||
}
|
||||
|
||||
.appIcon.small {
|
||||
@apply w-8 h-8;
|
||||
}
|
||||
|
||||
.appIcon.tiny {
|
||||
@apply w-6 h-6 text-base;
|
||||
}
|
||||
|
||||
.appIcon.xs {
|
||||
@apply w-5 h-5 text-base;
|
||||
}
|
||||
|
||||
.appIcon.rounded {
|
||||
@apply rounded-full;
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import AudioPlayer from '@/app/components/base/audio-btn/audio'
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||
// eslint-disable-next-line ts/consistent-type-definitions
|
||||
interface AudioPlayerManager {
|
||||
instance: AudioPlayerManager
|
||||
}
|
||||
@ -12,6 +12,7 @@ export class AudioPlayerManager {
|
||||
private audioPlayers: AudioPlayer | null = null
|
||||
private msgId: string | undefined
|
||||
|
||||
// eslint-disable-next-line
|
||||
private constructor() {
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ import Toast from '@/app/components/base/toast'
|
||||
import { textToAudioStream } from '@/service/share'
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||
// eslint-disable-next-line ts/consistent-type-definitions
|
||||
interface Window {
|
||||
ManagedMediaSource: any
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import Tooltip from '@/app/components/base/tooltip'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { AudioPlayerManager } from '@/app/components/base/audio-btn/audio.player.manager'
|
||||
|
||||
type AudioBtnProps = {
|
||||
interface AudioBtnProps {
|
||||
id?: string
|
||||
voice?: string
|
||||
value?: string
|
||||
|
||||
@ -2,15 +2,15 @@
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
background-color: var(--color-components-chat-input-audio-bg-alt);
|
||||
border-radius: 10px;
|
||||
padding: 8px;
|
||||
min-width: 240px;
|
||||
max-width: 420px;
|
||||
max-height: 40px;
|
||||
backdrop-filter: blur(5px);
|
||||
border: 1px solid rgba(16, 24, 40, 0.08);
|
||||
box-shadow: 0 1px 2px rgba(9, 9, 11, 0.05);
|
||||
border: 1px solid var(--color-components-panel-border-subtle);
|
||||
box-shadow: 0 1px 2px var(--color-shadow-shadow-3);
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
@ -19,8 +19,8 @@
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background-color: #296DFF;
|
||||
color: white;
|
||||
background-color: var(--color-components-button-primary-bg);
|
||||
color: var(--color-components-chat-input-audio-bg-alt);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
@ -30,16 +30,15 @@
|
||||
}
|
||||
|
||||
.playButton:hover {
|
||||
background-color: #3367d6;
|
||||
background-color: var(--color-components-button-primary-bg-hover);
|
||||
}
|
||||
|
||||
.playButton:disabled {
|
||||
background-color: #bdbdbf;
|
||||
background-color: var(--color-components-button-primary-bg-disabled);
|
||||
}
|
||||
|
||||
.audioControls {
|
||||
flex-grow: 1;
|
||||
|
||||
}
|
||||
|
||||
.progressBarContainer {
|
||||
@ -76,8 +75,8 @@
|
||||
|
||||
.timeDisplay {
|
||||
/* position: absolute; */
|
||||
color: #296DFF;
|
||||
border-radius: 2px;
|
||||
color: var(--color-text-accent-secondary);
|
||||
font-size: 12px;
|
||||
order: 0;
|
||||
height: 100%;
|
||||
width: 50px;
|
||||
@ -97,7 +96,6 @@
|
||||
} */
|
||||
|
||||
.duration {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
padding: 2px 4px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
@ -114,6 +112,6 @@
|
||||
}
|
||||
|
||||
.playButton svg path,
|
||||
.playButton svg rect{
|
||||
fill:currentColor;
|
||||
}
|
||||
.playButton svg rect {
|
||||
fill: currentColor;
|
||||
}
|
||||
@ -55,7 +55,7 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({ src }) => {
|
||||
audio.load()
|
||||
|
||||
// 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)
|
||||
|
||||
return () => {
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { memo } from 'react'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type BadgeProps = {
|
||||
className?: string
|
||||
text?: string
|
||||
children?: React.ReactNode
|
||||
text?: ReactNode
|
||||
children?: ReactNode
|
||||
uppercase?: boolean
|
||||
hasRedCornerMark?: boolean
|
||||
}
|
||||
|
||||
const Badge = ({
|
||||
@ -13,15 +15,20 @@ const Badge = ({
|
||||
text,
|
||||
children,
|
||||
uppercase = true,
|
||||
hasRedCornerMark,
|
||||
}: BadgeProps) => {
|
||||
return (
|
||||
<div
|
||||
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',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{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>
|
||||
)}
|
||||
{children || text}
|
||||
</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 cn from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
className?: string
|
||||
onClick: () => void
|
||||
}
|
||||
|
||||
@ -263,7 +263,7 @@ describe('build chat item tree and get thread messages', () => {
|
||||
expect(tree7).toMatchSnapshot()
|
||||
})
|
||||
|
||||
const partialMessages2 = (partialMessages as ChatItemInTree[])
|
||||
const partialMessages2 = partialMessages as ChatItemInTree[]
|
||||
const tree8 = buildChatItemTree(partialMessages2)
|
||||
it('should work with partial messages 2', () => {
|
||||
expect(tree8).toMatchSnapshot()
|
||||
|
||||
@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { memo } from 'react'
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
|
||||
type InputProps = {
|
||||
interface InputProps {
|
||||
form: any
|
||||
value: string
|
||||
onChange: (variable: string, value: string) => void
|
||||
|
||||
@ -16,7 +16,7 @@ import type {
|
||||
ConversationItem,
|
||||
} from '@/models/share'
|
||||
|
||||
export type ChatWithHistoryContextValue = {
|
||||
export interface ChatWithHistoryContextValue {
|
||||
appInfoError?: any
|
||||
appInfoLoading?: boolean
|
||||
appMeta?: AppMeta
|
||||
|
||||
@ -20,7 +20,7 @@ import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||
import { checkOrSetAccessToken } from '@/app/components/share/utils'
|
||||
import AppUnavailable from '@/app/components/base/app-unavailable'
|
||||
|
||||
type ChatWithHistoryProps = {
|
||||
interface ChatWithHistoryProps {
|
||||
className?: string
|
||||
}
|
||||
const ChatWithHistory: FC<ChatWithHistoryProps> = ({
|
||||
@ -99,7 +99,7 @@ const ChatWithHistory: FC<ChatWithHistoryProps> = ({
|
||||
)
|
||||
}
|
||||
|
||||
export type ChatWithHistoryWrapProps = {
|
||||
export interface ChatWithHistoryWrapProps {
|
||||
installedAppInfo?: InstalledApp
|
||||
className?: string
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user